@module-federation/node 0.0.0-feat-node-support-1702930274547 → 0.0.0-next-20231219093413

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 (99) hide show
  1. package/.babelrc +10 -0
  2. package/.eslintrc.json +47 -0
  3. package/CHANGELOG.md +1352 -0
  4. package/LICENSE +21 -0
  5. package/README.md +192 -0
  6. package/assets/banner.png +0 -0
  7. package/dist/jest.config.js +19 -0
  8. package/dist/jest.config.js.map +1 -0
  9. package/dist/package.json +62 -0
  10. package/dist/src/filesystem/stratagies.d.ts +11 -0
  11. package/{src → dist/src}/filesystem/stratagies.js +11 -31
  12. package/dist/src/filesystem/stratagies.js.map +1 -0
  13. package/{src → dist/src}/index.d.ts +2 -0
  14. package/{src → dist/src}/index.js +5 -1
  15. package/dist/src/index.js.map +1 -0
  16. package/dist/src/plugins/AutomaticPublicPathPlugin.js.map +1 -0
  17. package/dist/src/plugins/ChunkCorrelationPlugin.js +442 -0
  18. package/dist/src/plugins/ChunkCorrelationPlugin.js.map +1 -0
  19. package/dist/src/plugins/CommonJsChunkLoadingPlugin.js.map +1 -0
  20. package/{src → dist/src}/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js +13 -0
  21. package/dist/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js.map +1 -0
  22. package/dist/src/plugins/NodeContainerPlugin.d.ts +57 -0
  23. package/dist/src/plugins/NodeContainerPlugin.js +105 -0
  24. package/dist/src/plugins/NodeContainerPlugin.js.map +1 -0
  25. package/{src → dist/src}/plugins/NodeFederationPlugin.d.ts +20 -0
  26. package/dist/src/plugins/NodeFederationPlugin.js +127 -0
  27. package/dist/src/plugins/NodeFederationPlugin.js.map +1 -0
  28. package/dist/src/plugins/RemotePublicPathRuntimeModule.js.map +1 -0
  29. package/{src → dist/src}/plugins/StreamingTargetPlugin.js.map +1 -1
  30. package/{src → dist/src}/plugins/UniversalFederationPlugin.d.ts +0 -1
  31. package/{src → dist/src}/plugins/UniversalFederationPlugin.js +3 -3
  32. package/dist/src/plugins/UniversalFederationPlugin.js.map +1 -0
  33. package/{src → dist/src}/plugins/webpackChunkUtilities.js +5 -1
  34. package/dist/src/plugins/webpackChunkUtilities.js.map +1 -0
  35. package/dist/src/types/index.js.map +1 -0
  36. package/dist/src/utils/flush-chunks.js.map +1 -0
  37. package/dist/src/utils/hot-reload.js.map +1 -0
  38. package/dist/src/utils/index.js.map +1 -0
  39. package/global.d.ts +27 -0
  40. package/jest.config.js +14 -16
  41. package/package.json +17 -23
  42. package/project.json +58 -0
  43. package/src/filesystem/stratagies.ts +131 -0
  44. package/src/index.ts +7 -0
  45. package/src/plugins/AutomaticPublicPathPlugin.ts +48 -0
  46. package/src/plugins/ChunkCorrelationPlugin.js +474 -307
  47. package/src/plugins/CommonJsChunkLoadingPlugin.ts +168 -0
  48. package/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.ts +239 -0
  49. package/src/plugins/NodeContainerPlugin.ts +150 -0
  50. package/src/plugins/NodeFederationPlugin.ts +185 -0
  51. package/src/plugins/RemotePublicPathRuntimeModule.ts +137 -0
  52. package/src/plugins/StreamingTargetPlugin.md +88 -0
  53. package/src/plugins/StreamingTargetPlugin.ts +81 -0
  54. package/src/plugins/UniversalFederationPlugin.ts +81 -0
  55. package/src/plugins/webpackChunkUtilities.ts +383 -0
  56. package/src/types/index.ts +7 -0
  57. package/src/utils/flush-chunks.ts +182 -0
  58. package/src/utils/hot-reload.ts +169 -0
  59. package/src/utils/index.ts +2 -0
  60. package/tsconfig.json +28 -0
  61. package/tsconfig.lib.json +17 -0
  62. package/tsconfig.spec.json +9 -0
  63. package/jest.config.js.map +0 -1
  64. package/src/filesystem/stratagies.d.ts +0 -18
  65. package/src/filesystem/stratagies.js.map +0 -1
  66. package/src/index.js.map +0 -1
  67. package/src/plugins/AutomaticPublicPathPlugin.js.map +0 -1
  68. package/src/plugins/ChunkCorrelationPlugin.js.map +0 -1
  69. package/src/plugins/CommonJsChunkLoadingPlugin.js.map +0 -1
  70. package/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js.map +0 -1
  71. package/src/plugins/NodeFederationPlugin.js +0 -76
  72. package/src/plugins/NodeFederationPlugin.js.map +0 -1
  73. package/src/plugins/RemotePublicPathRuntimeModule.js.map +0 -1
  74. package/src/plugins/UniversalFederationPlugin.js.map +0 -1
  75. package/src/plugins/webpackChunkUtilities.js.map +0 -1
  76. package/src/types/index.js.map +0 -1
  77. package/src/utils/flush-chunks.js.map +0 -1
  78. package/src/utils/hot-reload.js.map +0 -1
  79. package/src/utils/index.js.map +0 -1
  80. package/{jest.config.d.ts → dist/jest.config.d.ts} +0 -0
  81. package/{src → dist/src}/plugins/AutomaticPublicPathPlugin.d.ts +0 -0
  82. package/{src → dist/src}/plugins/AutomaticPublicPathPlugin.js +0 -0
  83. package/{src → dist/src}/plugins/ChunkCorrelationPlugin.d.ts +6 -6
  84. /package/{src → dist/src}/plugins/CommonJsChunkLoadingPlugin.d.ts +0 -0
  85. /package/{src → dist/src}/plugins/CommonJsChunkLoadingPlugin.js +0 -0
  86. /package/{src → dist/src}/plugins/DynamicFilesystemChunkLoadingRuntimeModule.d.ts +0 -0
  87. /package/{src → dist/src}/plugins/RemotePublicPathRuntimeModule.d.ts +0 -0
  88. /package/{src → dist/src}/plugins/RemotePublicPathRuntimeModule.js +0 -0
  89. /package/{src → dist/src}/plugins/StreamingTargetPlugin.d.ts +0 -0
  90. /package/{src → dist/src}/plugins/StreamingTargetPlugin.js +0 -0
  91. /package/{src → dist/src}/plugins/webpackChunkUtilities.d.ts +0 -0
  92. /package/{src → dist/src}/types/index.d.ts +0 -0
  93. /package/{src → dist/src}/types/index.js +0 -0
  94. /package/{src → dist/src}/utils/flush-chunks.d.ts +0 -0
  95. /package/{src → dist/src}/utils/flush-chunks.js +0 -0
  96. /package/{src → dist/src}/utils/hot-reload.d.ts +0 -0
  97. /package/{src → dist/src}/utils/hot-reload.js +0 -0
  98. /package/{src → dist/src}/utils/index.d.ts +0 -0
  99. /package/{src → dist/src}/utils/index.js +0 -0
@@ -0,0 +1,168 @@
1
+ import type { Chunk, Compiler, Compilation, ChunkGraph } from 'webpack';
2
+ import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
3
+ import type { ModuleFederationPluginOptions } from '../types';
4
+ const StartupChunkDependenciesPlugin = require(
5
+ normalizeWebpackPath('webpack/lib/runtime/StartupChunkDependenciesPlugin'),
6
+ ) as typeof import('webpack/lib/runtime/StartupChunkDependenciesPlugin');
7
+ import ChunkLoadingRuntimeModule from './DynamicFilesystemChunkLoadingRuntimeModule';
8
+ import AutoPublicPathRuntimeModule from './RemotePublicPathRuntimeModule';
9
+
10
+ interface DynamicFilesystemChunkLoadingOptions
11
+ extends ModuleFederationPluginOptions {
12
+ baseURI: Compiler['options']['output']['publicPath'];
13
+ promiseBaseURI?: string;
14
+ remotes: Record<string, string>;
15
+ name?: string;
16
+ asyncChunkLoading: boolean;
17
+ debug?: boolean;
18
+ }
19
+
20
+ class DynamicFilesystemChunkLoadingPlugin {
21
+ private options: DynamicFilesystemChunkLoadingOptions;
22
+ private _asyncChunkLoading: boolean;
23
+
24
+ constructor(options: DynamicFilesystemChunkLoadingOptions) {
25
+ this.options = options || ({} as DynamicFilesystemChunkLoadingOptions);
26
+ this._asyncChunkLoading = this.options.asyncChunkLoading;
27
+ }
28
+
29
+ apply(compiler: Compiler) {
30
+ const { RuntimeGlobals } = compiler.webpack;
31
+ const chunkLoadingValue = this._asyncChunkLoading
32
+ ? 'async-node'
33
+ : 'require';
34
+
35
+ new StartupChunkDependenciesPlugin({
36
+ chunkLoading: chunkLoadingValue,
37
+ asyncChunkLoading: this._asyncChunkLoading,
38
+ //@ts-ignore
39
+ }).apply(compiler);
40
+
41
+ compiler.hooks.thisCompilation.tap(
42
+ 'DynamicFilesystemChunkLoadingPlugin',
43
+ (compilation: Compilation) => {
44
+ // Always enabled
45
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
46
+ const isEnabledForChunk = (_: Chunk) => true;
47
+ const onceForChunkSet = new WeakSet();
48
+
49
+ const handler = (chunk: Chunk, set: Set<string>) => {
50
+ if (onceForChunkSet.has(chunk)) {
51
+ return;
52
+ }
53
+
54
+ onceForChunkSet.add(chunk);
55
+ if (!isEnabledForChunk(chunk)) {
56
+ return;
57
+ }
58
+ set.add(RuntimeGlobals.moduleFactoriesAddOnly);
59
+ set.add(RuntimeGlobals.hasOwnProperty);
60
+
61
+ set.add(RuntimeGlobals.publicPath); // this breaks things
62
+ compilation.addRuntimeModule(
63
+ chunk,
64
+ new ChunkLoadingRuntimeModule(set, this.options, {
65
+ webpack: compiler.webpack,
66
+ }),
67
+ );
68
+ };
69
+ compilation.hooks.runtimeRequirementInTree
70
+ .for(RuntimeGlobals.ensureChunkHandlers)
71
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
72
+ compilation.hooks.runtimeRequirementInTree
73
+ .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
74
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
75
+ compilation.hooks.runtimeRequirementInTree
76
+ .for(RuntimeGlobals.hmrDownloadManifest)
77
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
78
+ compilation.hooks.runtimeRequirementInTree
79
+ .for(RuntimeGlobals.baseURI)
80
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
81
+ compilation.hooks.runtimeRequirementInTree
82
+ .for(RuntimeGlobals.externalInstallChunk)
83
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
84
+ compilation.hooks.runtimeRequirementInTree
85
+ .for(RuntimeGlobals.onChunksLoaded)
86
+ .tap('DynamicFilesystemChunkLoadingPlugin', handler);
87
+ compilation.hooks.runtimeRequirementInTree
88
+ .for(RuntimeGlobals.ensureChunkHandlers)
89
+ .tap(
90
+ 'DynamicFilesystemChunkLoadingPlugin',
91
+ (chunk: Chunk, set: Set<string>) => {
92
+ if (!isEnabledForChunk(chunk)) {
93
+ return;
94
+ }
95
+ set.add(RuntimeGlobals.getChunkScriptFilename);
96
+ },
97
+ );
98
+ compilation.hooks.runtimeRequirementInTree
99
+ .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
100
+ .tap(
101
+ 'DynamicFilesystemChunkLoadingPlugin',
102
+ (chunk: Chunk, set: Set<string>) => {
103
+ if (!isEnabledForChunk(chunk)) {
104
+ return;
105
+ }
106
+ set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
107
+ set.add(RuntimeGlobals.moduleCache);
108
+ set.add(RuntimeGlobals.hmrModuleData);
109
+ set.add(RuntimeGlobals.moduleFactoriesAddOnly);
110
+ },
111
+ );
112
+ compilation.hooks.runtimeRequirementInTree
113
+ .for(RuntimeGlobals.hmrDownloadManifest)
114
+ .tap(
115
+ 'DynamicFilesystemChunkLoadingPlugin',
116
+ (chunk: Chunk, set: Set<string>) => {
117
+ if (!isEnabledForChunk(chunk)) {
118
+ return;
119
+ }
120
+ set.add(RuntimeGlobals.getUpdateManifestFilename);
121
+ },
122
+ );
123
+
124
+ compilation.hooks.runtimeRequirementInTree
125
+ .for(RuntimeGlobals.publicPath)
126
+ .tap('RuntimePlugin', (chunk, set) => {
127
+ const { outputOptions } = compilation;
128
+ const { publicPath: globalPublicPath, scriptType } = outputOptions;
129
+ const entryOptions = chunk.getEntryOptions();
130
+ const publicPath =
131
+ entryOptions && entryOptions.publicPath !== undefined
132
+ ? entryOptions.publicPath
133
+ : globalPublicPath;
134
+
135
+ const module = new AutoPublicPathRuntimeModule(this.options);
136
+ if (publicPath === 'auto' && scriptType !== 'module') {
137
+ set.add(RuntimeGlobals.global);
138
+ } else if (
139
+ typeof publicPath !== 'string' ||
140
+ /\[(full)?hash\]/.test(publicPath)
141
+ ) {
142
+ module.fullHash = true;
143
+ }
144
+
145
+ compilation.addRuntimeModule(chunk, module);
146
+ return true;
147
+ });
148
+
149
+ compilation.hooks.additionalTreeRuntimeRequirements.tap(
150
+ 'StartupChunkDependenciesPlugin',
151
+ (
152
+ chunk: Chunk,
153
+ set: Set<string>,
154
+ { chunkGraph }: { chunkGraph: ChunkGraph },
155
+ ) => {
156
+ // compilation.addRuntimeModule(
157
+ // chunk,
158
+ // //@ts-ignore
159
+ // new FederationModuleInfoRuntimeModule(),
160
+ // );
161
+ },
162
+ );
163
+ },
164
+ );
165
+ }
166
+ }
167
+
168
+ export default DynamicFilesystemChunkLoadingPlugin;
@@ -0,0 +1,239 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ */
4
+ import type { Chunk, Compiler } from 'webpack';
5
+ import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
6
+ const { RuntimeGlobals, RuntimeModule } = require(
7
+ normalizeWebpackPath('webpack'),
8
+ ) as typeof import('webpack');
9
+ const { getUndoPath } = require(
10
+ normalizeWebpackPath('webpack/lib/util/identifier'),
11
+ ) as typeof import('webpack/lib/util/identifier');
12
+ import { SyncWaterfallHook } from 'tapable';
13
+ const compileBooleanMatcher = require(
14
+ normalizeWebpackPath('webpack/lib/util/compileBooleanMatcher'),
15
+ ) as typeof import('webpack/lib/util/compileBooleanMatcher');
16
+ import {
17
+ generateHmrCode,
18
+ getInitialChunkIds,
19
+ generateLoadingCode,
20
+ generateHmrManifestCode,
21
+ handleOnChunkLoad,
22
+ generateLoadScript,
23
+ generateInstallChunk,
24
+ generateExternalInstallChunkCode,
25
+ } from './webpackChunkUtilities';
26
+ import {
27
+ fileSystemRunInContextStrategy,
28
+ httpEvalStrategy,
29
+ httpVmStrategy,
30
+ } from '../filesystem/stratagies';
31
+
32
+ interface RemotesByType {
33
+ functional: string[];
34
+ normal: string[];
35
+ }
36
+
37
+ interface DynamicFilesystemChunkLoadingRuntimeModuleOptions {
38
+ baseURI: Compiler['options']['output']['publicPath'];
39
+ promiseBaseURI?: string;
40
+ remotes: Record<string, string>;
41
+ name?: string;
42
+ debug?: boolean;
43
+ }
44
+
45
+ interface ChunkLoadingContext {
46
+ webpack: Compiler['webpack'];
47
+ }
48
+
49
+ class DynamicFilesystemChunkLoadingRuntimeModule extends RuntimeModule {
50
+ private runtimeRequirements: Set<string>;
51
+ private options: DynamicFilesystemChunkLoadingRuntimeModuleOptions;
52
+ private chunkLoadingContext: ChunkLoadingContext;
53
+ hooks = {
54
+ strategyCase: new SyncWaterfallHook(['source']),
55
+ };
56
+
57
+ constructor(
58
+ runtimeRequirements: Set<string>,
59
+ options: DynamicFilesystemChunkLoadingRuntimeModuleOptions,
60
+ chunkLoadingContext: ChunkLoadingContext,
61
+ ) {
62
+ super('readFile chunk loading', RuntimeModule.STAGE_ATTACH + 1);
63
+ this.runtimeRequirements = runtimeRequirements;
64
+
65
+ this.options = options;
66
+ this.chunkLoadingContext = chunkLoadingContext;
67
+ }
68
+
69
+ /**
70
+ * @private
71
+ * @param {Chunk} chunk chunk
72
+ * @param {string} rootOutputDir root output directory
73
+ * @returns {string} generated code
74
+ */
75
+ _generateBaseUri(chunk: Chunk, rootOutputDir: string) {
76
+ const options = chunk.getEntryOptions();
77
+ if (options && options.baseUri) {
78
+ return `${RuntimeGlobals.baseURI} = ${JSON.stringify(options.baseUri)};`;
79
+ }
80
+
81
+ return `${RuntimeGlobals.baseURI} = require("url").pathToFileURL(${
82
+ rootOutputDir
83
+ ? `__dirname + ${JSON.stringify('/' + rootOutputDir)}`
84
+ : '__filename'
85
+ });`;
86
+ }
87
+
88
+ /**
89
+ * @private
90
+ * @param {unknown[]} items item to log
91
+ */
92
+ _getLogger(...items: unknown[]) {
93
+ if (!this.options.debug) {
94
+ return '';
95
+ }
96
+
97
+ return `console.log(${items.join(',')});`;
98
+ }
99
+
100
+ /**
101
+ * @returns {string} runtime code
102
+ */
103
+ override generate() {
104
+ const { remotes = {}, name } = this.options;
105
+ const { webpack } = this.chunkLoadingContext;
106
+ const { chunkGraph, chunk, compilation } = this;
107
+ const { Template } = webpack;
108
+ if (!chunkGraph || !chunk || !compilation) {
109
+ console.warn('Missing required properties. Returning empty string.');
110
+ return '';
111
+ }
112
+
113
+ const { runtimeTemplate } = compilation;
114
+ const jsModulePlugin =
115
+ webpack?.javascript?.JavascriptModulesPlugin ||
116
+ require('webpack/lib/javascript/JavascriptModulesPlugin');
117
+ const { chunkHasJs } = jsModulePlugin;
118
+ const fn = RuntimeGlobals.ensureChunkHandlers;
119
+
120
+ const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasJs);
121
+ const hasJsMatcher = compileBooleanMatcher(conditionMap);
122
+ const initialChunkIds = getInitialChunkIds(chunk, chunkGraph, chunkHasJs);
123
+
124
+ const outputName = compilation.getPath(
125
+ jsModulePlugin.getChunkFilenameTemplate(chunk, compilation.outputOptions),
126
+ { chunk, contentHashType: 'javascript' },
127
+ );
128
+ const rootOutputDir = getUndoPath(
129
+ outputName,
130
+ compilation.outputOptions.path,
131
+ false,
132
+ );
133
+ const stateExpression = this.runtimeRequirements.has(
134
+ RuntimeGlobals.hmrDownloadUpdateHandlers,
135
+ )
136
+ ? `${RuntimeGlobals.hmrRuntimeStatePrefix}_readFileVm`
137
+ : undefined;
138
+
139
+ const dynamicFilesystemChunkLoadingPluginCode = Template.asString([
140
+ fileSystemRunInContextStrategy.toString(),
141
+ httpEvalStrategy.toString(),
142
+ httpVmStrategy.toString(),
143
+ 'const loadChunkStrategy = async (strategyType,chunkId,rootOutputDir, remotes, callback) => {',
144
+ Template.indent([
145
+ 'switch (strategyType) {',
146
+ Template.indent([
147
+ 'case "filesystem": return await fileSystemRunInContextStrategy(chunkId,rootOutputDir, remotes, callback);',
148
+ 'case "http-eval": return await httpEvalStrategy(chunkId,rootOutputDir, remotes, callback);',
149
+ 'case "http-vm": return await httpVmStrategy(chunkId,rootOutputDir, remotes, callback);',
150
+ this.hooks.strategyCase.call(
151
+ 'default: throw new Error("Invalid strategy type");',
152
+ ) as string,
153
+ ]),
154
+ '}',
155
+ ]),
156
+ '};',
157
+ ]);
158
+ const remoteRegistry = Template.asString([
159
+ `var remotes = ${JSON.stringify(
160
+ Object.values(remotes).reduce(
161
+ (acc, remote) => {
162
+ const [global, url] = remote.split('@');
163
+ acc[global] = url;
164
+ return acc;
165
+ },
166
+ {} as Record<string, string>,
167
+ ),
168
+ )};`,
169
+ Template.asString([
170
+ 'Object.keys(remotes).forEach(function(remote) {',
171
+ Template.indent(
172
+ 'globalThis.__remote_scope__._config[remote] = remotes[remote];',
173
+ ),
174
+ '});',
175
+ ]),
176
+ ]);
177
+
178
+ return Template.asString([
179
+ remoteRegistry,
180
+ dynamicFilesystemChunkLoadingPluginCode,
181
+ this.runtimeRequirements.has(RuntimeGlobals.baseURI)
182
+ ? this._generateBaseUri(chunk, rootOutputDir)
183
+ : '// no baseURI',
184
+ '',
185
+ '// object to store loaded chunks',
186
+ '// "0" means "already loaded", Promise means loading',
187
+ `var installedChunks = ${
188
+ stateExpression ? `${stateExpression} = ${stateExpression} || ` : ''
189
+ }{`,
190
+ Template.indent(
191
+ Array.from(initialChunkIds, (id) => `${JSON.stringify(id)}: 0`).join(
192
+ ',\n',
193
+ ),
194
+ ),
195
+ '};',
196
+ '',
197
+ handleOnChunkLoad(
198
+ this.runtimeRequirements.has(RuntimeGlobals.onChunksLoaded),
199
+ runtimeTemplate,
200
+ ),
201
+ '',
202
+ generateInstallChunk(
203
+ runtimeTemplate,
204
+ this.runtimeRequirements.has(RuntimeGlobals.onChunksLoaded),
205
+ ),
206
+ '',
207
+ this.runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
208
+ ? generateLoadScript(runtimeTemplate)
209
+ : '// no remote script loader needed',
210
+ this.runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
211
+ ? generateLoadingCode(
212
+ this.runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers),
213
+ fn,
214
+ hasJsMatcher,
215
+ rootOutputDir,
216
+ remotes,
217
+ name,
218
+ )
219
+ : '// no chunk loading',
220
+ '',
221
+ generateExternalInstallChunkCode(
222
+ this.runtimeRequirements.has(RuntimeGlobals.externalInstallChunk),
223
+ this.options.debug,
224
+ ),
225
+ '',
226
+ generateHmrCode(
227
+ this.runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers),
228
+ rootOutputDir,
229
+ ),
230
+ '',
231
+ generateHmrManifestCode(
232
+ this.runtimeRequirements.has(RuntimeGlobals.hmrDownloadManifest),
233
+ rootOutputDir,
234
+ ),
235
+ ]);
236
+ }
237
+ }
238
+
239
+ export default DynamicFilesystemChunkLoadingRuntimeModule;
@@ -0,0 +1,150 @@
1
+ 'use strict';
2
+
3
+ import type { Compiler, container } from 'webpack';
4
+ import { extractUrlAndGlobal } from '@module-federation/utilities';
5
+
6
+ /**
7
+ * Interface for NodeContainerOptions which extends ContainerPluginOptions
8
+ * @interface
9
+ * @property {Record<string, unknown>} experiments - Optional experiments configuration
10
+ * @property {boolean} debug - Optional debug flag
11
+ */
12
+
13
+ /**
14
+ * Interface for Context
15
+ * @interface
16
+ * @property {typeof container.ContainerPlugin} ContainerPlugin - Optional ContainerPlugin
17
+ */
18
+ interface Context {
19
+ ContainerPlugin?: typeof container.ContainerPlugin;
20
+ }
21
+
22
+ // possible remote evaluators
23
+ // this depends on the chunk format selected.
24
+ // commonjs2 - it think, is lazily evaluated - beware
25
+ // const remote = eval(scriptContent + '\n try{' + moduleName + '}catch(e) { null; };');
26
+ // commonjs - fine to use but exports marker doesnt exist
27
+ // const remote = eval('let exports = {};' + scriptContent + 'exports');
28
+ // commonjs-module, ideal since it returns a commonjs module format
29
+ // const remote = eval(scriptContent + 'module.exports')
30
+
31
+ /**
32
+ * This function iterates over all remotes and checks if they
33
+ * are internal or not. If it's an internal remote then we add it to our new object
34
+ * with a key of the name of the remote and value as internal. If it's not an internal
35
+ * remote then we check if there is a '@' in that string which likely means it is a global @ url
36
+ *
37
+ * @param {Record<string, any>} remotes - The remotes to parse.
38
+ * @returns {Record<string, string>} - The parsed remotes.
39
+ * */
40
+
41
+ export const parseRemotes = (
42
+ remotes: Record<string, any>,
43
+ ): Record<string, string> => {
44
+ if (!remotes || typeof remotes !== 'object') {
45
+ throw new Error('remotes must be an object');
46
+ }
47
+
48
+ return Object.entries(remotes).reduce(
49
+ (acc: Record<string, string>, [key, value]) => {
50
+ const isInternal = value.startsWith('internal ');
51
+ const isGlobal =
52
+ value.includes('@') &&
53
+ !['window.', 'global.', 'globalThis.', 'self.'].some((prefix) =>
54
+ value.startsWith(prefix),
55
+ );
56
+
57
+ acc[key] = isInternal || !isGlobal ? value : parseRemoteSyntax(value);
58
+
59
+ return acc;
60
+ },
61
+ {},
62
+ );
63
+ };
64
+ /**
65
+ * Parses the remote syntax and returns a formatted string if the remote includes '@' and does not start with 'window', 'global', or 'globalThis'.
66
+ * Otherwise, it returns the original remote string.
67
+ *
68
+ * @param {string} remote - The remote string to parse.
69
+ * @returns {string} - The parsed remote string or the original remote string.
70
+ * @throws {Error} - Throws an error if the remote is not a string.
71
+ */
72
+ export const parseRemoteSyntax = (remote: any): string => {
73
+ if (typeof remote !== 'string') {
74
+ throw new Error('remote must be a string');
75
+ }
76
+
77
+ if (remote.includes('@')) {
78
+ const [url, global] = extractUrlAndGlobal(remote);
79
+ if (
80
+ !['window.', 'global.', 'globalThis.'].some((prefix) =>
81
+ global.startsWith(prefix),
82
+ )
83
+ ) {
84
+ return `globalThis.__remote_scope__.${global}@${url}`;
85
+ }
86
+ }
87
+ return remote;
88
+ };
89
+
90
+ /**
91
+ * Class representing a NodeContainerPlugin.
92
+ * @class
93
+ */
94
+ class NodeContainerPlugin {
95
+ private _options: any;
96
+ private context: Context;
97
+ private experiments: any['experiments'];
98
+
99
+ /**
100
+ * Create a NodeContainerPlugin.
101
+ * @constructor
102
+ * @param {NodeContainerOptions} options - The options for the NodeContainerPlugin
103
+ * @param {Context} context - The context for the NodeContainerPlugin
104
+ */
105
+ constructor({ experiments, debug, ...options }: any, context: Context) {
106
+ this._options = options || ({} as any);
107
+ this.context = context || ({} as Context);
108
+ this.experiments = experiments || {};
109
+ }
110
+
111
+ /**
112
+ * Apply method for the NodeContainerPlugin class.
113
+ * @method
114
+ * @param {Compiler} compiler - The webpack compiler.
115
+ */
116
+ apply(compiler: Compiler) {
117
+ // When used with Next.js, context is needed to use Next.js webpack
118
+ const { webpack } = compiler;
119
+
120
+ const pluginOptions = {
121
+ name: this._options.name,
122
+ filename: this._options.filename,
123
+ exposes: this._options.exposes,
124
+ library: this._options.library,
125
+ runtime: this._options.runtime,
126
+ shareScope: this._options.shareScope,
127
+ };
128
+ // //TODO can use import meta mock object but need to update data structure of remote_scope
129
+ // if (compiler.options && compiler.options.output) {
130
+ // compiler.options.output.importMetaName = 'remoteContainerRegistry';
131
+ // }
132
+
133
+ // const chunkFileName = compiler.options?.output?.chunkFilename;
134
+ // const uniqueName =
135
+ // compiler?.options?.output?.uniqueName || this._options.name;
136
+
137
+ // if (typeof chunkFileName === 'string' && uniqueName && !chunkFileName.includes(uniqueName)) {
138
+ // const suffix = `-[chunkhash].js`;
139
+ // compiler.options.output.chunkFilename = chunkFileName.replace('.js', suffix);
140
+ // }
141
+
142
+ new (this.context.ContainerPlugin ||
143
+ (webpack && webpack.container.ContainerPlugin) ||
144
+ require('webpack/lib/container/ContainerPlugin'))(pluginOptions).apply(
145
+ compiler,
146
+ );
147
+ }
148
+ }
149
+
150
+ export default NodeContainerPlugin;