diff --git a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts index ceb60c644949..3587ff99a618 100644 --- a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts +++ b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts @@ -254,9 +254,7 @@ export function createServerMainCodeBundleOptions( return (loadResultCache) => { const pluginOptions = createCompilerPluginOptions(options, sourceFileCache, loadResultCache); - const mainServerNamespace = 'angular:main-server'; - const mainServerInjectPolyfillsNamespace = 'angular:main-server-inject-polyfills'; const mainServerInjectManifestNamespace = 'angular:main-server-inject-manifest'; const zoneless = isZonelessApp(polyfills); const entryPoints: Record = { @@ -275,7 +273,9 @@ export function createServerMainCodeBundleOptions( const buildOptions: BuildOptions = { ...getEsBuildServerCommonOptions(options), target, - inject: [mainServerInjectPolyfillsNamespace, mainServerInjectManifestNamespace], + banner: { + js: `import './polyfills.server.mjs';`, + }, entryPoints, supported: getFeatureSupport(target, zoneless), plugins: [ @@ -311,18 +311,10 @@ export function createServerMainCodeBundleOptions( buildOptions.plugins.push( createServerBundleMetadata(), - createVirtualModulePlugin({ - namespace: mainServerInjectPolyfillsNamespace, - cache: loadResultCache, - loadContent: () => ({ - contents: `import './polyfills.server.mjs';`, - loader: 'js', - resolveDir: workspaceRoot, - }), - }), createVirtualModulePlugin({ namespace: mainServerInjectManifestNamespace, cache: loadResultCache, + entryPointOnly: false, loadContent: async () => { const contents: string[] = [ // Configure `@angular/ssr` manifest. @@ -348,16 +340,19 @@ export function createServerMainCodeBundleOptions( ); const contents: string[] = [ - // Re-export all symbols including default export from 'main.server.ts' - `export { default } from '${mainServerEntryPointJsImport}';`, - `export * from '${mainServerEntryPointJsImport}';`, + // Inject manifest + `import '${mainServerInjectManifestNamespace}';`, // Add @angular/ssr exports `export { - ɵdestroyAngularServerApp, - ɵextractRoutesAndCreateRouteTree, - ɵgetOrCreateAngularServerApp, - } from '@angular/ssr';`, + ɵdestroyAngularServerApp, + ɵextractRoutesAndCreateRouteTree, + ɵgetOrCreateAngularServerApp, + } from '@angular/ssr';`, + + // Re-export all symbols including default export from 'main.server.ts' + `export { default } from '${mainServerEntryPointJsImport}';`, + `export * from '${mainServerEntryPointJsImport}';`, ]; return { @@ -392,22 +387,24 @@ export function createSsrEntryCodeBundleOptions( return (loadResultCache) => { const pluginOptions = createCompilerPluginOptions(options, sourceFileCache, loadResultCache); - const ssrEntryNamespace = 'angular:ssr-entry'; const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest'; - const ssrInjectRequireNamespace = 'angular:ssr-entry-inject-require'; const isNodePlatform = options.ssrOptions?.platform !== ExperimentalPlatform.Neutral; - const inject: string[] = [ssrInjectManifestNamespace]; - if (isNodePlatform) { - inject.unshift(ssrInjectRequireNamespace); - } - const buildOptions: BuildOptions = { ...getEsBuildServerCommonOptions(options), target, + banner: isNodePlatform + ? { + js: [ + // Note: Needed as esbuild does not provide require shims / proxy from ESModules. + // See: https://github.com/evanw/esbuild/issues/1921. + `import { createRequire } from 'node:module';`, + `globalThis['require'] ??= createRequire(import.meta.url);`, + ].join('\n'), + } + : undefined, entryPoints: { - // TODO: consider renaming to index 'server': ssrEntryNamespace, }, supported: getFeatureSupport(target, true), @@ -420,7 +417,6 @@ export function createSsrEntryCodeBundleOptions( stylesheetBundler, ), ], - inject, }; buildOptions.plugins ??= []; @@ -443,27 +439,10 @@ export function createSsrEntryCodeBundleOptions( buildOptions.plugins.push( createServerBundleMetadata({ ssrEntryBundle: true }), - createVirtualModulePlugin({ - namespace: ssrInjectRequireNamespace, - cache: loadResultCache, - loadContent: () => { - const contents: string[] = [ - // Note: Needed as esbuild does not provide require shims / proxy from ESModules. - // See: https://github.com/evanw/esbuild/issues/1921. - `import { createRequire } from 'node:module';`, - `globalThis['require'] ??= createRequire(import.meta.url);`, - ]; - - return { - contents: contents.join('\n'), - loader: 'js', - resolveDir: workspaceRoot, - }; - }, - }), createVirtualModulePlugin({ namespace: ssrInjectManifestNamespace, cache: loadResultCache, + entryPointOnly: false, loadContent: () => { const contents: string[] = [ // Configure `@angular/ssr` app engine manifest. @@ -488,6 +467,9 @@ export function createSsrEntryCodeBundleOptions( serverEntryPoint, ); const contents: string[] = [ + // Configure `@angular/ssr` app engine manifest. + `import '${ssrInjectManifestNamespace}';`, + // Re-export all symbols including default export `import * as server from '${serverEntryPointJsImport}';`, `export * from '${serverEntryPointJsImport}';`, diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts index fd7b7eea2de0..232e0745cef9 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts @@ -11,6 +11,7 @@ import { import { updateJsonFile, useSha } from '../../../utils/project'; import { getGlobalVariable } from '../../../utils/env'; import { findFreePort } from '../../../utils/network'; +import { readFile } from 'node:fs/promises'; export default async function () { assert( @@ -68,6 +69,10 @@ export default async function () { }, ]; `, + 'src/app/app.config.ts': ` + import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; + ${(await readFile('src/app/app.config.ts', 'utf8')).replace('provideRouter(routes),', 'provideAnimationsAsync(), provideRouter(routes),')} + `, 'src/server.ts': ` import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; import { createApp, createRouter, toWebHandler, defineEventHandler, toWebRequest } from 'h3';