diff --git a/config/11ty/shortcodes.js b/config/11ty/shortcodes.js index 94237c9f..78da2458 100644 --- a/config/11ty/shortcodes.js +++ b/config/11ty/shortcodes.js @@ -1,76 +1,4 @@ -import path from 'node:path'; -import image from '@11ty/eleventy-img'; -import dimensions from 'image-size'; -// biome-ignore lint/suspicious/noShadowRestrictedNames: Eh escape sounds better. -import escape from 'lodash.escape'; - -const IMAGE_OPTIMIZATION = - process.env.IMAGE_OPTIMIZATION === '0' || - process.env.IMAGE_OPTIMIZATION === 'false' - ? false - : true; - -const stringifyAttributes = (attrs) => - Object.entries(attrs) - .map(([attr, value]) => { - if (value === undefined || value === '') return ''; - return `${attr}="${value}"`; - }) - .join(' '); - -const insertImage = async function (source, alt) { - if (!source) throw new Error('Missing source for image shortcode'); - if (!alt) throw new Error('Missing alt for image shortcode'); - - source = path.join('images', `${this.page.fileSlug}/${source}`); - - const { width } = dimensions(source); - - const data = await image(source, { - widths: IMAGE_OPTIMIZATION - ? [640, 750, 828, 1080, 1200, 1920, 2048, 3840, width] - .filter((a) => a <= width) - .sort((a, b) => a - b) - : [width], - formats: IMAGE_OPTIMIZATION ? ['avif', 'webp', 'png'] : ['png'], - outputDir: 'dist/assets/images/', - urlPath: '/assets/images/', - }); - - const base = data['png'].at(-1); - const sizes = '(min-width: 80ch) 80ch, 100vw'; - - const sources = Object.values(data) - .map((formatEntries) => { - const { sourceType } = formatEntries[0]; - const srcset = formatEntries.map((image) => image.srcset).join(', '); - - return ``; - }) - .join('\n'); - - return ` - - ${sources} - - -`; -}; - export const shortcodes = (eleventyConfig) => { - eleventyConfig.addNunjucksAsyncShortcode('image', insertImage); eleventyConfig.addShortcode('log', (...args) => { console.log(...args); return ''; diff --git a/eleventy.config.js b/eleventy.config.js index 8ca2bb4c..65ad78cf 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -7,10 +7,10 @@ import pluginAutoCacheBuster from 'eleventy-auto-cache-buster'; import pluginIcons from 'eleventy-plugin-icons'; import pluginValidate from 'eleventy-plugin-validate'; -import { VentoPlugin } from 'eleventy-plugin-vento'; +import { VentoPlugin as pluginVento } from 'eleventy-plugin-vento'; +import { eleventyImageTransformPlugin as pluginImageTransform } from '@11ty/eleventy-img'; import markdownLibrary from './config/markdown/core.js'; - import { processCss, processSass, @@ -25,7 +25,6 @@ const isDevelopment = process.env.NODE_ENV !== 'production'; import colors from 'picocolors'; import site from './site.config.js'; - import eleventy from '11ty.ts'; export default eleventy(function (eleventyConfig) { @@ -80,7 +79,20 @@ export default eleventy(function (eleventyConfig) { }, ], }); - eleventyConfig.addPlugin(VentoPlugin); + eleventyConfig.addPlugin(pluginVento); + eleventyConfig.addPlugin(pluginImageTransform, { + widths: [640, 750, 828, 1080, 1200, 1920, 2048, 3840, 'auto'], + formats: ['avif', 'webp', 'png'], + outputDir: 'dist/assets/images/', + urlPath: '/assets/images/', + htmlOptions: { + imgAttributes: { + loading: 'lazy', + decoding: 'async', + }, + pictureAttributes: {}, + }, + }); /* Passthrough Copy */ eleventyConfig.addPassthroughCopy({ 'public/': '.' }); diff --git a/package.json b/package.json index 6b060a48..859ebcc3 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "11ty.ts": "^0.0.5", "@11ty/eleventy": "3.0.0", "@11ty/eleventy-fetch": "^5.0.1", - "@11ty/eleventy-img": "^5.0.0", + "@11ty/eleventy-img": "^6.0.1", "@aloskutov/eleventy-plugin-external-links": "^2.1.1", "@catppuccin/palette": "^1.7.1", "@ryanccn/eleventy-plugin-rss": "github:uncenter/ryanccn-eleventy-plugin-rss", @@ -29,10 +29,8 @@ "eleventy-plugin-validate": "^0.1.3", "eleventy-plugin-vento": "^4.0.1", "html-minifier": "^4.0.0", - "image-size": "^1.2.0", "lightningcss": "^1.28.2", "linkedom": "^0.18.6", - "lodash.escape": "^4.0.1", "lucide-static": "^0.469.0", "luxon": "^3.4.4", "markdown-it": "^14.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25978648..e204acd4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^5.0.1 version: 5.0.1 '@11ty/eleventy-img': - specifier: ^5.0.0 - version: 5.0.0 + specifier: ^6.0.1 + version: 6.0.1 '@aloskutov/eleventy-plugin-external-links': specifier: ^2.1.1 version: 2.1.1 @@ -59,18 +59,12 @@ importers: html-minifier: specifier: ^4.0.0 version: 4.0.0 - image-size: - specifier: ^1.2.0 - version: 1.2.0 lightningcss: specifier: ^1.28.2 version: 1.28.2 linkedom: specifier: ^0.18.6 version: 0.18.6 - lodash.escape: - specifier: ^4.0.1 - version: 4.0.1 lucide-static: specifier: ^0.469.0 version: 0.469.0 @@ -151,16 +145,16 @@ packages: engines: {node: '>=18'} hasBin: true - '@11ty/eleventy-fetch@4.0.1': - resolution: {integrity: sha512-yIiLM5ziBmg86i4TlXpBdcIygJHvh/GgPJyAiFOckO9H4y9cQDM8eIcJCUQ4Mum0NEVui/OjhEut2R08xw0vlQ==} - engines: {node: '>=14'} - '@11ty/eleventy-fetch@5.0.1': resolution: {integrity: sha512-n79UhOAWG7XcJkRIoV8cZBpKgGln6mn+2UgsZkP6Xjgg8BqiMfxlYMJrNobSDdw3utyRAs8w/ZAPXoc18qrvMw==} engines: {node: '>=18'} - '@11ty/eleventy-img@5.0.0': - resolution: {integrity: sha512-hJ4X5ZIRSOCooL0uXegj+nZi1abWNj22BR4PzF6e9iJg9DGYGxPrC0rg0Hy+7xzP7mzTYiOpDjZVv/NgrHNx6w==} + '@11ty/eleventy-fetch@5.0.2': + resolution: {integrity: sha512-yu7oZ5iv7zvFDawSYcN19cz7ddJB7OXPGZ47z/MzYmLa2LkpJm0KnZW2xGwpKvVrXd+tyb96ts6AqlkJT/ibwQ==} + engines: {node: '>=18'} + + '@11ty/eleventy-img@6.0.1': + resolution: {integrity: sha512-Ktr1C42cu7rHR7M0lT+JfMjWaOIwS2rXqzrXkNfKAEljgJxCPVg2vsWr5iyPBg2IL7OY8ipPCr5jbovMAz6B9w==} engines: {node: '>=18'} '@11ty/eleventy-plugin-bundle@3.0.0': @@ -171,6 +165,10 @@ packages: resolution: {integrity: sha512-nULO91om7vQw4Y/UBjM8i7nJ1xl+/nyK4rImZ41lFxiY2d+XUz7ChAj1CDYFjrLZeu0utAYJTZ45LlcHTkUG4g==} engines: {node: '>=12'} + '@11ty/eleventy-utils@2.0.0': + resolution: {integrity: sha512-rKny6X7+ARuke0TaA6FwNv2PWJCNSdPQqbqDgaZgi+bPXwnPRTEi3CWzvr6vVgh/1XpO1G4FhRPreLhtcwHUyg==} + engines: {node: '>=18'} + '@11ty/eleventy@3.0.0': resolution: {integrity: sha512-0P0ZsJXVW2QiNdhd7z+GYy6n+ivh0enx1DRdua5ta6NlzY2AhbkeWBY6U+FKA8lPS3H4+XsTpfLLfIScpPZLaQ==} engines: {node: '>=18'} @@ -834,6 +832,15 @@ packages: supports-color: optional: true + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -973,6 +980,10 @@ packages: resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==} engines: {node: '>=0.12'} + entities@6.0.0: + resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==} + engines: {node: '>=0.12'} + errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -1056,10 +1067,6 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - flat-cache@6.1.2: resolution: {integrity: sha512-WakhGOkx886u7DJGpgMpUU81VUYHyQlXuqPDI53g6lIVHf7Shepr/XGo7Qa0yYOPwyMItQs34dG7X0KgnHwWtQ==} @@ -1074,9 +1081,6 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1101,10 +1105,6 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -1196,10 +1196,6 @@ packages: immutable@5.0.3: resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1282,9 +1278,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - junk@1.0.3: resolution: {integrity: sha512-3KF80UaaSSxo8jVnRYtMKNGFOoVPBdkkVPsw+Ad0y4oxKXPduS6G6iHkrf69yJVff/VAaYXkV42rtZ7daJxU3w==} engines: {node: '>=0.10.0'} @@ -1298,9 +1291,6 @@ packages: just-typeof@3.2.0: resolution: {integrity: sha512-nOKazfzrQDEGNwXPfWEB64QD+ATZUnpOTJn0xMnCk41p297P9Emt3BlsRyWbu+CErMjopnFTGcYHJnvFX97ZIQ==} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - keyv@5.2.1: resolution: {integrity: sha512-tpIgCaY02VCW2Pz0zAn4guyct+IeH6Mb5wZdOvpe4oqXeQOJO0C3Wo8fTnf7P3ZD83Vr9kghbkNmzG3lTOhy/A==} @@ -1400,9 +1390,6 @@ packages: list-to-array@1.1.0: resolution: {integrity: sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==} - lodash.escape@4.0.1: - resolution: {integrity: sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==} - lower-case@1.1.4: resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} @@ -1569,15 +1556,6 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} @@ -1628,9 +1606,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - oniguruma-to-es@0.10.0: resolution: {integrity: sha512-zapyOUOCJxt+xhiNRPPMtfJkHGsZ98HHB9qJEkdT8BGytO/+kpe4m1Ngf0MzbzTmhacn11w9yGeDP6tzDhnCdg==} @@ -1665,10 +1640,6 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1833,11 +1804,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@5.0.10: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true @@ -2017,9 +1983,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - transform-ast@2.4.4: resolution: {integrity: sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==} @@ -2089,12 +2052,6 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2113,9 +2070,6 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -2180,38 +2134,37 @@ snapshots: - supports-color - utf-8-validate - '@11ty/eleventy-fetch@4.0.1': + '@11ty/eleventy-fetch@5.0.1': dependencies: + '@rgrove/parse-xml': 4.2.0 debug: 4.3.7 - flat-cache: 3.2.0 - node-fetch: 2.7.0 + flat-cache: 6.1.2 + graceful-fs: 4.2.11 p-queue: 6.6.2 transitivePeerDependencies: - - encoding - supports-color - '@11ty/eleventy-fetch@5.0.1': + '@11ty/eleventy-fetch@5.0.2': dependencies: '@rgrove/parse-xml': 4.2.0 - debug: 4.3.7 + debug: 4.4.0 flat-cache: 6.1.2 graceful-fs: 4.2.11 p-queue: 6.6.2 transitivePeerDependencies: - supports-color - '@11ty/eleventy-img@5.0.0': + '@11ty/eleventy-img@6.0.1': dependencies: - '@11ty/eleventy-fetch': 4.0.1 - '@11ty/eleventy-utils': 1.0.3 + '@11ty/eleventy-fetch': 5.0.2 + '@11ty/eleventy-utils': 2.0.0 brotli-size: 4.0.0 - debug: 4.3.7 - entities: 5.0.0 + debug: 4.4.0 + entities: 6.0.0 image-size: 1.2.0 p-queue: 6.6.2 sharp: 0.33.5 transitivePeerDependencies: - - encoding - supports-color '@11ty/eleventy-plugin-bundle@3.0.0(posthtml@0.16.6)': @@ -2226,6 +2179,8 @@ snapshots: dependencies: normalize-path: 3.0.0 + '@11ty/eleventy-utils@2.0.0': {} + '@11ty/eleventy@3.0.0': dependencies: '@11ty/dependency-tree': 3.0.1 @@ -2880,6 +2835,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.0: + dependencies: + ms: 2.1.3 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -3009,6 +2968,8 @@ snapshots: entities@5.0.0: {} + entities@6.0.0: {} + errno@0.1.8: dependencies: prr: 1.0.1 @@ -3087,12 +3048,6 @@ snapshots: transitivePeerDependencies: - supports-color - flat-cache@3.2.0: - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - rimraf: 3.0.2 - flat-cache@6.1.2: dependencies: cacheable: 1.8.4 @@ -3108,8 +3063,6 @@ snapshots: fresh@0.5.2: {} - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -3140,15 +3093,6 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 @@ -3261,11 +3205,6 @@ snapshots: immutable@5.0.3: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} is-alphabetical@2.0.1: {} @@ -3330,8 +3269,6 @@ snapshots: dependencies: argparse: 2.0.1 - json-buffer@3.0.1: {} - junk@1.0.3: {} just-extend@6.2.0: {} @@ -3340,10 +3277,6 @@ snapshots: just-typeof@3.2.0: {} - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - keyv@5.2.1: dependencies: '@keyv/serialize': 1.0.1 @@ -3423,8 +3356,6 @@ snapshots: list-to-array@1.1.0: {} - lodash.escape@4.0.1: {} - lower-case@1.1.4: {} lru-cache@10.4.3: {} @@ -3598,10 +3529,6 @@ snapshots: node-addon-api@7.1.1: optional: true - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - node-html-parser@6.1.13: dependencies: css-select: 5.1.0 @@ -3647,10 +3574,6 @@ snapshots: dependencies: ee-first: 1.1.1 - once@1.4.0: - dependencies: - wrappy: 1.0.2 - oniguruma-to-es@0.10.0: dependencies: emoji-regex-xs: 1.0.0 @@ -3687,8 +3610,6 @@ snapshots: parseurl@1.3.3: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -3840,10 +3761,6 @@ snapshots: reusify@1.0.4: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rimraf@5.0.10: dependencies: glob: 10.4.5 @@ -4082,8 +3999,6 @@ snapshots: toidentifier@1.0.1: {} - tr46@0.0.3: {} - transform-ast@2.4.4: dependencies: acorn-node: 1.8.2 @@ -4162,13 +4077,6 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - which@2.0.2: dependencies: isexe: 2.0.0 @@ -4189,8 +4097,6 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: {} - ws@8.18.0: {} xtend@4.0.2: {} diff --git a/src/layouts/base.vto b/src/layouts/base.vto index f547d6d3..488262e8 100644 --- a/src/layouts/base.vto +++ b/src/layouts/base.vto @@ -90,6 +90,7 @@ socialLinks:
Email from GitHub Trust & Safety - {% image "github-trust-and-safety-email.png", "Email from GitHub Trust & Safety (GitHub Support), dated Jan 4, 2024, 1:01PM UTC. Part of the email reads: Your GitHub and npm everything-registry orgs were disabled following reports of activity that may have been in violation of our Open Source Terms and GitHub Acceptable Use Policies." %} + +![Email from GitHub Trust & Safety (GitHub Support), dated Jan 4, 2024, 1:01PM UTC. Part of the email reads: Your GitHub and npm everything-registry orgs were disabled following reports of activity that may have been in violation of our Open Source Terms and GitHub Acceptable Use Policies.](./github-trust-and-safety-email.png) + All of [our scoped packages](https://www.npmjs.com/org/everything-registry) have been deleted, so unpublishing packages should no longer be an issue. @@ -28,19 +30,21 @@ Another note; this story was picked up by some media outlets in the cybersecurit
The aforementioned articles - {% image "sc-media-article.png", "Screenshot of SC Media's article titled 'NPM registry prank leaves developers unable to unpublish packages'" %} - {% image "checkmarx-article.png", "Screenshot of Checkmarx's article titled 'When Everything Goes Wrong: NPM Dependency-Hell Campaign - 2024 Edition'" %} - {% image "bleepingcomputer-article.png", "Screenshot of BleepingComputer's article titled 'everything blocks devs from removing their own npm packages'" %} + +![Screenshot of SC Media's article titled 'NPM registry prank leaves developers unable to unpublish packages'](./sc-media-article.png) +![Screenshot of Checkmarx's article titled 'When Everything Goes Wrong: NPM Dependency-Hell Campaign - 2024 Edition'](./checkmarx-article.png) +![Screenshot of BleepingComputer's article titled 'everything blocks devs from removing their own npm packages'](./bleepingcomputer-article.png) +
-{% image "tech-twitter-knows.png", "A meme with an angry man standing behind huge flames with the text: Now all of tech Twitter knows you broke NPM" %} +![A meme with an angry man standing behind huge flames with the text: Now all of tech Twitter knows you broke NPM](./tech-twitter-knows.png) ::: Ten years ago, [PatrickJS](https://github.com/PatrickJS) created the `everything` package on NPM, containing every package on the NPM registry in the first 5 years of the registry's existence. The package remained the same for years, but that all changed just a few days ago with [a single tweet](https://twitter.com/trashh_dev/status/1740756965905875311). -{% image "the-tweet.png", "Screenshot of trash's tweet saying 'the perfect repo doesn’t exi…' followed by a link to Patrick's node-everything repository" %} +![Screenshot of trash's tweet saying 'the perfect repo doesn’t exi…' followed by a link to Patrick's node-everything repository](./the-tweet.png) I saw the tweet on my timeline and [made a quick PR](https://github.com/everything-registry/everything/pull/6) to clean up a few things and help bring the repository up to speed. At the same time, Patrick had started an attempt to publish a `2.0.0` version of the package, but he discovered that there was now a `10` megabyte limit for the uncompressed size of a package. I [made a comment](https://github.com/everything-registry/everything/pull/6#issuecomment-1872278630) about the issue and we quickly [began brainstorming](https://github.com/everything-registry/everything/pull/6#issuecomment-1872294994) a solution. @@ -48,7 +52,7 @@ I saw the tweet on my timeline and [made a quick PR](https://github.com/everythi We moved to Twitter DMs, and by this time others who saw Trash's tweet wanted to join — [Hacksore](https://hacksore.com/), and Trash himself. We came up with a plan to divide the ~2.5m packages into "scoped" groups of packages; a group for packages starting with the letter "a", the letter "b", and the rest of the alphabet, and then the numbers "0" to "9", and finally an "other" category for anything else. Since each of these scoped packages would only be a subset of the total, they would easily pass the size limit, and the main `everything` package could just depend on each of these scoped packages. -{% image "plan-a.png", "A diagram of the core 'everything' package depending on many other scoped packages" %} +![A diagram of the core 'everything' package depending on many other scoped packages](./plan-a.png) ## Unforeseen issues @@ -58,21 +62,21 @@ We moved to Twitter DMs, and by this time others who saw Trash's tweet wanted to I suggested a new, very basic plan: just split them into "chunks" (groups) of 800 dependencies. -{% image "plan-b-initial.png", "A diagram of the core 'everything' package with arrows toward many 'chunked' packages" %} +![A diagram of the core 'everything' package with arrows toward many 'chunked' packages](./plan-b-initial.png) This leaves 3246 groups though, and 3246 is still too many for our main `everything` package to hold. So we simply "chunk" the 3246 groups of 800 into groups of 800 again. -{% image "plan-b.png", "A diagram of the core 'everything' package with arrows toward many 'chunked' packages, each of which in turn has arrows toward more 'sub-chunked' packages" %} +![A diagram of the core 'everything' package with arrows toward many 'chunked' packages, each of which in turn has arrows toward more 'sub-chunked' packages](./plan-b.png) ## 3...2...1... go! Set on our new plan, we updated the code and triggered [our GitHub Actions workflow](https://github.com/everything-registry/everything/blob/1aef5aa3aa5e3d0e2107063cad6ce63f9cba9b0b/.github/workflows/release.yml)... -{% image "plan-b-countdown.png", "Screenshot of chat messages in a Discord channel counting down before I triggered the workflow to publish our packages" %} +![Screenshot of chat messages in a Discord channel counting down before I triggered the workflow to publish our packages](./plan-b-countdown.png) It worked! The [GitHub Action logs](https://github.com/everything-registry/everything/actions/runs/7361935655/job/20039814620) rolled in, one after another, as the packages slowly got published. We had a brief scare after realizing that [GitHub Actions jobs and workflows have a maximum time](https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration) that we might reach, but some quick calculations revealed that we had no cause for worry. Workflow jobs time out after 6 hours, and at the current rate of one package published every ~4.5 seconds, we could comfortably publish 4,800+ packages in that time. -{% image "plan-b-success.png", "Screenshot of Discord chat messages where I sent the link of the first chunk package on NPM followed by excited reactions" %} +![Screenshot of Discord chat messages where I sent the link of the first chunk package on NPM followed by excited reactions](./plan-b-success.png) We all went back to doing other things, and I checked the logs occasionally. Half an hour later though, we ran into a different problem... we had been rate limited. In 32 minutes, we had published 454 packages: the main `everything` package, all five "chunks", but only 448 "sub-chunks". It was only a fraction (roughly 14%) of everything (hah, pun intended) we needed to publish. @@ -82,7 +86,7 @@ I [made a quick fix](https://github.com/everything-registry/everything/commit/1a So it began. Throughout the day I (very irregularly) manually dispatched the workflow. For a while, we sat and waited. We even began an effort to actually run `npm install everything` (well, `yarn add everything`) and put up a Twitch stream of the installation on a virtual machine. -{% image "twitch-stream.png", "Screenshot of a Twitch.tv live stream under the account BuildFailedTV, with the stream description 'install everything and chill'" %} +![Screenshot of a Twitch.tv live stream under the account BuildFailedTV, with the stream description 'install everything and chill'](./twitch-stream.png) We also [made a website](https://everything.npm.lol/)! Many thanks to the rest of the contributors I have mentioned so far, but notably [Evan Boehs](https://boehs.org/) for leading the charge and [PickleNik](https://github.com/PickleNik) made it look nice. @@ -96,13 +100,13 @@ The initial response to our endeavour was... not positive. People began coming t Thankfully, on the night of January 2^nd^, GitHub reached out and let us know they were aware of the problem. On the 3^rd^ of January, we received a notice that our GitHub organization had been "flagged" and our organization and repositories were hidden. Not what we wanted to see, but progress nonetheless. -{% image "org-flagged.png", "Screenshot of GitHub's permanent warning banner on my account. The text reads: The everything-registry organization has been flagged. Because of that, your organization is hidden from the public. If you believe this is a mistake, contact support to have your organization's status reviewed" %} +![Screenshot of GitHub's permanent warning banner on my account. The text reads: The everything-registry organization has been flagged. Because of that, your organization is hidden from the public. If you believe this is a mistake, contact support to have your organization's status reviewed](./org-flagged.png) They also began removing our organization's scoped packages on NPM, as we had suggested. The initial problem had been solved, but we are still waiting to see how NPM prevents this issue in the future. My two cents are that NPM should either a) prevent folks from publishing packages with star versions in the package.json entirely, or b) don't consider a dependent of a package if it uses a star version when tallying how many packages depend on a package for unpublishing. Lastly, I want to apologize for anyone frustrated, annoyed, or just angry at us. We made a mistake, and we've owned up to it. This all started as a harmless joke and we had no intentions of breaking, abusing, or doing any sort of damage to the registry. In short we, uhh... fucked around and found out. -{% image "fuck-around-find-out.jpg", "A man standing next to a whiteboard with a marker pointed towards a graph illustrating how if you fuck around, you find out" %} +![A man standing next to a whiteboard with a marker pointed towards a graph illustrating how if you fuck around, you find out](./fuck-around-find-out.jpg) Thanks for reading this, and have a lovely day! diff --git a/images/npm-install-everything/org-flagged.png b/src/posts/npm-install-everything/org-flagged.png similarity index 100% rename from images/npm-install-everything/org-flagged.png rename to src/posts/npm-install-everything/org-flagged.png diff --git a/images/npm-install-everything/plan-a.png b/src/posts/npm-install-everything/plan-a.png similarity index 100% rename from images/npm-install-everything/plan-a.png rename to src/posts/npm-install-everything/plan-a.png diff --git a/images/npm-install-everything/plan-b-countdown.png b/src/posts/npm-install-everything/plan-b-countdown.png similarity index 100% rename from images/npm-install-everything/plan-b-countdown.png rename to src/posts/npm-install-everything/plan-b-countdown.png diff --git a/images/npm-install-everything/plan-b-initial.png b/src/posts/npm-install-everything/plan-b-initial.png similarity index 100% rename from images/npm-install-everything/plan-b-initial.png rename to src/posts/npm-install-everything/plan-b-initial.png diff --git a/images/npm-install-everything/plan-b-success.png b/src/posts/npm-install-everything/plan-b-success.png similarity index 100% rename from images/npm-install-everything/plan-b-success.png rename to src/posts/npm-install-everything/plan-b-success.png diff --git a/images/npm-install-everything/plan-b.png b/src/posts/npm-install-everything/plan-b.png similarity index 100% rename from images/npm-install-everything/plan-b.png rename to src/posts/npm-install-everything/plan-b.png diff --git a/images/npm-install-everything/sc-media-article.png b/src/posts/npm-install-everything/sc-media-article.png similarity index 100% rename from images/npm-install-everything/sc-media-article.png rename to src/posts/npm-install-everything/sc-media-article.png diff --git a/images/npm-install-everything/tech-twitter-knows.png b/src/posts/npm-install-everything/tech-twitter-knows.png similarity index 100% rename from images/npm-install-everything/tech-twitter-knows.png rename to src/posts/npm-install-everything/tech-twitter-knows.png diff --git a/images/npm-install-everything/the-tweet.png b/src/posts/npm-install-everything/the-tweet.png similarity index 100% rename from images/npm-install-everything/the-tweet.png rename to src/posts/npm-install-everything/the-tweet.png diff --git a/images/npm-install-everything/twitch-stream.png b/src/posts/npm-install-everything/twitch-stream.png similarity index 100% rename from images/npm-install-everything/twitch-stream.png rename to src/posts/npm-install-everything/twitch-stream.png diff --git a/src/posts/spellchecking-with-eleventy.md b/src/posts/spellchecking-with-eleventy/index.md similarity index 98% rename from src/posts/spellchecking-with-eleventy.md rename to src/posts/spellchecking-with-eleventy/index.md index 4822a6ea..7975f307 100644 --- a/src/posts/spellchecking-with-eleventy.md +++ b/src/posts/spellchecking-with-eleventy/index.md @@ -107,7 +107,7 @@ If you're using Netlify, you can run this script and the spell-check script duri command = "node ./utils/get-repos.js && npm run spell && npm run build" ``` -{% image "netlify-build-command.png", "Screenshot of our new build command in the Netlify GUI" %} +![Screenshot of our new build command in the Netlify GUI](./netlify-build-command.png) ### Ignore patterns diff --git a/images/spellchecking-with-eleventy/netlify-build-command.png b/src/posts/spellchecking-with-eleventy/netlify-build-command.png similarity index 100% rename from images/spellchecking-with-eleventy/netlify-build-command.png rename to src/posts/spellchecking-with-eleventy/netlify-build-command.png