From 1856d4d7cf3c6abb65fd2f0d317fea4e3d272a10 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sat, 28 Feb 2026 19:37:53 -0500 Subject: [PATCH] feat(minify): use SWC --- .github/dependabot.yml | 2 +- npm-shrinkwrap.json | 33 +++++++++++---------- package.json | 2 +- src/generators/legacy-html-all/generate.mjs | 2 +- src/generators/legacy-html/generate.mjs | 2 +- src/generators/web/utils/processing.mjs | 5 +--- src/utils/html-minifier.mjs | 30 ++++++++----------- 7 files changed, 35 insertions(+), 41 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ce3bf491..ff2fcd54 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -62,7 +62,7 @@ updates: - 'recma-*' compiling: patterns: - - '@minify-html/wasm' + - '@swc/html-wasm' - '@rollup/*' - 'rolldown' - 'lightningcss-wasm' diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index a894096f..62330dcf 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -8,12 +8,12 @@ "dependencies": { "@actions/core": "^3.0.0", "@heroicons/react": "^2.2.0", - "@minify-html/wasm": "^0.18.1", "@node-core/rehype-shiki": "^1.4.0", "@node-core/ui-components": "^1.6.0", "@orama/orama": "^3.1.18", "@orama/ui": "^1.5.4", "@rollup/plugin-virtual": "^3.0.2", + "@swc/html-wasm": "^1.15.17", "acorn": "^8.15.0", "commander": "^14.0.3", "dedent": "^1.7.1", @@ -637,12 +637,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@minify-html/wasm": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/@minify-html/wasm/-/wasm-0.18.1.tgz", - "integrity": "sha512-GBkBOJxe7duO+z2b00SP83EewOI+Qm4MsnajXHw4yT7/J+TuG3jLEatBHKnT59Zq4CgXBRpdkv/2hlCGnyqAzg==", - "license": "MIT" - }, "node_modules/@napi-rs/nice": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", @@ -966,7 +960,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -1032,7 +1025,6 @@ "resolved": "https://registry.npmjs.org/@orama/cuid2/-/cuid2-2.2.3.tgz", "integrity": "sha512-Lcak3chblMejdlSHgYU2lS2cdOhDpU6vkfIJH4m+YKvqQyLqs1bB8+w6NT1MG5bO12NUK2GFc34Mn2xshMIQ1g==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "^1.1.5" } @@ -1050,8 +1042,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/@orama/oramacore-events-parser/-/oramacore-events-parser-0.0.5.tgz", "integrity": "sha512-yAuSwog+HQBAXgZ60TNKEwu04y81/09mpbYBCmz1RCxnr4ObNY2JnPZI7HmALbjAhLJ8t5p+wc2JHRK93ubO4w==", - "license": "AGPL-3.0", - "peer": true + "license": "AGPL-3.0" }, "node_modules/@orama/stopwords": { "version": "3.1.16", @@ -2438,6 +2429,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@swc/html-wasm": { + "version": "1.15.17", + "resolved": "https://registry.npmjs.org/@swc/html-wasm/-/html-wasm-1.15.17.tgz", + "integrity": "sha512-PPYHYcNhUI/uthaovwMChnrfwaLn588louTK/ds9HJsC2rOsncDYvYV0irHQ8St6G/d//O/8l3WK7yrmEYCTrg==", + "license": "Apache-2.0" + }, "node_modules/@tailwindcss/node": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", @@ -3257,6 +3254,7 @@ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", @@ -3646,6 +3644,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4187,8 +4186,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/debug": { "version": "4.4.3", @@ -4391,6 +4389,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7083,6 +7082,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -7132,6 +7132,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-11.0.0-beta.0.tgz", "integrity": "sha512-IcODoASASYwJ9kxz7+MJeiJhvLriwSb4y4mHIyxdgaRZp6kPUud7xytrk/6GZw8U3y6EFJaRb5wi9SrEK+8+lg==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -7634,8 +7635,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/semver": { "version": "7.7.3", @@ -8180,6 +8180,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8534,6 +8535,7 @@ "integrity": "sha512-VUyWiTNQD7itdiMuJy+EuLEErLj3uwX/EpHQF8EOf33Dq3Ju6VW1GXm+swk6+1h7a49uv9fKZ+dft9jU7esdLA==", "dev": true, "hasInstallScript": true, + "peer": true, "dependencies": { "napi-postinstall": "^0.2.4" }, @@ -8964,7 +8966,6 @@ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", "license": "ISC", - "peer": true, "peerDependencies": { "zod": "^3.24.1" } diff --git a/package.json b/package.json index 608e4bd1..df740a53 100644 --- a/package.json +++ b/package.json @@ -43,12 +43,12 @@ "dependencies": { "@actions/core": "^3.0.0", "@heroicons/react": "^2.2.0", - "@minify-html/wasm": "^0.18.1", "@node-core/rehype-shiki": "^1.4.0", "@node-core/ui-components": "^1.6.0", "@orama/orama": "^3.1.18", "@orama/ui": "^1.5.4", "@rollup/plugin-virtual": "^3.0.2", + "@swc/html-wasm": "^1.15.17", "acorn": "^8.15.0", "commander": "^14.0.3", "dedent": "^1.7.1", diff --git a/src/generators/legacy-html-all/generate.mjs b/src/generators/legacy-html-all/generate.mjs index b9cc3a88..a322445e 100644 --- a/src/generators/legacy-html-all/generate.mjs +++ b/src/generators/legacy-html-all/generate.mjs @@ -63,7 +63,7 @@ export async function generate(input) { }); if (config.minify) { - result = Buffer.from(await minifyHTML(result)); + result = await minifyHTML(result); } if (config.output) { diff --git a/src/generators/legacy-html/generate.mjs b/src/generators/legacy-html/generate.mjs index 6888612d..4126c13c 100644 --- a/src/generators/legacy-html/generate.mjs +++ b/src/generators/legacy-html/generate.mjs @@ -130,7 +130,7 @@ export async function* generate(input, worker) { let result = replaceTemplateValues(apiTemplate, template, config); if (config.minify) { - result = Buffer.from(await minifyHTML(result)); + result = await minifyHTML(result); } await writeFile(join(config.output, `${template.api}.html`), result); diff --git a/src/generators/web/utils/processing.mjs b/src/generators/web/utils/processing.mjs index 902f1c22..14931700 100644 --- a/src/generators/web/utils/processing.mjs +++ b/src/generators/web/utils/processing.mjs @@ -123,10 +123,7 @@ export async function processJSXEntries( .replace('{{speculationRules}}', SPECULATION_RULES) .replace('{{ogTitle}}', title); - const minifiedHtml = await minifyHTML(renderedHtml); - const html = Buffer.from(minifiedHtml); - - return { html, api }; + return { html: await minifyHTML(renderedHtml), api }; }) ); diff --git a/src/utils/html-minifier.mjs b/src/utils/html-minifier.mjs index e3921288..df9729cd 100644 --- a/src/utils/html-minifier.mjs +++ b/src/utils/html-minifier.mjs @@ -1,24 +1,20 @@ -import { minify } from '@minify-html/wasm'; +import { readFile } from 'node:fs/promises'; -const DEFAULT_HTML_MINIFIER_OPTIONS = { - minify_css: true, - minify_js: true, -}; +import { minify, default as initSync } from '@swc/html-wasm'; -const textEncoder = new TextEncoder(); -const textDecoder = new TextDecoder(); +// See https://github.com/swc-project/swc/issues/11599 for why we need to load +// the WASM file in this way +await initSync( + readFile(new URL(import.meta.resolve('@swc/html-wasm/wasm_bg.wasm'))) +); /** - * Minifies HTML with project defaults and optional overrides. + * Minifies HTML with project defaults and optional overrides. At the moment, + * swc's defaults are suitable for our needs, but in the event that this changes, + * allowing project defaults is beneficial. * * @param {string} html - * @param {Record} [overrides] + * @param {import('@swc/html-wasm').Options} [options] */ -export const minifyHTML = async (html, overrides = {}) => { - const minified = minify(textEncoder.encode(html), { - ...DEFAULT_HTML_MINIFIER_OPTIONS, - ...overrides, - }); - - return textDecoder.decode(minified); -}; +export const minifyHTML = async (html, options = {}) => + (await minify(html, options)).code;