rspack-plugin-mock 1.3.0 → 2.0.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 +7 -2
- package/README.zh-CN.md +7 -2
- package/dist/{helper.d.mts → helper.d.ts} +1 -1
- package/dist/helper.js +172 -0
- package/dist/{index.d.mts → index.d.ts} +3 -3
- package/dist/index.js +84 -0
- package/dist/json5-loader.mjs +8 -0
- package/dist/options-Bd0PSZeT.js +446 -0
- package/dist/{rsbuild.d.mts → rsbuild.d.ts} +1 -1
- package/dist/rsbuild.js +92 -0
- package/dist/{server-4ETytB7L.d.mts → server-_doRwsZm.d.ts} +15 -15
- package/dist/{server.d.mts → server.d.ts} +1 -2
- package/dist/server.js +2 -0
- package/dist/{types-Bt_OTa7I.d.mts → types-GT6M6WuI.d.ts} +3 -3
- package/dist/ws-BcLCWVaK.js +1003 -0
- package/package.json +33 -34
- package/dist/helper.mjs +0 -4
- package/dist/index.mjs +0 -1
- package/dist/json5-loader.cjs +0 -1
- package/dist/options-BUfaThYe.mjs +0 -43
- package/dist/rsbuild.mjs +0 -1
- package/dist/server.mjs +0 -1
- package/dist/ws-BM06pHhL.mjs +0 -1
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { a as processRawData, c as normalizePath, f as getPackageDepList, i as processMockData, l as vfs, m as createMatcher, p as getPackageDeps, u as createLogger } from "./ws-BcLCWVaK.js";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { attemptAsync, isBoolean, isPlainObject, toArray, uniq } from "@pengzhanbo/utils";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
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.0.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 entryFile = path.resolve(process.cwd(), "node_modules/.cache/mock-server/mock-server.ts");
|
|
366
|
+
const { pattern, ignore } = createMatcher(options.include, options.exclude);
|
|
367
|
+
await writeMockEntryFile(entryFile, await glob(pattern, {
|
|
368
|
+
ignore,
|
|
369
|
+
cwd: path.join(options.cwd, options.dir)
|
|
370
|
+
}), options.cwd, options.dir);
|
|
371
|
+
const { code, externals } = await transformWithRspack({
|
|
372
|
+
entryFile,
|
|
373
|
+
cwd: options.cwd,
|
|
374
|
+
plugins: options.plugins,
|
|
375
|
+
alias: options.alias
|
|
376
|
+
});
|
|
377
|
+
await fsp.unlink(entryFile);
|
|
378
|
+
const outputList = [
|
|
379
|
+
{
|
|
380
|
+
filename: "mock-data.js",
|
|
381
|
+
source: code
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
filename: "index.js",
|
|
385
|
+
source: generatorServerEntryCode(options)
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
filename: "package.json",
|
|
389
|
+
source: generatePackageJson(options, externals)
|
|
390
|
+
}
|
|
391
|
+
];
|
|
392
|
+
const dist = path.resolve(outputDir, options.build.dist);
|
|
393
|
+
options.logger.info(`${ansis.green("✓")} generate mock server in ${ansis.cyan(path.relative(process.cwd(), dist))}`);
|
|
394
|
+
if (!fs.existsSync(dist)) await fsp.mkdir(dist, { recursive: true });
|
|
395
|
+
for (const { filename, source } of outputList) {
|
|
396
|
+
await fsp.writeFile(path.join(dist, filename), source, "utf8");
|
|
397
|
+
const sourceSize = (source.length / 1024).toFixed(2);
|
|
398
|
+
const space = filename.length < 24 ? " ".repeat(24 - filename.length) : "";
|
|
399
|
+
options.logger.info(` ${ansis.green(filename)}${space}${ansis.bold.dim(`${sourceSize} kB`)}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/options.ts
|
|
404
|
+
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 = {} }, { alias, context, plugins, proxies: rawProxies }) {
|
|
405
|
+
const logger = createLogger("rspack:mock", isBoolean(log) ? log ? "info" : "error" : log);
|
|
406
|
+
const proxies = [...toArray(prefix), ...rawProxies];
|
|
407
|
+
const wsProxies = toArray(wsPrefix);
|
|
408
|
+
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")}`);
|
|
409
|
+
const enabled = !!cors;
|
|
410
|
+
let corsOptions = {};
|
|
411
|
+
if (enabled && isPlainObject(cors)) corsOptions = {
|
|
412
|
+
...corsOptions,
|
|
413
|
+
...cors
|
|
414
|
+
};
|
|
415
|
+
return {
|
|
416
|
+
prefix,
|
|
417
|
+
wsPrefix,
|
|
418
|
+
cwd: cwd || context || process.cwd(),
|
|
419
|
+
dir,
|
|
420
|
+
include,
|
|
421
|
+
exclude,
|
|
422
|
+
reload,
|
|
423
|
+
cors: enabled ? corsOptions : false,
|
|
424
|
+
cookiesOptions,
|
|
425
|
+
log,
|
|
426
|
+
formidableOptions: {
|
|
427
|
+
multiples: true,
|
|
428
|
+
...formidableOptions
|
|
429
|
+
},
|
|
430
|
+
bodyParserOptions,
|
|
431
|
+
priority,
|
|
432
|
+
build: build ? {
|
|
433
|
+
serverPort: 8080,
|
|
434
|
+
dist: "mockServer",
|
|
435
|
+
log: "error",
|
|
436
|
+
...typeof build === "object" ? build : {}
|
|
437
|
+
} : false,
|
|
438
|
+
alias,
|
|
439
|
+
plugins,
|
|
440
|
+
proxies,
|
|
441
|
+
wsProxies,
|
|
442
|
+
logger
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
//#endregion
|
|
446
|
+
export { buildMockServer as n, createMockCompiler as r, resolvePluginOptions as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as WebSocketSetupContext, a as LogType, c as MockMatchPriority, d as MockRequest, f as MockResponse, g as ServerBuildOption, h as ResponseBody, i as LogLevel, l as MockMatchSpecialPriority, m as MockWebsocketItem, n as ExtraRequest, o as Method, p as MockServerPluginOptions, r as FormidableFile, s as MockHttpItem, t as BodyParserOptions, u as MockOptions } from "./types-
|
|
1
|
+
import { _ as WebSocketSetupContext, a as LogType, c as MockMatchPriority, d as MockRequest, f as MockResponse, g as ServerBuildOption, h as ResponseBody, i as LogLevel, l as MockMatchSpecialPriority, m as MockWebsocketItem, n as ExtraRequest, o as Method, p as MockServerPluginOptions, r as FormidableFile, s as MockHttpItem, t as BodyParserOptions, u as MockOptions } from "./types-GT6M6WuI.js";
|
|
2
2
|
import { RsbuildPlugin } from "@rsbuild/core";
|
|
3
3
|
|
|
4
4
|
//#region src/rsbuild.d.ts
|
package/dist/rsbuild.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { n as baseMiddleware, r as rewriteRequest, t as mockWebSocket } from "./ws-BcLCWVaK.js";
|
|
2
|
+
import { n as buildMockServer, r as createMockCompiler, t as resolvePluginOptions } from "./options-Bd0PSZeT.js";
|
|
3
|
+
import { isArray, objectEntries, toArray } from "@pengzhanbo/utils";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import rspack from "@rspack/core";
|
|
7
|
+
import ansis from "ansis";
|
|
8
|
+
import { Socket } from "node:net";
|
|
9
|
+
//#region src/rsbuild.ts
|
|
10
|
+
function pluginMockServer(options = {}) {
|
|
11
|
+
return {
|
|
12
|
+
name: "plugin-mock-server",
|
|
13
|
+
setup(api) {
|
|
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
|
+
api.modifyRsbuildConfig((config) => updateServerProxyConfigByHttpMock(config));
|
|
36
|
+
function initMockServer(server) {
|
|
37
|
+
server.middlewares.use(baseMiddleware(mockCompiler, resolvedOptions));
|
|
38
|
+
if (resolvedOptions.reload && api.context.action === "dev") mockCompiler.on("update", () => server.sockWrite("static-changed"));
|
|
39
|
+
if (toArray(resolvedOptions.wsPrefix).length > 0) mockWebSocket(mockCompiler, server.httpServer, resolvedOptions);
|
|
40
|
+
mockCompiler.run();
|
|
41
|
+
}
|
|
42
|
+
api.onBeforeStartDevServer(({ server }) => initMockServer(server));
|
|
43
|
+
api.onBeforeStartPreviewServer(({ server }) => initMockServer(server));
|
|
44
|
+
api.onExit(() => mockCompiler.close());
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function onProxyError(err, _req, res) {
|
|
49
|
+
console.error(ansis.red(err?.stack || err.message));
|
|
50
|
+
if (!(res instanceof Socket)) res.statusCode = 500;
|
|
51
|
+
res.end();
|
|
52
|
+
}
|
|
53
|
+
function wrapProxyOptions(options) {
|
|
54
|
+
const { on, ...rest } = options;
|
|
55
|
+
return {
|
|
56
|
+
...rest,
|
|
57
|
+
on: {
|
|
58
|
+
...on,
|
|
59
|
+
proxyReq: (proxyReq, req, ...args) => {
|
|
60
|
+
on?.proxyReq?.(proxyReq, req, ...args);
|
|
61
|
+
rewriteRequest(proxyReq, req);
|
|
62
|
+
},
|
|
63
|
+
error: on?.error || onProxyError
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function updateServerProxyConfigByHttpMock(config) {
|
|
68
|
+
if (!config.server?.proxy) return;
|
|
69
|
+
if (isArray(config.server.proxy)) config.server.proxy = config.server.proxy.map((item) => item.ws ? item : wrapProxyOptions(item));
|
|
70
|
+
else if (config.server.proxy) {
|
|
71
|
+
const proxy = config.server.proxy;
|
|
72
|
+
Object.keys(proxy).forEach((key) => {
|
|
73
|
+
const target = proxy[key];
|
|
74
|
+
const options = typeof target === "string" ? { target } : target;
|
|
75
|
+
if (options.ws) return;
|
|
76
|
+
proxy[key] = wrapProxyOptions(options);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function resolveConfigProxies(config) {
|
|
81
|
+
config.server ??= {};
|
|
82
|
+
const proxy = config.server.proxy ??= {};
|
|
83
|
+
const proxies = [];
|
|
84
|
+
if (isArray(proxy)) {
|
|
85
|
+
for (const item of proxy) if (item.pathFilter && !item.ws) proxies.push(...toArray(item.pathFilter));
|
|
86
|
+
} else objectEntries(proxy).forEach(([pathFilter, opt]) => {
|
|
87
|
+
if (typeof opt === "string" || !opt.ws) proxies.push(pathFilter);
|
|
88
|
+
});
|
|
89
|
+
return proxies;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { pluginMockServer };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { g as ServerBuildOption, i as LogLevel, m as MockWebsocketItem, p as MockServerPluginOptions, s as MockHttpItem, u as MockOptions } from "./types-
|
|
2
|
-
import { Compiler,
|
|
1
|
+
import { g as ServerBuildOption, i as LogLevel, m as MockWebsocketItem, p as MockServerPluginOptions, s as MockHttpItem, u as MockOptions } from "./types-GT6M6WuI.js";
|
|
2
|
+
import { Compiler, RspackPluginInstance } from "@rspack/core";
|
|
3
3
|
import { Matcher } from "picomatch";
|
|
4
4
|
import Debug from "debug";
|
|
5
|
-
import "memfs";
|
|
6
5
|
import EventEmitter from "node:events";
|
|
7
6
|
import { FSWatcher } from "chokidar";
|
|
8
|
-
import {
|
|
7
|
+
import { CorsOptions } from "cors";
|
|
8
|
+
import * as http$1 from "node:http";
|
|
9
|
+
import http, { Server } from "node:http";
|
|
9
10
|
import { Http2SecureServer } from "node:http2";
|
|
10
11
|
|
|
11
12
|
//#region src/utils/logger.d.ts
|
|
@@ -21,10 +22,11 @@ declare function createLogger(prefix: string, defaultLevel?: LogLevel): Logger;
|
|
|
21
22
|
//#region src/options.d.ts
|
|
22
23
|
interface ResolvedCompilerOptions {
|
|
23
24
|
alias: Record<string, false | string | (string | false)[]>;
|
|
24
|
-
proxies: (string | ((pathname: string, req:
|
|
25
|
-
wsProxies: (string | ((pathname: string, req:
|
|
25
|
+
proxies: (string | ((pathname: string, req: http.IncomingMessage) => boolean))[];
|
|
26
|
+
wsProxies: (string | ((pathname: string, req: http.IncomingMessage) => boolean))[];
|
|
26
27
|
plugins: RspackPluginInstance[];
|
|
27
28
|
context?: string;
|
|
29
|
+
cors: false | CorsOptions;
|
|
28
30
|
}
|
|
29
31
|
type ResolvePluginOptions = Required<Omit<MockServerPluginOptions, "build">> & ResolvedCompilerOptions & {
|
|
30
32
|
logger: Logger;
|
|
@@ -40,8 +42,8 @@ declare function sortByValidator(mocks: MockOptions): (MockHttpItem | MockWebsoc
|
|
|
40
42
|
declare class MockCompiler extends EventEmitter {
|
|
41
43
|
options: ResolvePluginOptions;
|
|
42
44
|
cwd: string;
|
|
43
|
-
mockWatcher
|
|
44
|
-
entryFile
|
|
45
|
+
mockWatcher!: FSWatcher;
|
|
46
|
+
entryFile!: string;
|
|
45
47
|
deps: string[];
|
|
46
48
|
isESM: boolean;
|
|
47
49
|
private _mockData;
|
|
@@ -56,14 +58,11 @@ declare class MockCompiler extends EventEmitter {
|
|
|
56
58
|
watchMockFiles(isMatch: Matcher): void;
|
|
57
59
|
}
|
|
58
60
|
//#endregion
|
|
59
|
-
//#region src/core/types.d.ts
|
|
60
|
-
type SetupMiddlewaresFn = NonNullable<NonNullable<RspackOptionsNormalized["devServer"]>["setupMiddlewares"]>;
|
|
61
|
-
type Middleware = SetupMiddlewaresFn extends ((middlewares: (infer T)[], devServer: any) => void) ? T : never;
|
|
62
|
-
//#endregion
|
|
63
61
|
//#region src/core/mockMiddleware.d.ts
|
|
64
62
|
interface BaseMiddlewareOptions extends Pick<MockServerPluginOptions, "formidableOptions" | "cookiesOptions" | "bodyParserOptions" | "priority"> {
|
|
65
63
|
proxies: (string | ((pathname: string, req: any) => boolean))[];
|
|
66
64
|
logger: Logger;
|
|
65
|
+
cors: false | CorsOptions;
|
|
67
66
|
}
|
|
68
67
|
declare function baseMiddleware(compiler: MockCompiler, {
|
|
69
68
|
formidableOptions,
|
|
@@ -71,8 +70,9 @@ declare function baseMiddleware(compiler: MockCompiler, {
|
|
|
71
70
|
proxies,
|
|
72
71
|
cookiesOptions,
|
|
73
72
|
logger,
|
|
74
|
-
priority
|
|
75
|
-
|
|
73
|
+
priority,
|
|
74
|
+
cors: corsOptions
|
|
75
|
+
}: BaseMiddlewareOptions): (req: http$1.IncomingMessage, res: http$1.ServerResponse, next: (err?: any) => void) => void;
|
|
76
76
|
//#endregion
|
|
77
77
|
//#region src/core/ws.d.ts
|
|
78
78
|
interface MockSocketOptions {
|
|
@@ -80,7 +80,7 @@ interface MockSocketOptions {
|
|
|
80
80
|
cookiesOptions: MockServerPluginOptions["cookiesOptions"];
|
|
81
81
|
logger: Logger;
|
|
82
82
|
}
|
|
83
|
-
declare function mockWebSocket(compiler: MockCompiler, httpServer: Server | Http2SecureServer, {
|
|
83
|
+
declare function mockWebSocket(compiler: MockCompiler, httpServer: Server | Http2SecureServer | null, {
|
|
84
84
|
wsProxies: proxies,
|
|
85
85
|
cookiesOptions,
|
|
86
86
|
logger
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import { a as processMockData, c as Logger, i as baseMiddleware, l as createLogger, n as mockWebSocket, o as processRawData, r as BaseMiddlewareOptions, s as sortByValidator, t as MockSocketOptions, u as logLevels } from "./server-4ETytB7L.mjs";
|
|
1
|
+
import { a as processMockData, c as Logger, i as baseMiddleware, l as createLogger, n as mockWebSocket, o as processRawData, r as BaseMiddlewareOptions, s as sortByValidator, t as MockSocketOptions, u as logLevels } from "./server-_doRwsZm.js";
|
|
3
2
|
export { BaseMiddlewareOptions, Logger, MockSocketOptions, baseMiddleware, createLogger, logLevels, mockWebSocket, processMockData, processRawData, sortByValidator };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as processRawData, d as logLevels, i as processMockData, n as baseMiddleware, o as sortByValidator, t as mockWebSocket, u as createLogger } from "./ws-BcLCWVaK.js";
|
|
2
|
+
export { baseMiddleware, createLogger, logLevels, mockWebSocket, processMockData, processRawData, sortByValidator };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Readable } from "node:stream";
|
|
2
|
+
import crypto from "node:crypto";
|
|
2
3
|
import { CorsOptions } from "cors";
|
|
3
4
|
import { Options } from "co-body";
|
|
4
5
|
import formidable from "formidable";
|
|
5
6
|
import http, { IncomingMessage, ServerResponse } from "node:http";
|
|
6
|
-
import crypto from "node:crypto";
|
|
7
7
|
import { Buffer } from "node:buffer";
|
|
8
8
|
import { WebSocketServer } from "ws";
|
|
9
9
|
|
|
10
10
|
//#region src/cookies/Keygrip.d.ts
|
|
11
11
|
declare class Keygrip {
|
|
12
|
-
private algorithm
|
|
13
|
-
private encoding
|
|
12
|
+
private algorithm!;
|
|
13
|
+
private encoding!;
|
|
14
14
|
private keys;
|
|
15
15
|
constructor(keys: string[], algorithm?: string, encoding?: crypto.BinaryToTextEncoding);
|
|
16
16
|
sign(data: string, key?: string): string;
|