@module-federation/nextjs-mf 5.5.0 → 5.6.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 (139) hide show
  1. package/README.md +1 -27
  2. package/{lib/client → client}/CombinedPages.d.ts +27 -28
  3. package/client/CombinedPages.js +38 -0
  4. package/client/CombinedPages.js.map +1 -0
  5. package/{lib/client → client}/MFClient.d.ts +72 -73
  6. package/client/MFClient.js +159 -0
  7. package/client/MFClient.js.map +1 -0
  8. package/{lib/client → client}/RemoteContainer.d.ts +46 -58
  9. package/client/RemoteContainer.js +121 -0
  10. package/client/RemoteContainer.js.map +1 -0
  11. package/{lib/client → client}/RemotePages.d.ts +49 -49
  12. package/client/RemotePages.js +138 -0
  13. package/client/RemotePages.js.map +1 -0
  14. package/{lib/client → client}/UrlNode.d.ts +17 -18
  15. package/{lib/client → client}/UrlNode.js +157 -161
  16. package/client/UrlNode.js.map +1 -0
  17. package/{lib/client → client}/helpers.d.ts +16 -17
  18. package/{lib/client → client}/helpers.js +90 -104
  19. package/client/helpers.js.map +1 -0
  20. package/client/index.d.ts +2 -0
  21. package/client/index.js +6 -0
  22. package/client/index.js.map +1 -0
  23. package/{lib/client → client}/useMFClient.d.ts +24 -25
  24. package/client/useMFClient.js +55 -0
  25. package/client/useMFClient.js.map +1 -0
  26. package/{lib/client → client}/useMFRemote.d.ts +16 -17
  27. package/client/useMFRemote.js +50 -0
  28. package/client/useMFRemote.js.map +1 -0
  29. package/jest.config.d.ts +13 -0
  30. package/jest.config.js +18 -0
  31. package/jest.config.js.map +1 -0
  32. package/package.json +19 -42
  33. package/src/include-defaults.d.ts +0 -0
  34. package/{lib → src}/include-defaults.js +4 -3
  35. package/src/include-defaults.js.map +1 -0
  36. package/src/index.d.ts +3 -0
  37. package/src/index.js +9 -0
  38. package/src/index.js.map +1 -0
  39. package/src/internal.d.ts +12 -0
  40. package/src/internal.js +260 -0
  41. package/src/internal.js.map +1 -0
  42. package/src/loaders/fixImageLoader.d.ts +16 -0
  43. package/src/loaders/fixImageLoader.js +53 -0
  44. package/src/loaders/fixImageLoader.js.map +1 -0
  45. package/src/loaders/fixUrlLoader.d.ts +13 -0
  46. package/src/loaders/fixUrlLoader.js +25 -0
  47. package/src/loaders/fixUrlLoader.js.map +1 -0
  48. package/src/loaders/helpers.d.ts +10 -0
  49. package/src/loaders/helpers.js +46 -0
  50. package/src/loaders/helpers.js.map +1 -0
  51. package/src/loaders/nextPageMapLoader.d.ts +15 -0
  52. package/src/loaders/nextPageMapLoader.js +151 -0
  53. package/src/loaders/nextPageMapLoader.js.map +1 -0
  54. package/src/loaders/patchNextClientPageLoader.d.ts +7 -0
  55. package/src/loaders/patchNextClientPageLoader.js +43 -0
  56. package/src/loaders/patchNextClientPageLoader.js.map +1 -0
  57. package/src/plugins/AddRuntimeRequirementToPromiseExternalPlugin.d.ts +5 -0
  58. package/src/plugins/AddRuntimeRequirementToPromiseExternalPlugin.js +19 -0
  59. package/src/plugins/AddRuntimeRequirementToPromiseExternalPlugin.js.map +1 -0
  60. package/src/plugins/ChildFederationPlugin.d.ts +9 -0
  61. package/src/plugins/ChildFederationPlugin.js +281 -0
  62. package/src/plugins/ChildFederationPlugin.js.map +1 -0
  63. package/src/plugins/DevHmrFixInvalidPongPlugin.d.ts +11 -0
  64. package/src/plugins/DevHmrFixInvalidPongPlugin.js +55 -0
  65. package/src/plugins/DevHmrFixInvalidPongPlugin.js.map +1 -0
  66. package/src/plugins/ModuleFederationPlugin.d.ts +7 -0
  67. package/src/plugins/ModuleFederationPlugin.js +50 -0
  68. package/src/plugins/ModuleFederationPlugin.js.map +1 -0
  69. package/src/plugins/NextFederationPlugin.d.ts +9 -0
  70. package/src/plugins/NextFederationPlugin.js +111 -0
  71. package/src/plugins/NextFederationPlugin.js.map +1 -0
  72. package/src/plugins/RemoveRRRuntimePlugin.d.ts +5 -0
  73. package/src/plugins/RemoveRRRuntimePlugin.js +39 -0
  74. package/src/plugins/RemoveRRRuntimePlugin.js.map +1 -0
  75. package/utils/Template.d.ts +148 -0
  76. package/utils/Template.js +381 -0
  77. package/utils/Template.js.map +1 -0
  78. package/utils/build-utils.d.ts +3 -0
  79. package/utils/build-utils.js +175 -0
  80. package/utils/build-utils.js.map +1 -0
  81. package/utils/index.d.ts +1 -0
  82. package/utils/index.js +7 -0
  83. package/utils/index.js.map +1 -0
  84. package/.prettierignore +0 -2
  85. package/.prettierrc +0 -7
  86. package/LICENSE +0 -21
  87. package/lib/ModuleFederationPlugin.js +0 -84
  88. package/lib/NextFederationPlugin.js +0 -513
  89. package/lib/_virtual/Template.js +0 -7
  90. package/lib/_virtual/UrlNode.js +0 -9
  91. package/lib/_virtual/_commonjsHelpers.js +0 -44
  92. package/lib/_virtual/_fast-glob.js +0 -16
  93. package/lib/_virtual/_fs.js +0 -16
  94. package/lib/_virtual/_path.js +0 -16
  95. package/lib/_virtual/_tslib.js +0 -277
  96. package/lib/_virtual/_webpack-sources.js +0 -16
  97. package/lib/_virtual/fs.js +0 -4
  98. package/lib/_virtual/fs2.js +0 -7
  99. package/lib/_virtual/helpers.js +0 -7
  100. package/lib/_virtual/nextPageMapLoader.js +0 -7
  101. package/lib/_virtual/options.js +0 -7
  102. package/lib/_virtual/utils.js +0 -7
  103. package/lib/build-utils.js +0 -176
  104. package/lib/client/CombinedPages.d.ts.map +0 -1
  105. package/lib/client/CombinedPages.js +0 -60
  106. package/lib/client/MFClient.d.ts.map +0 -1
  107. package/lib/client/MFClient.js +0 -213
  108. package/lib/client/RemoteContainer.d.ts.map +0 -1
  109. package/lib/client/RemoteContainer.js +0 -162
  110. package/lib/client/RemotePages.d.ts.map +0 -1
  111. package/lib/client/RemotePages.js +0 -194
  112. package/lib/client/UrlNode.d.ts.map +0 -1
  113. package/lib/client/helpers.d.ts.map +0 -1
  114. package/lib/client/useMFClient.d.ts.map +0 -1
  115. package/lib/client/useMFClient.js +0 -79
  116. package/lib/client/useMFRemote.d.ts.map +0 -1
  117. package/lib/client/useMFRemote.js +0 -72
  118. package/lib/dependencies/webpack/lib/Template.js +0 -437
  119. package/lib/dependencies/webpack/lib/container/options.js +0 -102
  120. package/lib/dependencies/webpack/lib/sharing/utils.js +0 -104
  121. package/lib/dependencies/webpack/lib/util/fs.js +0 -359
  122. package/lib/index.js +0 -3
  123. package/lib/internal.js +0 -271
  124. package/lib/loaders/UrlNode.js +0 -219
  125. package/lib/loaders/fixImageLoader.js +0 -65
  126. package/lib/loaders/fixUrlLoader.js +0 -25
  127. package/lib/loaders/helpers.js +0 -60
  128. package/lib/loaders/nextPageMapLoader.js +0 -200
  129. package/lib/loaders/patchNextClientPageLoader.js +0 -53
  130. package/lib/plugins/DevHmrFixInvalidPongPlugin.js +0 -82
  131. package/lib/utils.js +0 -125
  132. package/node-plugin/README.md +0 -27
  133. package/node-plugin/package.json +0 -4
  134. package/node-plugin/streaming/CommonJsChunkLoadingPlugin.js +0 -89
  135. package/node-plugin/streaming/LoadFileChunkLoadingRuntimeModule.js +0 -410
  136. package/node-plugin/streaming/NodeRuntime.js +0 -245
  137. package/node-plugin/streaming/index.js +0 -42
  138. package/node-plugin/streaming/loadScript.js +0 -51
  139. package/tsconfig.json +0 -33
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This plugin enables Module Federation on Next.js
4
4
 
5
- ### Supports
5
+ ## Supports
6
6
 
7
7
  - next ^11.x.x || ^12.x.x
8
8
  - Client side only, SSR has a PR open. Help needed
@@ -92,30 +92,6 @@ Make sure you are using `mini-css-extract-plugin@2` - version 2 supports resolvi
92
92
 
93
93
  You can see it in action here: https://github.com/module-federation/module-federation-examples/tree/master/nextjs
94
94
 
95
- ## Usage
96
-
97
- ```js
98
- const SampleComponent = dynamic(() => import('next2/sampleComponent'), {
99
- ssr: false,
100
- });
101
- ```
102
-
103
- If you want support for sync imports. It is possible in next@12 as long as there is an async boundary.
104
-
105
- #### See the implementation here: https://github.com/module-federation/module-federation-examples/tree/master/nextjs/home/pages
106
-
107
- With async boundary installed at the page level. You can then do the following
108
-
109
- ```js
110
- if (process.browser) {
111
- const SomeHook = require('next2/someHook');
112
- }
113
- // if client only file
114
- import SomeComponent from 'next2/someComponent';
115
- ```
116
-
117
- Make sure you are using `mini-css-extract-plugin@2` - version 2 supports resolving assets through `publicPath:'auto'`
118
-
119
95
  ## Options
120
96
 
121
97
  This plugin works exactly like ModuleFederationPlugin, use it as you'd normally.
@@ -134,7 +110,6 @@ new NextFederationPlugin({
134
110
  exposePages: true, // `false` by default
135
111
  enableImageLoaderFix: true, // `false` by default
136
112
  enableUrlLoaderFix: true, // `false` by default
137
- skipSharingNextInternals: true // `false` by default
138
113
  },
139
114
  });
140
115
  ```
@@ -142,7 +117,6 @@ new NextFederationPlugin({
142
117
  - `exposePages` – exposes automatically all nextjs pages for you and theirs `./pages-map`.
143
118
  - `enableImageLoaderFix` – adds public hostname to all assets bundled by `nextjs-image-loader`. So if you serve remoteEntry from `http://example.com` then all bundled assets will get this hostname in runtime. It's something like Base URL in HTML but for federated modules.
144
119
  - `enableUrlLoaderFix` – adds public hostname to all assets bundled by `url-loader`.
145
- - `skipSharingNextInternals` - skips sharing of common nextjs modules. Helpful when you would like explicit control over shared modules, such as a non-nextjs host with a federated nextjs child application.
146
120
 
147
121
  ## Demo
148
122
 
@@ -1,28 +1,27 @@
1
- import { RemotePages } from './RemotePages';
2
- /**
3
- * Class which provides combined sorted list of local and remote routes.
4
- */
5
- export declare class CombinedPages {
6
- /** Computable list of available local & remote pages in proper sorted order. */
7
- private sortedPageCache;
8
- /** List of pages that belongs to the current host application */
9
- private localPagesCache;
10
- /** List of known remote pages this list might be extent during runtime */
11
- private remotePagesCache;
12
- /** Nextjs getter which obtained from patchNextClientPageLoader */
13
- private localPagesGetter;
14
- /** Loader of remote pages */
15
- private remotePages;
16
- constructor(localPagesGetter: () => Promise<string[]>, remotePages: RemotePages);
17
- /**
18
- * Check that provided route belongs to host application
19
- */
20
- isLocalRoute(route: string): Promise<boolean>;
21
- /**
22
- * Return sorted list of local & remotes routes.
23
- * This method is used in patchNextClientPageLoader
24
- * for patching nextjs' getPageList method.
25
- */
26
- getPageList(): Promise<string[]>;
27
- }
28
- //# sourceMappingURL=CombinedPages.d.ts.map
1
+ import { RemotePages } from './RemotePages';
2
+ /**
3
+ * Class which provides combined sorted list of local and remote routes.
4
+ */
5
+ export declare class CombinedPages {
6
+ /** Computable list of available local & remote pages in proper sorted order. */
7
+ private sortedPageCache;
8
+ /** List of pages that belongs to the current host application */
9
+ private localPagesCache;
10
+ /** List of known remote pages this list might be extent during runtime */
11
+ private remotePagesCache;
12
+ /** Nextjs getter which obtained from patchNextClientPageLoader */
13
+ private localPagesGetter;
14
+ /** Loader of remote pages */
15
+ private remotePages;
16
+ constructor(localPagesGetter: () => Promise<string[]>, remotePages: RemotePages);
17
+ /**
18
+ * Check that provided route belongs to host application
19
+ */
20
+ isLocalRoute(route: string): Promise<boolean>;
21
+ /**
22
+ * Return sorted list of local & remotes routes.
23
+ * This method is used in patchNextClientPageLoader
24
+ * for patching nextjs' getPageList method.
25
+ */
26
+ getPageList(): Promise<string[]>;
27
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CombinedPages = void 0;
4
+ const helpers_1 = require("./helpers");
5
+ /**
6
+ * Class which provides combined sorted list of local and remote routes.
7
+ */
8
+ class CombinedPages {
9
+ constructor(localPagesGetter, remotePages) {
10
+ this.localPagesGetter = localPagesGetter;
11
+ this.remotePages = remotePages;
12
+ }
13
+ /**
14
+ * Check that provided route belongs to host application
15
+ */
16
+ async isLocalRoute(route) {
17
+ const localPages = await this.localPagesGetter();
18
+ return localPages.includes(route);
19
+ }
20
+ /**
21
+ * Return sorted list of local & remotes routes.
22
+ * This method is used in patchNextClientPageLoader
23
+ * for patching nextjs' getPageList method.
24
+ */
25
+ async getPageList() {
26
+ const localPages = await this.localPagesGetter();
27
+ const remotePages = this.remotePages.getPageList();
28
+ if (localPages !== this.localPagesCache ||
29
+ remotePages !== this.remotePagesCache) {
30
+ this.localPagesCache = localPages;
31
+ this.remotePagesCache = remotePages;
32
+ this.sortedPageCache = (0, helpers_1.sortNextPages)([...localPages, ...remotePages]);
33
+ }
34
+ return this.sortedPageCache;
35
+ }
36
+ }
37
+ exports.CombinedPages = CombinedPages;
38
+ //# sourceMappingURL=CombinedPages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CombinedPages.js","sourceRoot":"","sources":["../../../../packages/nextjs-mf/client/CombinedPages.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;AAG1C;;GAEG;AACH,MAAa,aAAa;IAgBxB,YACE,gBAAyC,EACzC,WAAwB;QAExB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,KAAa;QAC9B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACjD,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW;QACf,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACjD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QACnD,IACE,UAAU,KAAK,IAAI,CAAC,eAAe;YACnC,WAAW,KAAK,IAAI,CAAC,gBAAgB,EACrC;YACA,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;YAClC,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC;YACpC,IAAI,CAAC,eAAe,GAAG,IAAA,uBAAa,EAAC,CAAC,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC;SACvE;QACD,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;CACF;AAlDD,sCAkDC"}
@@ -1,73 +1,72 @@
1
- import type PageLoader from 'next/dist/client/page-loader';
2
- import EventEmitter from 'eventemitter3';
3
- import { CombinedPages } from './CombinedPages';
4
- import { RemotePages } from './RemotePages';
5
- import { RemoteContainer } from './RemoteContainer';
6
- declare type EventTypes = 'loadedRemoteRoute' | 'loadedLocalRoute';
7
- /** Remote Container string eg `home@https://example.com/_next/static/chunks/remoteEntry.js` */
8
- export declare type RemoteString = string;
9
- export declare type MFClientOptions = {
10
- mode: 'production' | 'development';
11
- };
12
- /**
13
- * The main class for Module Federation on the client side in runtime.
14
- * Instance of this class is a Singleton and stored in `window.mf_client` variable.
15
- */
16
- export declare class MFClient {
17
- /** List of registered remotes */
18
- remotes: Record<RemoteString, RemoteContainer>;
19
- /** Local & Remote pages sorted in correct order */
20
- combinedPages: CombinedPages;
21
- /** Remote pages loader */
22
- remotePages: RemotePages;
23
- /** EventEmitter which allows to subscribe on different events */
24
- events: EventEmitter<EventTypes>;
25
- /** Original nextjs PageLoader which passed by `patchNextClientPageLoader.js` */
26
- private _nextPageLoader;
27
- constructor(nextPageLoader: PageLoader, opts: MFClientOptions);
28
- /**
29
- * This method returns sorted list of local and federated pages.
30
- *
31
- * `patchNextClientPageLoader` change vanilla PageLoader.getPageList() method:
32
- * - exposes vanilla implementation as _getPageListOriginal()
33
- * - and PageLoader.getPageList() starting call this method under the hood
34
- */
35
- getPageList(): Promise<string[]>;
36
- /**
37
- * Check that current browser pathname is served by federated remotes.
38
- *
39
- * Eg. if cleanPathname `/shop/nodkz/product123` and pageListFederated is ['/shop/nodkz/[...mee]']
40
- * then this method will match federated dynamic route and return true.
41
- *
42
- * PS. This method is used by DevHmrFixInvalidPongPlugin (fix HMR page reloads in dev mode)
43
- */
44
- isFederatedPathname(cleanPathname: string): boolean;
45
- /**
46
- * Add remote entry to remotes registry of MFClient.
47
- * This RemoteContainer will be used for loading remote pages.
48
- *
49
- * @remoteStr string - eg. `home@https://example.com/_next/static/chunks/remoteEntry.js`
50
- */
51
- registerRemote(remoteStr: RemoteString): RemoteContainer;
52
- /**
53
- * Convert browser pathname to NextJS route.
54
- *
55
- * /shop/products/123 -> /shop/products/[...id]
56
- *
57
- * For regular pages logic is simple (just match exact name).
58
- * But for dynamic routes it's quite complicated - page list must be in specific order.
59
- */
60
- pathnameToRoute(cleanPathname: string): Promise<string | undefined>;
61
- /**
62
- * This method patch routeLoader.loadRoute() in runtime (on bootstrap).
63
- * During the build it's quite complicated to do.
64
- */
65
- private _wrapLoadRoute;
66
- /**
67
- * This method patch routeLoader.whenEntrypoint() in runtime (on bootstrap).
68
- * During the build it's quite complicated to do.
69
- */
70
- private _wrapWhenEntrypoint;
71
- }
72
- export {};
73
- //# sourceMappingURL=MFClient.d.ts.map
1
+ import type PageLoader from 'next/dist/client/page-loader';
2
+ import EventEmitter from 'eventemitter3';
3
+ import { CombinedPages } from './CombinedPages';
4
+ import { RemotePages } from './RemotePages';
5
+ import { RemoteContainer } from './RemoteContainer';
6
+ declare type EventTypes = 'loadedRemoteRoute' | 'loadedLocalRoute';
7
+ /** Remote Container string eg `home@https://example.com/_next/static/chunks/remoteEntry.js` */
8
+ export declare type RemoteString = string;
9
+ export declare type MFClientOptions = {
10
+ mode: 'production' | 'development';
11
+ };
12
+ /**
13
+ * The main class for Module Federation on the client side in runtime.
14
+ * Instance of this class is a Singleton and stored in `window.mf_client` variable.
15
+ */
16
+ export declare class MFClient {
17
+ /** List of registered remotes */
18
+ remotes: Record<RemoteString, RemoteContainer>;
19
+ /** Local & Remote pages sorted in correct order */
20
+ combinedPages: CombinedPages;
21
+ /** Remote pages loader */
22
+ remotePages: RemotePages;
23
+ /** EventEmitter which allows to subscribe on different events */
24
+ events: EventEmitter<EventTypes>;
25
+ /** Original nextjs PageLoader which passed by `patchNextClientPageLoader.js` */
26
+ private _nextPageLoader;
27
+ constructor(nextPageLoader: PageLoader, opts: MFClientOptions);
28
+ /**
29
+ * This method returns sorted list of local and federated pages.
30
+ *
31
+ * `patchNextClientPageLoader` change vanilla PageLoader.getPageList() method:
32
+ * - exposes vanilla implementation as _getPageListOriginal()
33
+ * - and PageLoader.getPageList() starting call this method under the hood
34
+ */
35
+ getPageList(): Promise<string[]>;
36
+ /**
37
+ * Check that current browser pathname is served by federated remotes.
38
+ *
39
+ * Eg. if cleanPathname `/shop/nodkz/product123` and pageListFederated is ['/shop/nodkz/[...mee]']
40
+ * then this method will match federated dynamic route and return true.
41
+ *
42
+ * PS. This method is used by DevHmrFixInvalidPongPlugin (fix HMR page reloads in dev mode)
43
+ */
44
+ isFederatedPathname(cleanPathname: string): boolean;
45
+ /**
46
+ * Add remote entry to remotes registry of MFClient.
47
+ * This RemoteContainer will be used for loading remote pages.
48
+ *
49
+ * @remoteStr string - eg. `home@https://example.com/_next/static/chunks/remoteEntry.js`
50
+ */
51
+ registerRemote(remoteStr: RemoteString): RemoteContainer;
52
+ /**
53
+ * Convert browser pathname to NextJS route.
54
+ *
55
+ * /shop/products/123 -> /shop/products/[...id]
56
+ *
57
+ * For regular pages logic is simple (just match exact name).
58
+ * But for dynamic routes it's quite complicated - page list must be in specific order.
59
+ */
60
+ pathnameToRoute(cleanPathname: string): Promise<string | undefined>;
61
+ /**
62
+ * This method patch routeLoader.loadRoute() in runtime (on bootstrap).
63
+ * During the build it's quite complicated to do.
64
+ */
65
+ private _wrapLoadRoute;
66
+ /**
67
+ * This method patch routeLoader.whenEntrypoint() in runtime (on bootstrap).
68
+ * During the build it's quite complicated to do.
69
+ */
70
+ private _wrapWhenEntrypoint;
71
+ }
72
+ export {};
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MFClient = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const eventemitter3_1 = tslib_1.__importDefault(require("eventemitter3"));
6
+ const helpers_1 = require("./helpers");
7
+ const CombinedPages_1 = require("./CombinedPages");
8
+ const RemotePages_1 = require("./RemotePages");
9
+ const RemoteContainer_1 = require("./RemoteContainer");
10
+ /**
11
+ * The main class for Module Federation on the client side in runtime.
12
+ * Instance of this class is a Singleton and stored in `window.mf_client` variable.
13
+ */
14
+ class MFClient {
15
+ constructor(nextPageLoader, opts) {
16
+ /** List of registered remotes */
17
+ this.remotes = {};
18
+ this._nextPageLoader = nextPageLoader;
19
+ this.events = new eventemitter3_1.default();
20
+ const cfg = global?.__NEXT_DATA__?.props?.mfRoutes || {};
21
+ this.remotePages = new RemotePages_1.RemotePages(opts?.mode);
22
+ Object.keys(cfg).forEach((remoteStr) => {
23
+ const remote = this.registerRemote(remoteStr);
24
+ this.remotePages.addRoutes(cfg[remoteStr], remote);
25
+ });
26
+ this.combinedPages = new CombinedPages_1.CombinedPages(this._nextPageLoader._getPageListOriginal.bind(this._nextPageLoader), this.remotePages);
27
+ this._wrapLoadRoute(nextPageLoader);
28
+ this._wrapWhenEntrypoint(nextPageLoader);
29
+ }
30
+ /**
31
+ * This method returns sorted list of local and federated pages.
32
+ *
33
+ * `patchNextClientPageLoader` change vanilla PageLoader.getPageList() method:
34
+ * - exposes vanilla implementation as _getPageListOriginal()
35
+ * - and PageLoader.getPageList() starting call this method under the hood
36
+ */
37
+ async getPageList() {
38
+ return this.combinedPages.getPageList();
39
+ }
40
+ /**
41
+ * Check that current browser pathname is served by federated remotes.
42
+ *
43
+ * Eg. if cleanPathname `/shop/nodkz/product123` and pageListFederated is ['/shop/nodkz/[...mee]']
44
+ * then this method will match federated dynamic route and return true.
45
+ *
46
+ * PS. This method is used by DevHmrFixInvalidPongPlugin (fix HMR page reloads in dev mode)
47
+ */
48
+ isFederatedPathname(cleanPathname) {
49
+ return !!this.remotePages.routeToRemote(cleanPathname);
50
+ }
51
+ /**
52
+ * Add remote entry to remotes registry of MFClient.
53
+ * This RemoteContainer will be used for loading remote pages.
54
+ *
55
+ * @remoteStr string - eg. `home@https://example.com/_next/static/chunks/remoteEntry.js`
56
+ */
57
+ registerRemote(remoteStr) {
58
+ const remote = RemoteContainer_1.RemoteContainer.createSingleton(remoteStr);
59
+ this.remotes[remote.global] = remote;
60
+ return remote;
61
+ }
62
+ /**
63
+ * Convert browser pathname to NextJS route.
64
+ *
65
+ * /shop/products/123 -> /shop/products/[...id]
66
+ *
67
+ * For regular pages logic is simple (just match exact name).
68
+ * But for dynamic routes it's quite complicated - page list must be in specific order.
69
+ */
70
+ async pathnameToRoute(cleanPathname) {
71
+ const routes = await this.getPageList();
72
+ return (0, helpers_1.pathnameToRoute)(cleanPathname, routes);
73
+ }
74
+ /**
75
+ * This method patch routeLoader.loadRoute() in runtime (on bootstrap).
76
+ * During the build it's quite complicated to do.
77
+ */
78
+ _wrapLoadRoute(nextPageLoader) {
79
+ if (!nextPageLoader?.routeLoader?.loadRoute) {
80
+ throw new Error('[nextjs-mf] Cannot wrap `pageLoader.routeLoader.loadRoute()` with custom logic.');
81
+ }
82
+ const routeLoader = nextPageLoader.routeLoader;
83
+ // if _loadRouteOriginal does not initialized then take original loadRoute method
84
+ if (!routeLoader._loadRouteOriginal) {
85
+ routeLoader._loadRouteOriginal = routeLoader.loadRoute.bind(routeLoader);
86
+ }
87
+ // replace loadRoute logic
88
+ routeLoader.loadRoute = async (route, prefetch) => {
89
+ let routeInfo;
90
+ if (await this.combinedPages.isLocalRoute(route)) {
91
+ routeInfo = await routeLoader._loadRouteOriginal(route);
92
+ this.events.emit('loadedLocalRoute', routeInfo, prefetch);
93
+ }
94
+ else {
95
+ try {
96
+ routeInfo = await this.remotePages.getRouteInfo(route);
97
+ this.events.emit('loadedRemoteRoute', routeInfo, prefetch, this.remotePages.routeToRemote(route));
98
+ }
99
+ catch (e) {
100
+ // as fallback try to use original loadRoute for keeping nextjs logic for routes load errors
101
+ routeInfo = await routeLoader._loadRouteOriginal(route);
102
+ }
103
+ }
104
+ return routeInfo;
105
+ };
106
+ }
107
+ /**
108
+ * This method patch routeLoader.whenEntrypoint() in runtime (on bootstrap).
109
+ * During the build it's quite complicated to do.
110
+ */
111
+ _wrapWhenEntrypoint(nextPageLoader) {
112
+ if (!nextPageLoader.routeLoader?.whenEntrypoint) {
113
+ throw new Error('[nextjs-mf] Cannot wrap `pageLoader.routeLoader.whenEntrypoint()` with custom logic.');
114
+ }
115
+ const routeLoader = nextPageLoader.routeLoader;
116
+ // if _whenEntrypointOriginal does not initialized then take original loadRoute method
117
+ if (!routeLoader._whenEntrypointOriginal) {
118
+ routeLoader._whenEntrypointOriginal =
119
+ routeLoader.whenEntrypoint.bind(routeLoader);
120
+ }
121
+ // replace routeLoader.whenEntrypoint logic
122
+ routeLoader.whenEntrypoint = async (route) => {
123
+ if (route === '/_error') {
124
+ try {
125
+ let route = await this.pathnameToRoute(window.location.pathname);
126
+ if (!route) {
127
+ // if route not found then try to load all non-downloaded remoteEntries
128
+ // and try to find route again
129
+ const awaitRemotes = [];
130
+ Object.values(this.remotes).forEach((remote) => {
131
+ if (!remote.isLoaded()) {
132
+ awaitRemotes.push(remote
133
+ .getContainer()
134
+ .then(() => this.remotePages.loadRemotePageMap(remote))
135
+ .catch(() => null));
136
+ }
137
+ });
138
+ await Promise.all(awaitRemotes);
139
+ route = await this.pathnameToRoute(window.location.pathname);
140
+ }
141
+ if (route) {
142
+ // TODO: fix router properties for the first page load of federated page http://localhost:3000/shop/products/B
143
+ console.warn('replace entrypoint /_error by', route);
144
+ const routeInfo = await this.remotePages.getRouteInfo(route);
145
+ this.events.emit('loadedRemoteRoute', routeInfo, false, this.remotePages.routeToRemote(route));
146
+ return routeInfo;
147
+ }
148
+ }
149
+ catch (e) {
150
+ // do nothing, load original entrypoint
151
+ }
152
+ }
153
+ const routeInfo = await routeLoader._whenEntrypointOriginal(route);
154
+ return routeInfo;
155
+ };
156
+ }
157
+ }
158
+ exports.MFClient = MFClient;
159
+ //# sourceMappingURL=MFClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MFClient.js","sourceRoot":"","sources":["../../../../packages/nextjs-mf/client/MFClient.ts"],"names":[],"mappings":"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"}
@@ -1,58 +1,46 @@
1
- import EventEmitter from 'eventemitter3';
2
- declare type EventTypes = 'loadStart' | 'loadComplete' | 'loadError';
3
- export declare type WebpackRemoteContainer = {
4
- get(modulePath: ModulePath): () => any;
5
- };
6
- export declare type NextRoute = string;
7
- export declare type ModulePath = string;
8
- export declare type RemoteData = {
9
- global: string;
10
- url: string;
11
- };
12
- export declare type PageMap = Record<NextRoute, ModulePath>;
13
- /**
14
- * This is a Lazy loader of webpack remote container with some NextJS-specific helper methods.
15
- *
16
- * It provides the ability to register remote, and load & init it on the first use.
17
- */
18
- export declare class RemoteContainer {
19
- global: string;
20
- url: string;
21
- container: WebpackRemoteContainer | undefined;
22
- pageMap: PageMap | undefined;
23
- error?: Error;
24
- events: EventEmitter<EventTypes>;
25
- static instances: Record<string, RemoteContainer>;
26
- /**
27
- * Create or reuse existed remote entry.
28
- *
29
- * Be careful, Singleton pattern does not work well in webpack builds,
30
- * because one module may be copied between different chunks. In such a way
31
- * you obtain several lists of instances.
32
- */
33
- static createSingleton(remote: string | RemoteData): RemoteContainer;
34
- constructor(opts: RemoteData);
35
- /**
36
- * Check is the current remoteEntry.js loaded or not
37
- */
38
- isLoaded(): boolean;
39
- /**
40
- * Returns initialized webpack RemoteContainer.
41
- * If its' script does not loaded - then load & init it firstly.
42
- */
43
- getContainer(): Promise<WebpackRemoteContainer>;
44
- /**
45
- * Return remote module from container.
46
- * If you provide `exportName` it automatically return exact property value from module.
47
- *
48
- * @example
49
- * remote.getModule('./pages/index', 'default')
50
- */
51
- getModule(modulePath: string, exportName?: string): Promise<any>;
52
- /**
53
- * Retrieve registered nextjs' routes from remote app
54
- */
55
- getPageMap(): Promise<PageMap | undefined>;
56
- }
57
- export {};
58
- //# sourceMappingURL=RemoteContainer.d.ts.map
1
+ import type { WebpackRemoteContainer, EventTypes, RemoteData, PageMap } from '@module-federation/utilities';
2
+ import EventEmitter from 'eventemitter3';
3
+ /**
4
+ * This is a Lazy loader of webpack remote container with some NextJS-specific helper methods.
5
+ *
6
+ * It provides the ability to register remote, and load & init it on the first use.
7
+ */
8
+ export declare class RemoteContainer {
9
+ global: string;
10
+ url: string;
11
+ container: WebpackRemoteContainer | undefined;
12
+ pageMap: PageMap | undefined;
13
+ error?: Error;
14
+ events: EventEmitter<EventTypes>;
15
+ static instances: Record<string, RemoteContainer>;
16
+ /**
17
+ * Create or reuse existed remote entry.
18
+ *
19
+ * Be careful, Singleton pattern does not work well in webpack builds,
20
+ * because one module may be copied between different chunks. In such a way
21
+ * you obtain several lists of instances.
22
+ */
23
+ static createSingleton(remote: string | RemoteData): RemoteContainer;
24
+ constructor(opts: RemoteData);
25
+ /**
26
+ * Check is the current remoteEntry.js loaded or not
27
+ */
28
+ isLoaded(): boolean;
29
+ /**
30
+ * Returns initialized webpack RemoteContainer.
31
+ * If its' script does not loaded - then load & init it firstly.
32
+ */
33
+ getContainer(): Promise<WebpackRemoteContainer>;
34
+ /**
35
+ * Return remote module from container.
36
+ * If you provide `exportName` it automatically return exact property value from module.
37
+ *
38
+ * @example
39
+ * remote.getModule('./pages/index', 'default')
40
+ */
41
+ getModule(modulePath: string, exportName?: string): Promise<any>;
42
+ /**
43
+ * Retrieve registered nextjs' routes from remote app
44
+ */
45
+ getPageMap(): Promise<PageMap | undefined>;
46
+ }