From 326134a3856bd8f47f48f3041fd242b14e48d398 Mon Sep 17 00:00:00 2001 From: Yutamago <12561505+yutamago@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:57:58 +0200 Subject: [PATCH] fix(native-federation): honour absolute outputPath when writing federation artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The federation output directory is resolved with path.join(workspaceRoot, outputPath) in several places. path.join() simply concatenates its segments, so when outputPath is absolute the result becomes `workspaceRoot + outputPath` — a bogus nested directory — instead of `outputPath`. When an absolute output path is used (e.g. `ng build --output-path `, which is common in CI), remoteEntry.json, importmap.json and the shared bundles are written outside the configured output directory. The @angular/build application builder honours the absolute path for the app bundles, so the app files and the federation artifacts end up in different directories and the remote fails to load at runtime (remoteEntry.json 404/403, "Unable to resolve specifier" for shared deps). Replace path.join(workspaceRoot, outputPath) with path.resolve(workspaceRoot, outputPath) at every site that combines the two. path.resolve is identical to join for relative paths but correctly honours an absolute outputPath. native-federation-core: - write-federation-info.ts (remoteEntry.json) - write-import-map.ts (importmap.json) - bundle-shared.ts (shared bundle copy + output path, 3 sites) native-federation (adapter): - utils/updateIndexHtml.ts (locating index.html) - plugin/index.ts (dev-server serve directory) --- libs/native-federation-core/src/lib/core/bundle-shared.ts | 6 +++--- .../src/lib/core/write-federation-info.ts | 2 +- .../native-federation-core/src/lib/core/write-import-map.ts | 2 +- libs/native-federation/src/plugin/index.ts | 2 +- libs/native-federation/src/utils/updateIndexHtml.ts | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libs/native-federation-core/src/lib/core/bundle-shared.ts b/libs/native-federation-core/src/lib/core/bundle-shared.ts index e69117c1..784ac2a6 100644 --- a/libs/native-federation-core/src/lib/core/bundle-shared.ts +++ b/libs/native-federation-core/src/lib/core/bundle-shared.ts @@ -48,7 +48,7 @@ export async function bundleShared( `Checksum of ${cacheOptions.bundleName} matched, Skipped artifact bundling`, ); bundleCache.copyFiles( - path.join(fedOptions.workspaceRoot, fedOptions.outputPath), + path.resolve(fedOptions.workspaceRoot, fedOptions.outputPath), ); return cacheMetadata.externals; } @@ -81,7 +81,7 @@ export async function bundleShared( return { fileName: pi.entryPoint, outName }; }); - const fullOutputPath = path.join( + const fullOutputPath = path.resolve( fedOptions.workspaceRoot, fedOptions.outputPath, ); @@ -174,7 +174,7 @@ export async function bundleShared( }); bundleCache.copyFiles( - path.join(fedOptions.workspaceRoot, fedOptions.outputPath), + path.resolve(fedOptions.workspaceRoot, fedOptions.outputPath), ); return result; diff --git a/libs/native-federation-core/src/lib/core/write-federation-info.ts b/libs/native-federation-core/src/lib/core/write-federation-info.ts index 1dcaa700..ffb44f1e 100644 --- a/libs/native-federation-core/src/lib/core/write-federation-info.ts +++ b/libs/native-federation-core/src/lib/core/write-federation-info.ts @@ -7,7 +7,7 @@ export function writeFederationInfo( federationInfo: FederationInfo, fedOptions: FederationOptions, ) { - const metaDataPath = path.join( + const metaDataPath = path.resolve( fedOptions.workspaceRoot, fedOptions.outputPath, 'remoteEntry.json', diff --git a/libs/native-federation-core/src/lib/core/write-import-map.ts b/libs/native-federation-core/src/lib/core/write-import-map.ts index fa1fde5f..97d7e52c 100644 --- a/libs/native-federation-core/src/lib/core/write-import-map.ts +++ b/libs/native-federation-core/src/lib/core/write-import-map.ts @@ -15,7 +15,7 @@ export function writeImportMap( }, {}); const importMap = { imports }; - const importMapPath = path.join( + const importMapPath = path.resolve( fedOption.workspaceRoot, fedOption.outputPath, 'importmap.json', diff --git a/libs/native-federation/src/plugin/index.ts b/libs/native-federation/src/plugin/index.ts index 0e38cfd1..91f2f1ef 100644 --- a/libs/native-federation/src/plugin/index.ts +++ b/libs/native-federation/src/plugin/index.ts @@ -56,7 +56,7 @@ const configureDevServer = async ( await federationBuilder.build(); const op = params.options; - const dist = path.join(op.workspaceRoot, op.outputPath); + const dist = path.resolve(op.workspaceRoot, op.outputPath); server.middlewares.use(serveFromDist(dist, fedInfo)); }; diff --git a/libs/native-federation/src/utils/updateIndexHtml.ts b/libs/native-federation/src/utils/updateIndexHtml.ts index fce3e09e..e6378889 100644 --- a/libs/native-federation/src/utils/updateIndexHtml.ts +++ b/libs/native-federation/src/utils/updateIndexHtml.ts @@ -7,7 +7,10 @@ export function updateIndexHtml( fedOptions: FederationOptions, nfOptions: NfBuilderSchema, ) { - const outputPath = path.join(fedOptions.workspaceRoot, fedOptions.outputPath); + const outputPath = path.resolve( + fedOptions.workspaceRoot, + fedOptions.outputPath, + ); const indexPathCands = [ path.join(outputPath, '../server/index.server.html'), path.join(outputPath, 'index.html'),