@softarc/native-federation 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +638 -0
  3. package/dist/config.js +17 -0
  4. package/dist/domain.js +2 -0
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.js +21 -0
  7. package/{src → dist}/internal.d.ts +6 -7
  8. package/dist/internal.js +26 -0
  9. package/dist/lib/config/configuration-context.js +15 -0
  10. package/dist/lib/config/default-skip-list.js +36 -0
  11. package/dist/lib/config/get-external-imports.d.ts +2 -0
  12. package/dist/lib/config/get-external-imports.js +60 -0
  13. package/dist/lib/config/get-used-dependencies.d.ts +24 -0
  14. package/dist/lib/config/get-used-dependencies.js +126 -0
  15. package/{src/lib/utils → dist/lib/config}/mapped-paths.d.ts +2 -2
  16. package/dist/lib/config/mapped-paths.js +31 -0
  17. package/dist/lib/config/remove-unused-deps.js +11 -0
  18. package/dist/lib/config/share-utils.d.ts +20 -0
  19. package/dist/lib/config/share-utils.js +344 -0
  20. package/dist/lib/config/with-native-federation.js +80 -0
  21. package/{src/lib/core → dist/lib/core/build}/build-adapter.d.ts +1 -1
  22. package/dist/lib/core/build/build-adapter.js +16 -0
  23. package/dist/lib/core/build/build-for-federation.d.ts +4 -0
  24. package/dist/lib/core/build/build-for-federation.js +207 -0
  25. package/{src/lib/utils → dist/lib/core/build}/build-result-map.d.ts +1 -1
  26. package/dist/lib/core/build/build-result-map.js +39 -0
  27. package/dist/lib/core/build/bundle-exposed-and-mappings.d.ts +13 -0
  28. package/dist/lib/core/build/bundle-exposed-and-mappings.js +178 -0
  29. package/dist/lib/core/build/bundle-shared.d.ts +34 -0
  30. package/dist/lib/core/build/bundle-shared.js +261 -0
  31. package/dist/lib/core/build/compute-integrity.d.ts +11 -0
  32. package/dist/lib/core/build/compute-integrity.js +20 -0
  33. package/dist/lib/core/build/default-external-list.js +32 -0
  34. package/dist/lib/core/build/get-externals.d.ts +2 -0
  35. package/dist/lib/core/build/get-externals.js +9 -0
  36. package/dist/lib/core/build/rebuild-for-federation.d.ts +4 -0
  37. package/dist/lib/core/build/rebuild-for-federation.js +52 -0
  38. package/dist/lib/core/build/rewrite-chunk-imports.d.ts +5 -0
  39. package/dist/lib/core/build/rewrite-chunk-imports.js +74 -0
  40. package/dist/lib/core/cache/cache-persistence.d.ts +22 -0
  41. package/dist/lib/core/cache/cache-persistence.js +63 -0
  42. package/{src/lib/core → dist/lib/core/cache}/federation-cache.d.ts +2 -2
  43. package/dist/lib/core/cache/federation-cache.js +22 -0
  44. package/dist/lib/core/federation-builder.js +53 -0
  45. package/{src → dist}/lib/core/normalize-options.d.ts +13 -1
  46. package/dist/lib/core/normalize-options.js +67 -0
  47. package/dist/lib/core/output/write-federation-info.d.ts +5 -0
  48. package/dist/lib/core/output/write-federation-info.js +17 -0
  49. package/dist/lib/core/output/write-import-map.d.ts +11 -0
  50. package/dist/lib/core/output/write-import-map.js +42 -0
  51. package/dist/lib/core/rebuild-queue.js +61 -0
  52. package/{src → dist}/lib/domain/config/external-config.contract.d.ts +2 -2
  53. package/dist/lib/domain/config/external-config.contract.js +0 -0
  54. package/{src → dist}/lib/domain/config/federation-config.contract.d.ts +6 -2
  55. package/dist/lib/domain/config/federation-config.contract.js +0 -0
  56. package/dist/lib/domain/config/index.js +0 -0
  57. package/dist/lib/domain/config/skip-list.contract.js +0 -0
  58. package/dist/lib/domain/core/build-adapter.contract.js +0 -0
  59. package/dist/lib/domain/core/build-notification-options.contract.js +9 -0
  60. package/dist/lib/domain/core/chunk.js +12 -0
  61. package/dist/lib/domain/core/federation-cache.contract.js +0 -0
  62. package/{src → dist}/lib/domain/core/federation-info.contract.d.ts +1 -0
  63. package/dist/lib/domain/core/federation-info.contract.js +0 -0
  64. package/dist/lib/domain/core/federation-options.contract.js +0 -0
  65. package/{src → dist}/lib/domain/core/index.d.ts +1 -0
  66. package/dist/lib/domain/core/index.js +9 -0
  67. package/dist/lib/domain/core/manifest.contract.d.ts +5 -0
  68. package/dist/lib/domain/core/manifest.contract.js +0 -0
  69. package/dist/lib/domain/utils/file-watcher.contract.js +0 -0
  70. package/dist/lib/domain/utils/io-port.contract.d.ts +45 -0
  71. package/dist/lib/domain/utils/io-port.contract.js +0 -0
  72. package/dist/lib/domain/utils/keyvaluepair.contract.js +0 -0
  73. package/dist/lib/domain/utils/mapped-path.contract.js +0 -0
  74. package/dist/lib/domain/utils/package-json.contract.d.ts +27 -0
  75. package/dist/lib/domain/utils/package-json.contract.js +0 -0
  76. package/dist/lib/domain/utils/used-dependencies.contract.js +0 -0
  77. package/dist/lib/utils/errors.js +10 -0
  78. package/{src → dist}/lib/utils/file-watcher.d.ts +2 -0
  79. package/dist/lib/utils/file-watcher.js +51 -0
  80. package/dist/lib/utils/hash-file.d.ts +7 -0
  81. package/dist/lib/utils/hash-file.js +15 -0
  82. package/dist/lib/utils/io/node-io-adapter.d.ts +2 -0
  83. package/dist/lib/utils/io/node-io-adapter.js +68 -0
  84. package/dist/lib/utils/io/package-json-repository.d.ts +5 -0
  85. package/dist/lib/utils/io/package-json-repository.js +79 -0
  86. package/dist/lib/utils/logger.js +29 -0
  87. package/dist/lib/utils/normalize.js +22 -0
  88. package/dist/lib/utils/package/entry-point-resolver.d.ts +2 -0
  89. package/dist/lib/utils/package/entry-point-resolver.js +78 -0
  90. package/dist/lib/utils/package/esm-detection.d.ts +5 -0
  91. package/dist/lib/utils/package/esm-detection.js +10 -0
  92. package/dist/lib/utils/package/exports-resolver.d.ts +13 -0
  93. package/dist/lib/utils/package/exports-resolver.js +55 -0
  94. package/dist/lib/utils/package/package-info.d.ts +7 -0
  95. package/dist/lib/utils/package/package-info.js +31 -0
  96. package/dist/lib/utils/package/resolve-wildcard-keys.d.ts +3 -0
  97. package/dist/lib/utils/package/resolve-wildcard-keys.js +22 -0
  98. package/dist/lib/utils/package/version-maps.d.ts +3 -0
  99. package/dist/lib/utils/package/version-maps.js +8 -0
  100. package/dist/lib/utils/path-patterns.d.ts +14 -0
  101. package/dist/lib/utils/path-patterns.js +28 -0
  102. package/package.json +45 -22
  103. package/src/config.js +0 -4
  104. package/src/domain.js +0 -2
  105. package/src/index.d.ts +0 -10
  106. package/src/index.js +0 -10
  107. package/src/internal.js +0 -11
  108. package/src/lib/config/configuration-context.js +0 -10
  109. package/src/lib/config/default-skip-list.js +0 -31
  110. package/src/lib/config/remove-unused-deps.js +0 -10
  111. package/src/lib/config/share-utils.d.ts +0 -10
  112. package/src/lib/config/share-utils.js +0 -302
  113. package/src/lib/config/with-native-federation.js +0 -71
  114. package/src/lib/core/build-adapter.js +0 -12
  115. package/src/lib/core/build-for-federation.d.ts +0 -4
  116. package/src/lib/core/build-for-federation.js +0 -173
  117. package/src/lib/core/bundle-exposed-and-mappings.d.ts +0 -7
  118. package/src/lib/core/bundle-exposed-and-mappings.js +0 -174
  119. package/src/lib/core/bundle-shared.d.ts +0 -13
  120. package/src/lib/core/bundle-shared.js +0 -222
  121. package/src/lib/core/default-external-list.js +0 -29
  122. package/src/lib/core/federation-builder.js +0 -45
  123. package/src/lib/core/federation-cache.js +0 -16
  124. package/src/lib/core/get-externals.d.ts +0 -2
  125. package/src/lib/core/get-externals.js +0 -6
  126. package/src/lib/core/normalize-options.js +0 -58
  127. package/src/lib/core/rebuild-for-federation.d.ts +0 -4
  128. package/src/lib/core/rebuild-for-federation.js +0 -43
  129. package/src/lib/core/write-federation-info.d.ts +0 -3
  130. package/src/lib/core/write-federation-info.js +0 -6
  131. package/src/lib/core/write-import-map.d.ts +0 -6
  132. package/src/lib/core/write-import-map.js +0 -33
  133. package/src/lib/domain/config/external-config.contract.js +0 -1
  134. package/src/lib/domain/config/federation-config.contract.js +0 -1
  135. package/src/lib/domain/config/index.js +0 -1
  136. package/src/lib/domain/config/skip-list.contract.js +0 -1
  137. package/src/lib/domain/config/with-native-federation.contract.d.ts +0 -2
  138. package/src/lib/domain/config/with-native-federation.contract.js +0 -1
  139. package/src/lib/domain/core/build-adapter.contract.js +0 -1
  140. package/src/lib/domain/core/build-notification-options.contract.js +0 -6
  141. package/src/lib/domain/core/chunk.js +0 -8
  142. package/src/lib/domain/core/federation-cache.contract.js +0 -1
  143. package/src/lib/domain/core/federation-info.contract.js +0 -1
  144. package/src/lib/domain/core/federation-options.contract.js +0 -1
  145. package/src/lib/domain/core/index.js +0 -2
  146. package/src/lib/domain/utils/file-watcher.contract.js +0 -1
  147. package/src/lib/domain/utils/index.d.ts +0 -2
  148. package/src/lib/domain/utils/index.js +0 -1
  149. package/src/lib/domain/utils/keyvaluepair.contract.js +0 -1
  150. package/src/lib/domain/utils/mapped-path.contract.js +0 -5
  151. package/src/lib/domain/utils/used-dependencies.contract.js +0 -1
  152. package/src/lib/utils/build-result-map.js +0 -29
  153. package/src/lib/utils/cache-persistence.d.ts +0 -19
  154. package/src/lib/utils/cache-persistence.js +0 -66
  155. package/src/lib/utils/errors.js +0 -7
  156. package/src/lib/utils/file-watcher.js +0 -51
  157. package/src/lib/utils/get-external-imports.d.ts +0 -1
  158. package/src/lib/utils/get-external-imports.js +0 -80
  159. package/src/lib/utils/get-used-dependencies.d.ts +0 -7
  160. package/src/lib/utils/get-used-dependencies.js +0 -123
  161. package/src/lib/utils/hash-file.d.ts +0 -3
  162. package/src/lib/utils/hash-file.js +0 -13
  163. package/src/lib/utils/logger.js +0 -27
  164. package/src/lib/utils/mapped-paths.js +0 -33
  165. package/src/lib/utils/normalize.js +0 -17
  166. package/src/lib/utils/package-info.d.ts +0 -30
  167. package/src/lib/utils/package-info.js +0 -268
  168. package/src/lib/utils/rebuild-queue.js +0 -63
  169. package/src/lib/utils/resolve-glob.d.ts +0 -1
  170. package/src/lib/utils/resolve-glob.js +0 -29
  171. package/src/lib/utils/resolve-wildcard-keys.d.ts +0 -29
  172. package/src/lib/utils/resolve-wildcard-keys.js +0 -126
  173. package/src/lib/utils/rewrite-chunk-imports.d.ts +0 -2
  174. package/src/lib/utils/rewrite-chunk-imports.js +0 -48
  175. /package/{src → dist}/config.d.ts +0 -0
  176. /package/{src → dist}/domain.d.ts +0 -0
  177. /package/{src → dist}/lib/config/configuration-context.d.ts +0 -0
  178. /package/{src → dist}/lib/config/default-skip-list.d.ts +0 -0
  179. /package/{src → dist}/lib/config/remove-unused-deps.d.ts +0 -0
  180. /package/{src → dist}/lib/config/with-native-federation.d.ts +0 -0
  181. /package/{src/lib/core → dist/lib/core/build}/default-external-list.d.ts +0 -0
  182. /package/{src → dist}/lib/core/federation-builder.d.ts +0 -0
  183. /package/{src/lib/utils → dist/lib/core}/rebuild-queue.d.ts +0 -0
  184. /package/{src → dist}/lib/domain/config/index.d.ts +0 -0
  185. /package/{src → dist}/lib/domain/config/skip-list.contract.d.ts +0 -0
  186. /package/{src → dist}/lib/domain/core/build-adapter.contract.d.ts +0 -0
  187. /package/{src → dist}/lib/domain/core/build-notification-options.contract.d.ts +0 -0
  188. /package/{src → dist}/lib/domain/core/chunk.d.ts +0 -0
  189. /package/{src → dist}/lib/domain/core/federation-cache.contract.d.ts +0 -0
  190. /package/{src → dist}/lib/domain/core/federation-options.contract.d.ts +0 -0
  191. /package/{src → dist}/lib/domain/utils/file-watcher.contract.d.ts +0 -0
  192. /package/{src → dist}/lib/domain/utils/keyvaluepair.contract.d.ts +0 -0
  193. /package/{src → dist}/lib/domain/utils/mapped-path.contract.d.ts +0 -0
  194. /package/{src → dist}/lib/domain/utils/used-dependencies.contract.d.ts +0 -0
  195. /package/{src → dist}/lib/utils/errors.d.ts +0 -0
  196. /package/{src → dist}/lib/utils/logger.d.ts +0 -0
  197. /package/{src → dist}/lib/utils/normalize.d.ts +0 -0
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2025 Native federation group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,638 @@
1
+ # @softarc/native-federation
2
+
3
+ Native Federation is a "browser-native" implementation of the successful mental model behind wepback Module Federation for building Micro Frontends and plugin-based solutions. It can be **used with any framework and build tool** for implementing **Micro Frontends** and plugin-based architectures.
4
+
5
+ > [!WARNING]
6
+ > **This is our v4 version**. For the v3 version, check out the [module-federation-plugin repository](https://github.com/angular-architects/module-federation-plugin/tree/main/libs/native-federation-core).
7
+
8
+ ## Features
9
+
10
+ - ✅ Mental Model of Module Federation
11
+ - ✅ Future Proof: Independent of build tools like webpack and frameworks
12
+ - ✅ Embraces Import Maps -- an emerging browser technology -- and EcmaScript modules
13
+ - ✅ Easy to configure
14
+ - ✅ Blazing Fast: The reference implementation not only uses the fast esbuild; it also caches already built shared dependencies (like Angular itself). However, as mentioned above, feel free to use it with any other build tool.
15
+
16
+ ## Stack
17
+
18
+ This library allows to augment your build process, to configure hosts (Micro Frontend shells) and remotes (Micro Frontends), and to load remotes at runtime.
19
+
20
+ While this core library can be used with any framework and build tool, there is a higher level API on top of it. It hooks into the Angular CLI and provides a builder and schematics:
21
+
22
+ ![Stack](https://github.com/angular-architects/module-federation-plugin/raw/main/libs/native-federation-core/stack.png)
23
+
24
+ > Please find the [Angular-based version here](https://www.npmjs.com/package/@angular-architects/native-federation).
25
+
26
+ > Please find the [vite plugin here](https://www.npmjs.com/package/@gioboa/vite-module-federation).
27
+
28
+ Also, other higher level abstractions on top of this core library are possible.
29
+
30
+ ## About the Mental Model
31
+
32
+ The underlying mental model allows for runtime integration: Loading a part of a separately built and deployed application into your host. This is needed for Micro Frontend architectures but also for plugin-based solutions.
33
+
34
+ For this, the mental model introduces several concepts:
35
+
36
+ - **Remote:** The remote is a separately built and deployed application. It can **expose EcmaScript** modules that can be loaded into other applications.
37
+ - **Host:** The host loads one or several remotes on demand. For your framework's perspective, this looks like traditional lazy loading. The big difference is that the host doesn't know the remotes at compilation time.
38
+ - **Shared Dependencies:** If a several remotes and the host use the same library, you might not want to download it several times. Instead, you might want to just download it once and share it at runtime. For this use case, the mental model allows for defining such shared dependencies.
39
+ - **Version Mismatch:** If two or more applications use a different version of the same shared library, we need to prevent a version mismatch. To deal with it, the mental model defines several strategies, like falling back to another version that fits the application, using a different compatible one (according to semantic versioning) or throwing an error.
40
+
41
+ ## Example
42
+
43
+ - [VanillaJS example](https://github.com/manfredsteyer/native-federation-core-microfrontend).
44
+ - [React example](https://github.com/manfredsteyer/native-federation-react-example)
45
+ - This example also shows the **watch mode** for compiling a federated application
46
+ - [Vite + Svelte example](https://github.com/gioboa/svelte-microfrontend-demo)
47
+ - [Vite + Angular example powered by AnalogJS](https://github.com/manfredsteyer/native-federation-vite-angular-demo)
48
+ - **Your Example:** If you have an example with aspects not covered here, let us know. We are happy to link it here.
49
+
50
+ ## Credits
51
+
52
+ Big thanks to:
53
+
54
+ - [Zack Jackson](https://twitter.com/ScriptedAlchemy) for originally coming up with the great idea of Module Federation and its successful mental model
55
+ - [Florian Rappl](https://twitter.com/FlorianRappl) for an good discussion about these topics during a speakers dinner in Nuremberg
56
+ - [Michael Egger-Zikes](https://twitter.com/MikeZks) for contributing to our Module Federation efforts and brining in valuable feedback
57
+ - The Angular CLI-Team, esp. [Alan Agius](https://twitter.com/AlanAgius4) and [Charles Lyding](https://twitter.com/charleslyding), for working on the experimental esbuild builder for Angular
58
+
59
+ ## Using this Library
60
+
61
+ ### Installing the Library
62
+
63
+ ```
64
+ npm i @softarc/native-federation
65
+ ```
66
+
67
+ As Native Federation is tooling agnostic, we need an adapter to make it work with specific build tools. The package `@softarc/native-federation-esbuild` contains a simple adapter that uses esbuild.
68
+
69
+ ```
70
+ npm i @softarc/native-federation-esbuild
71
+ ```
72
+
73
+ You can also provide your own adapter by providing a function aligning with the `NFBuildAdapter` [[src](https://github.com/native-federation/native-federation-core/blob/main/src/lib/core/build-adapter.ts)] type.
74
+
75
+ ### Augment your Build Process
76
+
77
+ > [!WARNING]
78
+ > The esbuild adapter is currently under construction, check the progress here: https://github.com/native-federation/esbuild-adapter
79
+
80
+ Just call three helper methods provided by our `federationBuilder` in your build process to adjust it for Native Federation.
81
+
82
+ ```typescript
83
+ import * as esbuild from 'esbuild';
84
+ import * as path from 'path';
85
+ import * as fs from 'fs';
86
+ import { esBuildAdapter } from '@softarc/native-federation-esbuild';
87
+ import { federationBuilder } from '@softarc/native-federation';
88
+
89
+
90
+ const projectName = 'shell';
91
+ const tsConfig = 'tsconfig.json';
92
+ const outputPath = `dist/${projectName}`;
93
+
94
+ /*
95
+ * Step 1: Initialize Native Federation
96
+ */
97
+ await federationBuilder.init({
98
+ options: {
99
+ workspaceRoot: path.join(__dirname, '..'),
100
+ outputPath,
101
+ tsConfig,
102
+ federationConfig: `${projectName}/federation.config.js`,
103
+ verbose: false,
104
+ },
105
+
106
+ /*
107
+ * As this core lib is tooling-agnostic, you
108
+ * need a simple adapter for your bundler.
109
+ * It's just a matter of one function.
110
+ */
111
+ adapter: esBuildAdapter
112
+ });
113
+
114
+ /*
115
+ * Step 2: Trigger your build process
116
+ *
117
+ * You can use any tool for this. Here, we go
118
+ * with a very simple esbuild-based build.
119
+ *
120
+ * Just respect the externals in
121
+ * `federationBuilder.externals`.
122
+ */
123
+
124
+ [...]
125
+
126
+ await esbuild.build({
127
+ [...]
128
+ external: federationBuilder.externals,
129
+ [...]
130
+ });
131
+
132
+ [...]
133
+
134
+ /*
135
+ * Step 3: Let the build method do the additional tasks
136
+ * for supporting Native Federation
137
+ */
138
+
139
+ await federationBuilder.build();
140
+ ```
141
+
142
+ The method `federationBuilder.build` bundles the shared and exposed parts of your app.
143
+
144
+ ### Configuring Hosts
145
+
146
+ The `withNativeFederation` function sets up a configuration for your applications. This is an example configuration for a host:
147
+
148
+ The `shareAll` helper shares all your dependencies defined in your `package.json`. The `package.json` is look up as described above:
149
+
150
+ ```typescript
151
+ // shell/federation.config.js
152
+
153
+ import { withNativeFederation, shareAll } from '@softarc/native-federation/config';
154
+
155
+ export default withNativeFederation({
156
+ name: 'host',
157
+
158
+ shared: {
159
+ ...shareAll({
160
+ singleton: true,
161
+ strictVersion: true,
162
+ requiredVersion: 'auto',
163
+ includeSecondaries: false,
164
+ }),
165
+ },
166
+ });
167
+ ```
168
+
169
+ The options passed to shareAll are applied to all dependencies found in your `package.json`.
170
+
171
+ This might come in handy in an mono repo scenario and when doing some experiments/ trouble shooting.
172
+
173
+ > Since v21.1 it's also possible to add overrides to the shareAll for specific packages.
174
+
175
+ ```typescript
176
+ // shell/federation.config.js
177
+
178
+ import { withNativeFederation, shareAll } from '@softarc/native-federation/config';
179
+
180
+ export default withNativeFederation({
181
+ name: 'host',
182
+
183
+ shared: {
184
+ ...shareAll(
185
+ {
186
+ singleton: true,
187
+ strictVersion: true,
188
+ requiredVersion: 'auto',
189
+ },
190
+ {
191
+ overrides: {
192
+ 'package-a/themes/xyz': {
193
+ singleton: true,
194
+ strictVersion: true,
195
+ requiredVersion: 'auto',
196
+ includeSecondaries: { skip: '@package-a/themes/xyz/*' },
197
+ build: 'package',
198
+ },
199
+ 'package-b': {
200
+ singleton: false,
201
+ strictVersion: true,
202
+ requiredVersion: 'auto',
203
+ includeSecondaries: { skip: 'package-b/icons/*' },
204
+ build: 'package',
205
+ },
206
+ },
207
+ }
208
+ ),
209
+ },
210
+ });
211
+ ```
212
+
213
+ ### Share Helper
214
+
215
+ The helper function share adds some additional options for the shared dependencies:
216
+
217
+ ```typescript
218
+ shared: share({
219
+ "package-a": {
220
+ singleton: true,
221
+ strictVersion: true,
222
+ requiredVersion: 'auto',
223
+ includeSecondaries: true
224
+ },
225
+ [...]
226
+ })
227
+ ```
228
+
229
+ The added options are `requireVersion: 'auto'` and `includeSecondaries`.
230
+
231
+ #### requireVersion: 'auto'
232
+
233
+ If you set `requireVersion` to `'auto'`, the helper takes the version defined in your `package.json`.
234
+
235
+ This helps to solve issues with not (fully) met peer dependencies and secondary entry points (see Pitfalls section below).
236
+
237
+ By default, it takes the `package.json` that is closest to the caller (normally the `webpack.config.js`). However, you can pass the path to an other `package.json` using the second optional parameter. Also, you need to define the shared libray within the node dependencies in your `package.json`.
238
+
239
+ Instead of setting requireVersion to auto time and again, you can also skip this option and call `setInferVersion(true)` before:
240
+
241
+ ```typescript
242
+ setInferVersion(true);
243
+ ```
244
+
245
+ #### includeSecondaries
246
+
247
+ If set to `true`, all secondary entry points are added too. In the case of `@angular/common` this is also `@angular/common/http`, `@angular/common/http/testing`, `@angular/common/testing`, `@angular/common/http/upgrade`, and `@angular/common/locales`. This exhaustive list shows that using this option for `@angular/common` is not the best idea because normally, you don't need most of them.
248
+
249
+ > `includeSecondaries` is true by default.
250
+
251
+ However, this option can come in handy for quick experiments or if you want to quickly share a package like `@angular/material` that comes with a myriad of secondary entry points.
252
+
253
+ Even if you share too much, Native Federation will only load the needed ones at runtime. However, please keep in mind that shared packages can not be tree-shaken.
254
+
255
+ To skip some secondary entry points, you can assign a configuration option instead of `true`:
256
+
257
+ ```typescript
258
+ shared: share({
259
+ "@angular/common": {
260
+ singleton: true,
261
+ strictVersion: true,
262
+ requiredVersion: 'auto',
263
+ includeSecondaries: {
264
+ skip: ['@angular/common/http/testing']
265
+ }
266
+ },
267
+ [...]
268
+ })
269
+ ```
270
+
271
+ By default, all entrypoints of a package are considered, you can disable expensive glob resolves using the `globResolve` property:
272
+
273
+ ```typescript
274
+ shared: share({
275
+ "package-a": {
276
+ singleton: true,
277
+ strictVersion: true,
278
+ requiredVersion: "auto",
279
+ includeSecondaries: {resolveGlob: true}
280
+ },
281
+ [...]
282
+ })
283
+ ```
284
+
285
+ This is enabled by default but might not always desirable since it will create a bundle of every valid exported file it finds, **Therefore it is recommended not to disable the `ignoreUnusedDeps` feature**. If you want to specifically skip certain parts of the glob export, you can also use the wildcard in the skip section:
286
+
287
+ ```typescript
288
+ shared: share({
289
+ "package-a/themes/xyz": {
290
+ singleton: true,
291
+ strictVersion: true,
292
+ requiredVersion: "auto",
293
+ includeSecondaries: {skip: "package-a/themes/xyz/*", resolveGlob: true}
294
+ },
295
+ [...]
296
+ })
297
+ ```
298
+
299
+ Finally, it's also possible to break out of the "removeUnusedDep" feature for specific externals if desired, for example when sharing a whole suite of interconnected external dependencies like @angular/core. This can be handy when you want to avoid the chance of cross-version secondary entrypoints being used by the different micro frontends. E.g. mfe1 uses @angular/core v20.1.0 and mfe2 uses @angular/core/rxjs-interop v20.0.8, then you might want to use consistent use of v20.1.0 so rxjs-interop should be exported by mfe1. The "keepAll" prop allows you to enforce this:
300
+
301
+ ```typescript
302
+ shared: share({
303
+ "@angular/core": {
304
+ singleton: true,
305
+ strictVersion: true,
306
+ requiredVersion: "auto",
307
+ includeSecondaries: {keepAll: true}
308
+ },
309
+ [...]
310
+ })
311
+ ```
312
+
313
+ The API for configuring and using Native Federation is very similar to the one provided by our Module Federation plugin [@angular-architects/module-federation](https://www.npmjs.com/package/@angular-architects/native-federation). Hence, most the articles on it are also valid for Native Federation.
314
+
315
+ ### Sharing
316
+
317
+ The `shareAll`-helper used here shares all dependencies found in your `package.json`. Hence, they only need to be loaded once (instead of once per remote and host). If you don't want to share all of them, you can opt-out of sharing by using the `skip` option:
318
+
319
+ ```typescript
320
+ n
321
+ export default withNativeFederation({
322
+ [...]
323
+
324
+ // Don't share my-lib
325
+ skip: [
326
+ 'my-lib'
327
+ ]
328
+
329
+ [...]
330
+ })
331
+ ```
332
+
333
+ ### Sharing Mapped Paths (Monorepo-internal Libraries)
334
+
335
+ Paths mapped in your `tsconfig.json` are shared by default too. While they are part of your (mono) repository, they are treaded like libraries:
336
+
337
+ ```json
338
+ {
339
+ "compilerOptions": {
340
+ [...]
341
+ "paths": {
342
+ "shared-lib": [
343
+ "libs/shared-lib/index.ts"
344
+ ]
345
+ }
346
+ }
347
+ }
348
+ ```
349
+
350
+ If you don't want to share (all of) them, put their names into the skip array (see above).
351
+
352
+ ### Detemining which internal libraries are shared
353
+
354
+ In Nx/monorepo setups, Native Federation shares all libraries from your `tsconfig` path mappings by default.
355
+
356
+ If you only want to share selected mapped paths, you can use `sharedMappings` in your `federation.config.js`:
357
+
358
+ ```js
359
+ module.exports = withNativeFederation({
360
+ shared: {
361
+ ...shareAll({
362
+ singleton: true,
363
+ strictVersion: true,
364
+ requiredVersion: 'auto',
365
+ }),
366
+ },
367
+ sharedMappings: ['@my-org/auth-lib', '@my-org/ui/*'],
368
+ });
369
+ ```
370
+
371
+ Notes:
372
+
373
+ - `sharedMappings` is optional. If you omit it, all mapped paths are shared.
374
+ - You can use wildcard suffixes (for example, `@my-org/ui/*`) to include multiple mapped paths.
375
+ - `skip` still applies and can be used to exclude mapped paths even if they were selected via `sharedMappings`.
376
+ - Mapped paths are read from the workspace root tsconfig file: `tsconfig.base.json` if present, otherwise `tsconfig.json`.
377
+ - The workspace root is detected by searching upward from the current working directory until a `package.json` is found.
378
+
379
+ If you don't want to share libraries within a monorepo and also distribute them as built libraries with a version, disable the `mappingVersion` feature flag in your `federation.config.js`. This ensures that the corresponding versions from your buildable libraries are used.
380
+
381
+ ```js
382
+ module.exports = withNativeFederation({
383
+ shared: {
384
+ ...shareAll({
385
+ singleton: true,
386
+ strictVersion: true,
387
+ requiredVersion: 'auto',
388
+ }),
389
+ },
390
+ sharedMappings: ['@my-org/auth-lib', '@my-org/ui/*'],
391
+ features: {
392
+ mappingVersion: false,
393
+ },
394
+ });
395
+ ```
396
+
397
+ If enabled, Native Federation tries to read the version from the mapped library's nearest `package.json`. By default this feature is set to `false`.
398
+
399
+ ### Code-Splitting for Shared Dependencies
400
+
401
+ By default, Native Federation enables code-splitting (chunking) for shared dependencies. This means large libraries can be split into smaller chunks which reduces the overal size, improving initial load times.
402
+
403
+ You can configure code-splitting at two levels:
404
+
405
+ #### Global Setting
406
+
407
+ Use the `chunks` option in your `federation.config.js` to control the default behavior for all shared dependencies:
408
+
409
+ ```js
410
+ module.exports = withNativeFederation({
411
+ // Disable code-splitting globally
412
+ chunks: false,
413
+
414
+ shared: {
415
+ ...shareAll({
416
+ singleton: true,
417
+ strictVersion: true,
418
+ requiredVersion: 'auto',
419
+ }),
420
+ },
421
+ });
422
+ ```
423
+
424
+ When `chunks` is set to `false` at the config level, all shared dependencies, shared mappings and exposed modules will be bundled as single files without code-splitting.
425
+
426
+ #### Per-Package Setting
427
+
428
+ You can also override the code-splitting behavior for individual packages in the `shared` configuration:
429
+
430
+ ```js
431
+ module.exports = withNativeFederation({
432
+ shared: {
433
+ ...shareAll(
434
+ {
435
+ singleton: true,
436
+ strictVersion: true,
437
+ requiredVersion: 'auto',
438
+ },
439
+ overrides: {
440
+ 'large-lib': {
441
+ singleton: true,
442
+ strictVersion: true,
443
+ requiredVersion: 'auto',
444
+ chunks: false,
445
+ build: 'package' // necessary for isolated bundles
446
+ },
447
+ }
448
+ ),
449
+ // Disable code-splitting for a specific package
450
+
451
+ },
452
+ });
453
+ ```
454
+
455
+ > **Note:** When setting `chunks` on individual packages, consider also setting `build: 'package'` to avoid your explicit chunk settings being ignored since all 'default' bundles are bundled in a single build step.
456
+
457
+ #### Dense Chunking
458
+
459
+ The `denseChunking` feature flag optimizes the `remoteEntry.json` file structure for better performance:
460
+
461
+ ```js
462
+ module.exports = withNativeFederation({
463
+ shared: {
464
+ ...shareAll({
465
+ singleton: true,
466
+ strictVersion: true,
467
+ requiredVersion: 'auto',
468
+ }),
469
+ },
470
+ features: {
471
+ denseChunking: true,
472
+ },
473
+ });
474
+ ```
475
+
476
+ When enabled, instead of listing each chunk as a separate shared dependency, chunks are grouped by bundle name in a dedicated `chunks` object. Each shared dependency gets a `bundle` property linking it to its chunk bundle. This results in a smaller `remoteEntry.json` and allows chunks to be skipped if the dependency is not used in the final import map.
477
+
478
+ ### Configuring Remotes
479
+
480
+ When configuring a remote, you can expose files that can be loaded into the shell at runtime:
481
+
482
+ ```javascript
483
+ import { withNativeFederation, shareAll } from '@softarc/native-federation/config';
484
+
485
+ export default withNativeFederation({
486
+ name: 'mfe1',
487
+
488
+ exposes: {
489
+ './component': './mfe1/component',
490
+ },
491
+
492
+ shared: {
493
+ ...shareAll({
494
+ singleton: true,
495
+ strictVersion: true,
496
+ requiredVersion: 'auto',
497
+ includeSecondaries: false,
498
+ }),
499
+ },
500
+ });
501
+ ```
502
+
503
+ ### Loading Remotes at Runtime
504
+
505
+ This core library covers the **build side** of Native Federation. The generated `remoteEntry.json` files are consumed at runtime by a separate, framework-agnostic package: **[`@softarc/native-federation-orchestrator`](https://github.com/native-federation/orchestrator)**. It loads micro frontends built with Native Federation into any web page — SPAs as well as server-rendered hosts (PHP, Java, Rails, …) that reload on navigation.
506
+
507
+ #### Quickstart (drop-in script)
508
+
509
+ For a zero-build integration, declare your remotes in a manifest and include the quickstart bundle:
510
+
511
+ ```html
512
+ <!-- Optional: enable shim mode for older browsers -->
513
+ <script type="esms-options">
514
+ { "shimMode": true }
515
+ </script>
516
+
517
+ <!-- Define your micro frontends -->
518
+ <script type="application/json" id="mfe-manifest">
519
+ {
520
+ "team/mfe1": "http://localhost:3000/remoteEntry.json",
521
+ "team/mfe2": "http://localhost:4000/remoteEntry.json"
522
+ }
523
+ </script>
524
+
525
+ <!-- Load modules once the orchestrator is ready -->
526
+ <script>
527
+ window.addEventListener(
528
+ 'mfe-loader-available',
529
+ (e) => {
530
+ e.detail.loadRemoteModule('team/mfe1', './Button');
531
+ e.detail.loadRemoteModule('team/mfe2', './Header');
532
+ },
533
+ { once: true }
534
+ );
535
+ </script>
536
+
537
+ <!-- Include the orchestrator -->
538
+ <script src="https://unpkg.com/@softarc/native-federation-orchestrator@4.3.0/quickstart.mjs"></script>
539
+ ```
540
+
541
+ The `mfe-loader-available` event signals that the orchestrator has fetched the
542
+ remote metadata, resolved dependencies and set up the import map, so
543
+ `loadRemoteModule` is ready to use.
544
+
545
+ #### Programmatic API
546
+
547
+ For full control, install the package and initialize federation yourself:
548
+
549
+ ```
550
+ npm i @softarc/native-federation-orchestrator
551
+ ```
552
+
553
+ ```typescript
554
+ import { initFederation } from '@softarc/native-federation-orchestrator';
555
+ import { consoleLogger, localStorageEntry } from '@softarc/native-federation-orchestrator/options';
556
+
557
+ const manifest = {
558
+ 'team/mfe1': 'http://localhost:3000/remoteEntry.json',
559
+ 'team/mfe2': 'http://localhost:4000/remoteEntry.json',
560
+ };
561
+
562
+ const { loadRemoteModule, load } = await initFederation(manifest, {
563
+ logLevel: 'error',
564
+ logger: consoleLogger,
565
+ storage: localStorageEntry,
566
+ });
567
+
568
+ const ButtonComponent = await load('team/mfe1', './Button');
569
+ const HeaderComponent = await loadRemoteModule('team/mfe2', './Header');
570
+ ```
571
+
572
+ The manifest maps logical remote names to their `remoteEntry.json` URLs (the
573
+ files generated by the build steps above). Entries can also be objects carrying
574
+ an `integrity` hash for Subresource Integrity. Manifests let you adjust your
575
+ application to different environments without recompilation.
576
+
577
+ #### Import maps & polyfills
578
+
579
+ The orchestrator uses **native browser import maps by default**, so no polyfill
580
+ is required for modern browsers. To support older browsers that lack import-map
581
+ support, add the [`es-module-shims`](https://github.com/guybedford/es-module-shims)
582
+ polyfill and opt into shim mode:
583
+
584
+ ```typescript
585
+ import 'es-module-shims';
586
+ import { initFederation } from '@softarc/native-federation-orchestrator';
587
+ import { useShimImportMap } from '@softarc/native-federation-orchestrator/options';
588
+
589
+ const { loadRemoteModule } = await initFederation(manifest, {
590
+ ...useShimImportMap({ shimMode: true }),
591
+ });
592
+ ```
593
+
594
+ > For server-side rendering, the event registry, version-conflict resolution and
595
+ > security / Trusted Types, see the
596
+ > [orchestrator documentation](https://github.com/native-federation/orchestrator#readme).
597
+
598
+ ## React and Other CommonJS Libs
599
+
600
+ Native Federation uses Web Standards like EcmaScript Modules. Most libs and frameworks support them meanwhile. Unfortunately, React still uses CommonJS (und UMD). We do our best to convert these libs to EcmaScript Modules. In the case of React there are some challenges due to the dynamic way the React bundles use the `exports` object.
601
+
602
+ As the community is moving to EcmaScrpt Modules, we expect that these issues will vanish over time. In between, we provide some solutions for dealing with CommonJS-based libraries using `exports` in a dynamic way.
603
+
604
+ One of them is `fileReplacemnts`:
605
+
606
+ ```javascript
607
+ import { reactReplacements } from '@softarc/native-federation-esbuild/src/lib/react-replacements';
608
+ import { createEsBuildAdapter } from '@softarc/native-federation-esbuild';
609
+
610
+ [...]
611
+
612
+ createEsBuildAdapter({
613
+ plugins: [],
614
+ fileReplacements: reactReplacements.prod
615
+ })
616
+ ```
617
+
618
+ Please note that the adapter comes with `fileReplacements` settings for React for both, `dev` mode and `prod` mode. For similar libraries you can add your own replacements. Also, using the `compensateExports` property, you can activate some additional logic for such libraries to make sure the exports are not lost
619
+
620
+ ```javascript
621
+ createEsBuildAdapter({
622
+ plugins: [],
623
+ fileReplacements: reactReplacements.prod,
624
+ compensateExports: [new RegExp('/my-lib/')],
625
+ });
626
+ ```
627
+
628
+ The default value for `compensateExports` is `[new RegExp('/react/')]`.
629
+
630
+ ## More: Blog Articles
631
+
632
+ Find out more about our work including Micro Frontends and Module Federation but also about alternatives to these approaches in our [blog](https://www.angulararchitects.io/en/aktuelles/the-microfrontend-revolution-part-2-module-federation-with-angular/).
633
+
634
+ ## More: Angular Architecture Workshop (100% online, interactive)
635
+
636
+ In our [Angular Architecture Workshop](https://www.angulararchitects.io/en/angular-workshops/advanced-angular-enterprise-architecture-incl-ivy/), we cover all these topics and far more. We provide different options and alternatives and show up their consequences.
637
+
638
+ [Details: Angular Architecture Workshop](https://www.angulararchitects.io/en/angular-workshops/advanced-angular-enterprise-architecture-incl-ivy/)
package/dist/config.js ADDED
@@ -0,0 +1,17 @@
1
+ export * from "./lib/domain/config/index.js";
2
+ import { withNativeFederation } from "./lib/config/with-native-federation.js";
3
+ import {
4
+ findRootTsConfigJson,
5
+ share,
6
+ shareAll,
7
+ setInferVersion
8
+ } from "./lib/config/share-utils.js";
9
+ import { DEFAULT_SKIP_LIST } from "./lib/config/default-skip-list.js";
10
+ export {
11
+ DEFAULT_SKIP_LIST,
12
+ findRootTsConfigJson,
13
+ setInferVersion,
14
+ share,
15
+ shareAll,
16
+ withNativeFederation
17
+ };
package/dist/domain.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./lib/domain/config/index.js";
2
+ export * from "./lib/domain/core/index.js";
@@ -0,0 +1,10 @@
1
+ export { setBuildAdapter } from './lib/core/build/build-adapter.js';
2
+ export { buildForFederation } from './lib/core/build/build-for-federation.js';
3
+ export { rebuildForFederation } from './lib/core/build/rebuild-for-federation.js';
4
+ export { createFederationCache } from './lib/core/cache/federation-cache.js';
5
+ export { bundleExposedAndMappings } from './lib/core/build/bundle-exposed-and-mappings.js';
6
+ export { getExternals } from './lib/core/build/get-externals.js';
7
+ export { normalizeFederationOptions } from './lib/core/normalize-options.js';
8
+ export { writeFederationInfo } from './lib/core/output/write-federation-info.js';
9
+ export { type BuildHelperParams, federationBuilder } from './lib/core/federation-builder.js';
10
+ export * from './domain.js';