@esmx/rspack 3.0.0-rc.11 → 3.0.0-rc.111
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/LICENSE +1 -1
- package/README.md +48 -20
- package/README.zh-CN.md +57 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.mjs +4 -4
- package/dist/module-link/config.d.ts +5 -0
- package/dist/module-link/config.mjs +100 -0
- package/dist/module-link/config1.d.ts +3 -0
- package/dist/module-link/config1.mjs +16 -0
- package/dist/module-link/config2.d.ts +3 -0
- package/dist/module-link/config2.mjs +17 -0
- package/dist/module-link/index.d.ts +4 -0
- package/dist/module-link/index.mjs +8 -0
- package/dist/module-link/manifest-plugin.d.ts +14 -0
- package/dist/module-link/manifest-plugin.mjs +141 -0
- package/dist/module-link/parse.d.ts +2 -0
- package/dist/module-link/parse.mjs +24 -0
- package/dist/module-link/types.d.ts +25 -0
- package/dist/rspack/app.d.ts +183 -0
- package/dist/{app.mjs → rspack/app.mjs} +18 -46
- package/dist/rspack/build-target.d.ts +7 -0
- package/dist/rspack/build-target.mjs +0 -0
- package/dist/{config.d.ts → rspack/chain-config.d.ts} +3 -4
- package/dist/rspack/chain-config.mjs +113 -0
- package/dist/rspack/index.d.ts +3 -0
- package/dist/rspack/index.mjs +4 -0
- package/dist/rspack/loader.d.ts +9 -0
- package/dist/{loader.mjs → rspack/loader.mjs} +2 -22
- package/dist/rspack/pack.d.ts +9 -0
- package/dist/{pack.mjs → rspack/pack.mjs} +33 -25
- package/dist/rspack/pack.test.d.ts +1 -0
- package/dist/rspack/pack.test.mjs +180 -0
- package/dist/rspack/utils/rsbuild.d.ts +6 -0
- package/dist/{utils → rspack/utils}/rsbuild.mjs +7 -37
- package/dist/rspack-html/index.d.ts +168 -0
- package/dist/rspack-html/index.mjs +160 -0
- package/dist/rspack-html/target-setting.d.ts +17 -0
- package/dist/rspack-html/target-setting.mjs +31 -0
- package/dist/rspack-html/target-setting.test.d.ts +1 -0
- package/dist/rspack-html/target-setting.test.mjs +105 -0
- package/package.json +23 -21
- package/src/index.ts +7 -6
- package/src/module-link/config.ts +157 -0
- package/src/module-link/config1.ts +24 -0
- package/src/module-link/config2.ts +28 -0
- package/src/module-link/index.ts +19 -0
- package/src/module-link/manifest-plugin.ts +179 -0
- package/src/module-link/parse.ts +31 -0
- package/src/module-link/types.ts +31 -0
- package/src/{app.ts → rspack/app.ts} +104 -107
- package/src/rspack/build-target.ts +7 -0
- package/src/rspack/chain-config.ts +165 -0
- package/src/rspack/index.ts +8 -0
- package/src/{loader.ts → rspack/loader.ts} +3 -22
- package/src/rspack/pack.test.ts +215 -0
- package/src/rspack/pack.ts +101 -0
- package/src/{utils → rspack/utils}/rsbuild.ts +11 -40
- package/src/rspack-html/index.ts +495 -0
- package/src/rspack-html/target-setting.test.ts +123 -0
- package/src/rspack-html/target-setting.ts +52 -0
- package/dist/app.d.ts +0 -160
- package/dist/build-target.d.ts +0 -8
- package/dist/config.mjs +0 -142
- package/dist/html-app.d.ts +0 -299
- package/dist/html-app.mjs +0 -214
- package/dist/loader.d.ts +0 -30
- package/dist/pack.d.ts +0 -2
- package/dist/utils/rsbuild.d.ts +0 -12
- package/src/build-target.ts +0 -8
- package/src/config.ts +0 -171
- package/src/html-app.ts +0 -560
- package/src/pack.ts +0 -79
- /package/dist/{build-target.mjs → module-link/types.mjs} +0 -0
- /package/dist/{utils → rspack/utils}/index.d.ts +0 -0
- /package/dist/{utils → rspack/utils}/index.mjs +0 -0
- /package/src/{utils → rspack/utils}/index.ts +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getTargetSetting, PRESET_TARGETS } from "./target-setting.mjs";
|
|
3
|
+
describe("getTargetSetting", () => {
|
|
4
|
+
const buildTargets = ["client", "server", "node"];
|
|
5
|
+
describe("when setting is undefined", () => {
|
|
6
|
+
it("should return compatible preset for all build targets", () => {
|
|
7
|
+
buildTargets.forEach((buildTarget) => {
|
|
8
|
+
const result = getTargetSetting(void 0, buildTarget);
|
|
9
|
+
expect(result).toEqual(PRESET_TARGETS.compatible[buildTarget]);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe("when setting is a string preset", () => {
|
|
14
|
+
it("should return compatible preset for all build targets", () => {
|
|
15
|
+
buildTargets.forEach((buildTarget) => {
|
|
16
|
+
const result = getTargetSetting("compatible", buildTarget);
|
|
17
|
+
expect(result).toEqual(PRESET_TARGETS.compatible[buildTarget]);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it("should return modern preset for all build targets", () => {
|
|
21
|
+
buildTargets.forEach((buildTarget) => {
|
|
22
|
+
const result = getTargetSetting("modern", buildTarget);
|
|
23
|
+
expect(result).toEqual(PRESET_TARGETS.modern[buildTarget]);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("when setting is a custom array", () => {
|
|
28
|
+
const customTargets = ["chrome>=90", "firefox>=80", "safari>=14"];
|
|
29
|
+
it("should return the custom array for all build targets", () => {
|
|
30
|
+
buildTargets.forEach((buildTarget) => {
|
|
31
|
+
const result = getTargetSetting(customTargets, buildTarget);
|
|
32
|
+
expect(result).toEqual(customTargets);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("when setting is an object with specific build targets", () => {
|
|
37
|
+
it("should return specified preset for configured build targets", () => {
|
|
38
|
+
const setting = {
|
|
39
|
+
client: "modern",
|
|
40
|
+
server: "compatible"
|
|
41
|
+
};
|
|
42
|
+
expect(getTargetSetting(setting, "client")).toEqual(
|
|
43
|
+
PRESET_TARGETS.modern.client
|
|
44
|
+
);
|
|
45
|
+
expect(getTargetSetting(setting, "server")).toEqual(
|
|
46
|
+
PRESET_TARGETS.compatible.server
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
it("should return compatible preset for unconfigured build targets", () => {
|
|
50
|
+
const setting = {
|
|
51
|
+
client: "modern"
|
|
52
|
+
};
|
|
53
|
+
expect(getTargetSetting(setting, "client")).toEqual(
|
|
54
|
+
PRESET_TARGETS.modern.client
|
|
55
|
+
);
|
|
56
|
+
expect(getTargetSetting(setting, "server")).toEqual(
|
|
57
|
+
PRESET_TARGETS.compatible.server
|
|
58
|
+
);
|
|
59
|
+
expect(getTargetSetting(setting, "node")).toEqual(
|
|
60
|
+
PRESET_TARGETS.compatible.node
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
it("should return custom array for configured build targets", () => {
|
|
64
|
+
const customClientTargets = ["chrome>=90", "firefox>=80"];
|
|
65
|
+
const customServerTargets = ["node>=18"];
|
|
66
|
+
const setting = {
|
|
67
|
+
client: customClientTargets,
|
|
68
|
+
server: customServerTargets
|
|
69
|
+
};
|
|
70
|
+
expect(getTargetSetting(setting, "client")).toEqual(
|
|
71
|
+
customClientTargets
|
|
72
|
+
);
|
|
73
|
+
expect(getTargetSetting(setting, "server")).toEqual(
|
|
74
|
+
customServerTargets
|
|
75
|
+
);
|
|
76
|
+
expect(getTargetSetting(setting, "node")).toEqual(
|
|
77
|
+
PRESET_TARGETS.compatible.node
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
it("should handle mixed preset and custom configurations", () => {
|
|
81
|
+
const setting = {
|
|
82
|
+
client: "modern",
|
|
83
|
+
server: ["node>=18"],
|
|
84
|
+
node: "compatible"
|
|
85
|
+
};
|
|
86
|
+
expect(getTargetSetting(setting, "client")).toEqual(
|
|
87
|
+
PRESET_TARGETS.modern.client
|
|
88
|
+
);
|
|
89
|
+
expect(getTargetSetting(setting, "server")).toEqual(["node>=18"]);
|
|
90
|
+
expect(getTargetSetting(setting, "node")).toEqual(
|
|
91
|
+
PRESET_TARGETS.compatible.node
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe("edge cases", () => {
|
|
96
|
+
it("should handle empty custom array", () => {
|
|
97
|
+
const result = getTargetSetting([], "client");
|
|
98
|
+
expect(result).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
it("should handle single item custom array", () => {
|
|
101
|
+
const result = getTargetSetting(["chrome>=90"], "client");
|
|
102
|
+
expect(result).toEqual(["chrome>=90"]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmx/rspack",
|
|
3
|
-
"description": "A high-performance Rspack integration for Esmx microfrontend framework, providing
|
|
3
|
+
"description": "A high-performance Rspack integration for Esmx microfrontend framework, providing Module Linking and SSR capabilities.",
|
|
4
4
|
"contributors": [
|
|
5
5
|
{
|
|
6
6
|
"name": "lzxb",
|
|
@@ -38,18 +38,21 @@
|
|
|
38
38
|
"Less",
|
|
39
39
|
"High Performance",
|
|
40
40
|
"Build Tool",
|
|
41
|
-
"Module
|
|
41
|
+
"Module Linking",
|
|
42
42
|
"SSR",
|
|
43
43
|
"Development Experience"
|
|
44
44
|
],
|
|
45
45
|
"scripts": {
|
|
46
46
|
"lint:js": "biome check --write --no-errors-on-unmatched",
|
|
47
|
-
"lint:css": "
|
|
47
|
+
"lint:css": "pnpm run lint:js",
|
|
48
48
|
"lint:type": "tsc --noEmit",
|
|
49
49
|
"test": "vitest run --pass-with-no-tests",
|
|
50
50
|
"coverage": "vitest run --coverage --pass-with-no-tests",
|
|
51
51
|
"build": "unbuild"
|
|
52
52
|
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=24"
|
|
55
|
+
},
|
|
53
56
|
"peerDependencies": {
|
|
54
57
|
"@esmx/core": "*",
|
|
55
58
|
"less": "*"
|
|
@@ -60,36 +63,35 @@
|
|
|
60
63
|
}
|
|
61
64
|
},
|
|
62
65
|
"dependencies": {
|
|
63
|
-
"@esmx/import": "3.0.0-rc.
|
|
64
|
-
"@
|
|
65
|
-
"@
|
|
66
|
-
"@rspack/core": "1.2.8",
|
|
66
|
+
"@esmx/import": "3.0.0-rc.111",
|
|
67
|
+
"@npmcli/arborist": "^9.1.6",
|
|
68
|
+
"@rspack/core": "1.7.2",
|
|
67
69
|
"css-loader": "^7.1.2",
|
|
68
|
-
"less-loader": "^12.
|
|
70
|
+
"less-loader": "^12.3.0",
|
|
69
71
|
"node-polyfill-webpack-plugin": "^4.1.0",
|
|
70
72
|
"pacote": "^21.0.0",
|
|
73
|
+
"rspack-chain": "^1.4.3",
|
|
71
74
|
"style-loader": "^4.0.0",
|
|
72
75
|
"style-resources-loader": "^1.5.0",
|
|
76
|
+
"upath": "^2.0.1",
|
|
73
77
|
"webpack-hot-middleware": "^2.26.1",
|
|
74
78
|
"webpack-node-externals": "~3.0.0",
|
|
75
79
|
"worker-rspack-loader": "^3.1.2"
|
|
76
80
|
},
|
|
77
81
|
"devDependencies": {
|
|
78
|
-
"@biomejs/biome": "
|
|
79
|
-
"@esmx/core": "3.0.0-rc.
|
|
80
|
-
"@
|
|
81
|
-
"@types/
|
|
82
|
-
"@types/npmcli__arborist": "^5.6.11",
|
|
82
|
+
"@biomejs/biome": "2.3.7",
|
|
83
|
+
"@esmx/core": "3.0.0-rc.111",
|
|
84
|
+
"@types/node": "^24.0.0",
|
|
85
|
+
"@types/npmcli__arborist": "^6.3.1",
|
|
83
86
|
"@types/pacote": "^11.1.8",
|
|
84
|
-
"@types/webpack-hot-middleware": "^2.25.
|
|
87
|
+
"@types/webpack-hot-middleware": "^2.25.12",
|
|
85
88
|
"@types/webpack-node-externals": "^3.0.4",
|
|
86
|
-
"@vitest/coverage-v8": "3.
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"vitest": "3.0.8"
|
|
89
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
90
|
+
"typescript": "5.9.3",
|
|
91
|
+
"unbuild": "3.6.1",
|
|
92
|
+
"vitest": "3.2.4"
|
|
91
93
|
},
|
|
92
|
-
"version": "3.0.0-rc.
|
|
94
|
+
"version": "3.0.0-rc.111",
|
|
93
95
|
"type": "module",
|
|
94
96
|
"private": false,
|
|
95
97
|
"exports": {
|
|
@@ -108,5 +110,5 @@
|
|
|
108
110
|
"template",
|
|
109
111
|
"public"
|
|
110
112
|
],
|
|
111
|
-
"gitHead": "
|
|
113
|
+
"gitHead": "3c8faeeebc43d40e13b9907c1723f8ecf107ddc2"
|
|
112
114
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export {
|
|
2
|
+
type BuildTarget,
|
|
3
|
+
createRspackApp,
|
|
4
|
+
RSPACK_LOADER,
|
|
5
|
+
type RspackAppChainContext,
|
|
2
6
|
type RspackAppConfigContext,
|
|
3
|
-
type RspackAppOptions
|
|
4
|
-
|
|
5
|
-
} from './
|
|
6
|
-
export { createRspackHtmlApp, type RspackHtmlAppOptions } from './html-app';
|
|
7
|
-
export type { BuildTarget } from './build-target';
|
|
8
|
-
export { RSPACK_LOADER } from './loader';
|
|
7
|
+
type RspackAppOptions
|
|
8
|
+
} from './rspack';
|
|
9
|
+
export { createRspackHtmlApp, type RspackHtmlAppOptions } from './rspack-html';
|
|
9
10
|
|
|
10
11
|
import * as rspack from '@rspack/core';
|
|
11
12
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { ExternalItem, ExternalItemFunctionData } from '@rspack/core';
|
|
2
|
+
import type RspackChain from 'rspack-chain';
|
|
3
|
+
import type { ParsedModuleLinkPluginOptions } from './types';
|
|
4
|
+
|
|
5
|
+
export function applyEntryConfig(
|
|
6
|
+
chain: RspackChain,
|
|
7
|
+
opts: ParsedModuleLinkPluginOptions
|
|
8
|
+
): void {
|
|
9
|
+
if (chain.entryPoints.has('main')) {
|
|
10
|
+
const mainEntry = chain.entry('main');
|
|
11
|
+
if (mainEntry.values().length === 0) {
|
|
12
|
+
chain.entryPoints.clear();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (const value of Object.values(opts.exports)) {
|
|
17
|
+
if (value.file) {
|
|
18
|
+
const entry = chain.entry(value.name);
|
|
19
|
+
for (const preEntry of opts.preEntries) {
|
|
20
|
+
entry.add(preEntry);
|
|
21
|
+
}
|
|
22
|
+
entry.add(value.file);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function applyModuleConfig(chain: RspackChain) {
|
|
28
|
+
chain.output
|
|
29
|
+
.set('module', true)
|
|
30
|
+
.set('chunkFormat', 'module')
|
|
31
|
+
.set('chunkLoading', 'import')
|
|
32
|
+
.set('workerChunkLoading', 'import');
|
|
33
|
+
chain.output.library({
|
|
34
|
+
type: 'module'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function applyExternalsConfig(
|
|
39
|
+
chain: RspackChain,
|
|
40
|
+
opts: ParsedModuleLinkPluginOptions
|
|
41
|
+
): void {
|
|
42
|
+
const existingExternals = chain.get('externals') || [];
|
|
43
|
+
const externals: ExternalItem[] = Array.isArray(existingExternals)
|
|
44
|
+
? [...existingExternals]
|
|
45
|
+
: [existingExternals];
|
|
46
|
+
|
|
47
|
+
const compilerContext = chain.get('context') ?? process.cwd();
|
|
48
|
+
const externalFunc = createExternalsFunction(opts, compilerContext);
|
|
49
|
+
externals.push(externalFunc);
|
|
50
|
+
|
|
51
|
+
chain.externals(externals);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createExternalsFunction(
|
|
55
|
+
opts: ParsedModuleLinkPluginOptions,
|
|
56
|
+
compilerContext: string
|
|
57
|
+
) {
|
|
58
|
+
const importMap = new Map<string, string>();
|
|
59
|
+
let initPromise: Promise<void> | null = null;
|
|
60
|
+
type ResolvePath = (
|
|
61
|
+
request: string,
|
|
62
|
+
context?: string
|
|
63
|
+
) => Promise<string | null>;
|
|
64
|
+
const init = (resolvePath: ResolvePath): Promise<void> => {
|
|
65
|
+
if (initPromise) return initPromise;
|
|
66
|
+
|
|
67
|
+
initPromise = (async () => {
|
|
68
|
+
await Promise.all(
|
|
69
|
+
Object.values(opts.exports).map(async (value) => {
|
|
70
|
+
const identifier = value.pkg
|
|
71
|
+
? value.name
|
|
72
|
+
: value.identifier;
|
|
73
|
+
importMap.set(identifier, identifier);
|
|
74
|
+
importMap.set(value.name, identifier);
|
|
75
|
+
|
|
76
|
+
const resolvedPath = await resolvePath(value.file);
|
|
77
|
+
if (resolvedPath) {
|
|
78
|
+
importMap.set(resolvedPath, identifier);
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
for (const key of Object.keys(opts.imports)) {
|
|
84
|
+
importMap.set(key, key);
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
|
|
88
|
+
return initPromise;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const match = async (
|
|
92
|
+
request: string,
|
|
93
|
+
context: string,
|
|
94
|
+
resolvePath: ResolvePath
|
|
95
|
+
): Promise<string | null> => {
|
|
96
|
+
if (!request) return null;
|
|
97
|
+
|
|
98
|
+
if (opts.deps.length > 0) {
|
|
99
|
+
const matchedDep = opts.deps.find(
|
|
100
|
+
(dep) => request === dep || request.startsWith(`${dep}/`)
|
|
101
|
+
);
|
|
102
|
+
if (matchedDep) {
|
|
103
|
+
return request;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let importName = importMap.get(request);
|
|
108
|
+
if (!importName) {
|
|
109
|
+
const resolvedPath = await resolvePath(request, context);
|
|
110
|
+
if (resolvedPath) {
|
|
111
|
+
importName = importMap.get(resolvedPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return importName || null;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const FILE_EXT_REGEX =
|
|
119
|
+
/\.worker\.(js|mjs|cjs|jsx|mjsx|cjsx|ts|mts|cts|tsx|mtsx|ctsx)$/i;
|
|
120
|
+
|
|
121
|
+
return async (data: ExternalItemFunctionData) => {
|
|
122
|
+
if (
|
|
123
|
+
!data.request ||
|
|
124
|
+
!data.context ||
|
|
125
|
+
!data.contextInfo?.issuer ||
|
|
126
|
+
FILE_EXT_REGEX.test(data.contextInfo.issuer)
|
|
127
|
+
)
|
|
128
|
+
return;
|
|
129
|
+
|
|
130
|
+
const defaultContext = compilerContext;
|
|
131
|
+
const resolvePath: ResolvePath = async (
|
|
132
|
+
request: string,
|
|
133
|
+
context = defaultContext
|
|
134
|
+
): Promise<string | null> => {
|
|
135
|
+
if (!data.getResolve) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const resolveFunc = data.getResolve();
|
|
139
|
+
return new Promise<string | null>((resolve) => {
|
|
140
|
+
resolveFunc(context, request, (err, res) => {
|
|
141
|
+
resolve(typeof res === 'string' ? res : null);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
await init(resolvePath);
|
|
147
|
+
const matchedIdentifier = await match(
|
|
148
|
+
data.request,
|
|
149
|
+
data.context,
|
|
150
|
+
resolvePath
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (matchedIdentifier) {
|
|
154
|
+
return `module-import ${matchedIdentifier}`;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type RspackChain from 'rspack-chain';
|
|
2
|
+
import {
|
|
3
|
+
applyEntryConfig,
|
|
4
|
+
applyExternalsConfig,
|
|
5
|
+
applyModuleConfig
|
|
6
|
+
} from './config';
|
|
7
|
+
import type { ParsedModuleLinkPluginOptions } from './types';
|
|
8
|
+
|
|
9
|
+
export function applyChainConfig1(
|
|
10
|
+
chain: RspackChain,
|
|
11
|
+
opts: ParsedModuleLinkPluginOptions
|
|
12
|
+
): void {
|
|
13
|
+
applyEntryConfig(chain, opts);
|
|
14
|
+
applyExternalsConfig(chain, opts);
|
|
15
|
+
|
|
16
|
+
// Set module compilation configuration
|
|
17
|
+
applyModuleConfig(chain);
|
|
18
|
+
if (chain.get('mode') === 'production') {
|
|
19
|
+
chain.output.library({
|
|
20
|
+
type: 'modern-module'
|
|
21
|
+
});
|
|
22
|
+
chain.optimization.set('avoidEntryIife', true);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { rspack } from '@rspack/core';
|
|
2
|
+
import type RspackChain from 'rspack-chain';
|
|
3
|
+
import {
|
|
4
|
+
applyEntryConfig,
|
|
5
|
+
applyExternalsConfig,
|
|
6
|
+
applyModuleConfig
|
|
7
|
+
} from './config';
|
|
8
|
+
import type { ParsedModuleLinkPluginOptions } from './types';
|
|
9
|
+
|
|
10
|
+
export function applyChainConfig2(
|
|
11
|
+
chain: RspackChain,
|
|
12
|
+
opts: ParsedModuleLinkPluginOptions
|
|
13
|
+
): void {
|
|
14
|
+
applyEntryConfig(chain, opts);
|
|
15
|
+
applyExternalsConfig(chain, opts);
|
|
16
|
+
|
|
17
|
+
// Set module compilation configuration
|
|
18
|
+
if (chain.get('mode') === 'production') {
|
|
19
|
+
chain.output.set('module', true);
|
|
20
|
+
|
|
21
|
+
chain
|
|
22
|
+
.plugin('esm-library')
|
|
23
|
+
.use(new rspack.experiments.EsmLibraryPlugin());
|
|
24
|
+
chain.optimization.set('runtimeChunk', 'single');
|
|
25
|
+
} else {
|
|
26
|
+
applyModuleConfig(chain);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type RspackChain from 'rspack-chain';
|
|
2
|
+
import { applyChainConfig1 } from './config1';
|
|
3
|
+
// import { applyChainConfig2 } from './config2';
|
|
4
|
+
import { ManifestPlugin } from './manifest-plugin';
|
|
5
|
+
import { parseOptions } from './parse';
|
|
6
|
+
import type { ModuleLinkPluginOptions } from './types';
|
|
7
|
+
|
|
8
|
+
export function initModuleLink(
|
|
9
|
+
chain: RspackChain,
|
|
10
|
+
options: ModuleLinkPluginOptions
|
|
11
|
+
): void {
|
|
12
|
+
const opts = parseOptions(options);
|
|
13
|
+
applyChainConfig1(chain, opts);
|
|
14
|
+
// applyChainConfig2(chain, opts);
|
|
15
|
+
|
|
16
|
+
chain.plugin('module-link-manifest').use(ManifestPlugin, [opts]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type { ModuleLinkPluginOptions } from './types';
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { Compilation, Compiler, StatsCompilation } from '@rspack/core';
|
|
2
|
+
import upath from 'upath';
|
|
3
|
+
import type {
|
|
4
|
+
ManifestJson,
|
|
5
|
+
ManifestJsonChunks,
|
|
6
|
+
ManifestJsonExports,
|
|
7
|
+
ParsedModuleLinkPluginOptions
|
|
8
|
+
} from './types';
|
|
9
|
+
|
|
10
|
+
export const RSPACK_PLUGIN_NAME = 'rspack-module-link-plugin';
|
|
11
|
+
|
|
12
|
+
export class ManifestPlugin {
|
|
13
|
+
constructor(private opts: ParsedModuleLinkPluginOptions) {}
|
|
14
|
+
|
|
15
|
+
apply(compiler: Compiler) {
|
|
16
|
+
const opts = this.opts;
|
|
17
|
+
const { Compilation } = compiler.rspack;
|
|
18
|
+
compiler.hooks.thisCompilation.tap(
|
|
19
|
+
RSPACK_PLUGIN_NAME,
|
|
20
|
+
(compilation) => {
|
|
21
|
+
let manifestJson: ManifestJson = {
|
|
22
|
+
name: opts.name,
|
|
23
|
+
exports: {},
|
|
24
|
+
scopes: opts.scopes,
|
|
25
|
+
files: [],
|
|
26
|
+
chunks: {}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
compilation.hooks.processAssets.tap(
|
|
30
|
+
{
|
|
31
|
+
name: RSPACK_PLUGIN_NAME,
|
|
32
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
|
|
33
|
+
},
|
|
34
|
+
(assets) => {
|
|
35
|
+
const stats = compilation.getStats().toJson({
|
|
36
|
+
hash: true,
|
|
37
|
+
entrypoints: true
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const exports = getExports(opts, stats);
|
|
41
|
+
const resources = Object.keys(assets)
|
|
42
|
+
.map(transFileName)
|
|
43
|
+
.filter((file) => !file.includes('hot-update'));
|
|
44
|
+
manifestJson = {
|
|
45
|
+
name: opts.name,
|
|
46
|
+
exports: exports,
|
|
47
|
+
scopes: opts.scopes,
|
|
48
|
+
files: resources,
|
|
49
|
+
chunks: getChunks(opts, compilation)
|
|
50
|
+
};
|
|
51
|
+
const { RawSource } = compiler.rspack.sources;
|
|
52
|
+
|
|
53
|
+
compilation.emitAsset(
|
|
54
|
+
'manifest.json',
|
|
55
|
+
new RawSource(JSON.stringify(manifestJson, null, 4))
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (opts.injectChunkName) {
|
|
61
|
+
compilation.hooks.processAssets.tap(
|
|
62
|
+
{
|
|
63
|
+
name: RSPACK_PLUGIN_NAME,
|
|
64
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
65
|
+
},
|
|
66
|
+
(assets) => {
|
|
67
|
+
const { RawSource } = compiler.rspack.sources;
|
|
68
|
+
for (const [key, value] of Object.entries(
|
|
69
|
+
manifestJson.chunks
|
|
70
|
+
)) {
|
|
71
|
+
const asset = assets[value.js];
|
|
72
|
+
if (!asset) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const source = new RawSource(
|
|
76
|
+
`import.meta.chunkName = import.meta.chunkName ?? ${JSON.stringify(key)};\n${asset.source()}`
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
compilation.updateAsset(value.js, source);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function transFileName(fileName: string): string {
|
|
90
|
+
return fileName.replace(/^.\//, '');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getExports(
|
|
94
|
+
opts: ParsedModuleLinkPluginOptions,
|
|
95
|
+
stats: StatsCompilation
|
|
96
|
+
): ManifestJsonExports {
|
|
97
|
+
const entrypoints = stats.entrypoints || {};
|
|
98
|
+
const exports: ManifestJsonExports = {};
|
|
99
|
+
for (const [key, value] of Object.entries(entrypoints)) {
|
|
100
|
+
const asset = value.assets?.find((item) => {
|
|
101
|
+
return (
|
|
102
|
+
item.name.endsWith(opts.ext) &&
|
|
103
|
+
item.name.startsWith(key) &&
|
|
104
|
+
!item.name.includes('hot-update')
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
if (!asset) continue;
|
|
108
|
+
if (key in opts.exports) {
|
|
109
|
+
exports[key] = {
|
|
110
|
+
...opts.exports[key],
|
|
111
|
+
file: asset.name
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return exports;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getChunks(
|
|
119
|
+
opts: ParsedModuleLinkPluginOptions,
|
|
120
|
+
compilation: Compilation
|
|
121
|
+
) {
|
|
122
|
+
const stats = compilation.getStats().toJson({
|
|
123
|
+
all: false,
|
|
124
|
+
chunks: true,
|
|
125
|
+
modules: true,
|
|
126
|
+
chunkModules: true,
|
|
127
|
+
ids: true
|
|
128
|
+
});
|
|
129
|
+
const buildChunks: ManifestJsonChunks = {};
|
|
130
|
+
if (!stats.chunks) return buildChunks;
|
|
131
|
+
|
|
132
|
+
for (const chunk of stats.chunks) {
|
|
133
|
+
const module = chunk.modules
|
|
134
|
+
?.sort((a, b) => {
|
|
135
|
+
return (a.index ?? -1) - (b?.index ?? -1);
|
|
136
|
+
})
|
|
137
|
+
?.find((module) => {
|
|
138
|
+
return module.moduleType?.includes('javascript/');
|
|
139
|
+
});
|
|
140
|
+
if (!module?.nameForCondition) continue;
|
|
141
|
+
|
|
142
|
+
const js = chunk.files?.find((file) => file.endsWith(opts.ext));
|
|
143
|
+
if (!js) continue;
|
|
144
|
+
|
|
145
|
+
const root = compilation.options.context ?? process.cwd();
|
|
146
|
+
const name = generateIdentifier({
|
|
147
|
+
root,
|
|
148
|
+
name: opts.name,
|
|
149
|
+
filePath: module.nameForCondition
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const css = chunk.files?.filter((file) => file.endsWith('.css')) ?? [];
|
|
153
|
+
const resources = chunk.auxiliaryFiles ?? [];
|
|
154
|
+
buildChunks[name] = {
|
|
155
|
+
name,
|
|
156
|
+
js,
|
|
157
|
+
css,
|
|
158
|
+
resources
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return buildChunks;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function generateIdentifier({
|
|
165
|
+
root,
|
|
166
|
+
name,
|
|
167
|
+
filePath
|
|
168
|
+
}: {
|
|
169
|
+
root: string;
|
|
170
|
+
name: string;
|
|
171
|
+
filePath: string;
|
|
172
|
+
}) {
|
|
173
|
+
const unixFilePath = upath.toUnix(filePath);
|
|
174
|
+
if (!root) {
|
|
175
|
+
return `${name}@${unixFilePath}`;
|
|
176
|
+
}
|
|
177
|
+
const file = upath.relative(upath.toUnix(root), unixFilePath);
|
|
178
|
+
return `${name}@${file}`;
|
|
179
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ModuleLinkPluginOptions,
|
|
3
|
+
ParsedModuleLinkPluginOptions
|
|
4
|
+
} from './types';
|
|
5
|
+
|
|
6
|
+
export function parseOptions(
|
|
7
|
+
options: ModuleLinkPluginOptions
|
|
8
|
+
): ParsedModuleLinkPluginOptions {
|
|
9
|
+
const exports: ParsedModuleLinkPluginOptions['exports'] = {};
|
|
10
|
+
if (options.exports) {
|
|
11
|
+
for (const [name, item] of Object.entries(options.exports)) {
|
|
12
|
+
exports[name] = {
|
|
13
|
+
name,
|
|
14
|
+
pkg: !!item.pkg,
|
|
15
|
+
file: item.file,
|
|
16
|
+
identifier: `${options.name}/${name}`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const deps = (options.deps ?? []).filter((name) => name !== options.name);
|
|
21
|
+
return {
|
|
22
|
+
name: options.name,
|
|
23
|
+
ext: options.ext ? `.${options.ext}` : '.mjs',
|
|
24
|
+
exports,
|
|
25
|
+
imports: options.imports ?? {},
|
|
26
|
+
scopes: options.scopes ?? {},
|
|
27
|
+
injectChunkName: options.injectChunkName ?? false,
|
|
28
|
+
preEntries: options.preEntries ?? [],
|
|
29
|
+
deps
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ManifestJsonExports } from '@esmx/core';
|
|
2
|
+
|
|
3
|
+
export type {
|
|
4
|
+
ManifestJson,
|
|
5
|
+
ManifestJsonChunk,
|
|
6
|
+
ManifestJsonChunks,
|
|
7
|
+
ManifestJsonExport,
|
|
8
|
+
ManifestJsonExports
|
|
9
|
+
} from '@esmx/core';
|
|
10
|
+
|
|
11
|
+
export interface ModuleLinkPluginOptions {
|
|
12
|
+
name: string;
|
|
13
|
+
ext?: string;
|
|
14
|
+
imports?: Record<string, string>;
|
|
15
|
+
scopes?: Record<string, Record<string, string>>;
|
|
16
|
+
exports?: Record<string, { pkg?: boolean; file: string }>;
|
|
17
|
+
injectChunkName?: boolean;
|
|
18
|
+
preEntries?: string[];
|
|
19
|
+
deps?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ParsedModuleLinkPluginOptions {
|
|
23
|
+
name: string;
|
|
24
|
+
ext: string;
|
|
25
|
+
exports: ManifestJsonExports;
|
|
26
|
+
imports: Record<string, string>;
|
|
27
|
+
scopes: Record<string, Record<string, string>>;
|
|
28
|
+
injectChunkName: boolean;
|
|
29
|
+
preEntries: string[];
|
|
30
|
+
deps: string[];
|
|
31
|
+
}
|