Skip to content

feat: Added support for shared-mapping glob patterns#1083

Merged
Aukevanoost merged 2 commits intomainfrom
issues/1081
Mar 17, 2026
Merged

feat: Added support for shared-mapping glob patterns#1083
Aukevanoost merged 2 commits intomainfrom
issues/1081

Conversation

@Aukevanoost
Copy link
Collaborator

Closes #1081

@maciekv
Copy link

maciekv commented Mar 17, 2026

Thanks for working on this. I’d be happy to test it against a real monorepo setup once it’s ready.

@Aukevanoost
Copy link
Collaborator Author

Cheers!

This should properly resolve shared-mappings with a glob (wildcard).
I tested this on my own setup and there it resolves properly, do let me know if you find anything!

@Aukevanoost Aukevanoost merged commit cc1b7f3 into main Mar 17, 2026
1 check passed
@Aukevanoost
Copy link
Collaborator Author

Hi @maciekv,

I prepared a release candidate for this specific feature. Do you mind double checking? Let me know what you find.

$ npm install @softarc/native-federation@3.5.5-RC1

@maciekv
Copy link

maciekv commented Mar 17, 2026

Hi @Aukevanoost !

Thanks for the quick turnaround on this!

I tested RC 3.5.5-RC1 with overrides in package.json to force a single version (without overrides, @angular-architects/native-federation installs its own nested @softarc/native-federation@3.5.4 which still has the wildcard filter):

"overrides": {
  "@softarc/native-federation": "^3.5.5-RC1"
}

Good news: The wildcard resolution works correctly — resolveTsConfigWildcard finds all 27 feature directories with index.ts barrel files, and getMappedPaths returns them properly. The old "Sharing mapped paths with wildcards (*) not supported" warning is gone.

Problem: The app crashes at runtime with a white page:

Unable to resolve specifier '@features/lang-switch/lang-switch.component?import' imported from http://localhost:4200/chunk-ADIIXRBT.js

What happens:

  1. getExternals() returns @features/lang-switch (the shared mapping key)
  2. esbuild receives external: ['@features/lang-switch', ...] and externalizes all sub-path imports too — so import { X } from '@features/lang-switch/lang-switch.component' becomes an external import in the output chunk
  3. At runtime, the import map only has an entry for @features/lang-switch, not for @features/lang-switch/lang-switch.component
  4. The browser cannot resolve the sub-path specifier → crash

The core issue: Our code imports individual files via wildcard tsconfig paths:

import { LangSwitchComponent } from '@features/lang-switch/lang-switch.component';

NF registers the shared mapping as @features/lang-switch (pointing to index.ts), but the actual import specifiers in the code are deeper sub-paths. The import map would need prefix/scope entries to redirect all @features/lang-switch/* requests to the shared bundle.

@Aukevanoost
Copy link
Collaborator Author

Aukevanoost commented Mar 17, 2026

Hi @maciekv, I see.

This is actually pretty fixable! But I think the real question here is, what is the desired behavior?

If native-federation bundles every little component or service into a separate entrypoint, then the bundles will become so small that they will lose their usefulness. Since every mapped path is transformed to an individual bundle.

I do understand that it should work at all times, therefore, I can see if I can rewrite the imports to the nearest entrypoint (barrel file). this way we're not polluting the remoteEntry.json with a million imports to individual typescript files.

How does that sound? In theory you wouldn't want the users of your library to be dependent directly on the internals of your shared library anyway (encapsulation rules). It might make sense for treeshaking purposes in an SPA, but not for shared libraries of your micro frontends. You'd prefer to bundle them into virtual "packages" that can be reused.

Let me know what you think

@maciekv
Copy link

maciekv commented Mar 17, 2026

That sounds like a very reasonable approach.

Rewriting imports to the nearest barrel file at build time keeps the shared bundles at a sensible granularity, while remaining transparent for developers — no need to change existing import paths in the codebase.

We already have index.ts barrel files in all 27 feature directories, so this should work well in our setup.

One small suggestion: it would be helpful if resolveTsConfigWildcard logged a warning when it skips a directory that has no index file, e.g.:

[shared-mapping] @features/spinner skipped: no index file found in libs/features/src/spinner/

Right now it silently skips, which makes debugging difficult.

Happy to test it once it's ready.

@Aukevanoost
Copy link
Collaborator Author

Hi @maciekv,

I did a little bit more digging and came across some other complications:

  • If I remap the import to the nearest barrel file, I am assuming that the file is exported there which it could not. That is a dangerous assumption since if it is not, the runtime error is changed to 'this other import doesn't expose or contain the class' which is confusing and very hard to debug. (This is also an issue for external shared libraries)
  • Right now, only the shared libraries imports are rewritten so I can't tap into the exposed modules (which includes shared mappings).
  • The worst part: for historical purposes, mappings (of shared internal and external libraries) are discovered eagerly at the moment (so before bundling the final output files). Therefore, performance is the biggest problem. It is true that the 'removeUnusedDeps' feature will remove unused mappings before the bundling part but they're still being exported. But it still takes time to discover and process all "potential imports".

So, to conclude, this will result in a breaking change. Native federation will need to see what is being imported before it starts processing wildcard exports. I will work on this on our next major v4 since it already contains breaking changes and gives us an opportunity to do it the right way.

For you this means (unfortunately) that you'll have to change your imports to use exclusively the barrel files for now.(which in my opinion in this case is the safer way anyway since it mimicks an external library). I will add the warning you asked about and leave it like this. I am fully aware that barrel files are not a silver bullet but for shared libraries, you need a more coarse-grained approach for reliable dependency sharing.

If you want you can create an issue on the v4 library with this information to keep track of my progress.
https://github.com/native-federation/native-federation-core/issues

Cheers for your time and the testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workspace libraries with wildcard tsconfig paths are not shared between shell and remotes (NG0912 collisions)

2 participants