From f82372501a5d658e3c78e84df3bd82ae6542dc36 Mon Sep 17 00:00:00 2001 From: Andreas Helmberger Date: Mon, 27 Oct 2025 03:10:59 +0100 Subject: [PATCH] EDU-1805 Add hash to all output filenames --- package.json | 1 + src/esbuild.js | 4 +++- src/less.js | 15 +++++++++++++-- yarn.lock | 33 ++++++++++++++++++++++++++++----- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 3ed39ae..9f59550 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "docker-cli-js": "^2.10.0", "envalid": "^8.0.0", "esbuild": "^0.19.8", + "escape-string-regexp": "^5.0.0", "eslint": "^8.55.0", "execa": "^8.0.1", "fs-extra": "^11.2.0", diff --git a/src/esbuild.js b/src/esbuild.js index 80074ee..7941c47 100644 --- a/src/esbuild.js +++ b/src/esbuild.js @@ -12,7 +12,8 @@ function printWithSpaceInbetween([leftCol, rightCol], width) { } function formatBytes(bytes) { - return `${(bytes / 1000).toFixed(2)} kB`; + const kb = bytes / 1000; + return kb < 1000 ? `${kb.toFixed(2)} KB` : `${(kb / 1000).toFixed(2)} MB`; } function printMetafileTable(metafile) { @@ -53,6 +54,7 @@ export const esbuild = { async bundle({ entryPoints, outdir, environment = process.env.NODE_ENV || 'development', minify = false, incremental = false, inject = [], metaFilePath = null, ...rest }) { const options = { entryPoints, + entryNames: '[name]-[hash]', target: ['esnext', 'chrome95', 'firefox93', 'safari13', 'edge95'], format: 'esm', bundle: true, diff --git a/src/less.js b/src/less.js index 2a1e92e..1cbb97a 100644 --- a/src/less.js +++ b/src/less.js @@ -1,9 +1,11 @@ import Less from 'less'; import fse from 'fs-extra'; import path from 'node:path'; +import crypto from 'node:crypto'; import CleanCss from 'clean-css'; import { promisify } from 'node:util'; import lessPluginGlob from 'less-plugin-glob'; +import escapeStringRegexp from 'escape-string-regexp'; import LessPluginAutoprefix from 'less-plugin-autoprefix'; import LessPluginFixedFileImport from './less-plugin-fixed-file-import.js'; @@ -39,12 +41,21 @@ async function compileLess({ inputFile, outputFile, optimize }) { }; } + const baseNameWithoutExtension = path.basename(inputFile, '.less'); + const hash = crypto.createHash('md5').update(finalResult.css).digest('hex').substring(0, 8).toUpperCase(); + + const realOutputFile = outputFile.replace(/\[name\]/, baseNameWithoutExtension).replace(/\[hash\]/, hash); + const realSourceMapOutputFile = sourceMapOutputFile.replace(/\[name\]/, baseNameWithoutExtension).replace(/\[hash\]/, hash); + const realRelativeSourceMapUrl = relativeSourceMapUrl.replace(/\[name\]/, baseNameWithoutExtension).replace(/\[hash\]/, hash); + + finalResult.css = finalResult.css.replace(new RegExp(escapeStringRegexp(relativeSourceMapUrl)), realRelativeSourceMapUrl); + // Less will fail if the output dir does not exist: await fse.mkdirp(outputDir); await Promise.all([ - fse.writeFile(outputFile, finalResult.css, 'utf8'), - fse.writeFile(sourceMapOutputFile, finalResult.map, 'utf8') + fse.writeFile(realOutputFile, finalResult.css, 'utf8'), + fse.writeFile(realSourceMapOutputFile, finalResult.map, 'utf8') ]); } diff --git a/yarn.lock b/yarn.lock index 5ebf6bf..d54955f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5144,8 +5144,7 @@ string-argv@~0.3.1: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - name string-width-cjs +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5163,6 +5162,15 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -5233,7 +5241,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5247,6 +5255,13 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -5909,8 +5924,7 @@ why-is-node-running@^2.2.2: siginfo "^2.0.0" stackback "0.0.2" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5936,6 +5950,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"