@shuvi/toolpack 2.0.0-dev.12 → 2.0.0-dev.13

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.
@@ -0,0 +1,22 @@
1
+ import { Configuration } from '@rspack/core';
2
+ import RspackChain from 'rspack-chain';
3
+ import { ModuleSnapshot } from '../moduleCollector';
4
+ export interface BuildOptions {
5
+ outputDir: string;
6
+ configRspack?: (chain: RspackChain) => RspackChain;
7
+ shared?: ShareConfig;
8
+ externals?: Configuration['externals'];
9
+ esmFullSpecific?: Boolean;
10
+ force?: boolean;
11
+ }
12
+ export type ShareConfig = Record<string, any>;
13
+ type OnBuildComplete = (error?: null | Error) => void;
14
+ export declare class RspackBundler {
15
+ private _nextBuild;
16
+ private _completeFns;
17
+ private _isBuilding;
18
+ build(snapshot: ModuleSnapshot, options: BuildOptions): Promise<void>;
19
+ private _buildDll;
20
+ onBuildComplete(fn: OnBuildComplete): void;
21
+ }
22
+ export {};
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RspackBundler = void 0;
13
+ const core_1 = require("@rspack/core");
14
+ const fs_extra_1 = require("fs-extra");
15
+ const path_1 = require("path");
16
+ const crypto_1 = require("crypto");
17
+ const constants_1 = require("../constants");
18
+ const dep_1 = require("../dep");
19
+ const metadata_1 = require("../metadata");
20
+ const utils_1 = require("../utils");
21
+ const rspack_config_1 = require("./rspack-config");
22
+ function getHash(text) {
23
+ return (0, crypto_1.createHash)('sha256').update(text).digest('hex').substring(0, 8);
24
+ }
25
+ /**
26
+ * hash everything that can change the build result
27
+ *
28
+ * @param {BuildOptions} options
29
+ * @returns {string}
30
+ */
31
+ function getMainHash(options) {
32
+ let content = JSON.stringify({
33
+ shared: options.shared
34
+ });
35
+ return getHash([utils_1.version, content].join(''));
36
+ }
37
+ function getBuildHash(hash, snapshot) {
38
+ return getHash(hash + JSON.stringify(snapshot));
39
+ }
40
+ function getRspackConfigFromOptions({ deps, entry, outputDir, shared, externals, esmFullSpecific }) {
41
+ const exposes = deps.reduce((memo, dep) => {
42
+ memo[`./${dep.request}`] = dep.filename;
43
+ return memo;
44
+ }, {});
45
+ const chain = (0, rspack_config_1.getRspackConfig)({
46
+ name: constants_1.NAME,
47
+ entry,
48
+ filename: constants_1.DLL_FILENAME,
49
+ outputDir,
50
+ publicPath: constants_1.DEFAULT_PUBLIC_PATH,
51
+ shared,
52
+ externals,
53
+ esmFullSpecific,
54
+ exposes
55
+ });
56
+ return chain.toConfig();
57
+ }
58
+ function buildDeps(_a) {
59
+ return __awaiter(this, arguments, void 0, function* ({ deps, dir }) {
60
+ (0, fs_extra_1.mkdirpSync)(dir);
61
+ // expose files
62
+ yield Promise.all(deps.map((dep) => __awaiter(this, void 0, void 0, function* () {
63
+ const content = yield dep.buildExposeContent();
64
+ yield (0, fs_extra_1.writeFile)(dep.filename, content, 'utf-8');
65
+ })));
66
+ // index file - export all modules using valid identifiers
67
+ const indexContent = deps
68
+ .map(dep => {
69
+ const moduleName = dep.request;
70
+ const filename = dep.filename;
71
+ // Convert module name to valid identifier
72
+ const validIdentifier = moduleName.replace(/[^a-zA-Z0-9_$]/g, '_');
73
+ return `export { default as ${validIdentifier} } from '${filename}';`;
74
+ })
75
+ .join('\n');
76
+ (0, fs_extra_1.writeFileSync)((0, path_1.join)(dir, 'index.js'), indexContent, 'utf-8');
77
+ return deps;
78
+ });
79
+ }
80
+ function rspackBuild(config) {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ return new Promise((resolve, reject) => {
83
+ const compiler = (0, core_1.rspack)(config);
84
+ compiler.run((err, stats) => {
85
+ if (err || (stats === null || stats === void 0 ? void 0 : stats.hasErrors())) {
86
+ if (err) {
87
+ reject(err);
88
+ }
89
+ if (stats) {
90
+ const errorMsg = stats.toString('errors-only');
91
+ reject(new Error(errorMsg));
92
+ }
93
+ }
94
+ else {
95
+ resolve(stats);
96
+ }
97
+ compiler.close(() => { });
98
+ });
99
+ });
100
+ });
101
+ }
102
+ function isSnapshotSame(pre, cur) {
103
+ const keys = Object.keys(cur);
104
+ for (let index = 0; index < keys.length; index++) {
105
+ const id = keys[index];
106
+ const preItem = pre[id];
107
+ const nextItem = cur[id];
108
+ if (!preItem) {
109
+ return false;
110
+ }
111
+ if (preItem.version !== nextItem.version) {
112
+ return false;
113
+ }
114
+ }
115
+ return true;
116
+ }
117
+ class RspackBundler {
118
+ constructor() {
119
+ this._nextBuild = null;
120
+ this._completeFns = [];
121
+ this._isBuilding = false;
122
+ }
123
+ build(snapshot, options) {
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ if (this._isBuilding) {
126
+ this._nextBuild = snapshot;
127
+ return;
128
+ }
129
+ let error = null;
130
+ this._isBuilding = true;
131
+ try {
132
+ yield this._buildDll(snapshot, options);
133
+ }
134
+ catch (err) {
135
+ error = err;
136
+ }
137
+ this._isBuilding = false;
138
+ if (error) {
139
+ console.error(`[@shuvi/dll]: Rspack Bundle Error`);
140
+ console.error(error);
141
+ }
142
+ this._completeFns.forEach(fn => fn(error));
143
+ this._completeFns = [];
144
+ });
145
+ }
146
+ _buildDll(snapshot, options) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ const { externals = {}, shared = {}, outputDir, force, esmFullSpecific = true } = options;
149
+ const mainHash = getMainHash(options);
150
+ const dllDir = (0, utils_1.getDllDir)(outputDir);
151
+ const preMetadata = (0, metadata_1.getMetadata)(outputDir);
152
+ const metadata = {
153
+ hash: mainHash,
154
+ buildHash: preMetadata.buildHash,
155
+ modules: snapshot
156
+ };
157
+ if (!force &&
158
+ preMetadata.hash === metadata.hash &&
159
+ isSnapshotSame(preMetadata.modules, snapshot)) {
160
+ return [false, preMetadata];
161
+ }
162
+ const dllPendingDir = (0, utils_1.getDllPendingDir)(outputDir);
163
+ // create a temporal dir to build. This avoids leaving the dll
164
+ // in a corrupted state if there is an error during the build
165
+ if ((0, fs_extra_1.existsSync)(dllPendingDir)) {
166
+ (0, fs_extra_1.emptyDirSync)(dllPendingDir);
167
+ }
168
+ const depsDir = (0, utils_1.getDepsDir)(dllPendingDir);
169
+ const deps = Object.entries(snapshot).map(([request, { version, libraryPath }]) => {
170
+ return new dep_1.Dep({
171
+ request,
172
+ libraryPath,
173
+ version,
174
+ outputPath: depsDir
175
+ });
176
+ });
177
+ yield buildDeps({
178
+ deps,
179
+ dir: depsDir
180
+ });
181
+ yield rspackBuild(getRspackConfigFromOptions({
182
+ deps,
183
+ entry: (0, path_1.join)(depsDir, 'index.js'),
184
+ shared,
185
+ externals,
186
+ esmFullSpecific,
187
+ outputDir: dllPendingDir
188
+ }));
189
+ if (this._nextBuild) {
190
+ const param = this._nextBuild;
191
+ this._nextBuild = null;
192
+ return yield this._buildDll(param, options);
193
+ }
194
+ metadata.buildHash = getBuildHash(metadata.hash, snapshot);
195
+ // finish build
196
+ (0, metadata_1.writeMetadata)(dllPendingDir, metadata);
197
+ (0, fs_extra_1.removeSync)(dllDir);
198
+ (0, fs_extra_1.renameSync)(dllPendingDir, dllDir);
199
+ return [true, metadata];
200
+ });
201
+ }
202
+ onBuildComplete(fn) {
203
+ if (this._isBuilding) {
204
+ this._completeFns.push(fn);
205
+ }
206
+ else {
207
+ fn();
208
+ }
209
+ }
210
+ }
211
+ exports.RspackBundler = RspackBundler;
@@ -0,0 +1,16 @@
1
+ import RspackChain from 'rspack-chain';
2
+ import type { Configuration } from '@rspack/core';
3
+ type ShareConfig = Record<string, any>;
4
+ export interface ConfigOptions {
5
+ name: string;
6
+ entry: string;
7
+ filename: string;
8
+ outputDir: string;
9
+ publicPath: string;
10
+ shared?: ShareConfig;
11
+ externals: Configuration['externals'];
12
+ esmFullSpecific: Boolean;
13
+ exposes: Record<string, string>;
14
+ }
15
+ export declare function getRspackConfig({ name, entry, filename, outputDir, publicPath, shared, externals, esmFullSpecific, exposes }: ConfigOptions): RspackChain;
16
+ export {};
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.getRspackConfig = getRspackConfig;
30
+ const rspack = __importStar(require("@rspack/core"));
31
+ const rspack_chain_1 = __importDefault(require("rspack-chain"));
32
+ const moduleFileExtensions = [
33
+ '.web.mjs',
34
+ '.mjs',
35
+ '.web.js',
36
+ '.js',
37
+ '.json',
38
+ '.web.jsx',
39
+ '.jsx'
40
+ ];
41
+ function getRspackConfig({ name, entry, filename, outputDir, publicPath, shared, externals, esmFullSpecific, exposes }) {
42
+ const config = new rspack_chain_1.default();
43
+ config.mode('development');
44
+ config.entry('main').add(entry);
45
+ config.devtool('cheap-module-source-map');
46
+ config.bail(true);
47
+ config.watch(false);
48
+ config.set('infrastructureLogging', {
49
+ level: 'none'
50
+ });
51
+ config.output.merge({
52
+ pathinfo: false,
53
+ path: outputDir,
54
+ filename: filename,
55
+ chunkFilename: '[name].js',
56
+ publicPath,
57
+ uniqueName: name
58
+ });
59
+ config.performance.hints(false);
60
+ config.optimization.merge({
61
+ emitOnErrors: true,
62
+ // need to use DefinePlugin to set process.env.NODE_ENV
63
+ nodeEnv: false,
64
+ runtimeChunk: false,
65
+ minimize: false,
66
+ realContentHash: false
67
+ });
68
+ // Disable splitChunks to avoid chunk naming conflicts
69
+ config.optimization.splitChunks(false);
70
+ config.resolve.extensions.merge(moduleFileExtensions);
71
+ // 添加 Node.js polyfills for browser environment
72
+ config.resolve.fallback.merge({
73
+ stream: false,
74
+ util: false,
75
+ buffer: false,
76
+ process: false,
77
+ assert: false,
78
+ crypto: false,
79
+ fs: false,
80
+ path: false,
81
+ os: false,
82
+ http: false,
83
+ https: false,
84
+ zlib: false,
85
+ url: false,
86
+ querystring: false,
87
+ events: false,
88
+ tty: false,
89
+ net: false,
90
+ child_process: false
91
+ });
92
+ // config.module.set('strictExportPresence', true); // Not supported in Rspack
93
+ // x-ref: https://github.com/webpack/webpack/issues/11467
94
+ if (!esmFullSpecific) {
95
+ config.module
96
+ .rule('rspackPatch')
97
+ .test(/\.m?js/)
98
+ .resolve.set('fullySpecified', false);
99
+ }
100
+ config.module
101
+ .rule('js')
102
+ .test(/\.(js|mjs|cjs|jsx)$/)
103
+ .use('esbuild-loader')
104
+ .loader(require.resolve('esbuild-loader'))
105
+ .options({
106
+ loader: 'jsx', // Remove this if you're not using JSX
107
+ target: 'es2015' // Syntax to compile to (see options below for possible values)
108
+ });
109
+ // Rspack cache configuration - simplified for now
110
+ // TODO: Implement proper cache configuration when Rspack supports it
111
+ config.cache(false);
112
+ config.plugin('private/ignore-plugin').use(rspack.IgnorePlugin, [
113
+ {
114
+ resourceRegExp: /^\.\/locale$/,
115
+ contextRegExp: /moment$/
116
+ }
117
+ ]);
118
+ config.plugin('define').use(rspack.DefinePlugin, [
119
+ {
120
+ 'process.env.NODE_ENV': JSON.stringify('development')
121
+ }
122
+ ]);
123
+ // 使用 ModuleFederationPlugin 来暴露模块
124
+ config
125
+ .plugin('module-federation')
126
+ .use(rspack.container.ModuleFederationPlugin, [
127
+ {
128
+ name: name,
129
+ filename: 'remoteEntry.js',
130
+ exposes: exposes,
131
+ shared: {
132
+ // 共享依赖配置
133
+ }
134
+ }
135
+ ]);
136
+ if (externals) {
137
+ config.externals(externals);
138
+ }
139
+ return config;
140
+ }
@@ -0,0 +1,20 @@
1
+ import type { Compiler } from '@rspack/core';
2
+ import { ModuleCollectorOptions, ModuleSnapshot } from '../moduleCollector';
3
+ export type SnapshotListener = (snapshot: ModuleSnapshot) => void;
4
+ export interface RspackDynamicDLLPluginOptions {
5
+ resolveRspackModule: (s: string) => ReturnType<typeof require>;
6
+ dllName: string;
7
+ onSnapshot: SnapshotListener;
8
+ shareScope?: string;
9
+ }
10
+ export declare class RspackDynamicDLLPlugin {
11
+ private _collector;
12
+ private _dllName;
13
+ private _timer;
14
+ private _matchCache;
15
+ private _onSnapshot;
16
+ private _disabled;
17
+ constructor(opts: RspackDynamicDLLPluginOptions & ModuleCollectorOptions);
18
+ disableDllReference(): void;
19
+ apply(compiler: Compiler): void;
20
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RspackDynamicDLLPlugin = void 0;
4
+ const moduleCollector_1 = require("../moduleCollector");
5
+ const PLUGIN_NAME = 'RspackDLLBuildDeps';
6
+ class RspackDynamicDLLPlugin {
7
+ constructor(opts) {
8
+ this._dllName = opts.dllName;
9
+ this._onSnapshot = opts.onSnapshot;
10
+ this._collector = (0, moduleCollector_1.getModuleCollector)({
11
+ include: opts.include,
12
+ exclude: opts.exclude
13
+ });
14
+ this._matchCache = new Map();
15
+ this._timer = null;
16
+ this._disabled = false;
17
+ }
18
+ disableDllReference() {
19
+ this._disabled = true;
20
+ }
21
+ apply(compiler) {
22
+ compiler.hooks.normalModuleFactory.tap(PLUGIN_NAME, nmf => {
23
+ nmf.hooks.beforeResolve.tap(PLUGIN_NAME, resolveData => {
24
+ const { request } = resolveData;
25
+ // Check cache first
26
+ const replaceValue = this._matchCache.get(request);
27
+ if (replaceValue) {
28
+ resolveData.request = replaceValue;
29
+ return;
30
+ }
31
+ // For beforeResolve, we can't use full ModuleCollector logic since we don't have resource yet
32
+ // So we'll do a basic check for node_modules requests and let createModule handle the rest
33
+ if (!this._disabled &&
34
+ request &&
35
+ !request.startsWith('.') &&
36
+ !request.startsWith('/')) {
37
+ // Basic check: if it looks like a node_modules request, we'll redirect it
38
+ // The actual filtering will happen in createModule
39
+ const name = this._dllName;
40
+ const dllRequest = `${name}/${request}`;
41
+ resolveData.request = dllRequest;
42
+ this._matchCache.set(request, dllRequest);
43
+ }
44
+ });
45
+ nmf.hooks.createModule.tap(PLUGIN_NAME, (_createData, resolveData) => {
46
+ const createData = (resolveData === null || resolveData === void 0 ? void 0 : resolveData.createData) || {};
47
+ const request = (resolveData === null || resolveData === void 0 ? void 0 : resolveData.request) || '';
48
+ const resource = (createData === null || createData === void 0 ? void 0 : createData.resource) || '';
49
+ const context = (resolveData === null || resolveData === void 0 ? void 0 : resolveData.context) || '';
50
+ if (!this._collector.shouldCollect({
51
+ request,
52
+ context,
53
+ resource
54
+ })) {
55
+ return;
56
+ }
57
+ const resourceResolveData = (createData === null || createData === void 0 ? void 0 : createData.resourceResolveData) || {};
58
+ const descriptionFileData = (resourceResolveData === null || resourceResolveData === void 0 ? void 0 : resourceResolveData.descriptionFileData) || {};
59
+ const version = (descriptionFileData === null || descriptionFileData === void 0 ? void 0 : descriptionFileData.version) || null;
60
+ this._collector.add(request, {
61
+ libraryPath: resource,
62
+ version
63
+ });
64
+ if (this._disabled) {
65
+ return;
66
+ }
67
+ const name = this._dllName;
68
+ const replaceValue = `${name}/${request}`;
69
+ if ((resolveData === null || resolveData === void 0 ? void 0 : resolveData.request) !== undefined) {
70
+ resolveData.request = replaceValue;
71
+ }
72
+ this._matchCache.set(request, replaceValue);
73
+ // For Rspack, we'll use Module Federation approach rather than RemoteModule
74
+ // The actual module federation is handled by the MF plugin in the config
75
+ return undefined; // Let Rspack handle the module creation
76
+ });
77
+ });
78
+ compiler.hooks.done.tap(PLUGIN_NAME, (stats) => {
79
+ if (!stats.hasErrors()) {
80
+ if (this._timer) {
81
+ clearTimeout(this._timer);
82
+ }
83
+ this._timer = setTimeout(() => {
84
+ this._onSnapshot(this._collector.snapshot());
85
+ }, 500);
86
+ }
87
+ });
88
+ }
89
+ }
90
+ exports.RspackDynamicDLLPlugin = RspackDynamicDLLPlugin;
@@ -0,0 +1,35 @@
1
+ import { IncomingMessage, ServerResponse } from 'http';
2
+ import type * as rspackType from '@rspack/core';
3
+ import type { Configuration } from '@rspack/core';
4
+ import type RspackChain from 'rspack-chain';
5
+ import { ShareConfig } from './bundler/rspack-bundler';
6
+ type IResolveRspackModule = <T extends string>(path: T) => T extends `@rspack/core` ? typeof rspackType : T extends `@rspack/core/${infer R}` ? any : never;
7
+ interface IOpts {
8
+ cwd?: string;
9
+ rootDir: string;
10
+ cacheDir: string;
11
+ resolveRspackModule?: IResolveRspackModule;
12
+ include?: RegExp[];
13
+ exclude?: RegExp[];
14
+ shared?: ShareConfig;
15
+ externals?: Configuration['externals'];
16
+ esmFullSpecific?: Boolean;
17
+ }
18
+ export declare class RspackDynamicDll {
19
+ private _opts;
20
+ private _bundler;
21
+ private _rootDir;
22
+ private _cacheDir;
23
+ private _resolveRspackModule;
24
+ private _dllPlugin;
25
+ private _hasBuilt;
26
+ constructor(opts: IOpts);
27
+ private getRemovedModules;
28
+ private handleSnapshot;
29
+ middleware: (req: IncomingMessage, res: ServerResponse, next: (...args: any[]) => any) => Promise<any>;
30
+ modifyRspackChain: (chain: RspackChain) => RspackChain;
31
+ modifyRspack: (config: Configuration) => Configuration;
32
+ private _buildDLL;
33
+ private _getMFconfig;
34
+ }
35
+ export {};
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.RspackDynamicDll = void 0;
16
+ const fs_extra_1 = require("fs-extra");
17
+ const path_1 = require("path");
18
+ const mrmime_1 = require("mrmime");
19
+ const core_1 = __importDefault(require("@rspack/core"));
20
+ const constants_1 = require("./constants");
21
+ const rspack_bundler_1 = require("./bundler/rspack-bundler");
22
+ const rspack_dynamic_dll_plugin_1 = require("./plugin/rspack-dynamic-dll-plugin");
23
+ const metadata_1 = require("./metadata");
24
+ const utils_1 = require("./utils");
25
+ const check_not_in_node_modules_1 = require("./helper/check-not-in-node-modules");
26
+ class RspackDynamicDll {
27
+ constructor(opts) {
28
+ this._hasBuilt = false;
29
+ this.handleSnapshot = (snapshot) => __awaiter(this, void 0, void 0, function* () {
30
+ if (this._hasBuilt) {
31
+ (0, metadata_1.writeUpdate)(this._cacheDir, snapshot);
32
+ return;
33
+ }
34
+ const originModules = (0, metadata_1.getMetadata)(this._cacheDir).modules;
35
+ const diffNames = this.getRemovedModules(snapshot, originModules);
36
+ const requiredSnapshot = Object.assign(Object.assign({}, originModules), snapshot);
37
+ diffNames.forEach(lib => {
38
+ delete requiredSnapshot[lib];
39
+ });
40
+ yield this._buildDLL(requiredSnapshot);
41
+ this._dllPlugin.disableDllReference();
42
+ this._hasBuilt = true;
43
+ });
44
+ this.middleware = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
45
+ const url = req.url || '';
46
+ const shouldServe = url.startsWith(constants_1.DEFAULT_PUBLIC_PATH);
47
+ if (!shouldServe) {
48
+ return next();
49
+ }
50
+ this._bundler.onBuildComplete(() => {
51
+ const relativePath = url.replace(new RegExp(`^${constants_1.DEFAULT_PUBLIC_PATH}`), '/');
52
+ const filePath = (0, path_1.join)((0, utils_1.getDllDir)(this._cacheDir), relativePath);
53
+ const { mtime } = (0, fs_extra_1.statSync)(filePath);
54
+ // Get the last modification time of the file and convert the time into a world time string
55
+ let lastModified = mtime.toUTCString();
56
+ const ifModifiedSince = req.headers['if-modified-since'];
57
+ // Tell the browser what time to use the browser cache without asking the server directly, but it seems that it is not effective, and needs to learn why.
58
+ res.setHeader('cache-control', 'no-cache');
59
+ if (ifModifiedSince && lastModified <= ifModifiedSince) {
60
+ // If the request header contains the request ifModifiedSince and the file is not modified, it returns 304
61
+ res.writeHead(304, 'Not Modified');
62
+ res.end();
63
+ return;
64
+ }
65
+ // Return the header Last-Modified for the last modification time of the current request file
66
+ res.setHeader('Last-Modified', lastModified);
67
+ // Return file
68
+ res.setHeader('content-type', (0, mrmime_1.lookup)((0, path_1.extname)(url)) || 'text/plain');
69
+ const content = (0, fs_extra_1.readFileSync)(filePath);
70
+ res.statusCode = 200;
71
+ res.end(content);
72
+ });
73
+ });
74
+ this.modifyRspackChain = (chain) => {
75
+ // Keep entries as-is for Rspack since we don't have virtual modules support
76
+ chain
77
+ .plugin('dynamic-dll-mf')
78
+ .use(core_1.default.container.ModuleFederationPlugin, [this._getMFconfig()]);
79
+ chain.plugin('dynamic-dll-plugin').use(this._dllPlugin);
80
+ return chain;
81
+ };
82
+ this.modifyRspack = (config) => {
83
+ // Keep config.entry as-is for Rspack since we don't have virtual modules support
84
+ if (!config.plugins) {
85
+ config.plugins = [];
86
+ }
87
+ config.plugins.push(new core_1.default.container.ModuleFederationPlugin(this._getMFconfig()), this._dllPlugin);
88
+ return config;
89
+ };
90
+ this._opts = opts;
91
+ this._cacheDir = opts.cacheDir;
92
+ this._rootDir = opts.rootDir;
93
+ this._resolveRspackModule = opts.resolveRspackModule || require;
94
+ this._bundler = new rspack_bundler_1.RspackBundler();
95
+ this._dllPlugin = new rspack_dynamic_dll_plugin_1.RspackDynamicDLLPlugin({
96
+ include: opts.include,
97
+ exclude: opts.exclude,
98
+ dllName: constants_1.NAME,
99
+ resolveRspackModule: this._resolveRspackModule, // Type compatibility
100
+ onSnapshot: this.handleSnapshot
101
+ });
102
+ }
103
+ getRemovedModules(snapshot, originModules) {
104
+ return Object.keys(originModules).filter(key => {
105
+ if (snapshot[key]) {
106
+ return false;
107
+ }
108
+ return (0, check_not_in_node_modules_1.checkNotInNodeModules)(key, this._rootDir);
109
+ });
110
+ }
111
+ _buildDLL(snapshot) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ yield this._bundler.build(snapshot, {
114
+ outputDir: this._cacheDir,
115
+ shared: this._opts.shared,
116
+ externals: this._opts.externals,
117
+ esmFullSpecific: this._opts.esmFullSpecific,
118
+ force: process.env.DLL_FORCE_BUILD === 'true'
119
+ });
120
+ });
121
+ }
122
+ _getMFconfig() {
123
+ return {
124
+ name: '__',
125
+ remotes: {
126
+ // [NAME]: `${NAME}@${DEFAULT_PUBLIC_PATH}${DLL_FILENAME}`,
127
+ // https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes
128
+ [constants_1.NAME]: `
129
+ promise new Promise(resolve => {
130
+ const remoteUrl = '${constants_1.DEFAULT_PUBLIC_PATH}${constants_1.DLL_FILENAME}';
131
+ const script = document.createElement('script');
132
+ script.src = remoteUrl;
133
+ script.onload = () => {
134
+ // the injected script has loaded and is available on window
135
+ // we can now resolve this Promise
136
+ const proxy = {
137
+ get: (request) => {
138
+ const promise = window['${constants_1.NAME}'].get(request);
139
+ return promise;
140
+ },
141
+ init: (arg) => {
142
+ try {
143
+ return window['${constants_1.NAME}'].init(arg);
144
+ } catch(e) {
145
+ // remote container already initialized
146
+ }
147
+ }
148
+ }
149
+ resolve(proxy);
150
+ }
151
+ // inject this script with the src set to the versioned remoteEntry.js
152
+ document.head.appendChild(script);
153
+ })`.trim()
154
+ }
155
+ };
156
+ }
157
+ }
158
+ exports.RspackDynamicDll = RspackDynamicDll;
@@ -1,8 +1,6 @@
1
1
  import { rspack, ChunkGroup } from '@rspack/core';
2
2
  export { RspackChain } from './config/base.rspack';
3
- /**
4
- * @todo back to DLL topic later
5
- */
3
+ export { RspackDynamicDll } from './dynamic-dll/rspack-dynamic-dll';
6
4
  export { rspack, ChunkGroup };
7
5
  /**
8
6
  * re-export for shuvi plugin
@@ -172,12 +170,10 @@ StatsCompilation, StatsError,
172
170
  * @unsupported Rspack does not export StatsLoggingEntry.
173
171
  * TODO: Remove or replace after Rspack support is available.
174
172
  */
175
- StatsModule
176
- /**
173
+ StatsModule } from /**
177
174
  * @unsupported Rspack does not export StatsModuleIssuer.
178
175
  * TODO: Remove or replace after Rspack support is available.
179
- */
180
- } from
176
+ */
181
177
  /**
182
178
  * @unsupported Rspack does not export StatsModuleReason.
183
179
  * TODO: Remove or replace after Rspack support is available.
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SingleEntryPlugin = exports.RuntimeModule = exports.ProvidePlugin = exports.ProgressPlugin = exports.MultiCompiler = exports.NormalModuleReplacementPlugin = exports.NormalModule = exports.NoEmitOnErrorsPlugin = exports.Module = exports.LoaderTargetPlugin = exports.LoaderOptionsPlugin = exports.IgnorePlugin = exports.HotModuleReplacementPlugin = exports.ExternalsPlugin = exports.ExternalModule = exports.EvalSourceMapDevToolPlugin = exports.EvalDevToolModulePlugin = exports.EnvironmentPlugin = exports.EntryPlugin = exports.EntryOptionPlugin = exports.DynamicEntryPlugin = exports.DllReferencePlugin = exports.DllPlugin = exports.Dependency = exports.DefinePlugin = exports.ContextReplacementPlugin = exports.Compiler = exports.Compilation = exports.BannerPlugin = exports.AsyncDependenciesBlock = exports.experiments = exports.sources = exports.util = exports.sharing = exports.container = exports.library = exports.wasm = exports.electron = exports.node = exports.webworker = exports.web = exports.optimize = exports.javascript = exports.config = exports.ValidationError = exports.RuntimeGlobals = exports.ModuleFilenameHelpers = exports.version = exports.rspack = exports.RspackChain = void 0;
4
- exports.MultiStats = exports.WebpackOptionsApply = exports.WebpackError = exports.Template = exports.Stats = exports.SourceMapDevToolPlugin = void 0;
3
+ exports.RuntimeModule = exports.ProvidePlugin = exports.ProgressPlugin = exports.MultiCompiler = exports.NormalModuleReplacementPlugin = exports.NormalModule = exports.NoEmitOnErrorsPlugin = exports.Module = exports.LoaderTargetPlugin = exports.LoaderOptionsPlugin = exports.IgnorePlugin = exports.HotModuleReplacementPlugin = exports.ExternalsPlugin = exports.ExternalModule = exports.EvalSourceMapDevToolPlugin = exports.EvalDevToolModulePlugin = exports.EnvironmentPlugin = exports.EntryPlugin = exports.EntryOptionPlugin = exports.DynamicEntryPlugin = exports.DllReferencePlugin = exports.DllPlugin = exports.Dependency = exports.DefinePlugin = exports.ContextReplacementPlugin = exports.Compiler = exports.Compilation = exports.BannerPlugin = exports.AsyncDependenciesBlock = exports.experiments = exports.sources = exports.util = exports.sharing = exports.container = exports.library = exports.wasm = exports.electron = exports.node = exports.webworker = exports.web = exports.optimize = exports.javascript = exports.config = exports.ValidationError = exports.RuntimeGlobals = exports.ModuleFilenameHelpers = exports.version = exports.rspack = exports.RspackDynamicDll = exports.RspackChain = void 0;
4
+ exports.MultiStats = exports.WebpackOptionsApply = exports.WebpackError = exports.Template = exports.Stats = exports.SourceMapDevToolPlugin = exports.SingleEntryPlugin = void 0;
5
5
  const core_1 = require("@rspack/core");
6
6
  Object.defineProperty(exports, "rspack", { enumerable: true, get: function () { return core_1.rspack; } });
7
7
  var base_rspack_1 = require("./config/base.rspack");
8
8
  Object.defineProperty(exports, "RspackChain", { enumerable: true, get: function () { return base_rspack_1.RspackChain; } });
9
+ var rspack_dynamic_dll_1 = require("./dynamic-dll/rspack-dynamic-dll");
10
+ Object.defineProperty(exports, "RspackDynamicDll", { enumerable: true, get: function () { return rspack_dynamic_dll_1.RspackDynamicDll; } });
9
11
  /**
10
12
  * re-export for shuvi plugin
11
13
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shuvi/toolpack",
3
- "version": "2.0.0-dev.12",
3
+ "version": "2.0.0-dev.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/shuvijs/shuvi.git",
@@ -36,9 +36,9 @@
36
36
  "@rspack/cli": "^1.4.2",
37
37
  "@rspack/core": "^1.4.2",
38
38
  "@rspack/plugin-html": "^0.5.8",
39
- "@shuvi/compiler": "2.0.0-dev.12",
40
- "@shuvi/shared": "2.0.0-dev.12",
41
- "@shuvi/utils": "2.0.0-dev.12",
39
+ "@shuvi/compiler": "2.0.0-dev.13",
40
+ "@shuvi/shared": "2.0.0-dev.13",
41
+ "@shuvi/utils": "2.0.0-dev.13",
42
42
  "@swc/helpers": "0.4.3",
43
43
  "babel-loader": "8.2.2",
44
44
  "babel-plugin-syntax-jsx": "6.18.0",