From 1626f3d430eb4d2075d71f8131bfc0f363215300 Mon Sep 17 00:00:00 2001 From: Aukevanoost Date: Fri, 25 Sep 2026 08:55:03 +0200 Subject: [PATCH] fix(builders): externalize synthesized imports in exposed and mapping bundles The shared-mappings plugin was only wired into the app build. An exposed module that reaches a mapped lib through an NgModule still got Angular's synthesized deep import inlined, shipping a second instance of the lib and its InjectionTokens (NG0201). Since core 4.7 exposes and mappings build in separate contexts, so the copy is inlined outright. With one context (core 4.6) it collapses onto the remote's own chunk, but the host's copy of the mapping wins the import map at runtime, so it is still a second instance. Closes #145 --- src/tools/esbuild/angular-bundler.spec.ts | 20 ++++++++++++++++++++ src/tools/esbuild/angular-bundler.ts | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/tools/esbuild/angular-bundler.spec.ts b/src/tools/esbuild/angular-bundler.spec.ts index 11b94dc..a93b16f 100644 --- a/src/tools/esbuild/angular-bundler.spec.ts +++ b/src/tools/esbuild/angular-bundler.spec.ts @@ -166,4 +166,24 @@ describe('createAngularEsbuildContext', () => { ngJitMode: 'false', }); }); + + // #145: the #128 fix only covered the app build; exposes still inlined synthesized deep imports. + it('externalizes synthesized deep imports into shared mappings', async () => { + await createAngularEsbuildContext( + makeOptions({ mappedPaths: { [path.join(workspaceRoot, 'libs/ui/src/index.ts')]: '@myorg/ui' } }), + 'mapping-or-exposed' + ); + + expect(lastBuildOptions().plugins!.map(p => p.name)).toEqual([ + 'angular-compiler', + 'nf-shared-mappings', + 'commonjs', + ]); + }); + + it('leaves the plugin out without shared mappings', async () => { + await createAngularEsbuildContext(makeOptions(), 'mapping-or-exposed'); + + expect(lastBuildOptions().plugins!.map(p => p.name)).toEqual(['angular-compiler', 'commonjs']); + }); }); diff --git a/src/tools/esbuild/angular-bundler.ts b/src/tools/esbuild/angular-bundler.ts index 656aa8e..37b2e51 100644 --- a/src/tools/esbuild/angular-bundler.ts +++ b/src/tools/esbuild/angular-bundler.ts @@ -17,6 +17,7 @@ import { normalizeOptimization, normalizeSourceMaps } from '../../utils/normaliz import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js'; import type { NormalizedContextOptions } from '../../utils/normalize-context-options.js'; import { writeContextTsConfig } from './write-context-tsconfig.js'; +import { createSharedMappingsPlugin } from './shared-mappings-plugin.js'; export async function createAngularEsbuildContext( options: NormalizedContextOptions, @@ -36,6 +37,7 @@ export async function createAngularEsbuildContext( hash, chunks, platform, + mappedPaths, } = options; const federationTsConfig = options.tsConfigPath; @@ -172,7 +174,13 @@ export async function createAngularEsbuildContext( format: 'esm', target: target, logLimit: 0, - plugins: [compilerPlugin, commonjsPlugin(), ...customPlugins], + plugins: [ + compilerPlugin, + // Angular's synthesized deep imports would otherwise inline a second copy of a mapped lib. + ...(Object.keys(mappedPaths).length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []), + commonjsPlugin(), + ...customPlugins, + ], define: { ...builderOptions.define, ...(dev ? {} : { ngDevMode: 'false' }),