@module-federation/nextjs-mf 5.2.2 → 5.3.1

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 (49) hide show
  1. package/lib/ModuleFederationPlugin.js +80 -0
  2. package/lib/NextFederationPlugin.js +524 -1
  3. package/lib/_virtual/_tslib.js +101 -0
  4. package/lib/client/CombinedPages.d.ts +28 -0
  5. package/lib/client/CombinedPages.d.ts.map +1 -0
  6. package/lib/client/CombinedPages.js +60 -0
  7. package/lib/client/MFClient.d.ts +70 -0
  8. package/lib/client/MFClient.d.ts.map +1 -0
  9. package/lib/client/MFClient.js +197 -0
  10. package/lib/client/RemoteContainer.d.ts +58 -0
  11. package/lib/client/RemoteContainer.d.ts.map +1 -0
  12. package/lib/client/RemoteContainer.js +161 -0
  13. package/lib/client/RemotePages.d.ts +48 -0
  14. package/lib/client/RemotePages.d.ts.map +1 -0
  15. package/lib/client/RemotePages.js +168 -0
  16. package/lib/client/UrlNode.d.ts +18 -0
  17. package/lib/client/UrlNode.d.ts.map +1 -0
  18. package/lib/client/UrlNode.js +162 -0
  19. package/lib/client/helpers.d.ts +17 -0
  20. package/lib/client/helpers.d.ts.map +1 -0
  21. package/lib/client/helpers.js +108 -0
  22. package/lib/client/useMFClient.d.ts +25 -0
  23. package/lib/client/useMFClient.d.ts.map +1 -0
  24. package/lib/client/useMFClient.js +79 -0
  25. package/lib/client/useMFRemote.d.ts +17 -0
  26. package/lib/client/useMFRemote.d.ts.map +1 -0
  27. package/lib/client/useMFRemote.js +72 -0
  28. package/lib/include-defaults.js +1 -3
  29. package/lib/internal.js +241 -0
  30. package/lib/loaders/UrlNode.js +209 -0
  31. package/lib/loaders/nextPageMapLoader.js +63 -13
  32. package/lib/loaders/patchNextClientPageLoader.js +53 -0
  33. package/lib/node-plugin/streaming/CommonJsChunkLoadingPlugin.js +86 -0
  34. package/lib/node-plugin/streaming/LoadFileChunkLoadingRuntimeModule.js +410 -0
  35. package/lib/node-plugin/streaming/NodeRuntime.js +147 -0
  36. package/lib/node-plugin/streaming/index.js +44 -0
  37. package/lib/node-plugin/streaming/loadScript.js +55 -0
  38. package/lib/plugins/DevHmrFixInvalidPongPlugin.js +60 -0
  39. package/lib/utils.js +14 -3
  40. package/node-plugin/README.md +27 -0
  41. package/node-plugin/package.json +4 -0
  42. package/node-plugin/streaming/CommonJsChunkLoadingPlugin.js +89 -0
  43. package/node-plugin/streaming/LoadFileChunkLoadingRuntimeModule.js +410 -0
  44. package/node-plugin/streaming/NodeRuntime.js +245 -0
  45. package/node-plugin/streaming/index.js +42 -0
  46. package/node-plugin/streaming/loadScript.js +51 -0
  47. package/package.json +22 -5
  48. package/tsconfig.json +33 -0
  49. package/lib/NextFederationPlugin2.js +0 -0
@@ -0,0 +1,80 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
4
+ */
5
+
6
+ 'use strict';
7
+ /*
8
+ plugin was copied over because ContainerPlugin is called in compiler.hooks.afterPlugins which doest seem to work in child compiler
9
+ */
10
+ /** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ExternalsType} ExternalsType */
11
+ /** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ModuleFederationPluginOptions} ModuleFederationPluginOptions */
12
+
13
+ /** @typedef {import("webpack").Shared} Shared */
14
+ /** @typedef {import("webpack").Compiler} Compiler */
15
+
16
+ class ModuleFederationPlugin {
17
+ /**
18
+ * @param {ModuleFederationPluginOptions} options options
19
+ */
20
+ constructor(options) {
21
+ this._options = options;
22
+ }
23
+
24
+ /**
25
+ * Apply the plugin
26
+ * @param {Compiler} compiler the compiler instance
27
+ * @returns {void}
28
+ */
29
+ apply(compiler) {
30
+ const { _options: options } = this;
31
+ const webpack = compiler.webpack;
32
+ const { ContainerPlugin, ContainerReferencePlugin } = webpack.container;
33
+ const { SharePlugin } = webpack.sharing;
34
+ const library = options.library || { type: 'var', name: options.name };
35
+ const remoteType =
36
+ options.remoteType ||
37
+ (options.library && /** @type {ExternalsType} */ options.library.type) ||
38
+ 'script';
39
+ if (
40
+ library &&
41
+ !compiler.options.output.enabledLibraryTypes.includes(library.type)
42
+ ) {
43
+ compiler.options.output.enabledLibraryTypes.push(library.type);
44
+ }
45
+
46
+ if (
47
+ options.exposes &&
48
+ (Array.isArray(options.exposes)
49
+ ? options.exposes.length > 0
50
+ : Object.keys(options.exposes).length > 0)
51
+ ) {
52
+ new ContainerPlugin({
53
+ name: options.name,
54
+ library,
55
+ filename: options.filename,
56
+ runtime: options.runtime,
57
+ exposes: options.exposes,
58
+ }).apply(compiler);
59
+ }
60
+ if (
61
+ options.remotes &&
62
+ (Array.isArray(options.remotes)
63
+ ? options.remotes.length > 0
64
+ : Object.keys(options.remotes).length > 0)
65
+ ) {
66
+ new ContainerReferencePlugin({
67
+ remoteType,
68
+ remotes: options.remotes,
69
+ }).apply(compiler);
70
+ }
71
+ if (options.shared) {
72
+ new SharePlugin({
73
+ shared: options.shared,
74
+ shareScope: options.shareScope,
75
+ }).apply(compiler);
76
+ }
77
+ }
78
+ }
79
+
80
+ export default ModuleFederationPlugin;
@@ -1,7 +1,530 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Zackary Jackson @ScriptedAlchemy
4
+ */
1
5
  'use strict';
2
6
 
3
- var NextFederationPlugin = require('./NextFederationPlugin2.js');
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ const {
10
+ injectRuleLoader,
11
+ hasLoader,
12
+ toDisplayErrors,
13
+ } = require('./loaders/helpers');
14
+ const { exposeNextjsPages } = require('./loaders/nextPageMapLoader');
15
+ const DevHmrFixInvalidPongPlugin = require('./plugins/DevHmrFixInvalidPongPlugin');
4
16
 
17
+ import {
18
+ reKeyHostShared,
19
+ DEFAULT_SHARE_SCOPE,
20
+ extractUrlAndGlobal,
21
+ generateRemoteTemplate,
22
+ internalizeSharedPackages,
23
+ getOutputPath,
24
+ externalizedShares,
25
+ removePlugins
26
+ } from './internal';
27
+ import StreamingTargetPlugin from '../node-plugin/streaming';
28
+ import NodeFederationPlugin from '../node-plugin/streaming/NodeRuntime';
29
+ import ChildFriendlyModuleFederationPlugin from './ModuleFederationPlugin';
5
30
 
31
+ const CHILD_PLUGIN_NAME = 'ChildFederationPlugin';
32
+
33
+ class RemoveRRRuntimePlugin {
34
+ /**
35
+ * Apply the plugin
36
+ * @param {Compiler} compiler the compiler instance
37
+ * @returns {void}
38
+ */
39
+ apply(compiler) {
40
+ const webpack = compiler.webpack;
41
+ // only impacts dev mode - dont waste the memory during prod build
42
+ if (compiler.options.mode === 'development') {
43
+ compiler.hooks.thisCompilation.tap(
44
+ 'RemoveRRRuntimePlugin',
45
+ (compilation) => {
46
+ compilation.hooks.processAssets.tap(
47
+ {
48
+ name: 'RemoveRRRuntimePlugin',
49
+ state:
50
+ compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE,
51
+ },
52
+ (assets) => {
53
+ //can this be improved? I need react refresh not to cause global collision in dev mode
54
+ Object.keys(assets).forEach((filename) => {
55
+ if (filename.endsWith('.js') || filename.endsWith('.mjs')) {
56
+ const asset = compilation.getAsset(filename);
57
+ // easiest way to solve it is to prevent react refresh helpers from running when its a federated module chunk
58
+ const newSource = asset.source
59
+ .source()
60
+ .replace(/RefreshHelpers/g, 'NoExist');
61
+ const updatedAsset = new webpack.sources.RawSource(newSource);
62
+
63
+ if (asset) {
64
+ compilation.updateAsset(filename, updatedAsset);
65
+ } else {
66
+ compilation.emitAsset(filename, updatedAsset);
67
+ }
68
+ }
69
+ });
70
+ }
71
+ );
72
+ }
73
+ );
74
+ }
75
+ }
76
+ }
77
+
78
+ const computeRemoteFilename = (isServer, filename) => {
79
+ if (isServer && filename) {
80
+ return path.basename(filename);
81
+ }
82
+ return filename;
83
+ };
84
+ const childCompilers = {};
85
+ class ChildFederationPlugin {
86
+ constructor(options, extraOptions = {}) {
87
+ this._options = options;
88
+ this._extraOptions = extraOptions;
89
+ }
90
+ /**
91
+ * Apply the plugin
92
+ * @param {Compiler} compiler the compiler instance
93
+ * @returns {void}
94
+ */
95
+ apply(compiler) {
96
+ const webpack = compiler.webpack;
97
+ const LibraryPlugin = webpack.library.EnableLibraryPlugin;
98
+ const LoaderTargetPlugin = webpack.LoaderTargetPlugin;
99
+ const library = compiler.options.output.library;
100
+ const isServer = compiler.options.name === 'server';
101
+ const isDev = compiler.options.mode === 'development';
102
+ let outputPath;
103
+ if (isDev && isServer) {
104
+ outputPath = path.join(getOutputPath(compiler), 'static/ssr');
105
+ } else {
106
+ if (isServer) {
107
+ outputPath = path.join(getOutputPath(compiler), 'static/ssr');
108
+ } else {
109
+ outputPath = compiler.options.output.path;
110
+ }
111
+ }
112
+
113
+ compiler.hooks.thisCompilation.tap(CHILD_PLUGIN_NAME, (compilation) => {
114
+ const buildName = this._options.name;
115
+ const childOutput = {
116
+ ...compiler.options.output,
117
+ path: outputPath,
118
+ // path: deriveOutputPath(isServer, compiler.options.output.path),
119
+ publicPath: 'auto',
120
+ chunkLoadingGlobal: buildName + 'chunkLoader',
121
+ uniqueName: buildName,
122
+ library: {
123
+ name: buildName,
124
+ type: library.type,
125
+ },
126
+ chunkFilename: compiler.options.output.chunkFilename.replace(
127
+ '.js',
128
+ '-fed.js'
129
+ ),
130
+ filename: compiler.options.output.filename.replace('.js', '-fed.js'),
131
+ };
132
+
133
+ // using ModuleFederationPlugin does not work, i had to fork because of afterPlugins hook on containerPlugin.
134
+ const FederationPlugin = ChildFriendlyModuleFederationPlugin;
135
+
136
+ const federationPluginOptions = {
137
+ // library: {type: 'var', name: buildName},
138
+ ...this._options,
139
+ filename: computeRemoteFilename(isServer, this._options.filename),
140
+ exposes: {
141
+ ...this._options.exposes,
142
+ ...(this._extraOptions.exposePages
143
+ ? exposeNextjsPages(compiler.options.context)
144
+ : {}),
145
+ },
146
+ runtime: false,
147
+ shared: {
148
+ ...(this._extraOptions.skipSharingNextInternals
149
+ ? {}
150
+ : externalizedShares),
151
+ ...this._options.shared,
152
+ },
153
+ };
154
+
155
+ let plugins;
156
+ if (compiler.options.name === 'client') {
157
+ plugins = [
158
+ new FederationPlugin(federationPluginOptions),
159
+ new webpack.web.JsonpTemplatePlugin(childOutput),
160
+ new LoaderTargetPlugin('web'),
161
+ new LibraryPlugin(this._options.library.type),
162
+ new webpack.DefinePlugin({
163
+ 'process.env.REMOTES': createRuntimeVariables(
164
+ this._options.remotes
165
+ ),
166
+ 'process.env.CURRENT_HOST': JSON.stringify(this._options.name),
167
+ }),
168
+ new AddRuntimeRequirementToPromiseExternal(),
169
+ ];
170
+ } else if (compiler.options.name === 'server') {
171
+ plugins = [
172
+ new NodeFederationPlugin(federationPluginOptions, {ModuleFederationPlugin: FederationPlugin}),
173
+ new webpack.node.NodeTemplatePlugin(childOutput),
174
+ //TODO: Externals function needs to internalize any shared module for host and remote build
175
+ new webpack.ExternalsPlugin(compiler.options.externalsType, [
176
+ // next dynamic needs to be within webpack, cannot be externalized
177
+ ...Object.keys(DEFAULT_SHARE_SCOPE).filter(
178
+ (k) => k !== 'next/dynamic'
179
+ ),
180
+ 'react/jsx-runtime',
181
+ 'react/jsx-dev-runtime',
182
+ ]),
183
+ // new LoaderTargetPlugin('async-node'),
184
+ new StreamingTargetPlugin(federationPluginOptions, webpack),
185
+ new LibraryPlugin(federationPluginOptions.library.type),
186
+ // new webpack.DefinePlugin({
187
+ // 'process.env.REMOTES': JSON.stringify(this._options.remotes),
188
+ // 'process.env.CURRENT_HOST': JSON.stringify(this._options.name),
189
+ // }),
190
+ new AddRuntimeRequirementToPromiseExternal(),
191
+ ];
192
+ }
193
+ const childCompiler = compilation.createChildCompiler(
194
+ CHILD_PLUGIN_NAME,
195
+ childOutput,
196
+ plugins
197
+ );
198
+
199
+ childCompiler.outputPath = outputPath;
200
+ childCompiler.options.module.rules.forEach((rule) => {
201
+ // next-image-loader fix which adds remote's hostname to the assets url
202
+ if (
203
+ this._extraOptions.enableImageLoaderFix &&
204
+ hasLoader(rule, 'next-image-loader')
205
+ ) {
206
+ injectRuleLoader(rule, {
207
+ loader: path.resolve(__dirname, './loaders/fixImageLoader.js'),
208
+ });
209
+ }
210
+
211
+ // url-loader fix for which adds remote's hostname to the assets url
212
+ if (
213
+ this._extraOptions.enableUrlLoaderFix &&
214
+ hasLoader(rule, 'url-loader')
215
+ ) {
216
+ injectRuleLoader({
217
+ loader: path.resolve(__dirname, './loaders/fixUrlLoader.js'),
218
+ });
219
+ }
220
+ });
221
+ childCompiler.options.experiments.lazyCompilation = false;
222
+ childCompiler.options.optimization.runtimeChunk = false;
223
+ // no custom chunk splitting should be derived from host (next)
224
+ delete childCompiler.options.optimization.splitChunks;
225
+ childCompiler.outputFileSystem = fs;
226
+
227
+ if (compiler.options.optimization.minimize) {
228
+ for (const minimizer of compiler.options.optimization.minimizer) {
229
+ if (typeof minimizer === "function") {
230
+ minimizer.call(childCompiler, childCompiler)
231
+ } else if (minimizer !== "...") {
232
+ minimizer.apply(childCompiler);
233
+ }
234
+ }
235
+ }
236
+
237
+ new RemoveRRRuntimePlugin().apply(childCompiler);
238
+
239
+ const MiniCss = childCompiler.options.plugins.find((p) => {
240
+ return p.constructor.name === 'NextMiniCssExtractPlugin';
241
+ });
242
+
243
+ childCompiler.options.plugins = childCompiler.options.plugins.filter(
244
+ (plugin) => !removePlugins.includes(plugin.constructor.name)
245
+ );
246
+
247
+ if (MiniCss) {
248
+ // grab mini-css and reconfigure it to avoid conflicts with host
249
+ new MiniCss.constructor({
250
+ ...MiniCss.options,
251
+ filename: MiniCss.options.filename.replace('.css', '-fed.css'),
252
+ chunkFilename: MiniCss.options.chunkFilename.replace(
253
+ '.css',
254
+ '-fed.css'
255
+ ),
256
+ }).apply(childCompiler);
257
+ }
258
+
259
+
260
+ // TODO: this can likely be deleted now, if running server child compiler under client is the best way to go
261
+ // help wanted for all asset pipeline stuff below
262
+ // let childAssets
263
+ // if (isServer) {
264
+ // childAssets = new Promise((resolve) => {
265
+ // childCompiler.hooks.afterEmit.tap(
266
+ // CHILD_PLUGIN_NAME,
267
+ // (childCompilation) => {
268
+ // console.log('after emit assets server');
269
+ // resolve(childCompilation.assets);
270
+ // }
271
+ // );
272
+ // });
273
+ // } else {
274
+ // if(isDev) {
275
+ // childAssets = new Promise((resolve) => {
276
+ // childCompiler.hooks.afterEmit.tap(
277
+ // CHILD_PLUGIN_NAME,
278
+ // (childCompilation) => {
279
+ // resolve(childCompilation.assets);
280
+ // }
281
+ // );
282
+ // });
283
+ //
284
+ // } else {
285
+ //
286
+ // TODO: improve this
287
+ // childAssets = new Promise((resolve, reject) => {
288
+ // fs.readdir(
289
+ // path.join(childCompiler.context, '.next/ssr'),
290
+ // function (err, files) {
291
+ // if (err) {
292
+ // reject('Unable to scan directory: ' + err);
293
+ // return;
294
+ // }
295
+ //
296
+ // const allFiles = files.map(function (file) {
297
+ // return new Promise((res, rej) => {
298
+ // fs.readFile(
299
+ // path.join(childCompiler.context, '.next/ssr', file),
300
+ // (err, data) => {
301
+ // if (err) rej(err);
302
+ // compilation.assets[path.join('static/ssr', file)] = new compiler.webpack.sources.RawSource(data)
303
+ // res();
304
+ // }
305
+ // );
306
+ // });
307
+ // });
308
+ // Promise.all(allFiles).then(resolve).catch(reject)
309
+ // }
310
+ // );
311
+ // });
312
+ // }
313
+ // }
314
+ // on main compiler add extra assets from server output to browser build
315
+ // compilation.hooks.additionalAssets.tapPromise(CHILD_PLUGIN_NAME, () => {
316
+ // console.log('additional hooks', compiler.options.name);
317
+ // console.log('in additional assets hook for main build');
318
+ // return childAssets
319
+ // });
320
+
321
+ // cache the serer compiler instance, we will run the server child compiler during the client main compilation
322
+ // we need to do this because i need access to data from the client build to inject into the server build
323
+ // in prod builds, server build runs first, followed by client build
324
+ // in dev, client build runs first, followed by server build
325
+ childCompilers[compiler.options.name] = childCompiler;
326
+
327
+ if (isDev) {
328
+ // in dev, run the compilers in the order they are created (client, server)
329
+ childCompiler.run((err, stats) => {
330
+ if (err) {
331
+ compilation.errors.push(err);
332
+ }
333
+ if (stats && stats.hasErrors()) {
334
+ compilation.errors.push(
335
+ new Error(toDisplayErrors(stats.compilation.errors))
336
+ );
337
+ }
338
+ });
339
+ // in prod, if client
340
+ } else if (!isServer) {
341
+ // if ssr enabled and server in compiler cache
342
+ if(childCompilers['server']) {
343
+ //wrong hook for this
344
+ // add hook for additional assets to prevent compile from sealing.
345
+ compilation.hooks.additionalAssets.tapPromise(CHILD_PLUGIN_NAME, () => {
346
+ return new Promise((res, rej) => {
347
+ // run server child compilation during client main compilation
348
+ childCompilers['server'].run((err, stats) => {
349
+ if (err) {
350
+ compilation.errors.push(err);
351
+ rej()
352
+ }
353
+ if (stats && stats.hasErrors()) {
354
+ compilation.errors.push(
355
+ new Error(toDisplayErrors(stats.compilation.errors))
356
+ );
357
+ rej()
358
+ }
359
+ res()
360
+ });
361
+ });
362
+ });
363
+ }
364
+ // run client child compiler like normal
365
+ childCompiler.run((err, stats) => {
366
+ if (err) {
367
+ compilation.errors.push(err);
368
+ }
369
+ if (stats && stats.hasErrors()) {
370
+ compilation.errors.push(
371
+ new Error(toDisplayErrors(stats.compilation.errors))
372
+ );
373
+ }
374
+ });
375
+ }
376
+ });
377
+ }
378
+ }
379
+
380
+ class AddRuntimeRequirementToPromiseExternal {
381
+ /**
382
+ * Apply the plugin
383
+ * @param {Compiler} compiler the compiler instance
384
+ * @returns {void}
385
+ */
386
+ apply(compiler) {
387
+ compiler.hooks.compilation.tap(
388
+ 'AddRuntimeRequirementToPromiseExternal',
389
+ (compilation) => {
390
+ const RuntimeGlobals = compiler.webpack.RuntimeGlobals;
391
+ // if (compilation.outputOptions.trustedTypes) {
392
+ compilation.hooks.additionalModuleRuntimeRequirements.tap(
393
+ 'AddRuntimeRequirementToPromiseExternal',
394
+ (module, set, context) => {
395
+ if (module.externalType === 'promise') {
396
+ set.add(RuntimeGlobals.loadScript);
397
+ set.add(RuntimeGlobals.require);
398
+ }
399
+ }
400
+ );
401
+ // }
402
+ }
403
+ );
404
+ }
405
+ }
406
+
407
+ function createRuntimeVariables(remotes) {
408
+ return Object.entries(remotes).reduce((acc, remote) => {
409
+ // handle promise new promise and external new promise
410
+ if (remote[1].startsWith('promise ') || remote[1].startsWith('external ')) {
411
+ const promiseCall = remote[1]
412
+ .replace('promise ', '')
413
+ .replace('external ', '');
414
+ acc[remote[0]] = `function() {
415
+ return ${promiseCall}
416
+ }`;
417
+ return acc;
418
+ }
419
+ // if somehow its just the @ syntax or something else, pass it through
420
+ acc[remote[0]] = JSON.stringify(remote[1]);
421
+ return acc;
422
+ }, {});
423
+ }
424
+
425
+ class NextFederationPlugin {
426
+ constructor(options) {
427
+ const {extraOptions, ...mainOpts} = options;
428
+ this._options = mainOpts;
429
+ this._extraOptions = extraOptions || {};
430
+ }
431
+
432
+ /**
433
+ * Apply the plugin
434
+ * @param {Compiler} compiler the compiler instance
435
+ * @returns {void}
436
+ */
437
+ apply(compiler) {
438
+ const isServer = compiler.options.name === 'server';
439
+ const webpack = compiler.webpack;
440
+ if (isServer) {
441
+ console.error('[nextjs-mf] WARNING: SSR IS NOT FULLY SUPPORTED YET, Only use pluign on client builds');
442
+ // target false because we use our own target for node env
443
+ compiler.options.target = false;
444
+ new StreamingTargetPlugin(this._options, webpack).apply(compiler);
445
+ this._options.library = {};
446
+ this._options.library.type = 'commonjs-module';
447
+ this._options.library.name = this._options.name;
448
+ // output remote to ssr if server
449
+ this._options.filename = this._options.filename.replace(
450
+ '/chunks',
451
+ '/ssr'
452
+ );
453
+
454
+ // should this be a plugin that we apply to the compiler?
455
+ internalizeSharedPackages(this._options, compiler);
456
+ } else {
457
+ if (this._extraOptions.automaticPageStitching) {
458
+ compiler.options.module.rules.push({
459
+ test: /next[\\/]dist[\\/]client[\\/]page-loader\.js$/,
460
+ loader: path.resolve(__dirname, './loaders/patchNextClientPageLoader'),
461
+ });
462
+ }
463
+ if (this._options.remotes) {
464
+ const parsedRemotes = Object.entries(this._options.remotes).reduce(
465
+ (acc, remote) => {
466
+ if (remote[1].includes('@')) {
467
+ const [url, global] = extractUrlAndGlobal(remote[1]);
468
+ acc[remote[0]] = generateRemoteTemplate(url, global);
469
+ return acc;
470
+ }
471
+ acc[remote[0]] = remote[1];
472
+ return acc;
473
+ },
474
+ {}
475
+ );
476
+ this._options.remotes = parsedRemotes;
477
+ }
478
+ if (this._options.library) {
479
+ console.error('[mf] you cannot set custom library');
480
+ }
481
+ this._options.library = {
482
+ // assign remote name to object to avoid SWC mangling top level variable
483
+ type: 'window',
484
+ name: this._options.name,
485
+ };
486
+ }
487
+ //todo runtime variable creation needs to be applied for server as well. this is just for client
488
+ // todo: this needs to be refactored into something more comprehensive. this is just a quick fix
489
+ new webpack.DefinePlugin({
490
+ 'process.env.REMOTES': createRuntimeVariables(this._options.remotes),
491
+ 'process.env.CURRENT_HOST': JSON.stringify(this._options.name),
492
+ }).apply(compiler);
493
+
494
+
495
+ const ModuleFederationPlugin = {
496
+ client: webpack.container.ModuleFederationPlugin,
497
+ server: NodeFederationPlugin,
498
+ }[compiler.options.name];
499
+ // ignore edge runtime and middleware builds
500
+ if (ModuleFederationPlugin) {
501
+ const internalShare = reKeyHostShared(this._options.shared);
502
+ const hostFederationPluginOptions = {
503
+ ...this._options,
504
+ exposes: {},
505
+ shared: {
506
+ noop: {
507
+ import: 'data:text/javascript,module.exports = {};',
508
+ requiredVersion: false,
509
+ eager: true,
510
+ version: '0',
511
+ },
512
+ ...internalShare,
513
+ },
514
+ };
515
+
516
+ compiler.options.optimization.chunkIds = 'named';
517
+
518
+ new ModuleFederationPlugin(hostFederationPluginOptions, {
519
+ ModuleFederationPlugin,
520
+ }).apply(compiler);
521
+ new ChildFederationPlugin(this._options, this._extraOptions).apply(compiler);
522
+ new AddRuntimeRequirementToPromiseExternal().apply(compiler);
523
+ if (compiler.options.mode === 'development') {
524
+ new DevHmrFixInvalidPongPlugin().apply(compiler);
525
+ }
526
+ }
527
+ }
528
+ }
6
529
 
7
530
  module.exports = NextFederationPlugin;