Skip to content

Commit d5b5f86

Browse files
committed
fix(@angular/build): use stable worker filenames during dev server to prevent hash changes on rebuild
During `ng serve`, web workers were always bundled with `entryNames: 'worker-[hash]'` regardless of whether the parent build used hashing. Combined with inherited `footer` and `splitting` options from the parent build that could change between rebuilds, this caused the worker filename hash to change on every rebuild even when the worker content was unchanged, breaking debugging sessions. The fix conditionally uses `worker-[hash]` only when the parent build uses hashing (production builds), and `worker-[name]` otherwise (dev server). It also explicitly sets `splitting: false` and `footer: undefined` in the worker build to prevent non-deterministic output that could affect hashing. Closes #30494
1 parent 7fbc715 commit d5b5f86

File tree

3 files changed

+19
-4
lines changed

3 files changed

+19
-4
lines changed

packages/angular/build/src/builders/application/tests/behavior/rebuild-web-workers_spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ import {
1717

1818
/**
1919
* A regular expression used to check if a built worker is correctly referenced in application code.
20+
* Matches both hashed (worker-ABCD1234.js) and non-hashed (worker-worker.js) filenames.
2021
*/
2122
const REFERENCED_WORKER_REGEXP =
22-
/new Worker\(new URL\("worker-[A-Z0-9]{8}\.js", import\.meta\.url\)/;
23+
/new Worker\(new URL\("worker-.+\.js", import\.meta\.url\)/;
2324

2425
describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
2526
describe('Behavior: "Rebuilds when Web Worker files change"', () => {

packages/angular/build/src/builders/application/tests/behavior/web-workers-application_spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setu
1111

1212
/**
1313
* A regular expression used to check if a built worker is correctly referenced in application code.
14+
* Matches both hashed (worker-ABCD1234.js) and non-hashed (worker-worker.js) filenames.
1415
*/
1516
const REFERENCED_WORKER_REGEXP =
16-
/new Worker\(new URL\("worker-[A-Z0-9]{8}\.js", import\.meta\.url\)/;
17+
/new Worker\(new URL\("worker-.+\.js", import\.meta\.url\)/;
1718

1819
describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
1920
describe('Behavior: "Bundles web worker files within application code"', () => {

packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ export function createCompilerPlugin(
286286
);
287287

288288
// Return bundled worker file entry name to be used in the built output
289+
// Match both hashed (worker-ABCD1234.js) and non-hashed (worker-<name>.js) patterns
289290
const workerCodeFile = workerResult.outputFiles.find((file) =>
290-
/^worker-[A-Z0-9]{8}.[cm]?js$/.test(path.basename(file.path)),
291+
/^worker-.+\.[cm]?js$/.test(path.basename(file.path)),
291292
);
292293
assert(workerCodeFile, 'Web Worker bundled code file should always be present.');
293294
const workerCodePath = path.relative(
@@ -763,20 +764,32 @@ function bundleWebWorker(
763764
workerFile: string,
764765
) {
765766
try {
767+
// Use content hashing only when the parent build uses hashing in entry names.
768+
// During dev server (ng serve), hashing is disabled and using it for workers
769+
// causes the filename hash to change on every rebuild even when the worker
770+
// content hasn't changed, breaking debugging sessions.
771+
const parentEntryNames = build.initialOptions.entryNames ?? '';
772+
const useHashing = parentEntryNames.includes('[hash]');
773+
766774
return build.esbuild.buildSync({
767775
...build.initialOptions,
768776
platform: 'browser',
769777
write: false,
770778
bundle: true,
771779
metafile: true,
772780
format: 'esm',
773-
entryNames: 'worker-[hash]',
781+
entryNames: useHashing ? 'worker-[hash]' : 'worker-[name]',
774782
entryPoints: [workerFile],
775783
sourcemap: pluginOptions.sourcemap,
776784
// Zone.js is not used in Web workers so no need to disable
777785
supported: undefined,
778786
// Plugins are not supported in sync esbuild calls
779787
plugins: undefined,
788+
// Splitting is not needed for workers and can cause non-deterministic output
789+
splitting: false,
790+
// Footer may contain build-specific data (e.g., i18n hashes) that changes
791+
// between rebuilds, causing unnecessary hash changes for workers
792+
footer: undefined,
780793
});
781794
} catch (error) {
782795
if (error && typeof error === 'object' && 'errors' in error && 'warnings' in error) {

0 commit comments

Comments
 (0)