@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.
Files changed (76) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +48 -20
  3. package/README.zh-CN.md +57 -0
  4. package/dist/index.d.ts +2 -4
  5. package/dist/index.mjs +4 -4
  6. package/dist/module-link/config.d.ts +5 -0
  7. package/dist/module-link/config.mjs +100 -0
  8. package/dist/module-link/config1.d.ts +3 -0
  9. package/dist/module-link/config1.mjs +16 -0
  10. package/dist/module-link/config2.d.ts +3 -0
  11. package/dist/module-link/config2.mjs +17 -0
  12. package/dist/module-link/index.d.ts +4 -0
  13. package/dist/module-link/index.mjs +8 -0
  14. package/dist/module-link/manifest-plugin.d.ts +14 -0
  15. package/dist/module-link/manifest-plugin.mjs +141 -0
  16. package/dist/module-link/parse.d.ts +2 -0
  17. package/dist/module-link/parse.mjs +24 -0
  18. package/dist/module-link/types.d.ts +25 -0
  19. package/dist/rspack/app.d.ts +183 -0
  20. package/dist/{app.mjs → rspack/app.mjs} +18 -46
  21. package/dist/rspack/build-target.d.ts +7 -0
  22. package/dist/rspack/build-target.mjs +0 -0
  23. package/dist/{config.d.ts → rspack/chain-config.d.ts} +3 -4
  24. package/dist/rspack/chain-config.mjs +113 -0
  25. package/dist/rspack/index.d.ts +3 -0
  26. package/dist/rspack/index.mjs +4 -0
  27. package/dist/rspack/loader.d.ts +9 -0
  28. package/dist/{loader.mjs → rspack/loader.mjs} +2 -22
  29. package/dist/rspack/pack.d.ts +9 -0
  30. package/dist/{pack.mjs → rspack/pack.mjs} +33 -25
  31. package/dist/rspack/pack.test.d.ts +1 -0
  32. package/dist/rspack/pack.test.mjs +180 -0
  33. package/dist/rspack/utils/rsbuild.d.ts +6 -0
  34. package/dist/{utils → rspack/utils}/rsbuild.mjs +7 -37
  35. package/dist/rspack-html/index.d.ts +168 -0
  36. package/dist/rspack-html/index.mjs +160 -0
  37. package/dist/rspack-html/target-setting.d.ts +17 -0
  38. package/dist/rspack-html/target-setting.mjs +31 -0
  39. package/dist/rspack-html/target-setting.test.d.ts +1 -0
  40. package/dist/rspack-html/target-setting.test.mjs +105 -0
  41. package/package.json +23 -21
  42. package/src/index.ts +7 -6
  43. package/src/module-link/config.ts +157 -0
  44. package/src/module-link/config1.ts +24 -0
  45. package/src/module-link/config2.ts +28 -0
  46. package/src/module-link/index.ts +19 -0
  47. package/src/module-link/manifest-plugin.ts +179 -0
  48. package/src/module-link/parse.ts +31 -0
  49. package/src/module-link/types.ts +31 -0
  50. package/src/{app.ts → rspack/app.ts} +104 -107
  51. package/src/rspack/build-target.ts +7 -0
  52. package/src/rspack/chain-config.ts +165 -0
  53. package/src/rspack/index.ts +8 -0
  54. package/src/{loader.ts → rspack/loader.ts} +3 -22
  55. package/src/rspack/pack.test.ts +215 -0
  56. package/src/rspack/pack.ts +101 -0
  57. package/src/{utils → rspack/utils}/rsbuild.ts +11 -40
  58. package/src/rspack-html/index.ts +495 -0
  59. package/src/rspack-html/target-setting.test.ts +123 -0
  60. package/src/rspack-html/target-setting.ts +52 -0
  61. package/dist/app.d.ts +0 -160
  62. package/dist/build-target.d.ts +0 -8
  63. package/dist/config.mjs +0 -142
  64. package/dist/html-app.d.ts +0 -299
  65. package/dist/html-app.mjs +0 -214
  66. package/dist/loader.d.ts +0 -30
  67. package/dist/pack.d.ts +0 -2
  68. package/dist/utils/rsbuild.d.ts +0 -12
  69. package/src/build-target.ts +0 -8
  70. package/src/config.ts +0 -171
  71. package/src/html-app.ts +0 -560
  72. package/src/pack.ts +0 -79
  73. /package/dist/{build-target.mjs → module-link/types.mjs} +0 -0
  74. /package/dist/{utils → rspack/utils}/index.d.ts +0 -0
  75. /package/dist/{utils → rspack/utils}/index.mjs +0 -0
  76. /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 module federation and SSR capabilities.",
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 Federation",
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": "stylelint '**/*.{css,vue}' --fix --aei",
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.11",
64
- "@esmx/rspack-module-link-plugin": "3.0.0-rc.11",
65
- "@npmcli/arborist": "^8.0.0",
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.2.0",
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": "1.9.4",
79
- "@esmx/core": "3.0.0-rc.11",
80
- "@esmx/lint": "3.0.0-rc.11",
81
- "@types/node": "22.13.10",
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.9",
87
+ "@types/webpack-hot-middleware": "^2.25.12",
85
88
  "@types/webpack-node-externals": "^3.0.4",
86
- "@vitest/coverage-v8": "3.0.8",
87
- "stylelint": "16.15.0",
88
- "typescript": "5.8.2",
89
- "unbuild": "2.0.0",
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.11",
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": "0920e0485284528eb642a7078f4cb48b013352a5"
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
- createRspackApp
5
- } from './app';
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
+ }