fix(app): hash emitted license asset names (#3416)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-12 13:58:28 +02:00
1 parent f8d85f0e5e
commit 85d9ef7386
2 files changed
+26 -5

No files matched your search

-1
View File
@@ -21,7 +21,6 @@
<meta name="msapplication-TileColor" content="#4641D9"> <meta name="msapplication-TileColor" content="#4641D9">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="display" content="standalone"> <meta name="display" content="standalone">
<link rel="license" href="/assets/fonts-NOTICE.txt">
<link rel="expect" href="#fluxer-boot-end" blocking="render"> <link rel="expect" href="#fluxer-boot-end" blocking="render">
<script nonce="{{CSP_NONCE_PLACEHOLDER}}">(function(){try{var loc=window.location;if(loc.pathname==='/'){var target='/channels/@me';if(loc.search)target+=loc.search;if(loc.hash)target+=loc.hash;loc.replace(target);}}catch(e){}})();</script> <script nonce="{{CSP_NONCE_PLACEHOLDER}}">(function(){try{var loc=window.location;if(loc.pathname==='/'){var target='/channels/@me';if(loc.search)target+=loc.search;if(loc.hash)target+=loc.hash;loc.replace(target);}}catch(e){}})();</script>
<script nonce="{{CSP_NONCE_PLACEHOLDER}}">(function(){try{var t=localStorage.getItem('theme');if(t){document.documentElement.classList.add('theme-'+t)}}catch{}})()</script> <script nonce="{{CSP_NONCE_PLACEHOLDER}}">(function(){try{var t=localStorage.getItem('theme');if(t){document.documentElement.classList.add('theme-'+t)}}catch{}})()</script>
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-License-Identifier: AGPL-3.0-or-later
import {createHash} from 'node:crypto';
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import {sources} from '@rspack/core'; import {HtmlRspackPlugin, sources} from '@rspack/core';
const STATIC_CDN_ENDPOINT_PLACEHOLDER = '{{STATIC_CDN_ENDPOINT}}'; const STATIC_CDN_ENDPOINT_PLACEHOLDER = '{{STATIC_CDN_ENDPOINT}}';
@@ -104,22 +105,41 @@ export class StaticFilesPlugin {
} }
emitLicenseFiles(compilation, dir, files, subject) { emitLicenseFiles(compilation, dir, files, subject) {
const assetNames = new Map();
if (!dir) { if (!dir) {
return; return assetNames;
} }
for (const {source, asset} of files) { for (const {source, asset} of files) {
const sourcePath = path.join(dir, source); const sourcePath = path.join(dir, source);
compilation.fileDependencies.add(sourcePath);
if (!fs.existsSync(sourcePath)) { if (!fs.existsSync(sourcePath)) {
throw new Error( throw new Error(
`StaticFilesPlugin: ${sourcePath} is missing. The bundled ${subject} may not be redistributed without it.`, `StaticFilesPlugin: ${sourcePath} is missing. The bundled ${subject} may not be redistributed without it.`,
); );
} }
compilation.emitAsset(asset, new sources.RawSource(fs.readFileSync(sourcePath))); const content = fs.readFileSync(sourcePath);
const extension = path.extname(asset);
const hash = createHash('sha256').update(content).digest('hex').slice(0, 16);
const name = `${asset.slice(0, -extension.length)}.${hash}${extension}`;
compilation.emitAsset(name, new sources.RawSource(content));
assetNames.set(source, name);
} }
return assetNames;
} }
apply(compiler) { apply(compiler) {
compiler.hooks.thisCompilation.tap('StaticFilesPlugin', (compilation) => { compiler.hooks.thisCompilation.tap('StaticFilesPlugin', (compilation) => {
let fontNoticeAsset;
HtmlRspackPlugin.getCompilationHooks(compilation).alterAssetTagGroups.tap('StaticFilesPlugin', (data) => {
if (fontNoticeAsset) {
data.headTags.push({
tagName: 'link',
voidTag: true,
attributes: {rel: 'license', href: `${data.publicPath}${fontNoticeAsset}`},
});
}
return data;
});
compilation.hooks.processAssets.tap( compilation.hooks.processAssets.tap(
{ {
name: 'StaticFilesPlugin', name: 'StaticFilesPlugin',
@@ -132,7 +152,9 @@ export class StaticFilesPlugin {
new sources.RawSource(generateBrowserConfig(this.staticCdnEndpoint)), new sources.RawSource(generateBrowserConfig(this.staticCdnEndpoint)),
); );
compilation.emitAsset('robots.txt', new sources.RawSource(generateRobotsTxt())); compilation.emitAsset('robots.txt', new sources.RawSource(generateRobotsTxt()));
this.emitLicenseFiles(compilation, this.fontsDir, FONT_LICENSE_FILES, 'fonts'); fontNoticeAsset = this.emitLicenseFiles(compilation, this.fontsDir, FONT_LICENSE_FILES, 'fonts').get(
'NOTICE.md',
);
this.emitLicenseFiles(compilation, this.wasmCratesDir, WASM_LICENSE_FILES, 'WebAssembly modules'); this.emitLicenseFiles(compilation, this.wasmCratesDir, WASM_LICENSE_FILES, 'WebAssembly modules');
}, },
); );