With what library do you have an issue?
native-federation
Reproduction of the bug/regression with instructions
When ignoreUnusedDeps: true is enabled, the removeUnusedDeps scanner traces the dependency graph starting only from src/main.ts (hardcoded in builder.js). It uses @softarc/sheriff-core's getProjectData(main, ...) to discover used packages.
The problem: Files referenced in federation.config.js → exposes are not passed to the scanner as additional entry points. If an exposed module imports a shared dependency that is not also imported somewhere in the main.ts → routing chain, that dependency is silently filtered out of remoteEntry.json.
Steps to reproduce:
- Create a remote with
ignoreUnusedDeps: true in federation.config.js
- Expose a component via
exposes (e.g., './FaxWrapper': './src/app/wrapper/wrapper.component.ts')
- In that exposed component, import a shared library entry point (e.g.,
import { MyService } from 'my-lib/services/results')
- Do not import
my-lib/services/results anywhere in the main app routing tree (the component is only loaded by the host via federation)
- Build the remote
- Inspect
remoteEntry.json → my-lib/services/results is missing from the shared list, even though the exposed component uses it
The exposed component IS compiled (it appears in remoteEntry.json → exposes), but its dependencies are not recognized as "used" by the scanner.
Root cause in source code
In builder.js — entry point is hardcoded to src/main.ts:
// @angular-architects/native-federation/src/builders/build/builder.js line 116
const entryPoint = path.join(path.dirname(options.tsConfig), 'src/main.ts');
In remove-unused-deps.js — only main.ts is scanned:
// @softarc/native-federation/src/lib/core/remove-unused-deps.js line 12-14
const fileInfos = getProjectData(main, cwd(), {
includeExternalLibraries: true,
});
Only main.ts is used as the scanner entry point. The config.exposes values are never fed into the scanner.
Then filterShared keeps only packages found by the scanner — even explicitly added shared entries are dropped:
// remove-unused-deps.js line 22-25
function filterShared(config, usedPackageNamesWithTransient) {
const filteredSharedNames = Object.keys(config.shared).filter(
(shared) => usedPackageNamesWithTransient.has(shared)
);
// ...
}
This means even if you manually add the package to the shared config, ignoreUnusedDeps will override and remove it.
Expected behavior
The removeUnusedDeps scanner should also scan files referenced in federation.config.js → exposes, since those are compiled entry points whose shared dependencies must be available at runtime. Alternatively, explicitly added shared entries should not be filtered out by ignoreUnusedDeps.
Suggested fix
In remove-unused-deps.js, also pass exposed module paths to getProjectData (or run separate scans for each exposed file and merge the results):
// Pseudo-code
const exposedFiles = Object.values(config.exposes);
const allEntryPoints = [main, ...exposedFiles];
// Scan each and merge usedDeps
Or at minimum, preserve explicitly configured shared entries even when ignoreUnusedDeps is active.
Workaround
Add a side-effect import in bootstrap.ts (which IS reachable from main.ts) for any dependency only used by exposed modules:
// Side-effect import: ensures ignoreUnusedDeps scanner discovers this entry point
import 'my-lib/services/results';
Versions
@angular-architects/native-federation: 19.0.4
@softarc/native-federation: 19.0.7
- Angular: 19
- Node: 22.x
With what library do you have an issue?
native-federation
Reproduction of the bug/regression with instructions
When
ignoreUnusedDeps: trueis enabled, theremoveUnusedDepsscanner traces the dependency graph starting only fromsrc/main.ts(hardcoded inbuilder.js). It uses@softarc/sheriff-core'sgetProjectData(main, ...)to discover used packages.The problem: Files referenced in
federation.config.js→exposesare not passed to the scanner as additional entry points. If an exposed module imports a shared dependency that is not also imported somewhere in themain.ts→ routing chain, that dependency is silently filtered out ofremoteEntry.json.Steps to reproduce:
ignoreUnusedDeps: trueinfederation.config.jsexposes(e.g.,'./FaxWrapper': './src/app/wrapper/wrapper.component.ts')import { MyService } from 'my-lib/services/results')my-lib/services/resultsanywhere in the main app routing tree (the component is only loaded by the host via federation)remoteEntry.json→my-lib/services/resultsis missing from the shared list, even though the exposed component uses itThe exposed component IS compiled (it appears in
remoteEntry.json→exposes), but its dependencies are not recognized as "used" by the scanner.Root cause in source code
In
builder.js— entry point is hardcoded tosrc/main.ts:In
remove-unused-deps.js— onlymain.tsis scanned:Only
main.tsis used as the scanner entry point. Theconfig.exposesvalues are never fed into the scanner.Then
filterSharedkeeps only packages found by the scanner — even explicitly added shared entries are dropped:This means even if you manually add the package to the
sharedconfig,ignoreUnusedDepswill override and remove it.Expected behavior
The
removeUnusedDepsscanner should also scan files referenced infederation.config.js→exposes, since those are compiled entry points whose shared dependencies must be available at runtime. Alternatively, explicitly added shared entries should not be filtered out byignoreUnusedDeps.Suggested fix
In
remove-unused-deps.js, also pass exposed module paths togetProjectData(or run separate scans for each exposed file and merge the results):Or at minimum, preserve explicitly configured shared entries even when
ignoreUnusedDepsis active.Workaround
Add a side-effect import in
bootstrap.ts(which IS reachable frommain.ts) for any dependency only used by exposed modules:Versions
@angular-architects/native-federation: 19.0.4@softarc/native-federation: 19.0.7