diff --git a/packages/angular/build/src/builders/application/tests/behavior/web-workers-application_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/web-workers-application_spec.ts index 135d5ff68165..10112afd3b6b 100644 --- a/packages/angular/build/src/builders/application/tests/behavior/web-workers-application_spec.ts +++ b/packages/angular/build/src/builders/application/tests/behavior/web-workers-application_spec.ts @@ -57,5 +57,78 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { // Ensure built worker is referenced in the application code harness.expectFile('dist/browser/main.js').content.toMatch(REFERENCED_WORKER_REGEXP); }); + + it('should emit all chunks referenced by a web worker when chunk optimization is enabled', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + optimization: true, + }); + + await harness.writeFile( + 'src/app/shared.ts', + `export function sharedHelper(value: string) { return [value, value.toUpperCase(), value.toLowerCase(), value.repeat(3)].join('-'); }`, + ); + await harness.writeFile( + 'src/app/lazy-a.ts', + `import { sharedHelper } from './shared'; export const a = () => sharedHelper('a');`, + ); + await harness.writeFile( + 'src/app/lazy-b.ts', + `import { sharedHelper } from './shared'; export const b = () => sharedHelper('b');`, + ); + await harness.writeFile('src/app/lazy-c.ts', `export const c = () => 'c';`); + + await harness.writeFile( + 'src/app/worker.ts', + ` + addEventListener('message', async () => { + const [{ a }, { b }] = await Promise.all([import('./lazy-a'), import('./lazy-b')]); + postMessage(a() + b()); + }); + `, + ); + + await harness.writeFile( + 'src/app/app.component.ts', + ` + import { Component } from '@angular/core'; + @Component({ + selector: 'app-root', + standalone: false, + template: '

Worker Test

', + }) + export class AppComponent { + worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); + constructor() { + Promise.all([import('./lazy-a'), import('./lazy-b'), import('./lazy-c')]).then(console.log); + } + } + `, + ); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + expect(harness.hasFileMatch('dist/browser', /^worker-chunk-/)).toBeTrue(); + + const mainContent = harness.readFile('dist/browser/main.js'); + const workerMatch = mainContent.match(/(worker-[A-Z0-9]{8}\.js)/); + expect(workerMatch).not.toBeNull(); + + const filesToCheck = new Set(['main.js']); + if (workerMatch) { + filesToCheck.add(workerMatch[1]); + } + + for (const file of filesToCheck) { + expect(harness.hasFile(`dist/browser/${file}`)) + .withContext(`Expected dist/browser/${file} to exist`) + .toBeTrue(); + + const content = harness.readFile(`dist/browser/${file}`); + for (const match of content.matchAll(/(?:from|import)\s*\(?["']\.\/([^"']+\.js)["']\)?/g)) { + filesToCheck.add(match[1]); + } + } + }); }); }); diff --git a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts index 9a36eea56d61..928c9dac7797 100644 --- a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts +++ b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts @@ -727,6 +727,7 @@ function bundleWebWorker( metafile: true, format: 'esm', entryNames: 'worker-[hash]', + chunkNames: 'worker-chunk-[hash]', entryPoints: [workerFile], sourcemap: pluginOptions.sourcemap, // Zone.js is not used in Web workers so no need to disable