rspack-plugin-mock 1.3.0 → 2.1.0
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/README.md +413 -67
- package/README.zh-CN.md +412 -67
- package/dist/{helper.d.mts → helper.d.ts} +46 -8
- package/dist/helper.js +267 -0
- package/dist/{types-Bt_OTa7I.d.mts → index-BMMGM-eD.d.ts} +537 -172
- package/dist/index.d.ts +16 -0
- package/dist/index.js +87 -0
- package/dist/json5-loader.mjs +8 -0
- package/dist/logger-CzeuHKAL.js +1563 -0
- package/dist/options-CI0LRpJZ.js +487 -0
- package/dist/rsbuild.d.ts +8 -0
- package/dist/rsbuild.js +80 -0
- package/dist/server-pC78IYdH.d.ts +113 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2 -0
- package/package.json +38 -34
- package/dist/helper.mjs +0 -4
- package/dist/index.d.mts +0 -13
- package/dist/index.mjs +0 -1
- package/dist/json5-loader.cjs +0 -1
- package/dist/options-BUfaThYe.mjs +0 -43
- package/dist/rsbuild.d.mts +0 -7
- package/dist/rsbuild.mjs +0 -1
- package/dist/server-4ETytB7L.d.mts +0 -89
- package/dist/server.d.mts +0 -3
- package/dist/server.mjs +0 -1
- package/dist/ws-BM06pHhL.mjs +0 -1
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { c as processRawData, d as normalizePath, f as vfs, h as createMatcher, m as getPackageDeps, p as getPackageDepList, s as processMockData, t as createLogger } from "./logger-CzeuHKAL.js";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { attemptAsync, isBoolean, isPlainObject, toArray, uniq } from "@pengzhanbo/utils";
|
|
6
|
+
import * as rspackCore from "@rspack/core";
|
|
7
|
+
import fs, { promises } from "node:fs";
|
|
8
|
+
import fsp from "node:fs/promises";
|
|
9
|
+
import ansis from "ansis";
|
|
10
|
+
import { glob } from "tinyglobby";
|
|
11
|
+
import isCore from "is-core-module";
|
|
12
|
+
import { loadPackageJSONSync } from "local-pkg";
|
|
13
|
+
import { pathToFileURL } from "node:url";
|
|
14
|
+
import { createHash } from "node:crypto";
|
|
15
|
+
import EventEmitter from "node:events";
|
|
16
|
+
import chokidar from "chokidar";
|
|
17
|
+
//#region src/compiler/createRspackCompiler.ts
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
function createCompiler(options, callback) {
|
|
20
|
+
const rspackOptions = resolveRspackOptions(options);
|
|
21
|
+
const isWatch = rspackOptions.watch === true;
|
|
22
|
+
async function handler(err, stats) {
|
|
23
|
+
const name = "[rspack:mock]";
|
|
24
|
+
const logError = (...args) => {
|
|
25
|
+
if (stats) stats.compilation.getLogger(name).error(...args);
|
|
26
|
+
else console.error(ansis.red(name), ...args);
|
|
27
|
+
};
|
|
28
|
+
if (err) {
|
|
29
|
+
logError(err.stack || err);
|
|
30
|
+
if ("details" in err) logError(err.details);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (stats?.hasErrors()) logError(stats.toJson().errors);
|
|
34
|
+
const code = vfs.readFileSync("/output.js", "utf-8");
|
|
35
|
+
const externals = [];
|
|
36
|
+
if (!isWatch) {
|
|
37
|
+
const modules = stats?.toJson().modules || [];
|
|
38
|
+
const aliasList = Object.keys(options.alias || {}).map((key) => key.replace(/\$$/g, ""));
|
|
39
|
+
for (const { name } of modules) if (name?.startsWith("external")) {
|
|
40
|
+
const packageName = normalizePackageName(name);
|
|
41
|
+
if (!isCore(packageName) && !aliasList.includes(packageName)) externals.push(normalizePackageName(name));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
await callback({
|
|
45
|
+
code,
|
|
46
|
+
externals
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const compiler = rspackCore.rspack(rspackOptions);
|
|
50
|
+
compiler.outputFileSystem = vfs;
|
|
51
|
+
if (!isWatch) compiler.run(async (...args) => {
|
|
52
|
+
await handler(...args);
|
|
53
|
+
compiler.close(() => {});
|
|
54
|
+
});
|
|
55
|
+
else compiler.watch({}, handler);
|
|
56
|
+
return compiler;
|
|
57
|
+
}
|
|
58
|
+
function transformWithRspack(options) {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
createCompiler({
|
|
61
|
+
...options,
|
|
62
|
+
watch: false
|
|
63
|
+
}, (result) => {
|
|
64
|
+
resolve(result);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function normalizePackageName(name) {
|
|
69
|
+
const filepath = name.replace("external ", "").slice(1, -1);
|
|
70
|
+
const [scope, packageName] = filepath.split("/");
|
|
71
|
+
if (filepath[0] === "@") return `${scope}/${packageName}`;
|
|
72
|
+
return scope;
|
|
73
|
+
}
|
|
74
|
+
function resolveRspackOptions({ cwd, isEsm = true, entryFile, plugins, alias, watch = false }) {
|
|
75
|
+
const targets = ["node >= 20.0.0"];
|
|
76
|
+
if (alias && "@swc/helpers" in alias) delete alias["@swc/helpers"];
|
|
77
|
+
const externals = getPackageDepList(cwd);
|
|
78
|
+
const externalPattern = new RegExp(`^(${externals.join("|")})($|/)`, "i");
|
|
79
|
+
return {
|
|
80
|
+
mode: "production",
|
|
81
|
+
context: cwd,
|
|
82
|
+
entry: entryFile,
|
|
83
|
+
watch,
|
|
84
|
+
target: `node${(process.versions.node || "").replace(/\.\d+$/, "")}`,
|
|
85
|
+
externalsType: isEsm ? "module" : "commonjs2",
|
|
86
|
+
externals: [externalPattern],
|
|
87
|
+
resolve: {
|
|
88
|
+
alias,
|
|
89
|
+
extensions: [
|
|
90
|
+
".js",
|
|
91
|
+
".ts",
|
|
92
|
+
".cjs",
|
|
93
|
+
".mjs",
|
|
94
|
+
".json5",
|
|
95
|
+
".json"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
plugins,
|
|
99
|
+
output: {
|
|
100
|
+
library: { type: !isEsm ? "commonjs2" : "module" },
|
|
101
|
+
filename: "output.js",
|
|
102
|
+
module: isEsm,
|
|
103
|
+
path: "/"
|
|
104
|
+
},
|
|
105
|
+
optimization: { minimize: !watch },
|
|
106
|
+
node: {
|
|
107
|
+
__dirname: false,
|
|
108
|
+
__filename: false
|
|
109
|
+
},
|
|
110
|
+
module: { rules: [
|
|
111
|
+
{
|
|
112
|
+
test: /\.json5?$/,
|
|
113
|
+
loader: require.resolve("#json5-loader"),
|
|
114
|
+
type: "javascript/auto"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
test: /\.[cm]?js$/,
|
|
118
|
+
use: [{
|
|
119
|
+
loader: "builtin:swc-loader",
|
|
120
|
+
options: {
|
|
121
|
+
jsc: { parser: { syntax: "ecmascript" } },
|
|
122
|
+
env: { targets }
|
|
123
|
+
}
|
|
124
|
+
}]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
test: /\.[cm]?ts$/,
|
|
128
|
+
use: [{
|
|
129
|
+
loader: "builtin:swc-loader",
|
|
130
|
+
options: {
|
|
131
|
+
jsc: { parser: { syntax: "typescript" } },
|
|
132
|
+
env: { targets }
|
|
133
|
+
}
|
|
134
|
+
}]
|
|
135
|
+
}
|
|
136
|
+
] }
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/compiler/loadFromCode.ts
|
|
141
|
+
async function loadFromCode({ filepath, code, isESM, cwd }) {
|
|
142
|
+
filepath = path.resolve(cwd, filepath);
|
|
143
|
+
const ext = isESM ? ".mjs" : ".cjs";
|
|
144
|
+
const filepathTmp = `${filepath}.${getHash(code)}${ext}`;
|
|
145
|
+
await promises.writeFile(filepathTmp, code, "utf8");
|
|
146
|
+
const [, mod] = await attemptAsync(importDefault, String(pathToFileURL(filepathTmp)));
|
|
147
|
+
await attemptAsync(promises.unlink, filepathTmp);
|
|
148
|
+
return mod;
|
|
149
|
+
}
|
|
150
|
+
async function importDefault(filepath) {
|
|
151
|
+
const mod = await import(filepath);
|
|
152
|
+
return mod.default || mod;
|
|
153
|
+
}
|
|
154
|
+
function getHash(str) {
|
|
155
|
+
return createHash("md5").update(str).digest("hex");
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/compiler/mockCompiler.ts
|
|
159
|
+
function createMockCompiler(options) {
|
|
160
|
+
return new MockCompiler(options);
|
|
161
|
+
}
|
|
162
|
+
var MockCompiler = class extends EventEmitter {
|
|
163
|
+
cwd;
|
|
164
|
+
mockWatcher;
|
|
165
|
+
entryFile;
|
|
166
|
+
deps = [];
|
|
167
|
+
isESM = false;
|
|
168
|
+
_mockData = {};
|
|
169
|
+
watchInfo;
|
|
170
|
+
compiler;
|
|
171
|
+
constructor(options) {
|
|
172
|
+
super();
|
|
173
|
+
this.options = options;
|
|
174
|
+
this.cwd = options.cwd || process.cwd();
|
|
175
|
+
try {
|
|
176
|
+
const pkg = loadPackageJSONSync(this.cwd);
|
|
177
|
+
this.isESM = pkg?.type === "module";
|
|
178
|
+
} catch {}
|
|
179
|
+
this.entryFile = path.resolve(process.cwd(), "node_modules/.cache/mock-server/mock-server.ts");
|
|
180
|
+
}
|
|
181
|
+
get mockData() {
|
|
182
|
+
return this._mockData;
|
|
183
|
+
}
|
|
184
|
+
async run() {
|
|
185
|
+
const { include, exclude } = this.options;
|
|
186
|
+
const { pattern, ignore, isMatch } = createMatcher(include, exclude);
|
|
187
|
+
const files = await glob(pattern, {
|
|
188
|
+
ignore,
|
|
189
|
+
cwd: path.join(this.cwd, this.options.dir)
|
|
190
|
+
});
|
|
191
|
+
this.deps = files.map((file) => normalizePath(file));
|
|
192
|
+
this.updateMockEntry();
|
|
193
|
+
this.watchMockFiles(isMatch);
|
|
194
|
+
const { plugins, alias } = this.options;
|
|
195
|
+
const options = {
|
|
196
|
+
isEsm: this.isESM,
|
|
197
|
+
cwd: this.cwd,
|
|
198
|
+
plugins,
|
|
199
|
+
entryFile: this.entryFile,
|
|
200
|
+
alias,
|
|
201
|
+
watch: true
|
|
202
|
+
};
|
|
203
|
+
this.compiler = createCompiler(options, async ({ code }) => {
|
|
204
|
+
try {
|
|
205
|
+
const result = await loadFromCode({
|
|
206
|
+
filepath: "mock.bundle.js",
|
|
207
|
+
code,
|
|
208
|
+
isESM: this.isESM,
|
|
209
|
+
cwd: this.cwd
|
|
210
|
+
});
|
|
211
|
+
this._mockData = processMockData(processRawData(result));
|
|
212
|
+
this.emit("update", this.watchInfo || {});
|
|
213
|
+
} catch (e) {
|
|
214
|
+
this.options.logger.error(e.stack || e.message);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
close() {
|
|
219
|
+
this.mockWatcher.close();
|
|
220
|
+
this.compiler?.close(() => {});
|
|
221
|
+
this.emit("close");
|
|
222
|
+
}
|
|
223
|
+
updateAlias(alias) {
|
|
224
|
+
this.options.alias = {
|
|
225
|
+
...this.options.alias,
|
|
226
|
+
...alias
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async updateMockEntry() {
|
|
230
|
+
await writeMockEntryFile(this.entryFile, this.deps, this.cwd, this.options.dir);
|
|
231
|
+
}
|
|
232
|
+
watchMockFiles(isMatch) {
|
|
233
|
+
const watcher = this.mockWatcher = chokidar.watch(this.options.dir, {
|
|
234
|
+
ignoreInitial: true,
|
|
235
|
+
cwd: this.cwd,
|
|
236
|
+
ignored: (filepath, stats) => {
|
|
237
|
+
if (filepath.includes("node_modules")) return true;
|
|
238
|
+
return !!stats?.isFile() && !isMatch(filepath);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
watcher.on("add", (filepath) => {
|
|
242
|
+
filepath = normalizePath(filepath);
|
|
243
|
+
if (isMatch(filepath)) {
|
|
244
|
+
this.watchInfo = {
|
|
245
|
+
filepath,
|
|
246
|
+
type: "add"
|
|
247
|
+
};
|
|
248
|
+
this.deps = uniq([...this.deps, filepath]);
|
|
249
|
+
this.updateMockEntry();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
watcher.on("change", (filepath) => {
|
|
253
|
+
filepath = normalizePath(filepath);
|
|
254
|
+
if (isMatch(filepath)) this.watchInfo = {
|
|
255
|
+
filepath,
|
|
256
|
+
type: "change"
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
watcher.on("unlink", async (filepath) => {
|
|
260
|
+
filepath = normalizePath(filepath);
|
|
261
|
+
if (isMatch(filepath)) {
|
|
262
|
+
this.watchInfo = {
|
|
263
|
+
filepath,
|
|
264
|
+
type: "unlink"
|
|
265
|
+
};
|
|
266
|
+
this.deps = this.deps.filter((dep) => dep !== filepath);
|
|
267
|
+
this.updateMockEntry();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region package.json
|
|
274
|
+
var name = "rspack-plugin-mock";
|
|
275
|
+
var version = "2.1.0";
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/build/packageJson.ts
|
|
278
|
+
function generatePackageJson(options, externals) {
|
|
279
|
+
const deps = getPackageDeps(options.context);
|
|
280
|
+
const exclude = [
|
|
281
|
+
name,
|
|
282
|
+
"connect",
|
|
283
|
+
"cors"
|
|
284
|
+
];
|
|
285
|
+
const mockPkg = {
|
|
286
|
+
name: "mock-server",
|
|
287
|
+
type: "module",
|
|
288
|
+
scripts: { start: "node index.js" },
|
|
289
|
+
dependencies: {
|
|
290
|
+
connect: "^3.7.0",
|
|
291
|
+
[name]: `^${version}`,
|
|
292
|
+
cors: "^2.8.5"
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
externals.filter((dep) => !exclude.includes(dep)).forEach((dep) => {
|
|
296
|
+
mockPkg.dependencies[dep] = deps[dep] || "latest";
|
|
297
|
+
});
|
|
298
|
+
return JSON.stringify(mockPkg, null, 2);
|
|
299
|
+
}
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/build/serverEntryCode.ts
|
|
302
|
+
function generatorServerEntryCode({ proxies, wsPrefix, cookiesOptions, bodyParserOptions, priority, build }) {
|
|
303
|
+
const { serverPort, log } = build;
|
|
304
|
+
return `import { createServer } from 'node:http';
|
|
305
|
+
import connect from 'connect';
|
|
306
|
+
import corsMiddleware from 'cors';
|
|
307
|
+
import {
|
|
308
|
+
baseMiddleware,
|
|
309
|
+
createLogger,
|
|
310
|
+
mockWebSocket,
|
|
311
|
+
processMockData,
|
|
312
|
+
processRawData
|
|
313
|
+
} from 'rspack-plugin-mock/server';
|
|
314
|
+
import rawData from './mock-data.js';
|
|
315
|
+
|
|
316
|
+
const app = connect();
|
|
317
|
+
const server = createServer(app);
|
|
318
|
+
const logger = createLogger('mock-server', '${log}');
|
|
319
|
+
const proxies = ${JSON.stringify(proxies)};
|
|
320
|
+
const wsProxies = ${JSON.stringify(toArray(wsPrefix))};
|
|
321
|
+
const cookiesOptions = ${JSON.stringify(cookiesOptions)};
|
|
322
|
+
const bodyParserOptions = ${JSON.stringify(bodyParserOptions)};
|
|
323
|
+
const priority = ${JSON.stringify(priority)};
|
|
324
|
+
const mockConfig = {
|
|
325
|
+
mockData: processMockData(processRawData(rawData)),
|
|
326
|
+
on: () => {},
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
mockWebSocket(mockConfig, server, { wsProxies, cookiesOptions, logger });
|
|
330
|
+
|
|
331
|
+
app.use(corsMiddleware());
|
|
332
|
+
app.use(baseMiddleware(mockConfig, {
|
|
333
|
+
formidableOptions: { multiples: true },
|
|
334
|
+
proxies,
|
|
335
|
+
priority,
|
|
336
|
+
cookiesOptions,
|
|
337
|
+
bodyParserOptions,
|
|
338
|
+
logger,
|
|
339
|
+
}));
|
|
340
|
+
|
|
341
|
+
server.listen(${serverPort});
|
|
342
|
+
|
|
343
|
+
console.log('listen: http://localhost:${serverPort}');
|
|
344
|
+
`;
|
|
345
|
+
}
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/build/writeEntryFile.ts
|
|
348
|
+
async function writeMockEntryFile(entryFile, files, cwd, dir) {
|
|
349
|
+
const importers = [];
|
|
350
|
+
const exporters = [];
|
|
351
|
+
for (const [index, filepath] of files.entries()) {
|
|
352
|
+
const relative = normalizePath(path.join(dir, filepath));
|
|
353
|
+
const file = normalizePath(path.join(cwd, relative));
|
|
354
|
+
importers.push(`import * as m${index} from '${file}'`);
|
|
355
|
+
exporters.push(`[m${index}, '${relative}']`);
|
|
356
|
+
}
|
|
357
|
+
const code = `${importers.join("\n")}\n\nexport default [\n ${exporters.join(",\n ")}\n]`;
|
|
358
|
+
const dirname = path.dirname(entryFile);
|
|
359
|
+
if (!fs.existsSync(dirname)) await fsp.mkdir(dirname, { recursive: true });
|
|
360
|
+
await fsp.writeFile(entryFile, code, "utf8");
|
|
361
|
+
}
|
|
362
|
+
//#endregion
|
|
363
|
+
//#region src/build/generate.ts
|
|
364
|
+
async function buildMockServer(options, outputDir) {
|
|
365
|
+
const buildOptions = options.build;
|
|
366
|
+
const entryFile = path.resolve(process.cwd(), "node_modules/.cache/mock-server/mock-server.ts");
|
|
367
|
+
const { pattern, ignore } = createMatcher(options.include, options.exclude);
|
|
368
|
+
await writeMockEntryFile(entryFile, await glob(pattern, {
|
|
369
|
+
ignore,
|
|
370
|
+
cwd: path.join(options.cwd, options.dir)
|
|
371
|
+
}), options.cwd, options.dir);
|
|
372
|
+
const { code, externals } = await transformWithRspack({
|
|
373
|
+
entryFile,
|
|
374
|
+
cwd: options.cwd,
|
|
375
|
+
plugins: options.plugins,
|
|
376
|
+
alias: options.alias
|
|
377
|
+
});
|
|
378
|
+
await fsp.unlink(entryFile);
|
|
379
|
+
const outputList = [
|
|
380
|
+
{
|
|
381
|
+
filename: "mock-data.js",
|
|
382
|
+
source: code
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
filename: "index.js",
|
|
386
|
+
source: generatorServerEntryCode(options)
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
filename: "package.json",
|
|
390
|
+
source: generatePackageJson(options, externals)
|
|
391
|
+
}
|
|
392
|
+
];
|
|
393
|
+
if (options.record.enabled && buildOptions.includeRecord) {
|
|
394
|
+
const files = await glob(path.join(options.record.dir, "**/*.json"), {
|
|
395
|
+
cwd: options.cwd,
|
|
396
|
+
dot: true
|
|
397
|
+
});
|
|
398
|
+
for (const file of files) outputList.push({
|
|
399
|
+
filename: path.join(outputDir, file),
|
|
400
|
+
source: await fsp.readFile(path.join(options.cwd, file), "utf-8")
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
const dist = path.resolve(outputDir, options.build.dist);
|
|
404
|
+
options.logger.info(`${ansis.green("✓")} generate mock server in ${ansis.cyan(path.relative(process.cwd(), dist))}`);
|
|
405
|
+
if (!fs.existsSync(dist)) await fsp.mkdir(dist, { recursive: true });
|
|
406
|
+
for (const { filename, source } of outputList) {
|
|
407
|
+
await fsp.writeFile(path.join(dist, filename), source, "utf8");
|
|
408
|
+
const sourceSize = (source.length / 1024).toFixed(2);
|
|
409
|
+
const space = filename.length < 24 ? " ".repeat(24 - filename.length) : "";
|
|
410
|
+
options.logger.info(` ${ansis.green(filename)}${space}${ansis.bold.dim(`${sourceSize} kB`)}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/core/options.ts
|
|
415
|
+
function resolvePluginOptions({ prefix = [], wsPrefix = [], cwd, dir = "mock", include = ["**/*.mock.{js,ts,cjs,mjs,json,json5}"], exclude = [], reload = false, log = "info", cors = true, formidableOptions = {}, build = false, cookiesOptions = {}, bodyParserOptions = {}, priority = {}, activeScene = [], record = false, replay }, { alias, context, plugins, proxies: rawProxies }) {
|
|
416
|
+
const logger = createLogger("rspack:mock", isBoolean(log) ? log ? "info" : "error" : log);
|
|
417
|
+
const proxies = [...toArray(prefix), ...rawProxies];
|
|
418
|
+
const wsProxies = toArray(wsPrefix);
|
|
419
|
+
if (!proxies.length && !wsProxies.length) logger.warn(`No proxy was configured, mock server will not work. See ${ansis.cyan("https://vite-plugin-mock-dev-server.netlify.app/guide/usage")}`);
|
|
420
|
+
const enabled = !!cors;
|
|
421
|
+
let corsOptions = {};
|
|
422
|
+
if (enabled && isPlainObject(cors)) corsOptions = {
|
|
423
|
+
...corsOptions,
|
|
424
|
+
...cors
|
|
425
|
+
};
|
|
426
|
+
cwd = cwd || context || process.cwd();
|
|
427
|
+
const resolvedRecord = resolveRecordOptions(cwd, dir, record);
|
|
428
|
+
return {
|
|
429
|
+
enabled: true,
|
|
430
|
+
prefix,
|
|
431
|
+
wsPrefix,
|
|
432
|
+
cwd,
|
|
433
|
+
dir,
|
|
434
|
+
include,
|
|
435
|
+
exclude,
|
|
436
|
+
reload,
|
|
437
|
+
cors: enabled ? corsOptions : false,
|
|
438
|
+
cookiesOptions,
|
|
439
|
+
log,
|
|
440
|
+
formidableOptions: {
|
|
441
|
+
multiples: true,
|
|
442
|
+
...formidableOptions
|
|
443
|
+
},
|
|
444
|
+
bodyParserOptions,
|
|
445
|
+
priority,
|
|
446
|
+
build: build ? {
|
|
447
|
+
serverPort: 8080,
|
|
448
|
+
dist: "mockServer",
|
|
449
|
+
log: "error",
|
|
450
|
+
...typeof build === "object" ? build : {}
|
|
451
|
+
} : false,
|
|
452
|
+
alias,
|
|
453
|
+
plugins,
|
|
454
|
+
proxies,
|
|
455
|
+
wsProxies,
|
|
456
|
+
logger,
|
|
457
|
+
activeScene: toArray(activeScene),
|
|
458
|
+
record: resolvedRecord,
|
|
459
|
+
replay: replay ?? resolvedRecord.enabled ?? false
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Resolve record options
|
|
464
|
+
*
|
|
465
|
+
* 解析录制配置
|
|
466
|
+
*
|
|
467
|
+
* @param cwd - Current working directory / 当前工作目录
|
|
468
|
+
* @param dir - Mock context directory / 模拟上下文目录
|
|
469
|
+
* @param record - Record options / 录制配置
|
|
470
|
+
* @returns Resolved record options / 解析后的录制配置
|
|
471
|
+
*/
|
|
472
|
+
function resolveRecordOptions(cwd, dir, record) {
|
|
473
|
+
const recordOptions = typeof record === "boolean" ? { enabled: record } : record;
|
|
474
|
+
const expires = recordOptions?.expires ?? 0;
|
|
475
|
+
return {
|
|
476
|
+
enabled: recordOptions?.enabled ?? false,
|
|
477
|
+
cwd,
|
|
478
|
+
dir: path.join(dir, recordOptions?.dir || ".recordings"),
|
|
479
|
+
overwrite: recordOptions?.overwrite ?? true,
|
|
480
|
+
status: toArray(recordOptions?.status).map(Number),
|
|
481
|
+
expires: expires === 0 ? Number.MAX_SAFE_INTEGER : expires * 1e3,
|
|
482
|
+
gitignore: recordOptions?.gitignore ?? true,
|
|
483
|
+
filter: recordOptions?.filter || (() => true)
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
//#endregion
|
|
487
|
+
export { buildMockServer as n, createMockCompiler as r, resolvePluginOptions as t };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { A as ResponseBody, C as HandleFunction, D as MockResponse, E as MockRequest, M as CookiesOption, N as GetCookieOption, O as NextFunction, P as SetCookieOption, S as ExtraRequest, T as Method, _ as RecordedMeta, a as MockWebsocketItem, b as RecordedRes, c as MockHttpItem, d as LogType, f as MockMatchPriority, g as RecordOptions, h as ServerBuildOption, i as MockOptions, j as SimpleHandleFunction, k as NextHandleFunction, l as BodyParserOptions, m as MockServerPluginOptions, n as HttpProxyPlugin, o as WebSocketSetupContext, p as MockMatchSpecialPriority, r as PathFilter, s as MockErrorConfig, t as FormidableFile, u as LogLevel, v as RecordedReq, w as Headers, x as ResolvedRecordOptions, y as RecordedRequest } from "./index-BMMGM-eD.js";
|
|
2
|
+
import { DefineMockDataOptions, HeaderStream, MockData, SSEMessage, createDefineMock, createSSEStream, defineMock, defineMockData } from "./helper.js";
|
|
3
|
+
import { RsbuildPlugin } from "@rsbuild/core";
|
|
4
|
+
|
|
5
|
+
//#region src/core/rsbuild.d.ts
|
|
6
|
+
declare function pluginMockServer(options?: MockServerPluginOptions): RsbuildPlugin;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { BodyParserOptions, CookiesOption, DefineMockDataOptions, ExtraRequest, type FormidableFile, GetCookieOption, HandleFunction, HeaderStream, Headers, HttpProxyPlugin, LogLevel, LogType, Method, MockData, MockErrorConfig, type MockHttpItem, MockMatchPriority, MockMatchSpecialPriority, type MockOptions, type MockRequest, MockResponse, type MockServerPluginOptions, type MockWebsocketItem, NextFunction, NextHandleFunction, PathFilter, RecordOptions, RecordedMeta, RecordedReq, RecordedRequest, RecordedRes, ResolvedRecordOptions, ResponseBody, SSEMessage, ServerBuildOption, SetCookieOption, SimpleHandleFunction, WebSocketSetupContext, createDefineMock, createSSEStream, defineMock, defineMockData, pluginMockServer };
|
package/dist/rsbuild.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { a as rewriteRequest, i as createMockMiddleware, o as Recorder, r as mockWebSocket } from "./logger-CzeuHKAL.js";
|
|
2
|
+
import { n as buildMockServer, r as createMockCompiler, t as resolvePluginOptions } from "./options-CI0LRpJZ.js";
|
|
3
|
+
import { createDefineMock, createSSEStream, defineMock, defineMockData } from "./helper.js";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { isArray, objectEntries, toArray } from "@pengzhanbo/utils";
|
|
7
|
+
import rspack from "@rspack/core";
|
|
8
|
+
//#region src/core/rsbuild.ts
|
|
9
|
+
function pluginMockServer(options = {}) {
|
|
10
|
+
return {
|
|
11
|
+
name: "plugin-mock-server",
|
|
12
|
+
setup(api) {
|
|
13
|
+
if (options.enabled === false) return;
|
|
14
|
+
const rsbuildConfig = api.getRsbuildConfig();
|
|
15
|
+
const resolvedOptions = resolvePluginOptions(options, {
|
|
16
|
+
proxies: resolveConfigProxies(rsbuildConfig),
|
|
17
|
+
alias: {},
|
|
18
|
+
context: api.context.rootPath,
|
|
19
|
+
plugins: [new rspack.DefinePlugin(rsbuildConfig.source?.define || {})]
|
|
20
|
+
});
|
|
21
|
+
if (api.context.action === "build") {
|
|
22
|
+
if (resolvedOptions.build) api.onAfterBuild(async () => {
|
|
23
|
+
const config = api.getNormalizedConfig();
|
|
24
|
+
await buildMockServer(resolvedOptions, path.resolve(process.cwd(), config.output.distPath.root || "dist"));
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const mockCompiler = createMockCompiler(resolvedOptions);
|
|
29
|
+
api.onAfterCreateCompiler(({ compiler }) => {
|
|
30
|
+
if ("compilers" in compiler) compiler.compilers.forEach((compiler) => {
|
|
31
|
+
mockCompiler.updateAlias(compiler.options.resolve?.alias || {});
|
|
32
|
+
});
|
|
33
|
+
else mockCompiler.updateAlias(compiler.options.resolve?.alias || {});
|
|
34
|
+
});
|
|
35
|
+
let recorder = null;
|
|
36
|
+
if (resolvedOptions.record.enabled) recorder = new Recorder(resolvedOptions.record);
|
|
37
|
+
function wrapProxyOptions(options) {
|
|
38
|
+
const plugins = options.plugins ??= [];
|
|
39
|
+
plugins.push((proxyServer) => proxyServer.on("proxyReq", rewriteRequest));
|
|
40
|
+
if (resolvedOptions.record.enabled && recorder) plugins.push(recorder.getPlugin());
|
|
41
|
+
return options;
|
|
42
|
+
}
|
|
43
|
+
api.modifyRsbuildConfig((config) => {
|
|
44
|
+
if (!config.server?.proxy) return;
|
|
45
|
+
if (isArray(config.server.proxy)) config.server.proxy = config.server.proxy.map((item) => item.ws ? item : wrapProxyOptions(item));
|
|
46
|
+
else if (config.server.proxy) {
|
|
47
|
+
const proxy = config.server.proxy;
|
|
48
|
+
Object.keys(proxy).forEach((key) => {
|
|
49
|
+
const target = proxy[key];
|
|
50
|
+
const options = typeof target === "string" ? { target } : target;
|
|
51
|
+
if (options.ws) return;
|
|
52
|
+
proxy[key] = wrapProxyOptions(options);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
function initMockServer(server) {
|
|
57
|
+
server.middlewares.use(createMockMiddleware(mockCompiler, resolvedOptions));
|
|
58
|
+
if (resolvedOptions.reload && api.context.action === "dev") mockCompiler.on("update", () => server.sockWrite("static-changed"));
|
|
59
|
+
if (toArray(resolvedOptions.wsPrefix).length > 0) mockWebSocket(mockCompiler, server.httpServer, resolvedOptions);
|
|
60
|
+
mockCompiler.run();
|
|
61
|
+
}
|
|
62
|
+
api.onBeforeStartDevServer(({ server }) => initMockServer(server));
|
|
63
|
+
api.onBeforeStartPreviewServer(({ server }) => initMockServer(server));
|
|
64
|
+
api.onExit(() => mockCompiler.close());
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function resolveConfigProxies(config) {
|
|
69
|
+
config.server ??= {};
|
|
70
|
+
const proxy = config.server.proxy ??= {};
|
|
71
|
+
const proxies = [];
|
|
72
|
+
if (isArray(proxy)) {
|
|
73
|
+
for (const item of proxy) if (item.pathFilter && !item.ws) proxies.push(...toArray(item.pathFilter));
|
|
74
|
+
} else objectEntries(proxy).forEach(([pathFilter, opt]) => {
|
|
75
|
+
if (typeof opt === "string" || !opt.ws) proxies.push(pathFilter);
|
|
76
|
+
});
|
|
77
|
+
return proxies;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { createDefineMock, createSSEStream, defineMock, defineMockData, pluginMockServer };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { a as MockWebsocketItem, c as MockHttpItem, h as ServerBuildOption, i as MockOptions, k as NextHandleFunction, m as MockServerPluginOptions, r as PathFilter, u as LogLevel, x as ResolvedRecordOptions } from "./index-BMMGM-eD.js";
|
|
2
|
+
import { Arrayable } from "@pengzhanbo/utils";
|
|
3
|
+
import { Compiler, RspackPluginInstance } from "@rspack/core";
|
|
4
|
+
import { Matcher } from "picomatch";
|
|
5
|
+
import EventEmitter from "node:events";
|
|
6
|
+
import { FSWatcher } from "chokidar";
|
|
7
|
+
import { CorsOptions } from "cors";
|
|
8
|
+
import { Server } from "node:http";
|
|
9
|
+
import { Http2SecureServer } from "node:http2";
|
|
10
|
+
|
|
11
|
+
//#region src/core/logger.d.ts
|
|
12
|
+
interface Logger {
|
|
13
|
+
debug: (msg: string, level?: boolean | LogLevel) => void;
|
|
14
|
+
info: (msg: string, level?: boolean | LogLevel) => void;
|
|
15
|
+
warn: (msg: string, level?: boolean | LogLevel) => void;
|
|
16
|
+
error: (msg: string, level?: boolean | LogLevel) => void;
|
|
17
|
+
}
|
|
18
|
+
declare const logLevels: Record<LogLevel, number>;
|
|
19
|
+
declare function createLogger(prefix: string, defaultLevel?: LogLevel): Logger;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/core/options.d.ts
|
|
22
|
+
interface ResolvedCompilerOptions {
|
|
23
|
+
alias: Record<string, Arrayable<false | string>>;
|
|
24
|
+
proxies: PathFilter[];
|
|
25
|
+
wsProxies: PathFilter[];
|
|
26
|
+
plugins: RspackPluginInstance[];
|
|
27
|
+
context?: string;
|
|
28
|
+
}
|
|
29
|
+
type ResolvePluginOptions = Required<Omit<MockServerPluginOptions, "build">> & ResolvedCompilerOptions & {
|
|
30
|
+
logger: Logger;
|
|
31
|
+
build: false | ServerBuildOption;
|
|
32
|
+
cors: false | CorsOptions;
|
|
33
|
+
record: ResolvedRecordOptions;
|
|
34
|
+
activeScene: string[];
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/compiler/mockCompiler.d.ts
|
|
38
|
+
declare class MockCompiler extends EventEmitter {
|
|
39
|
+
options: ResolvePluginOptions;
|
|
40
|
+
cwd: string;
|
|
41
|
+
mockWatcher!: FSWatcher;
|
|
42
|
+
entryFile!: string;
|
|
43
|
+
deps: string[];
|
|
44
|
+
isESM: boolean;
|
|
45
|
+
private _mockData;
|
|
46
|
+
private watchInfo?;
|
|
47
|
+
compiler?: Compiler | null;
|
|
48
|
+
constructor(options: ResolvePluginOptions);
|
|
49
|
+
get mockData(): Record<string, MockOptions>;
|
|
50
|
+
run(): Promise<void>;
|
|
51
|
+
close(): void;
|
|
52
|
+
updateAlias(alias: Record<string, false | string | (string | false)[]>): void;
|
|
53
|
+
updateMockEntry(): Promise<void>;
|
|
54
|
+
watchMockFiles(isMatch: Matcher): void;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/compiler/processData.d.ts
|
|
58
|
+
declare function processRawData(rawData: (readonly [any, string])[]): (MockHttpItem | MockWebsocketItem | MockOptions)[];
|
|
59
|
+
declare function processMockData(mockList: (MockHttpItem | MockWebsocketItem | MockOptions)[]): Record<string, MockOptions>;
|
|
60
|
+
declare function sortByValidator(mocks: MockOptions): (MockHttpItem | MockWebsocketItem)[];
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/mockHttp/middleware.d.ts
|
|
63
|
+
interface CreateMockMiddlewareOptions extends Pick<ResolvePluginOptions, "formidableOptions" | "cookiesOptions" | "bodyParserOptions" | "priority" | "record" | "replay" | "activeScene"> {
|
|
64
|
+
proxies: PathFilter[];
|
|
65
|
+
logger: Logger;
|
|
66
|
+
cors: false | CorsOptions;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create mock middleware
|
|
70
|
+
*
|
|
71
|
+
* 创建 Mock 中间件
|
|
72
|
+
*
|
|
73
|
+
* @param compiler - Compiler instance / 编译器实例
|
|
74
|
+
* @param options - Middleware options / 中间件配置项
|
|
75
|
+
* @param options.formidableOptions - Formidable options / Formidable 配置项
|
|
76
|
+
* @param options.bodyParserOptions - Body parser options / 请求体解析配置项
|
|
77
|
+
* @param options.proxies - Proxy paths / 代理路径
|
|
78
|
+
* @param options.cookiesOptions - Cookies options / Cookies 配置项
|
|
79
|
+
* @param options.logger - Logger instance / 日志实例
|
|
80
|
+
* @param options.priority - Path matching priority / 路径匹配优先级
|
|
81
|
+
* @param options.cors - CORS options / CORS 配置项
|
|
82
|
+
* @param options.record - Record options / 录制配置项
|
|
83
|
+
* @param options.replay - Replay options / 回放配置项
|
|
84
|
+
* @param options.activeScene - Active scene / 活动场景
|
|
85
|
+
*
|
|
86
|
+
* @returns Connect middleware function / Connect 中间件函数
|
|
87
|
+
*/
|
|
88
|
+
declare function createMockMiddleware(compiler: MockCompiler, {
|
|
89
|
+
formidableOptions,
|
|
90
|
+
bodyParserOptions,
|
|
91
|
+
proxies,
|
|
92
|
+
cookiesOptions,
|
|
93
|
+
logger,
|
|
94
|
+
priority,
|
|
95
|
+
cors: corsOptions,
|
|
96
|
+
record,
|
|
97
|
+
replay,
|
|
98
|
+
activeScene
|
|
99
|
+
}: CreateMockMiddlewareOptions): NextHandleFunction;
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/mockWebsocket/server.d.ts
|
|
102
|
+
interface MockSocketOptions {
|
|
103
|
+
wsProxies: PathFilter[];
|
|
104
|
+
cookiesOptions: MockServerPluginOptions["cookiesOptions"];
|
|
105
|
+
logger: Logger;
|
|
106
|
+
}
|
|
107
|
+
declare function mockWebSocket(compiler: MockCompiler, httpServer: Server | Http2SecureServer | null, {
|
|
108
|
+
wsProxies: proxies,
|
|
109
|
+
cookiesOptions,
|
|
110
|
+
logger
|
|
111
|
+
}: MockSocketOptions): void;
|
|
112
|
+
//#endregion
|
|
113
|
+
export { processMockData as a, MockCompiler as c, createLogger as d, logLevels as f, createMockMiddleware as i, ResolvePluginOptions as l, mockWebSocket as n, processRawData as o, CreateMockMiddlewareOptions as r, sortByValidator as s, MockSocketOptions as t, Logger as u };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as processMockData, d as createLogger, f as logLevels, i as createMockMiddleware, n as mockWebSocket, o as processRawData, r as CreateMockMiddlewareOptions, s as sortByValidator, t as MockSocketOptions, u as Logger } from "./server-pC78IYdH.js";
|
|
2
|
+
export { CreateMockMiddlewareOptions, Logger, MockSocketOptions, createLogger, createMockMiddleware, logLevels, mockWebSocket, processMockData, processRawData, sortByValidator };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { c as processRawData, i as createMockMiddleware, l as sortByValidator, n as logLevels, r as mockWebSocket, s as processMockData, t as createLogger } from "./logger-CzeuHKAL.js";
|
|
2
|
+
export { createLogger, createMockMiddleware, logLevels, mockWebSocket, processMockData, processRawData, sortByValidator };
|