From 5e6f1a9f4362e9b12db64c7c2e609a346b17963d Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 5 Feb 2024 08:24:58 +0000 Subject: [PATCH] fix(@angular-devkit/build-angular): avoid preloading server chunks https://github.com/angular/angular-cli/commit/41ea985f9317b11cfa6627a2d3f6b34ff4dbc134#diff-239ad7beb7d8a76046cdc7b4d2263b2e05c300e3e0510916cb907e93efec5af0 introduced a regression which causes server enter-points --- .../behavior/index-preload-hints_spec.ts | 27 +++++++++++++++++++ .../src/tools/esbuild/bundler-context.ts | 19 ++++++++----- .../src/tools/esbuild/index-html-generator.ts | 15 ++++++----- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/application/tests/behavior/index-preload-hints_spec.ts b/packages/angular_devkit/build_angular/src/builders/application/tests/behavior/index-preload-hints_spec.ts index 6b7a4ff9df78..e8fb7137d2b0 100644 --- a/packages/angular_devkit/build_angular/src/builders/application/tests/behavior/index-preload-hints_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/application/tests/behavior/index-preload-hints_spec.ts @@ -33,5 +33,32 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { '', ); }); + + it('should not add preload hints for ssr files', async () => { + await harness.modifyFile('src/tsconfig.app.json', (content) => { + const tsConfig = JSON.parse(content); + tsConfig.files ??= []; + tsConfig.files.push('main.server.ts', 'server.ts'); + + return JSON.stringify(tsConfig); + }); + + await harness.writeFile('src/server.ts', `console.log('Hello!');`); + + harness.useTarget('build', { + ...BASE_OPTIONS, + server: 'src/main.server.ts', + ssr: true, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/server/main.server.mjs').toExist(); + + harness + .expectFile('dist/browser/index.html') + .content.not.toMatch(//); + }); }); }); diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts index 652ebf985ff0..387aed470139 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts @@ -42,6 +42,7 @@ export interface InitialFileRecord { name?: string; type: 'script' | 'style'; external?: boolean; + serverFile: boolean; } export enum BuildOutputFileType { @@ -75,7 +76,6 @@ export class BundlerContext { #esbuildResult?: BundleContextResult; #optionsFactory: BundlerOptionsFactory; #shouldCacheResult: boolean; - #loadCache?: MemoryLoadResultCache; readonly watchFiles = new Set(); @@ -222,7 +222,7 @@ export class BundlerContext { result = await build(this.#esbuildOptions); } - if (this.#esbuildOptions?.platform === 'node') { + if (this.#platformIsServer) { for (const entry of Object.values(result.metafile.outputs)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any (entry as any)['ng-platform-server'] = true; @@ -297,6 +297,7 @@ export class BundlerContext { name, type, entrypoint: true, + serverFile: this.#platformIsServer, }; if (!this.initialFilter || this.initialFilter(record)) { @@ -319,6 +320,7 @@ export class BundlerContext { type: initialImport.kind === 'import-rule' ? 'style' : 'script', entrypoint: false, external: initialImport.external, + serverFile: this.#platformIsServer, }; if (!this.initialFilter || this.initialFilter(record)) { @@ -350,15 +352,16 @@ export class BundlerContext { assert(this.#esbuildOptions, 'esbuild options cannot be undefined.'); - const { platform, assetNames = '' } = this.#esbuildOptions; - const platformIsServer = platform === 'node'; + const { assetNames = '' } = this.#esbuildOptions; const mediaDirname = dirname(assetNames); const outputFiles = result.outputFiles.map((file) => { let fileType: BuildOutputFileType; if (dirname(file.path) === mediaDirname) { fileType = BuildOutputFileType.Media; } else { - fileType = platformIsServer ? BuildOutputFileType.Server : BuildOutputFileType.Browser; + fileType = this.#platformIsServer + ? BuildOutputFileType.Server + : BuildOutputFileType.Browser; } return convertOutputFile(file, fileType); @@ -370,7 +373,7 @@ export class BundlerContext { outputFiles, initialFiles, externalImports: { - [platformIsServer ? 'server' : 'browser']: externalImports, + [this.#platformIsServer ? 'server' : 'browser']: externalImports, }, externalConfiguration: this.#esbuildOptions.external, errors: undefined, @@ -392,6 +395,10 @@ export class BundlerContext { } } + get #platformIsServer(): boolean { + return this.#esbuildOptions?.platform === 'node'; + } + /** * Invalidate a stored bundler result based on the previous watch files * and a list of changed files. diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/index-html-generator.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/index-html-generator.ts index 2104a61ba237..ebfa183bd24d 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/index-html-generator.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/index-html-generator.ts @@ -40,10 +40,11 @@ export async function generateIndexHtml( if (!externalPackages && indexHtmlOptions.preloadInitial) { for (const [key, value] of initialFiles) { - if (value.entrypoint) { + if (value.entrypoint || value.serverFile) { // Entry points are already referenced in the HTML continue; } + if (value.type === 'script') { hints.push({ url: key, mode: 'modulepreload' as const }); } else if (value.type === 'style') { @@ -91,11 +92,13 @@ export async function generateIndexHtml( baseHref, lang, outputPath: virtualOutputPath, - files: [...initialFiles].map(([file, record]) => ({ - name: record.name ?? '', - file, - extension: path.extname(file), - })), + files: [...initialFiles] + .filter(([, file]) => !file.serverFile) + .map(([file, record]) => ({ + name: record.name ?? '', + file, + extension: path.extname(file), + })), hints, });