@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,108 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _tslib = require('../_virtual/_tslib.js');
6
+ var UrlNode = require('./UrlNode.js');
7
+
8
+ var TEST_DYNAMIC_ROUTE = /\/\[[^/]+?\](?=\/|$)/;
9
+ function isDynamicRoute(route) {
10
+ return TEST_DYNAMIC_ROUTE.test(route);
11
+ }
12
+ /**
13
+ * Parses a given parameter from a route to a data structure that can be used
14
+ * to generate the parametrized route. Examples:
15
+ * - `[...slug]` -> `{ name: 'slug', repeat: true, optional: true }`
16
+ * - `[foo]` -> `{ name: 'foo', repeat: false, optional: true }`
17
+ * - `bar` -> `{ name: 'bar', repeat: false, optional: false }`
18
+ */
19
+ function parseParameter(param) {
20
+ var optional = param.startsWith('[') && param.endsWith(']');
21
+ if (optional) {
22
+ param = param.slice(1, -1);
23
+ }
24
+ var repeat = param.startsWith('...');
25
+ if (repeat) {
26
+ param = param.slice(3);
27
+ }
28
+ return { key: param, repeat: repeat, optional: optional };
29
+ }
30
+ function getParametrizedRoute(route) {
31
+ // const segments = removeTrailingSlash(route).slice(1).split('/')
32
+ var segments = route.slice(1).split('/');
33
+ var groups = {};
34
+ var groupIndex = 1;
35
+ return {
36
+ parameterizedRoute: segments
37
+ .map(function (segment) {
38
+ if (segment.startsWith('[') && segment.endsWith(']')) {
39
+ var _a = parseParameter(segment.slice(1, -1)), key = _a.key, optional = _a.optional, repeat = _a.repeat;
40
+ groups[key] = { pos: groupIndex++, repeat: repeat, optional: optional };
41
+ return repeat ? (optional ? '(?:/(.+?))?' : '/(.+?)') : '/([^/]+?)';
42
+ }
43
+ else {
44
+ return "/".concat(escapeStringRegexp(segment));
45
+ }
46
+ })
47
+ .join(''),
48
+ groups: groups,
49
+ };
50
+ }
51
+ function getRouteRegex(normalizedRoute) {
52
+ var _a = getParametrizedRoute(normalizedRoute), parameterizedRoute = _a.parameterizedRoute, groups = _a.groups;
53
+ return {
54
+ re: new RegExp("^".concat(parameterizedRoute, "(?:/)?$")),
55
+ groups: groups,
56
+ };
57
+ }
58
+ var reHasRegExp = /[|\\{}()[\]^$+*?.-]/;
59
+ var reReplaceRegExp = /[|\\{}()[\]^$+*?.-]/g;
60
+ function escapeStringRegexp(str) {
61
+ // see also: https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/escapeRegExp.js#L23
62
+ if (reHasRegExp.test(str)) {
63
+ return str.replace(reReplaceRegExp, '\\$&');
64
+ }
65
+ return str;
66
+ }
67
+ /**
68
+ * Convert browser pathname to NextJs route.
69
+ * This method is required for proper work of Dynamic routes in NextJS.
70
+ */
71
+ function pathnameToRoute(cleanPathname, routes) {
72
+ var e_1, _a;
73
+ if (routes.includes(cleanPathname)) {
74
+ return cleanPathname;
75
+ }
76
+ try {
77
+ for (var routes_1 = _tslib.__values(routes), routes_1_1 = routes_1.next(); !routes_1_1.done; routes_1_1 = routes_1.next()) {
78
+ var route = routes_1_1.value;
79
+ if (isDynamicRoute(route) && getRouteRegex(route).re.test(cleanPathname)) {
80
+ return route;
81
+ }
82
+ }
83
+ }
84
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
85
+ finally {
86
+ try {
87
+ if (routes_1_1 && !routes_1_1.done && (_a = routes_1.return)) _a.call(routes_1);
88
+ }
89
+ finally { if (e_1) throw e_1.error; }
90
+ }
91
+ return undefined;
92
+ }
93
+ /**
94
+ * Sort provided pages in correct nextjs order.
95
+ * This sorting is required if you are using dynamic routes in your apps.
96
+ * If order is incorrect then Nextjs may use dynamicRoute instead of exact page.
97
+ */
98
+ function sortNextPages(pages) {
99
+ var root = new UrlNode.UrlNode();
100
+ pages.forEach(function (pageRoute) { return root.insert(pageRoute); });
101
+ // Smoosh will then sort those sublevels up to the point where you get the correct route definition priority
102
+ return root.smoosh();
103
+ }
104
+
105
+ exports.getRouteRegex = getRouteRegex;
106
+ exports.isDynamicRoute = isDynamicRoute;
107
+ exports.pathnameToRoute = pathnameToRoute;
108
+ exports.sortNextPages = sortNextPages;
@@ -0,0 +1,25 @@
1
+ import type { MFClient } from './MFClient';
2
+ import type { RemoteContainer } from './RemoteContainer';
3
+ export declare type MFClientHookOptions = {
4
+ /**
5
+ * This callback will be called when user switches to federated page
6
+ * - as a first arg you will receive RemoteContainer
7
+ * If user return back to the host application page
8
+ * - then the first argument became `undefined`
9
+ *
10
+ * This callback is called only if changed remote from which served current visible page
11
+ * and does not called on internal nextjs route changes.
12
+ *
13
+ * This callback helps in very convenient way in _app.tsx (or any other React component)
14
+ * load additional data from RemoteContainer and pass it to your application. Eg.:
15
+ * - application menu
16
+ * - apollo configs
17
+ * - translation strings
18
+ */
19
+ onChangeRemote?: (remote: RemoteContainer | undefined, MFClient: MFClient) => void;
20
+ };
21
+ /**
22
+ * React hook which provides convenient way for working with ModuleFederation runtime changes in runtime;
23
+ */
24
+ export declare function useMFClient(opts: MFClientHookOptions): MFClient;
25
+ //# sourceMappingURL=useMFClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMFClient.d.ts","sourceRoot":"","sources":["../../src/client/useMFClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,oBAAY,mBAAmB,GAAG;IAChC;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,eAAe,GAAG,SAAS,EACnC,QAAQ,EAAE,QAAQ,KACf,IAAI,CAAC;CACX,CAAC;AAQF;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG,QAAQ,CAgD/D"}
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var singletonRouter = require('next/dist/client/router');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n["default"] = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
29
+ var singletonRouter__default = /*#__PURE__*/_interopDefaultLegacy(singletonRouter);
30
+
31
+ var isBrowser = typeof window !== 'undefined';
32
+ /**
33
+ * React hook which provides convenient way for working with ModuleFederation runtime changes in runtime;
34
+ */
35
+ function useMFClient(opts) {
36
+ var MFClient = isBrowser
37
+ ? window.mf_client
38
+ : /* TODO: inject here SSR version of MFClient if it will be needed in future */ {};
39
+ var innerState = React__namespace.useRef({
40
+ remote: undefined,
41
+ });
42
+ React__namespace.useEffect(function () {
43
+ // Step 1: Define handlers and helpers
44
+ var processRemoteChange = function (remote) {
45
+ if (innerState.current.remote !== remote) {
46
+ innerState.current.remote = remote;
47
+ if (opts === null || opts === void 0 ? void 0 : opts.onChangeRemote) {
48
+ opts.onChangeRemote(remote, MFClient);
49
+ }
50
+ }
51
+ };
52
+ var handleRouterChange = function (pathname) {
53
+ if (MFClient.isFederatedPathname(pathname)) {
54
+ var remote = MFClient.remotePages.routeToRemote(pathname);
55
+ processRemoteChange(remote);
56
+ }
57
+ else {
58
+ processRemoteChange(undefined);
59
+ }
60
+ };
61
+ // Step 2: run bootstrap logic
62
+ var initialRemote = MFClient.isFederatedPathname(window.location.pathname)
63
+ ? MFClient.remotePages.routeToRemote(window.location.pathname)
64
+ : undefined;
65
+ if (initialRemote) {
66
+ // important for first load to fire `onChangeRemote` with different remote
67
+ // because in innerState by default we assume that used local application
68
+ processRemoteChange(initialRemote);
69
+ }
70
+ // Step 3: Subscribe on events
71
+ singletonRouter__default["default"].events.on('routeChangeStart', handleRouterChange);
72
+ return function () {
73
+ singletonRouter__default["default"].events.off('routeChangeStart', handleRouterChange);
74
+ };
75
+ }, []);
76
+ return MFClient;
77
+ }
78
+
79
+ exports.useMFClient = useMFClient;
@@ -0,0 +1,17 @@
1
+ import { RemoteContainer } from './RemoteContainer';
2
+ declare type UseMFRemoteResult = {
3
+ /** is container loaded or not */
4
+ loaded: boolean;
5
+ /** remote is Lazy, so it will be loaded if getModule(), getContainer() were called */
6
+ remote: RemoteContainer;
7
+ /** Present if error occurs during remote container loading */
8
+ error: Error | undefined;
9
+ };
10
+ /**
11
+ * React hook which provides an access to RemoteContainer in Module Federation
12
+ *
13
+ * @param global - can be a global variable name OR connection string "global@url"
14
+ */
15
+ export declare function useMFRemote(global: string): UseMFRemoteResult;
16
+ export {};
17
+ //# sourceMappingURL=useMFRemote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMFRemote.d.ts","sourceRoot":"","sources":["../../src/client/useMFRemote.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,aAAK,iBAAiB,GAAG;IACvB,iCAAiC;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,sFAAsF;IACtF,MAAM,EAAE,eAAe,CAAC;IACxB,8DAA8D;IAC9D,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;CAC1B,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAwC7D"}
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _tslib = require('../_virtual/_tslib.js');
6
+ var React = require('react');
7
+ var RemoteContainer = require('./RemoteContainer.js');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n["default"] = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
+
29
+ var isBrowser = typeof window !== 'undefined';
30
+ /**
31
+ * React hook which provides an access to RemoteContainer in Module Federation
32
+ *
33
+ * @param global - can be a global variable name OR connection string "global@url"
34
+ */
35
+ function useMFRemote(global) {
36
+ var remote;
37
+ if (isBrowser) {
38
+ // on client (we get instances from global variable because webpack breaks Singletons)
39
+ var MFClient_1 = window.mf_client;
40
+ remote = MFClient_1.remotes[global] || MFClient_1.registerRemote(global);
41
+ }
42
+ else {
43
+ // on server side
44
+ remote = RemoteContainer.RemoteContainer.createSingleton(global);
45
+ }
46
+ var _a = _tslib.__read(React__namespace.useState(remote.isLoaded()), 2), loaded = _a[0], setLoaded = _a[1];
47
+ var _b = _tslib.__read(React__namespace.useState(remote.error), 2), error = _b[0], setError = _b[1];
48
+ React__namespace.useEffect(function () {
49
+ var handleLoadComplete = function () {
50
+ setLoaded(true);
51
+ };
52
+ var handleLoadError = function (e) {
53
+ setError(e);
54
+ };
55
+ if (!loaded && remote.isLoaded()) {
56
+ handleLoadComplete();
57
+ }
58
+ remote.events.on('loadComplete', handleLoadComplete);
59
+ remote.events.on('loadError', handleLoadError);
60
+ return function () {
61
+ remote.events.off('loadComplete', handleLoadComplete);
62
+ remote.events.off('loadError', handleLoadError);
63
+ };
64
+ }, [remote]);
65
+ return {
66
+ remote: remote,
67
+ loaded: loaded,
68
+ error: error,
69
+ };
70
+ }
71
+
72
+ exports.useMFRemote = useMFRemote;
@@ -1,6 +1,4 @@
1
- // if(process.browser && (typeof __webpack_share_scopes__ === "undefined" || !__webpack_share_scopes__.default)) {
2
- // __webpack_init_sharing__('default');
3
- // }
1
+ // this is needed to ensure webpack does not attempt to tree shake unused modules. Since these should always come from host
4
2
  require('react');
5
3
  require('react-dom');
6
4
  require('next/link');
@@ -0,0 +1,241 @@
1
+ import { parseOptions } from 'webpack/lib/container/options';
2
+ import { isRequiredVersion } from 'webpack/lib/sharing/utils';
3
+ import path from 'path';
4
+
5
+ // the share scope we attach by default
6
+ // in hosts we re-key them to prevent webpack moving the modules into their own chunks (cause eager error)
7
+ // in remote these are marked as import:false as we always expect the host to prove them
8
+ export const DEFAULT_SHARE_SCOPE = {
9
+ react: {
10
+ singleton: true,
11
+ requiredVersion: false,
12
+ },
13
+ 'react/jsx-runtime': {
14
+ singleton: true,
15
+ requiredVersion: false,
16
+ },
17
+ 'react-dom': {
18
+ singleton: true,
19
+ requiredVersion: false,
20
+ },
21
+ 'next/dynamic': {
22
+ requiredVersion: false,
23
+ singleton: true,
24
+ },
25
+ 'styled-jsx': {
26
+ requiredVersion: false,
27
+ singleton: true,
28
+ },
29
+ 'next/link': {
30
+ requiredVersion: false,
31
+ singleton: true,
32
+ },
33
+ 'next/router': {
34
+ requiredVersion: false,
35
+ singleton: true,
36
+ },
37
+ 'next/script': {
38
+ requiredVersion: false,
39
+ singleton: true,
40
+ },
41
+ 'next/head': {
42
+ requiredVersion: false,
43
+ singleton: true,
44
+ },
45
+ };
46
+ // put host infront of any shared module key, so "hostreact"
47
+ export const reKeyHostShared = (options) => {
48
+ return Object.entries({
49
+ ...(options || {}),
50
+ ...DEFAULT_SHARE_SCOPE,
51
+ }).reduce((acc, item) => {
52
+ const [itemKey, shareOptions] = item;
53
+
54
+ const shareKey = 'host' + (item.shareKey || itemKey);
55
+ acc[shareKey] = shareOptions;
56
+ if (!shareOptions.import) {
57
+ acc[shareKey].import = itemKey;
58
+ }
59
+ if (!shareOptions.shareKey) {
60
+ acc[shareKey].shareKey = itemKey;
61
+ }
62
+
63
+ if (DEFAULT_SHARE_SCOPE[itemKey]) {
64
+ acc[shareKey].packageName = itemKey;
65
+ }
66
+ return acc;
67
+ }, {});
68
+ };
69
+
70
+ // split the @ syntax into url and global
71
+ export const extractUrlAndGlobal = (urlAndGlobal) => {
72
+ const index = urlAndGlobal.indexOf('@');
73
+ if (index <= 0 || index === urlAndGlobal.length - 1) {
74
+ throw new Error(`Invalid request "${urlAndGlobal}"`);
75
+ }
76
+ return [urlAndGlobal.substring(index + 1), urlAndGlobal.substring(0, index)];
77
+ };
78
+
79
+ // browser template to convert remote into promise new promise and use require.loadChunk to load the chunk
80
+ export const generateRemoteTemplate = (url, global) => {
81
+ return `promise new Promise(function (resolve, reject) {
82
+ var __webpack_error__ = new Error();
83
+ if (typeof ${global} !== 'undefined') return resolve();
84
+ __webpack_require__.l(
85
+ ${JSON.stringify(url)},
86
+ function (event) {
87
+ if (typeof ${global} !== 'undefined') return resolve();
88
+ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
89
+ var realSrc = event && event.target && event.target.src;
90
+ __webpack_error__.message =
91
+ 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';
92
+ __webpack_error__.name = 'ScriptExternalLoadError';
93
+ __webpack_error__.type = errorType;
94
+ __webpack_error__.request = realSrc;
95
+ reject(__webpack_error__);
96
+ },
97
+ ${JSON.stringify(global)},
98
+ );
99
+ }).then(function () {
100
+ const proxy = {
101
+ get: ${global}.get,
102
+ init: function(shareScope) {
103
+ const handler = {
104
+ get(target, prop) {
105
+ if (target[prop]) {
106
+ Object.values(target[prop]).forEach(function(o) {
107
+ if(o.from === '_N_E') {
108
+ o.loaded = 1
109
+ }
110
+ })
111
+ }
112
+ return target[prop]
113
+ },
114
+ set(target, property, value, receiver) {
115
+ if (target[property]) {
116
+ return target[property]
117
+ }
118
+ target[property] = value
119
+ return true
120
+ }
121
+ }
122
+ try {
123
+ ${global}.init(new Proxy(shareScope, handler))
124
+ } catch (e) {
125
+
126
+ }
127
+ ${global}.__initialized = true
128
+ }
129
+ }
130
+ if (!${global}.__initialized) {
131
+ proxy.init()
132
+ }
133
+ return proxy
134
+ })`;
135
+ }
136
+
137
+ const parseShareOptions = (options) => {
138
+ const sharedOptions = parseOptions(
139
+ options.shared,
140
+ (item, key) => {
141
+ if (typeof item !== 'string')
142
+ throw new Error('Unexpected array in shared');
143
+ /** @type {SharedConfig} */
144
+ const config =
145
+ item === key || !isRequiredVersion(item)
146
+ ? {
147
+ import: item,
148
+ }
149
+ : {
150
+ import: key,
151
+ requiredVersion: item,
152
+ };
153
+ return config;
154
+ },
155
+ (item) => item
156
+ );
157
+ return sharedOptions.reduce((acc, [key, options]) => {
158
+ acc[key] = {
159
+ import: options.import,
160
+ shareKey: options.shareKey || key,
161
+ shareScope: options.shareScope,
162
+ requiredVersion: options.requiredVersion,
163
+ strictVersion: options.strictVersion,
164
+ singleton: options.singleton,
165
+ packageName: options.packageName,
166
+ eager: options.eager,
167
+ };
168
+ return acc;
169
+ }, {});
170
+ };
171
+
172
+ // shared packages must be compiled into webpack bundle, not require() pass through
173
+ export const internalizeSharedPackages = (options, compiler) => {
174
+ //TODO: should use this util for other areas where we read MF options from userland
175
+ if (!options.shared) {
176
+ return;
177
+ }
178
+ const sharedOptions = parseShareOptions(options);
179
+ // get share keys from user, filter out ones that need to be external
180
+ const internalizableKeys = Object.keys(sharedOptions).filter((key) => {
181
+ if (!DEFAULT_SHARE_SCOPE[key]) {
182
+ return true;
183
+ }
184
+ if (!DEFAULT_SHARE_SCOPE[sharedOptions[key].import]) {
185
+ return true;
186
+ }
187
+ });
188
+ // take original externals regex
189
+ const backupExternals = compiler.options.externals[0];
190
+ // if externals is a function (like when you're not running in serverless mode or creating a single build)
191
+ if (typeof backupExternals === 'function') {
192
+ // replace externals function with short-circuit, or fall back to original algo
193
+ compiler.options.externals[0] = (mod, callback) => {
194
+ if (!internalizableKeys.some((v) => mod.request.includes(v))) {
195
+ return backupExternals(mod, callback);
196
+ }
197
+ // bundle it
198
+ return Promise.resolve();
199
+ };
200
+ }
201
+ };
202
+
203
+ export const externalizedShares = Object.entries(DEFAULT_SHARE_SCOPE).reduce(
204
+ (acc, item) => {
205
+ const [key, value] = item;
206
+ acc[key] = { ...value, import: false };
207
+ if (key === 'react/jsx-runtime') {
208
+ delete acc[key].import;
209
+ }
210
+ return acc;
211
+ },
212
+ {}
213
+ );
214
+
215
+ // determine output base path, derives .next folder location
216
+ export const getOutputPath = (compiler) => {
217
+ const isServer = compiler.options.target !== 'client';
218
+ let outputPath = compiler.options.output.path.split(path.sep);
219
+ const foundIndex = outputPath.findIndex((i) => {
220
+ return i === (isServer ? 'server' : 'static');
221
+ });
222
+ outputPath = outputPath
223
+ .slice(0, foundIndex > 0 ? foundIndex : outputPath.length)
224
+ .join(path.sep);
225
+
226
+ return outputPath;
227
+ };
228
+
229
+ export const removePlugins = [
230
+ 'NextJsRequireCacheHotReloader',
231
+ 'BuildManifestPlugin',
232
+ 'WellKnownErrorsPlugin',
233
+ 'WebpackBuildEventsPlugin',
234
+ 'HotModuleReplacementPlugin',
235
+ 'NextMiniCssExtractPlugin',
236
+ 'NextFederationPlugin',
237
+ 'CopyFilePlugin',
238
+ 'ProfilingPlugin',
239
+ 'DropClientPage',
240
+ 'ReactFreshWebpackPlugin',
241
+ ];