@module-federation/data-prefetch 0.0.0-next-20240701101956 → 0.0.0-next-20240808065005
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.
- package/CHANGELOG.md +3 -5
- package/__tests__/prefetch.spec.ts +19 -8
- package/__tests__/react.spec.ts +5 -4
- package/dist/cli/babel.d.ts +1 -1
- package/dist/cli/babel.js +1 -1
- package/dist/cli/index.js +8 -5
- package/dist/esm/{chunk-VJO2H3UO.js → chunk-WLE6YNDH.js} +16 -0
- package/dist/esm/cli/babel.js +1 -1
- package/dist/esm/cli/index.js +8 -5
- package/dist/esm/index.js +1 -1
- package/dist/esm/plugin.js +1 -1
- package/dist/index.js +16 -0
- package/dist/plugin.js +16 -0
- package/jest.config.js +1 -1
- package/package.json +3 -3
- package/src/cli/babel.ts +2 -2
- package/src/cli/index.ts +8 -6
- package/src/plugin.ts +21 -1
- package/src/prefetch.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
@module-federation/data-prefetch
|
|
2
2
|
|
|
3
|
-
## 0.0.0-next-
|
|
3
|
+
## 0.0.0-next-20240808065005
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- 3ddab21: feat(@module-federation/data-prefetch): support data prefetch in Module Federation
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- @module-federation/sdk@0.0.0-next-20240701101956
|
|
11
|
-
- @module-federation/runtime@0.0.0-next-20240701101956
|
|
8
|
+
- @module-federation/runtime@0.0.0-next-20240808065005
|
|
9
|
+
- @module-federation/sdk@0.0.0-next-20240808065005
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
// Import the necessary modules and functions
|
|
2
2
|
import { MFDataPrefetch } from '../src/prefetch';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
loadScript,
|
|
5
|
+
MFPrefetchCommon,
|
|
6
|
+
encodeName,
|
|
7
|
+
} from '@module-federation/sdk';
|
|
4
8
|
|
|
5
9
|
// Mock loadScript function from SDK
|
|
6
|
-
jest.mock('@module-federation/sdk', () =>
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
jest.mock('@module-federation/sdk', () => {
|
|
11
|
+
const originalModule = jest.requireActual('@module-federation/sdk');
|
|
12
|
+
return {
|
|
13
|
+
...originalModule,
|
|
14
|
+
loadScript: jest.fn(() => Promise.resolve()),
|
|
15
|
+
};
|
|
16
|
+
});
|
|
9
17
|
|
|
10
18
|
describe('MF Data Prefetch', () => {
|
|
11
19
|
let prefetch: MFDataPrefetch;
|
|
@@ -17,6 +25,7 @@ describe('MF Data Prefetch', () => {
|
|
|
17
25
|
globalName: 'TestGlobalName',
|
|
18
26
|
},
|
|
19
27
|
};
|
|
28
|
+
const exposeId = `${options.name}/button/${MFPrefetchCommon.identifier}`;
|
|
20
29
|
|
|
21
30
|
beforeEach(() => {
|
|
22
31
|
globalThis.__FEDERATION__.__PREFETCH__ = {
|
|
@@ -53,20 +62,22 @@ describe('MF Data Prefetch', () => {
|
|
|
53
62
|
nyPrefetch: () => {},
|
|
54
63
|
};
|
|
55
64
|
const projectExport = {
|
|
56
|
-
[
|
|
65
|
+
[encodeName(exposeId)]: exposeExport,
|
|
57
66
|
};
|
|
58
67
|
globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__[options.name] =
|
|
59
68
|
Promise.resolve(projectExport);
|
|
60
69
|
|
|
61
70
|
await prefetch.getProjectExports();
|
|
62
|
-
expect(prefetch.getExposeExports(options.name)).toEqual(
|
|
71
|
+
expect(prefetch.getExposeExports(`${options.name}/button`)).toEqual(
|
|
72
|
+
exposeExport,
|
|
73
|
+
);
|
|
63
74
|
});
|
|
64
75
|
// Prefetching with memory and executing prefetch function
|
|
65
76
|
it('executes prefetch using prefetch function with and without memory', async () => {
|
|
66
77
|
const id = options.name;
|
|
67
78
|
const functionId = 'nyPrefetch';
|
|
68
79
|
const refetchParams = 'testParams';
|
|
69
|
-
const prefetchOptions = { id
|
|
80
|
+
const prefetchOptions = { id: `${id}/button`, functionId, refetchParams };
|
|
70
81
|
|
|
71
82
|
// Creating a mock prefetch function
|
|
72
83
|
const executePrefetch = jest.fn(() => 'Expected Result');
|
|
@@ -75,7 +86,7 @@ describe('MF Data Prefetch', () => {
|
|
|
75
86
|
// Mock Project Exports
|
|
76
87
|
globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__[id] =
|
|
77
88
|
Promise.resolve({
|
|
78
|
-
[
|
|
89
|
+
[encodeName(exposeId)]: prefetchExports,
|
|
79
90
|
});
|
|
80
91
|
|
|
81
92
|
await prefetch.getProjectExports();
|
package/__tests__/react.spec.ts
CHANGED
|
@@ -57,8 +57,9 @@ describe('usePrefetch', () => {
|
|
|
57
57
|
const exposeExport = {
|
|
58
58
|
[functionId]: executePrefetch,
|
|
59
59
|
};
|
|
60
|
+
const exposeId = `${options.name}/button/${ModuleFederationSDK.MFPrefetchCommon.identifier}`;
|
|
60
61
|
const projectExport = {
|
|
61
|
-
[
|
|
62
|
+
[ModuleFederationSDK.encodeName(exposeId)]: exposeExport,
|
|
62
63
|
};
|
|
63
64
|
globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__[options.name] =
|
|
64
65
|
Promise.resolve(projectExport);
|
|
@@ -76,7 +77,7 @@ describe('usePrefetch', () => {
|
|
|
76
77
|
|
|
77
78
|
it('should prefetch data on first mount', async () => {
|
|
78
79
|
const { result } = renderHook(() =>
|
|
79
|
-
usePrefetch({ id: options.name
|
|
80
|
+
usePrefetch({ id: `${options.name}/button`, functionId }),
|
|
80
81
|
);
|
|
81
82
|
await result.current[0];
|
|
82
83
|
expect(executePrefetch).toHaveBeenCalled();
|
|
@@ -86,14 +87,14 @@ describe('usePrefetch', () => {
|
|
|
86
87
|
|
|
87
88
|
it('should refetch data when refreshExecutor is called', async () => {
|
|
88
89
|
const { result } = renderHook(() =>
|
|
89
|
-
usePrefetch({ id: options.name
|
|
90
|
+
usePrefetch({ id: `${options.name}/button`, functionId }),
|
|
90
91
|
);
|
|
91
92
|
|
|
92
93
|
await result.current[0];
|
|
93
94
|
expect(executePrefetch).toHaveBeenCalled();
|
|
94
95
|
executePrefetch.mockClear();
|
|
95
96
|
const { result: newCallResult } = renderHook(() =>
|
|
96
|
-
usePrefetch({ id: options.name
|
|
97
|
+
usePrefetch({ id: `${options.name}/button`, functionId }),
|
|
97
98
|
);
|
|
98
99
|
await newCallResult.current[0];
|
|
99
100
|
expect(executePrefetch).not.toHaveBeenCalled();
|
package/dist/cli/babel.d.ts
CHANGED
package/dist/cli/babel.js
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -88,6 +88,14 @@ var PrefetchPlugin = class {
|
|
|
88
88
|
this.options.runtimePlugins.push(
|
|
89
89
|
import_path2.default.resolve(__dirname, "../esm/shared/index.js")
|
|
90
90
|
);
|
|
91
|
+
const encodedName = (0, import_sdk2.encodeName)(name);
|
|
92
|
+
const asyncEntryPath = import_path2.default.resolve(
|
|
93
|
+
compiler.options.context,
|
|
94
|
+
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`
|
|
95
|
+
);
|
|
96
|
+
if (import_fs_extra2.default.existsSync(asyncEntryPath)) {
|
|
97
|
+
import_fs_extra2.default.unlinkSync(asyncEntryPath);
|
|
98
|
+
}
|
|
91
99
|
if (!this.options.dataPrefetch) {
|
|
92
100
|
return;
|
|
93
101
|
}
|
|
@@ -118,11 +126,6 @@ var PrefetchPlugin = class {
|
|
|
118
126
|
if (!this._reWriteExports) {
|
|
119
127
|
return;
|
|
120
128
|
}
|
|
121
|
-
const encodedName = (0, import_sdk2.encodeName)(name);
|
|
122
|
-
const asyncEntryPath = import_path2.default.resolve(
|
|
123
|
-
compiler.options.context,
|
|
124
|
-
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`
|
|
125
|
-
);
|
|
126
129
|
const tempDirRealPath = import_path2.default.resolve(
|
|
127
130
|
compiler.options.context,
|
|
128
131
|
"node_modules",
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-EWCGK4XA.js";
|
|
10
10
|
|
|
11
11
|
// src/plugin.ts
|
|
12
|
+
import { Module } from "@module-federation/runtime";
|
|
12
13
|
import { getResourceUrl } from "@module-federation/sdk";
|
|
13
14
|
var loadingArray = [];
|
|
14
15
|
var strategy = "loaded-first";
|
|
@@ -111,6 +112,21 @@ var prefetchPlugin = () => ({
|
|
|
111
112
|
return options;
|
|
112
113
|
}
|
|
113
114
|
const promise = instance.loadEntry(prefetchUrl).then(async () => {
|
|
115
|
+
let module = origin.moduleCache.get(remote.name);
|
|
116
|
+
const moduleOptions = {
|
|
117
|
+
host: origin,
|
|
118
|
+
remoteInfo: remote
|
|
119
|
+
};
|
|
120
|
+
if (!module) {
|
|
121
|
+
module = new Module(moduleOptions);
|
|
122
|
+
origin.moduleCache.set(remote.name, module);
|
|
123
|
+
}
|
|
124
|
+
const idPart = id.split("/");
|
|
125
|
+
let expose = idPart[idPart.length - 1];
|
|
126
|
+
if (expose !== ".") {
|
|
127
|
+
expose = `./${expose}`;
|
|
128
|
+
}
|
|
129
|
+
await module.get(id, expose, {}, remoteSnapshot);
|
|
114
130
|
const projectExports = instance.getProjectExports();
|
|
115
131
|
if (projectExports instanceof Promise) {
|
|
116
132
|
await projectExports;
|
package/dist/esm/cli/babel.js
CHANGED
package/dist/esm/cli/index.js
CHANGED
|
@@ -60,6 +60,14 @@ var PrefetchPlugin = class {
|
|
|
60
60
|
this.options.runtimePlugins.push(
|
|
61
61
|
path2.resolve(__dirname, "../esm/shared/index.js")
|
|
62
62
|
);
|
|
63
|
+
const encodedName = encodeName(name);
|
|
64
|
+
const asyncEntryPath = path2.resolve(
|
|
65
|
+
compiler.options.context,
|
|
66
|
+
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`
|
|
67
|
+
);
|
|
68
|
+
if (fs2.existsSync(asyncEntryPath)) {
|
|
69
|
+
fs2.unlinkSync(asyncEntryPath);
|
|
70
|
+
}
|
|
63
71
|
if (!this.options.dataPrefetch) {
|
|
64
72
|
return;
|
|
65
73
|
}
|
|
@@ -90,11 +98,6 @@ var PrefetchPlugin = class {
|
|
|
90
98
|
if (!this._reWriteExports) {
|
|
91
99
|
return;
|
|
92
100
|
}
|
|
93
|
-
const encodedName = encodeName(name);
|
|
94
|
-
const asyncEntryPath = path2.resolve(
|
|
95
|
-
compiler.options.context,
|
|
96
|
-
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`
|
|
97
|
-
);
|
|
98
101
|
const tempDirRealPath = path2.resolve(
|
|
99
102
|
compiler.options.context,
|
|
100
103
|
"node_modules",
|
package/dist/esm/index.js
CHANGED
package/dist/esm/plugin.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -192,6 +192,7 @@ var MFDataPrefetch = class {
|
|
|
192
192
|
};
|
|
193
193
|
|
|
194
194
|
// src/plugin.ts
|
|
195
|
+
var import_runtime2 = require("@module-federation/runtime");
|
|
195
196
|
var import_sdk4 = require("@module-federation/sdk");
|
|
196
197
|
|
|
197
198
|
// src/logger/index.ts
|
|
@@ -300,6 +301,21 @@ var prefetchPlugin = () => ({
|
|
|
300
301
|
return options;
|
|
301
302
|
}
|
|
302
303
|
const promise = instance.loadEntry(prefetchUrl).then(async () => {
|
|
304
|
+
let module2 = origin.moduleCache.get(remote.name);
|
|
305
|
+
const moduleOptions = {
|
|
306
|
+
host: origin,
|
|
307
|
+
remoteInfo: remote
|
|
308
|
+
};
|
|
309
|
+
if (!module2) {
|
|
310
|
+
module2 = new import_runtime2.Module(moduleOptions);
|
|
311
|
+
origin.moduleCache.set(remote.name, module2);
|
|
312
|
+
}
|
|
313
|
+
const idPart = id.split("/");
|
|
314
|
+
let expose = idPart[idPart.length - 1];
|
|
315
|
+
if (expose !== ".") {
|
|
316
|
+
expose = `./${expose}`;
|
|
317
|
+
}
|
|
318
|
+
await module2.get(id, expose, {}, remoteSnapshot);
|
|
303
319
|
const projectExports = instance.getProjectExports();
|
|
304
320
|
if (projectExports instanceof Promise) {
|
|
305
321
|
await projectExports;
|
package/dist/plugin.js
CHANGED
|
@@ -24,6 +24,7 @@ __export(plugin_exports, {
|
|
|
24
24
|
prefetchPlugin: () => prefetchPlugin
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(plugin_exports);
|
|
27
|
+
var import_runtime2 = require("@module-federation/runtime");
|
|
27
28
|
var import_sdk4 = require("@module-federation/sdk");
|
|
28
29
|
|
|
29
30
|
// src/common/runtime-utils.ts
|
|
@@ -296,6 +297,21 @@ var prefetchPlugin = () => ({
|
|
|
296
297
|
return options;
|
|
297
298
|
}
|
|
298
299
|
const promise = instance.loadEntry(prefetchUrl).then(async () => {
|
|
300
|
+
let module2 = origin.moduleCache.get(remote.name);
|
|
301
|
+
const moduleOptions = {
|
|
302
|
+
host: origin,
|
|
303
|
+
remoteInfo: remote
|
|
304
|
+
};
|
|
305
|
+
if (!module2) {
|
|
306
|
+
module2 = new import_runtime2.Module(moduleOptions);
|
|
307
|
+
origin.moduleCache.set(remote.name, module2);
|
|
308
|
+
}
|
|
309
|
+
const idPart = id.split("/");
|
|
310
|
+
let expose = idPart[idPart.length - 1];
|
|
311
|
+
if (expose !== ".") {
|
|
312
|
+
expose = `./${expose}`;
|
|
313
|
+
}
|
|
314
|
+
await module2.get(id, expose, {}, remoteSnapshot);
|
|
299
315
|
const projectExports = instance.getProjectExports();
|
|
300
316
|
if (projectExports instanceof Promise) {
|
|
301
317
|
await projectExports;
|
package/jest.config.js
CHANGED
|
@@ -21,7 +21,7 @@ module.exports = {
|
|
|
21
21
|
'/node_modules/(?!((@byted/garfish-)|(byted-tea-sdk))).+\\.js$',
|
|
22
22
|
],
|
|
23
23
|
transform: {
|
|
24
|
-
'^.+\\.(t|j)sx?$': ['@swc/jest'],
|
|
24
|
+
'^.+\\.(t|j)sx?$': ['@swc/jest', { swcrc: false }],
|
|
25
25
|
},
|
|
26
26
|
rootDir: __dirname,
|
|
27
27
|
testMatch: ['<rootDir>__tests__/**/**.spec.[jt]s?(x)'],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/data-prefetch",
|
|
3
3
|
"description": "Module Federation Data Prefetch",
|
|
4
|
-
"version": "0.0.0-next-
|
|
4
|
+
"version": "0.0.0-next-20240808065005",
|
|
5
5
|
"author": "nieyan <nyqykk@foxmail.com>",
|
|
6
6
|
"homepage": "https://github.com/module-federation/core",
|
|
7
7
|
"license": "MIT",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"fs-extra": "9.1.0",
|
|
88
|
-
"@module-federation/sdk": "0.0.0-next-
|
|
89
|
-
"@module-federation/runtime": "0.0.0-next-
|
|
88
|
+
"@module-federation/sdk": "0.0.0-next-20240808065005",
|
|
89
|
+
"@module-federation/runtime": "0.0.0-next-20240808065005"
|
|
90
90
|
},
|
|
91
91
|
"scripts": {
|
|
92
92
|
"dev": "cross-env WATCH=true tsup",
|
package/src/cli/babel.ts
CHANGED
|
@@ -9,7 +9,7 @@ interface BabelPluginOptions {
|
|
|
9
9
|
hook_id: string;
|
|
10
10
|
import_pkg: string;
|
|
11
11
|
attribute: string;
|
|
12
|
-
|
|
12
|
+
name: string;
|
|
13
13
|
exposes: moduleFederationPlugin.ModuleFederationPluginOptions['exposes'];
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -18,7 +18,7 @@ export default (babel: { types: any }, options: BabelPluginOptions) => {
|
|
|
18
18
|
const t = babel.types;
|
|
19
19
|
let shouldHandle = false;
|
|
20
20
|
let scope = '';
|
|
21
|
-
const {
|
|
21
|
+
const { name, exposes } = options;
|
|
22
22
|
if (!exposes) {
|
|
23
23
|
return {};
|
|
24
24
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -41,6 +41,14 @@ export class PrefetchPlugin implements WebpackPluginInstance {
|
|
|
41
41
|
this.options.runtimePlugins!.push(
|
|
42
42
|
path.resolve(__dirname, '../esm/shared/index.js'),
|
|
43
43
|
);
|
|
44
|
+
const encodedName = encodeName(name as string);
|
|
45
|
+
const asyncEntryPath = path.resolve(
|
|
46
|
+
compiler.options.context,
|
|
47
|
+
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`,
|
|
48
|
+
);
|
|
49
|
+
if (fs.existsSync(asyncEntryPath)) {
|
|
50
|
+
fs.unlinkSync(asyncEntryPath);
|
|
51
|
+
}
|
|
44
52
|
if (!this.options.dataPrefetch) {
|
|
45
53
|
return;
|
|
46
54
|
}
|
|
@@ -73,12 +81,6 @@ export class PrefetchPlugin implements WebpackPluginInstance {
|
|
|
73
81
|
if (!this._reWriteExports) {
|
|
74
82
|
return;
|
|
75
83
|
}
|
|
76
|
-
|
|
77
|
-
const encodedName = encodeName(name as string);
|
|
78
|
-
const asyncEntryPath = path.resolve(
|
|
79
|
-
compiler.options.context,
|
|
80
|
-
`node_modules/${TEMP_DIR}/${encodedName}/bootstrap.js`,
|
|
81
|
-
);
|
|
82
84
|
const tempDirRealPath = path.resolve(
|
|
83
85
|
compiler.options.context,
|
|
84
86
|
'node_modules',
|
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Module } from '@module-federation/runtime';
|
|
2
|
+
import type {
|
|
3
|
+
FederationRuntimePlugin,
|
|
4
|
+
RemoteInfo,
|
|
5
|
+
} from '@module-federation/runtime/types';
|
|
2
6
|
import { ModuleInfo, getResourceUrl } from '@module-federation/sdk';
|
|
3
7
|
|
|
4
8
|
import { getSignalFromManifest } from './common/runtime-utils';
|
|
@@ -150,6 +154,22 @@ export const prefetchPlugin = (): FederationRuntimePlugin => ({
|
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
const promise = instance.loadEntry(prefetchUrl).then(async () => {
|
|
157
|
+
let module = origin.moduleCache.get(remote.name);
|
|
158
|
+
const moduleOptions = {
|
|
159
|
+
host: origin,
|
|
160
|
+
remoteInfo: remote as RemoteInfo,
|
|
161
|
+
};
|
|
162
|
+
if (!module) {
|
|
163
|
+
module = new Module(moduleOptions);
|
|
164
|
+
origin.moduleCache.set(remote.name, module);
|
|
165
|
+
}
|
|
166
|
+
const idPart = id.split('/');
|
|
167
|
+
let expose = idPart[idPart.length - 1];
|
|
168
|
+
if (expose !== '.') {
|
|
169
|
+
expose = `./${expose}`;
|
|
170
|
+
}
|
|
171
|
+
await module.get(id, expose, {}, remoteSnapshot);
|
|
172
|
+
|
|
153
173
|
const projectExports = instance!.getProjectExports();
|
|
154
174
|
if (projectExports instanceof Promise) {
|
|
155
175
|
await projectExports;
|
package/src/prefetch.ts
CHANGED
|
@@ -106,7 +106,8 @@ export class MFDataPrefetch {
|
|
|
106
106
|
globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__?.[name];
|
|
107
107
|
const resolve = exportsPromise.then(
|
|
108
108
|
(exports: Record<string, Record<string, any>> = {}) => {
|
|
109
|
-
//
|
|
109
|
+
// Match prefetch based on the function name suffix so that other capabilities can be expanded later.
|
|
110
|
+
// Not all functions should be directly identified as prefetch functions
|
|
110
111
|
const memory: Record<string, Record<string, any>> = {};
|
|
111
112
|
Object.keys(exports).forEach((key) => {
|
|
112
113
|
memory[key] = {};
|