diff --git a/scripts/minify/.gitignore b/scripts/minify/.gitignore new file mode 100644 index 00000000..a14702c4 --- /dev/null +++ b/scripts/minify/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/scripts/minify/README.md b/scripts/minify/README.md new file mode 100644 index 00000000..66d10477 --- /dev/null +++ b/scripts/minify/README.md @@ -0,0 +1,15 @@ +# minify + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.3.12. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. diff --git a/scripts/minify/bun.lock b/scripts/minify/bun.lock new file mode 100644 index 00000000..9128e427 --- /dev/null +++ b/scripts/minify/bun.lock @@ -0,0 +1,86 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "minify", + "dependencies": { + "@swc/core": "^1.15.30", + "@swc/html": "^1.15.30", + }, + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@swc/core": ["@swc/core@1.15.30", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.26" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.30", "@swc/core-darwin-x64": "1.15.30", "@swc/core-linux-arm-gnueabihf": "1.15.30", "@swc/core-linux-arm64-gnu": "1.15.30", "@swc/core-linux-arm64-musl": "1.15.30", "@swc/core-linux-ppc64-gnu": "1.15.30", "@swc/core-linux-s390x-gnu": "1.15.30", "@swc/core-linux-x64-gnu": "1.15.30", "@swc/core-linux-x64-musl": "1.15.30", "@swc/core-win32-arm64-msvc": "1.15.30", "@swc/core-win32-ia32-msvc": "1.15.30", "@swc/core-win32-x64-msvc": "1.15.30" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-R8VQbQY1BZcbIF2p3gjlTCwAQzx1A194ugWfwld5y+WgVVWqVKm7eURGGOVbQVubgKWzidP2agomBbg96rZilQ=="], + + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.30", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VvpP+vq08HmGYewMWvrdsxh9s2lthz/808zXm8Yu5kaqeR8Yia2b0eYXleHQ3VAjoStUDk6LzTheBW9KXYQdMA=="], + + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.30", "", { "os": "darwin", "cpu": "x64" }, "sha512-WiJA0hiZI3nwQAO6mu5RqigtWGDtth4Hiq6rbZxAaQyhIcqKIg5IoMRc1Y071lrNJn29eEDMC86Rq58xgUxlDg=="], + + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.30", "", { "os": "linux", "cpu": "arm" }, "sha512-YANuFUo48kIT6plJgCD0keae9HFXfjxsbvsgevqc0hr/07X/p7sAWTFOGYEc2SXcASaK7UvuQqzlbW8pr7R79g=="], + + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.30", "", { "os": "linux", "cpu": "arm64" }, "sha512-VndG8jaR4ugY6u+iVOT0Q+d2fZd7sLgjPgN8W/Le+3EbZKl+cRfFxV7Eoz4gfLqhmneZPdcIzf9T3LkgkmqNLg=="], + + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.30", "", { "os": "linux", "cpu": "arm64" }, "sha512-1SYGs2l0Yyyi0pR/P/NKz/x0kqxkoiw+BXeJjLUdecSk/KasncWlJrc6hOvFSgKHOBrzgM5jwuluKtlT8dnrcA=="], + + "@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.15.30", "", { "os": "linux", "cpu": "ppc64" }, "sha512-TXREtiXeRhbfDFbmhnkIsXpKfzbfT73YkV2ZF6w0sfxgjC5zI2ZAbaCOq25qxvegofj2K93DtOpm9RLaBgqR2g=="], + + "@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.15.30", "", { "os": "linux", "cpu": "s390x" }, "sha512-DCR2YYeyd6DQE4OuDhImouuNcjXEiEdnn1Y0DyGteugPEDvVuvYk8Xddi+4o2SgWH6jiW8/I+3emZvbep1NC+g=="], + + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.30", "", { "os": "linux", "cpu": "x64" }, "sha512-5Pizw3NgfOJ5BJOBK8TIRa59xFW2avESTOBDPTAYwZYa1JNDs+KMF9lUfjJiJLM5HiMs/wPheA9eiT0q9m2AoA=="], + + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.30", "", { "os": "linux", "cpu": "x64" }, "sha512-qyqydP/wyH8alcIP4a2hnGSjHLJjm9H7yDFup+CPy9oTahFgLLwnNcv5UHXqO2Qs3AIND+cls5f/Bb6hqpxdgA=="], + + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.30", "", { "os": "win32", "cpu": "arm64" }, "sha512-CaQENgDHVGOg1mSF5sQVgvfFHG9kjMor2rkLMLeLOkfZYNj13ppnJ9+lfaBZLZUMMbnlGQnavCJb8PVBUOso7Q=="], + + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.30", "", { "os": "win32", "cpu": "ia32" }, "sha512-30VdLeGk6fugiUs/kUdJ/pAg7z/zpvVbR11RH60jZ0Z42WIeIniYx0rLEWN7h/pKJ3CopqsQ3RsogCAkRKiA2g=="], + + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.30", "", { "os": "win32", "cpu": "x64" }, "sha512-4iObHPR+Q4oDY110EF5SF5eIaaVJNpMdG9C0q3Q92BsJ5y467uHz7sYQhP60WYlLFsLQ1el2YrIPUItUAQGOKg=="], + + "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], + + "@swc/html": ["@swc/html@1.15.30", "", { "dependencies": { "@swc/counter": "^0.1.3" }, "optionalDependencies": { "@swc/html-darwin-arm64": "1.15.30", "@swc/html-darwin-x64": "1.15.30", "@swc/html-linux-arm-gnueabihf": "1.15.30", "@swc/html-linux-arm64-gnu": "1.15.30", "@swc/html-linux-arm64-musl": "1.15.30", "@swc/html-linux-ppc64-gnu": "1.15.30", "@swc/html-linux-s390x-gnu": "1.15.30", "@swc/html-linux-x64-gnu": "1.15.30", "@swc/html-linux-x64-musl": "1.15.30", "@swc/html-win32-arm64-msvc": "1.15.30", "@swc/html-win32-ia32-msvc": "1.15.30", "@swc/html-win32-x64-msvc": "1.15.30" } }, "sha512-2tOC3fs+8ifLCXU2LvrVsU/yt1frU/mkKel4xW2Iloh12fxKvUlo01oMCiBP47fRiBn138z4l3W6H+TxlqXzLQ=="], + + "@swc/html-darwin-arm64": ["@swc/html-darwin-arm64@1.15.30", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4OJ7TedJNQ/BqPAwu5SG4pvGRBc623AUqdeoQUykN5Zb4KBzHKt5cmB4G81f9mbB2ljI/B7MtYjDgK5PYljBWw=="], + + "@swc/html-darwin-x64": ["@swc/html-darwin-x64@1.15.30", "", { "os": "darwin", "cpu": "x64" }, "sha512-hftUoWRe+ctCOGNI9GMDzNo5I89y/N2aSf9HPG5760zUVVoRZ+HavDbWh6/i7TIk699Z9MKYapk1u3GMXOObBA=="], + + "@swc/html-linux-arm-gnueabihf": ["@swc/html-linux-arm-gnueabihf@1.15.30", "", { "os": "linux", "cpu": "arm" }, "sha512-zHMiUDDifPMF1DB6OffdvxVmg2ZpMGf4Tnr4bTTi+SR9/eSh/u9Bm9zB47Aj5MukbY4J+wHC/+0kunO86+pmhw=="], + + "@swc/html-linux-arm64-gnu": ["@swc/html-linux-arm64-gnu@1.15.30", "", { "os": "linux", "cpu": "arm64" }, "sha512-x2bc5JEtuLrE9NALLms+XeNZfg6rhGrr63sRZjac8VTTyN2uF5z0xilY2Scvms5UDJyIfmp/zKGZVUVzpVDlbg=="], + + "@swc/html-linux-arm64-musl": ["@swc/html-linux-arm64-musl@1.15.30", "", { "os": "linux", "cpu": "arm64" }, "sha512-/4SCjzKHa+sqgqykn8F3uw4UWRuXNxygl20v2wMvH3EgY6yvV/yP2z7FhxOkAcVVkbv7L7oRwlCtA2s2NFNHBQ=="], + + "@swc/html-linux-ppc64-gnu": ["@swc/html-linux-ppc64-gnu@1.15.30", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BJ+SouIXFY+YCPi36gXPjFZa5Yx2Kow6SSGQp99AkA8yZ/PVDI19op9czyiNLB3N9pW5Zznpv7UH2g7XCICybQ=="], + + "@swc/html-linux-s390x-gnu": ["@swc/html-linux-s390x-gnu@1.15.30", "", { "os": "linux", "cpu": "s390x" }, "sha512-Kw3giWoeEWFTpYzYMduJXQCj+efG/LVwH+4SLdkFf3cqLT25sZubZZBLOF+MLuFVm5x6NwW0aCPIn7qc/aA9WQ=="], + + "@swc/html-linux-x64-gnu": ["@swc/html-linux-x64-gnu@1.15.30", "", { "os": "linux", "cpu": "x64" }, "sha512-C0T0BZH/uWcrOL3Jd4oQ5WZ5vpGUAxTMG9dNIvzJwb5Xdh0U7csQUeuqmfCoM0JXNcxhCjsm5JzfgaLMiCPqLw=="], + + "@swc/html-linux-x64-musl": ["@swc/html-linux-x64-musl@1.15.30", "", { "os": "linux", "cpu": "x64" }, "sha512-zF8aj+qqKvcQb2S1Sj1YB5JKLRD8ZS4VfK139ZUlfAlW6GqloF2tSAZ8tgvzPxHuDnth/5dzydut/XcJ4w7a0Q=="], + + "@swc/html-win32-arm64-msvc": ["@swc/html-win32-arm64-msvc@1.15.30", "", { "os": "win32", "cpu": "arm64" }, "sha512-V+f6VX2Yrq94JCYFBmJBU6ehHrmBBl/UtQECKoCrrSTl919Wk1yBaDxs7y+pHnSMDTOIRIt/yzuFYByDytEpHQ=="], + + "@swc/html-win32-ia32-msvc": ["@swc/html-win32-ia32-msvc@1.15.30", "", { "os": "win32", "cpu": "ia32" }, "sha512-qmZMzP/3YxImUVyZHVm/9LNzeJioasMKjW6fBQkSysSaFCbC1iD6W8EKzYK20EqfjrL24CpYbU5snRLUh4qD5A=="], + + "@swc/html-win32-x64-msvc": ["@swc/html-win32-x64-msvc@1.15.30", "", { "os": "win32", "cpu": "x64" }, "sha512-WRKAsAjJmOuz+0HgjlPFyGWVz34AvBVTAWpyqczY+Bhiqz+asr7h3ukeY4vjSFsFddzoZbrEKt541z9YrlVxfQ=="], + + "@swc/types": ["@swc/types@0.1.26", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw=="], + + "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="], + + "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], + + "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], + } +} diff --git a/scripts/minify/index.ts b/scripts/minify/index.ts new file mode 100644 index 00000000..a945ae33 --- /dev/null +++ b/scripts/minify/index.ts @@ -0,0 +1,79 @@ +import { glob } from "node:fs"; +import { transform as transformJS } from "@swc/core"; +import { minify as minifyHTML } from "@swc/html"; +import { basename, dirname, join } from "node:path"; + +type Kind = "html" | "js"; + +function isIgnored(path: string) { + return ( + path.startsWith("internal/go-proxmox") || basename(path).includes(".min.") + ); +} + +function globAssets(extension: Kind, callback: (matches: string) => void) { + glob( + [`internal/**/*.${extension}`, `goutils/**/*.${extension}`], + (err, matches) => { + if (err) { + console.error(err); + } + matches.forEach((e) => { + if (!isIgnored(e)) { + callback(e); + } + }); + }, + ); +} + +async function minify(filePath: string, kind: Kind): Promise { + const content = await Bun.file(filePath).text(); + if (kind === "js") { + const out = await transformJS(content, { + sourceMaps: false, + isModule: false, + minify: true, + }); + if (!out.code) { + return Promise.reject("out code is empty"); + } + return out.code; + } + const out = await minifyHTML(content, { + forceSetHtml5Doctype: true, + collapseBooleanAttributes: true, + collapseWhitespaces: "all", + minifyCss: { lib: "lightningcss" }, + minifyJs: true, + removeComments: true, + removeEmptyMetadataElements: true, + }); + if (out.errors && out.errors.length > 0) { + const err = `html minify error for "${filePath}": ${out.errors.map((e) => e.message)}`; + if (!out.code) { + return Promise.reject(err); + } + console.error(err); + } + return out.code; +} + +async function minifyOut(filePath: string, kind: Kind) { + const minified = await minify(filePath, kind); + + const fnameNoExt = basename(filePath).split(".")[0]!; + const outPath = join(dirname(filePath), `${fnameNoExt}.min.${kind}`); + + console.log(`minify ${filePath} -> ${outPath}`); + await Bun.file(outPath).write(minified); +} + +async function main() { + const promises = new Array>(); + globAssets("html", (e) => promises.push(minifyOut(e, "html"))); + globAssets("js", (e) => promises.push(minifyOut(e, "js"))); + await Promise.allSettled(promises); +} + +await main(); diff --git a/scripts/minify/package.json b/scripts/minify/package.json new file mode 100644 index 00000000..49462434 --- /dev/null +++ b/scripts/minify/package.json @@ -0,0 +1,16 @@ +{ + "name": "minify", + "module": "index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "@swc/core": "^1.15.30", + "@swc/html": "^1.15.30" + } +} diff --git a/scripts/minify/tsconfig.json b/scripts/minify/tsconfig.json new file mode 100644 index 00000000..b44e35ac --- /dev/null +++ b/scripts/minify/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + "types": ["bun", "node"], + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}