vite-plugin-mock-dev-server 0.3.16 → 0.3.18
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 +47 -1
- package/README.zh-CN.md +42 -1
- package/dist/index.cjs +473 -213
- package/dist/index.d.ts +68 -2
- package/dist/index.js +469 -210
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +1,60 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import { parse as urlParse } from "url";
|
|
3
|
-
import { match, pathToRegexp } from "path-to-regexp";
|
|
4
|
-
|
|
5
|
-
// src/MockLoader.ts
|
|
6
|
-
import EventEmitter from "events";
|
|
1
|
+
// src/build.ts
|
|
7
2
|
import fs2 from "fs";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { pathToFileURL } from "url";
|
|
11
|
-
import chokidar from "chokidar";
|
|
3
|
+
import fsp2 from "fs/promises";
|
|
4
|
+
import path3 from "path";
|
|
12
5
|
import { build } from "esbuild";
|
|
13
|
-
import
|
|
14
|
-
import
|
|
6
|
+
import fg from "fast-glob";
|
|
7
|
+
import isCore from "is-core-module";
|
|
15
8
|
import { createFilter } from "vite";
|
|
16
9
|
|
|
10
|
+
// package.json
|
|
11
|
+
var name = "vite-plugin-mock-dev-server";
|
|
12
|
+
var version = "0.3.18";
|
|
13
|
+
|
|
14
|
+
// src/esbuildPlugin.ts
|
|
15
|
+
import fsp from "fs/promises";
|
|
16
|
+
import path from "path";
|
|
17
|
+
import JSON5 from "json5";
|
|
18
|
+
var externalizeDeps = {
|
|
19
|
+
name: "externalize-deps",
|
|
20
|
+
setup(build3) {
|
|
21
|
+
build3.onResolve({ filter: /.*/ }, ({ path: id }) => {
|
|
22
|
+
if (id[0] !== "." && !path.isAbsolute(id)) {
|
|
23
|
+
return {
|
|
24
|
+
external: true
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var json5Loader = {
|
|
31
|
+
name: "json5-loader",
|
|
32
|
+
setup(build3) {
|
|
33
|
+
build3.onLoad({ filter: /\.json5$/ }, async ({ path: path5 }) => {
|
|
34
|
+
const content = await fsp.readFile(path5, "utf-8");
|
|
35
|
+
return {
|
|
36
|
+
contents: `export default ${JSON.stringify(JSON5.parse(content))}`,
|
|
37
|
+
loader: "js"
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var jsonLoader = {
|
|
43
|
+
name: "json-loader",
|
|
44
|
+
setup(build3) {
|
|
45
|
+
build3.onLoad({ filter: /\.json$/ }, async ({ path: path5 }) => {
|
|
46
|
+
const content = await fsp.readFile(path5, "utf-8");
|
|
47
|
+
return {
|
|
48
|
+
contents: `export default ${content}`,
|
|
49
|
+
loader: "js"
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
17
55
|
// src/utils.ts
|
|
18
56
|
import fs from "fs";
|
|
19
|
-
import
|
|
57
|
+
import path2 from "path";
|
|
20
58
|
import { fileURLToPath } from "url";
|
|
21
59
|
import Debug from "debug";
|
|
22
60
|
var isArray = (val) => Array.isArray(val);
|
|
@@ -25,12 +63,12 @@ function sleep(timeout) {
|
|
|
25
63
|
return new Promise((resolve) => setTimeout(resolve, timeout));
|
|
26
64
|
}
|
|
27
65
|
function getDirname(importMetaUrl) {
|
|
28
|
-
return
|
|
66
|
+
return path2.dirname(fileURLToPath(importMetaUrl));
|
|
29
67
|
}
|
|
30
68
|
var debug = Debug("vite:plugin-mock-dev-server");
|
|
31
69
|
function lookupFile(dir, formats, options) {
|
|
32
70
|
for (const format of formats) {
|
|
33
|
-
const fullPath =
|
|
71
|
+
const fullPath = path2.join(dir, format);
|
|
34
72
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
|
35
73
|
const result = (options == null ? void 0 : options.pathOnly) ? fullPath : fs.readFileSync(fullPath, "utf-8");
|
|
36
74
|
if (!(options == null ? void 0 : options.predicate) || options.predicate(result)) {
|
|
@@ -38,13 +76,355 @@ function lookupFile(dir, formats, options) {
|
|
|
38
76
|
}
|
|
39
77
|
}
|
|
40
78
|
}
|
|
41
|
-
const parentDir =
|
|
79
|
+
const parentDir = path2.dirname(dir);
|
|
42
80
|
if (parentDir !== dir && (!(options == null ? void 0 : options.rootDir) || parentDir.startsWith(options == null ? void 0 : options.rootDir))) {
|
|
43
81
|
return lookupFile(parentDir, formats, options);
|
|
44
82
|
}
|
|
45
83
|
}
|
|
46
84
|
|
|
85
|
+
// src/build.ts
|
|
86
|
+
async function generateMockServer(ctx, config, options) {
|
|
87
|
+
const include = isArray(options.include) ? options.include : [options.include];
|
|
88
|
+
const exclude = isArray(options.exclude) ? options.exclude : [options.exclude];
|
|
89
|
+
const define = {};
|
|
90
|
+
if (config.define) {
|
|
91
|
+
for (const key in config.define) {
|
|
92
|
+
const val = config.define[key];
|
|
93
|
+
define[key] = typeof val === "string" ? val : JSON.stringify(val);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let pkg = {};
|
|
97
|
+
try {
|
|
98
|
+
const pkgStr = lookupFile(config.root, ["package.json"]);
|
|
99
|
+
if (pkgStr) {
|
|
100
|
+
pkg = JSON.parse(pkgStr);
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
const outputDir = options.build.dist;
|
|
105
|
+
const content = await generateMockEntryCode(process.cwd(), include, exclude);
|
|
106
|
+
const mockEntry = path3.join(config.root, `mock-data-${Date.now()}.js`);
|
|
107
|
+
await fsp2.writeFile(mockEntry, content, "utf-8");
|
|
108
|
+
const { code, deps } = await buildMockEntry(mockEntry, define);
|
|
109
|
+
const mockDeps = getMockDependencies(deps);
|
|
110
|
+
await fsp2.unlink(mockEntry);
|
|
111
|
+
const outputList = [
|
|
112
|
+
{
|
|
113
|
+
filename: path3.join(outputDir, "mock-data.js"),
|
|
114
|
+
source: code
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
filename: path3.join(outputDir, "index.js"),
|
|
118
|
+
source: generatorServerEntryCode(
|
|
119
|
+
config.server.proxy || {},
|
|
120
|
+
options.build.serverPort
|
|
121
|
+
)
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
filename: path3.join(outputDir, "package.json"),
|
|
125
|
+
source: generatePackageJson(pkg, mockDeps)
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
try {
|
|
129
|
+
if (path3.isAbsolute(outputDir)) {
|
|
130
|
+
await fsp2.rm(outputDir, { recursive: true });
|
|
131
|
+
fs2.mkdirSync(outputDir, { recursive: true });
|
|
132
|
+
for (const { filename, source } of outputList) {
|
|
133
|
+
await fsp2.writeFile(filename, source, "utf-8");
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
for (const { filename, source } of outputList) {
|
|
137
|
+
ctx.emitFile({
|
|
138
|
+
type: "asset",
|
|
139
|
+
fileName: filename,
|
|
140
|
+
source
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function getMockDependencies(deps) {
|
|
148
|
+
const list = /* @__PURE__ */ new Set();
|
|
149
|
+
const excludeDeps = [name, "connect"];
|
|
150
|
+
Object.keys(deps).forEach((mPath) => {
|
|
151
|
+
const imports = deps[mPath].imports.filter((_) => _.external).map((_) => _.path);
|
|
152
|
+
imports.forEach((dep) => {
|
|
153
|
+
if (!excludeDeps.includes(dep) && !isCore(dep)) {
|
|
154
|
+
list.add(dep);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
return Array.from(list);
|
|
159
|
+
}
|
|
160
|
+
function generatePackageJson(pkg, mockDeps) {
|
|
161
|
+
const { dependencies = {}, devDependencies = {} } = pkg;
|
|
162
|
+
const dependents = { ...dependencies, ...devDependencies };
|
|
163
|
+
const mockPkg = {
|
|
164
|
+
name: "mock-server",
|
|
165
|
+
type: "module",
|
|
166
|
+
scripts: {
|
|
167
|
+
start: "node index.js"
|
|
168
|
+
},
|
|
169
|
+
dependencies: {
|
|
170
|
+
"connect": "^3.7.0",
|
|
171
|
+
"vite-plugin-mock-dev-server": `^${version}`
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
mockDeps.forEach((dep) => {
|
|
175
|
+
mockPkg.dependencies[dep] = dependents[dep] || "latest";
|
|
176
|
+
});
|
|
177
|
+
return JSON.stringify(mockPkg, null, 2);
|
|
178
|
+
}
|
|
179
|
+
function generatorServerEntryCode(proxy = {}, port = 8080) {
|
|
180
|
+
const proxies = Object.keys(proxy || {});
|
|
181
|
+
return `import connect from 'connect'
|
|
182
|
+
import { baseMiddleware } from 'vite-plugin-mock-dev-server'
|
|
183
|
+
import mockData from './mock-data.js'
|
|
184
|
+
const app = connect()
|
|
185
|
+
app.use(baseMiddleware(mockData, {
|
|
186
|
+
formidableOptions: { multiples: true },
|
|
187
|
+
proxies: ${JSON.stringify(proxies)}
|
|
188
|
+
}))
|
|
189
|
+
app.listen(${port})
|
|
190
|
+
console.log('listen: http://localhost:${port}')
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
async function generateMockEntryCode(cwd, include, exclude) {
|
|
194
|
+
const includePaths = await fg(include, { cwd });
|
|
195
|
+
const includeFilter = createFilter(include, exclude, {
|
|
196
|
+
resolve: false
|
|
197
|
+
});
|
|
198
|
+
const mockFiles = includePaths.filter(includeFilter);
|
|
199
|
+
let importers = "";
|
|
200
|
+
let exporters = "";
|
|
201
|
+
mockFiles.forEach((filepath, index) => {
|
|
202
|
+
const file = path3.join(cwd, filepath);
|
|
203
|
+
importers += `import * as m${index} from '${file}'
|
|
204
|
+
`;
|
|
205
|
+
exporters += `m${index}, `;
|
|
206
|
+
});
|
|
207
|
+
return `${importers}const mockData = [${exporters}];
|
|
208
|
+
|
|
209
|
+
const data = [];
|
|
210
|
+
const mocks = {};
|
|
211
|
+
mockData.forEach(mock => {
|
|
212
|
+
Object.keys(mock).forEach(key => {
|
|
213
|
+
const mockData = mock[key];
|
|
214
|
+
if (Array.isArray(mockData)) {
|
|
215
|
+
data.push(...mockData);
|
|
216
|
+
} else {
|
|
217
|
+
if (typeof mockData === 'object' && Object.prototype.hasOwnProperty.call(mockData, 'url')) {
|
|
218
|
+
data.push(mockData);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
data
|
|
224
|
+
.filter((mock) => mock.enabled || typeof mock.enabled === "undefined")
|
|
225
|
+
.forEach((mock) => {
|
|
226
|
+
if (!mocks[mock.url]) {
|
|
227
|
+
mocks[mock.url] = [];
|
|
228
|
+
}
|
|
229
|
+
const list = mocks[mock.url];
|
|
230
|
+
mock.validator ? list.unshift(mock) : list.push(mock);
|
|
231
|
+
});
|
|
232
|
+
export default mocks;
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
async function buildMockEntry(inputFile, define) {
|
|
236
|
+
var _a;
|
|
237
|
+
try {
|
|
238
|
+
const result = await build({
|
|
239
|
+
entryPoints: [inputFile],
|
|
240
|
+
outfile: "out.js",
|
|
241
|
+
write: false,
|
|
242
|
+
target: ["node14.18", "node16"],
|
|
243
|
+
platform: "node",
|
|
244
|
+
bundle: true,
|
|
245
|
+
metafile: true,
|
|
246
|
+
format: "esm",
|
|
247
|
+
define,
|
|
248
|
+
plugins: [externalizeDeps, json5Loader, jsonLoader]
|
|
249
|
+
});
|
|
250
|
+
return {
|
|
251
|
+
code: result.outputFiles[0].text,
|
|
252
|
+
deps: ((_a = result.metafile) == null ? void 0 : _a.inputs) || {}
|
|
253
|
+
};
|
|
254
|
+
} catch (e) {
|
|
255
|
+
console.error(e);
|
|
256
|
+
}
|
|
257
|
+
return { code: "", deps: {} };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/baseMiddleware.ts
|
|
261
|
+
import { parse as urlParse } from "url";
|
|
262
|
+
import { match, pathToRegexp } from "path-to-regexp";
|
|
263
|
+
|
|
264
|
+
// src/parseReqBody.ts
|
|
265
|
+
import bodyParser from "co-body";
|
|
266
|
+
import formidable from "formidable";
|
|
267
|
+
async function parseReqBody(req, options) {
|
|
268
|
+
const method = req.method.toUpperCase();
|
|
269
|
+
if (["GET", "DELETE", "HEAD"].includes(method))
|
|
270
|
+
return void 0;
|
|
271
|
+
const type = req.headers["content-type"];
|
|
272
|
+
try {
|
|
273
|
+
if (type === "application/json") {
|
|
274
|
+
return await bodyParser.json(req);
|
|
275
|
+
}
|
|
276
|
+
if (type === "application/x-www-form-urlencoded") {
|
|
277
|
+
return await bodyParser.form(req);
|
|
278
|
+
}
|
|
279
|
+
if (type === "text/plain") {
|
|
280
|
+
return await bodyParser.text(req);
|
|
281
|
+
}
|
|
282
|
+
if (type == null ? void 0 : type.startsWith("multipart/form-data;")) {
|
|
283
|
+
return await parseMultipart(req, options);
|
|
284
|
+
}
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.error(e);
|
|
287
|
+
}
|
|
288
|
+
return void 0;
|
|
289
|
+
}
|
|
290
|
+
async function parseMultipart(req, options) {
|
|
291
|
+
const form = formidable(options);
|
|
292
|
+
return new Promise((resolve, reject) => {
|
|
293
|
+
form.parse(req, (error, fields, files) => {
|
|
294
|
+
if (error) {
|
|
295
|
+
reject(error);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
resolve({ ...fields, ...files });
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/validator.ts
|
|
304
|
+
function validate(request, validator) {
|
|
305
|
+
return equalObj(request.headers, validator.headers) && equalObj(request.body, validator.body) && equalObj(request.params, validator.params) && equalObj(request.query, validator.query);
|
|
306
|
+
}
|
|
307
|
+
function equalObj(left, right) {
|
|
308
|
+
if (!right)
|
|
309
|
+
return true;
|
|
310
|
+
for (const key in right) {
|
|
311
|
+
if (right[key] !== left[key])
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/baseMiddleware.ts
|
|
318
|
+
function baseMiddleware(mockData, { formidableOptions = {}, proxies }) {
|
|
319
|
+
return async function(req, res, next) {
|
|
320
|
+
const method = req.method.toUpperCase();
|
|
321
|
+
const { query, pathname } = urlParse(req.url, true);
|
|
322
|
+
if (!pathname || proxies.length === 0 || !proxies.some((context) => doesProxyContextMatchUrl(context, req.url))) {
|
|
323
|
+
return next();
|
|
324
|
+
}
|
|
325
|
+
const mockUrl = Object.keys(mockData).find((key) => {
|
|
326
|
+
return pathToRegexp(key).test(pathname);
|
|
327
|
+
});
|
|
328
|
+
if (!mockUrl) {
|
|
329
|
+
return next();
|
|
330
|
+
}
|
|
331
|
+
const mockList = mockData[mockUrl];
|
|
332
|
+
const reqBody = await parseReqBody(req, formidableOptions);
|
|
333
|
+
const currentMock = mockList.find((mock) => {
|
|
334
|
+
if (!pathname || !mock || !mock.url)
|
|
335
|
+
return false;
|
|
336
|
+
const methods = mock.method ? isArray(mock.method) ? mock.method : [mock.method] : ["GET", "POST"];
|
|
337
|
+
if (!methods.includes(req.method.toUpperCase()))
|
|
338
|
+
return false;
|
|
339
|
+
const hasMock = pathToRegexp(mock.url).test(pathname);
|
|
340
|
+
if (hasMock && mock.validator) {
|
|
341
|
+
const urlMatch2 = match(mock.url, { decode: decodeURIComponent })(
|
|
342
|
+
pathname
|
|
343
|
+
) || { params: {} };
|
|
344
|
+
const params2 = urlMatch2.params || {};
|
|
345
|
+
const request = {
|
|
346
|
+
query,
|
|
347
|
+
params: params2,
|
|
348
|
+
body: reqBody,
|
|
349
|
+
headers: req.headers
|
|
350
|
+
};
|
|
351
|
+
if (isFunction(mock.validator)) {
|
|
352
|
+
return mock.validator(request);
|
|
353
|
+
} else {
|
|
354
|
+
return validate(request, mock.validator);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return hasMock;
|
|
358
|
+
});
|
|
359
|
+
if (!currentMock)
|
|
360
|
+
return next();
|
|
361
|
+
debug("middleware: ", method, pathname);
|
|
362
|
+
if (currentMock.delay && currentMock.delay > 0) {
|
|
363
|
+
await sleep(currentMock.delay);
|
|
364
|
+
}
|
|
365
|
+
res.statusCode = currentMock.status || 200;
|
|
366
|
+
res.statusMessage = currentMock.statusText || "OK";
|
|
367
|
+
const urlMatch = match(currentMock.url, { decode: decodeURIComponent })(
|
|
368
|
+
pathname
|
|
369
|
+
) || { params: {} };
|
|
370
|
+
const params = urlMatch.params || {};
|
|
371
|
+
req.body = reqBody;
|
|
372
|
+
req.query = query;
|
|
373
|
+
req.params = params;
|
|
374
|
+
res.setHeader("Content-Type", "application/json");
|
|
375
|
+
res.setHeader("X-Mock", "generate by vite:mock-dev-server");
|
|
376
|
+
if (currentMock.headers) {
|
|
377
|
+
const headers = isFunction(currentMock.headers) ? await currentMock.headers({
|
|
378
|
+
query,
|
|
379
|
+
body: reqBody,
|
|
380
|
+
params,
|
|
381
|
+
headers: req.headers
|
|
382
|
+
}) : currentMock.headers;
|
|
383
|
+
Object.keys(headers).forEach((key) => {
|
|
384
|
+
res.setHeader(key, headers[key]);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (currentMock.body) {
|
|
388
|
+
let body;
|
|
389
|
+
if (isFunction(currentMock.body)) {
|
|
390
|
+
body = await currentMock.body({
|
|
391
|
+
query,
|
|
392
|
+
body: reqBody,
|
|
393
|
+
params,
|
|
394
|
+
headers: req.headers
|
|
395
|
+
});
|
|
396
|
+
} else {
|
|
397
|
+
body = currentMock.body;
|
|
398
|
+
}
|
|
399
|
+
res.end(JSON.stringify(body));
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (currentMock.response) {
|
|
403
|
+
await currentMock.response(
|
|
404
|
+
req,
|
|
405
|
+
res,
|
|
406
|
+
next
|
|
407
|
+
);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
res.end("");
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function doesProxyContextMatchUrl(context, url) {
|
|
414
|
+
return context.startsWith("^") && new RegExp(context).test(url) || url.startsWith(context);
|
|
415
|
+
}
|
|
416
|
+
|
|
47
417
|
// src/MockLoader.ts
|
|
418
|
+
import EventEmitter from "events";
|
|
419
|
+
import fs3 from "fs";
|
|
420
|
+
import { createRequire } from "module";
|
|
421
|
+
import path4 from "path";
|
|
422
|
+
import { pathToFileURL } from "url";
|
|
423
|
+
import chokidar from "chokidar";
|
|
424
|
+
import { build as build2 } from "esbuild";
|
|
425
|
+
import fastGlob from "fast-glob";
|
|
426
|
+
import JSON52 from "json5";
|
|
427
|
+
import { createFilter as createFilter2 } from "vite";
|
|
48
428
|
var _dirname = typeof __dirname !== "undefined" ? __dirname : getDirname(import.meta.url);
|
|
49
429
|
var _require = createRequire(_dirname);
|
|
50
430
|
var _MockLoader = class extends EventEmitter {
|
|
@@ -53,8 +433,8 @@ var _MockLoader = class extends EventEmitter {
|
|
|
53
433
|
this.options = options;
|
|
54
434
|
this.moduleCache = /* @__PURE__ */ new Map();
|
|
55
435
|
this.moduleDeps = /* @__PURE__ */ new Map();
|
|
56
|
-
this._mockList = {};
|
|
57
436
|
this.moduleType = "cjs";
|
|
437
|
+
this._mockData = {};
|
|
58
438
|
this.cwd = options.cwd || process.cwd();
|
|
59
439
|
try {
|
|
60
440
|
const pkg = lookupFile(this.cwd, ["package.json"]);
|
|
@@ -62,15 +442,15 @@ var _MockLoader = class extends EventEmitter {
|
|
|
62
442
|
} catch (e) {
|
|
63
443
|
}
|
|
64
444
|
}
|
|
65
|
-
get
|
|
66
|
-
return this.
|
|
445
|
+
get mockData() {
|
|
446
|
+
return this._mockData;
|
|
67
447
|
}
|
|
68
448
|
async load() {
|
|
69
449
|
const { include, exclude } = this.options;
|
|
70
450
|
const includePaths = await fastGlob(include, {
|
|
71
451
|
cwd: this.cwd
|
|
72
452
|
});
|
|
73
|
-
const includeFilter =
|
|
453
|
+
const includeFilter = createFilter2(include, exclude, {
|
|
74
454
|
resolve: false
|
|
75
455
|
});
|
|
76
456
|
this.watchMockEntry();
|
|
@@ -156,7 +536,7 @@ var _MockLoader = class extends EventEmitter {
|
|
|
156
536
|
const list = mocks[mock.url];
|
|
157
537
|
mock.validator ? list.unshift(mock) : list.push(mock);
|
|
158
538
|
});
|
|
159
|
-
this.
|
|
539
|
+
this._mockData = mocks;
|
|
160
540
|
}
|
|
161
541
|
updateModuleDeps(filepath, deps) {
|
|
162
542
|
Object.keys(deps).forEach((mPath) => {
|
|
@@ -181,9 +561,9 @@ var _MockLoader = class extends EventEmitter {
|
|
|
181
561
|
}
|
|
182
562
|
}
|
|
183
563
|
async loadJson(filepath) {
|
|
184
|
-
const content = await
|
|
564
|
+
const content = await fs3.promises.readFile(filepath, "utf-8");
|
|
185
565
|
try {
|
|
186
|
-
const mockConfig =
|
|
566
|
+
const mockConfig = JSON52.parse(content);
|
|
187
567
|
this.moduleCache.set(filepath, mockConfig);
|
|
188
568
|
} catch (e) {
|
|
189
569
|
}
|
|
@@ -214,19 +594,19 @@ var _MockLoader = class extends EventEmitter {
|
|
|
214
594
|
const fileBase = `${filepath}.timestamp-${Date.now()}`;
|
|
215
595
|
const fileNameTmp = `${fileBase}.mjs`;
|
|
216
596
|
const fileUrl = `${pathToFileURL(fileBase)}.mjs`;
|
|
217
|
-
await
|
|
597
|
+
await fs3.promises.writeFile(fileNameTmp, code, "utf8");
|
|
218
598
|
try {
|
|
219
599
|
return await import(fileUrl);
|
|
220
600
|
} finally {
|
|
221
601
|
try {
|
|
222
|
-
|
|
602
|
+
fs3.unlinkSync(fileNameTmp);
|
|
223
603
|
} catch {
|
|
224
604
|
}
|
|
225
605
|
}
|
|
226
606
|
} else {
|
|
227
|
-
filepath =
|
|
228
|
-
const extension =
|
|
229
|
-
const realFileName =
|
|
607
|
+
filepath = path4.resolve(this.cwd, filepath);
|
|
608
|
+
const extension = path4.extname(filepath);
|
|
609
|
+
const realFileName = fs3.realpathSync(filepath);
|
|
230
610
|
const loaderExt = extension in _require.extensions ? extension : ".js";
|
|
231
611
|
const defaultLoader = _require.extensions[loaderExt];
|
|
232
612
|
_require.extensions[loaderExt] = (module, filename) => {
|
|
@@ -246,7 +626,7 @@ var _MockLoader = class extends EventEmitter {
|
|
|
246
626
|
async transformWithEsbuild(filepath, isESM) {
|
|
247
627
|
var _a;
|
|
248
628
|
try {
|
|
249
|
-
const result = await
|
|
629
|
+
const result = await build2({
|
|
250
630
|
entryPoints: [filepath],
|
|
251
631
|
outfile: "out.js",
|
|
252
632
|
write: false,
|
|
@@ -256,20 +636,7 @@ var _MockLoader = class extends EventEmitter {
|
|
|
256
636
|
metafile: true,
|
|
257
637
|
format: isESM ? "esm" : "cjs",
|
|
258
638
|
define: this.options.define,
|
|
259
|
-
plugins: [
|
|
260
|
-
{
|
|
261
|
-
name: "externalize-deps",
|
|
262
|
-
setup(build2) {
|
|
263
|
-
build2.onResolve({ filter: /.*/ }, ({ path: id }) => {
|
|
264
|
-
if (id[0] !== "." && !path2.isAbsolute(id)) {
|
|
265
|
-
return {
|
|
266
|
-
external: true
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
]
|
|
639
|
+
plugins: [externalizeDeps]
|
|
273
640
|
});
|
|
274
641
|
return {
|
|
275
642
|
code: result.outputFiles[0].text,
|
|
@@ -286,59 +653,6 @@ var _MockLoader = class extends EventEmitter {
|
|
|
286
653
|
var MockLoader = _MockLoader;
|
|
287
654
|
MockLoader.EXT_JSON = /\.json5?$/;
|
|
288
655
|
|
|
289
|
-
// src/parseReqBody.ts
|
|
290
|
-
import bodyParser from "co-body";
|
|
291
|
-
import formidable from "formidable";
|
|
292
|
-
async function parseReqBody(req, options) {
|
|
293
|
-
const method = req.method.toUpperCase();
|
|
294
|
-
if (["GET", "DELETE", "HEAD"].includes(method))
|
|
295
|
-
return void 0;
|
|
296
|
-
const type = req.headers["content-type"];
|
|
297
|
-
try {
|
|
298
|
-
if (type === "application/json") {
|
|
299
|
-
return await bodyParser.json(req);
|
|
300
|
-
}
|
|
301
|
-
if (type === "application/x-www-form-urlencoded") {
|
|
302
|
-
return await bodyParser.form(req);
|
|
303
|
-
}
|
|
304
|
-
if (type === "text/plain") {
|
|
305
|
-
return await bodyParser.text(req);
|
|
306
|
-
}
|
|
307
|
-
if (type == null ? void 0 : type.startsWith("multipart/form-data;")) {
|
|
308
|
-
return await parseMultipart(req, options);
|
|
309
|
-
}
|
|
310
|
-
} catch (e) {
|
|
311
|
-
console.error(e);
|
|
312
|
-
}
|
|
313
|
-
return void 0;
|
|
314
|
-
}
|
|
315
|
-
async function parseMultipart(req, options) {
|
|
316
|
-
const form = formidable(options);
|
|
317
|
-
return new Promise((resolve, reject) => {
|
|
318
|
-
form.parse(req, (error, fields, files) => {
|
|
319
|
-
if (error) {
|
|
320
|
-
reject(error);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
resolve({ ...fields, ...files });
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// src/validator.ts
|
|
329
|
-
function validate(request, validator) {
|
|
330
|
-
return equalObj(request.headers, validator.headers) && equalObj(request.body, validator.body) && equalObj(request.params, validator.params) && equalObj(request.query, validator.query);
|
|
331
|
-
}
|
|
332
|
-
function equalObj(left, right) {
|
|
333
|
-
if (!right)
|
|
334
|
-
return true;
|
|
335
|
-
for (const key in right) {
|
|
336
|
-
if (right[key] !== left[key])
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
656
|
// src/mockMiddleware.ts
|
|
343
657
|
async function mockServerMiddleware(httpServer, config, options) {
|
|
344
658
|
const include = isArray(options.include) ? options.include : [options.include];
|
|
@@ -358,106 +672,13 @@ async function mockServerMiddleware(httpServer, config, options) {
|
|
|
358
672
|
await loader.load();
|
|
359
673
|
httpServer == null ? void 0 : httpServer.on("close", () => loader.close());
|
|
360
674
|
const proxies = Object.keys(config.server.proxy || {});
|
|
361
|
-
return
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return next();
|
|
366
|
-
}
|
|
367
|
-
const mockUrl = Object.keys(loader._mockList).find((key) => {
|
|
368
|
-
return pathToRegexp(key).test(pathname);
|
|
369
|
-
});
|
|
370
|
-
if (!mockUrl) {
|
|
371
|
-
return next();
|
|
372
|
-
}
|
|
373
|
-
const mockList = loader.mockList[mockUrl];
|
|
374
|
-
const reqBody = await parseReqBody(req, options.formidableOptions);
|
|
375
|
-
const currentMock = mockList.find((mock) => {
|
|
376
|
-
if (!pathname || !mock || !mock.url)
|
|
377
|
-
return false;
|
|
378
|
-
const methods = mock.method ? isArray(mock.method) ? mock.method : [mock.method] : ["GET", "POST"];
|
|
379
|
-
if (!methods.includes(req.method.toUpperCase()))
|
|
380
|
-
return false;
|
|
381
|
-
const hasMock = pathToRegexp(mock.url).test(pathname);
|
|
382
|
-
if (hasMock && mock.validator) {
|
|
383
|
-
const urlMatch2 = match(mock.url, { decode: decodeURIComponent })(
|
|
384
|
-
pathname
|
|
385
|
-
) || { params: {} };
|
|
386
|
-
const params2 = urlMatch2.params || {};
|
|
387
|
-
const request = {
|
|
388
|
-
query,
|
|
389
|
-
params: params2,
|
|
390
|
-
body: reqBody,
|
|
391
|
-
headers: req.headers
|
|
392
|
-
};
|
|
393
|
-
if (isFunction(mock.validator)) {
|
|
394
|
-
return mock.validator(request);
|
|
395
|
-
} else {
|
|
396
|
-
return validate(request, mock.validator);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
return hasMock;
|
|
400
|
-
});
|
|
401
|
-
if (!currentMock)
|
|
402
|
-
return next();
|
|
403
|
-
debug("middleware: ", method, pathname);
|
|
404
|
-
if (currentMock.delay && currentMock.delay > 0) {
|
|
405
|
-
await sleep(currentMock.delay);
|
|
406
|
-
}
|
|
407
|
-
res.statusCode = currentMock.status || 200;
|
|
408
|
-
res.statusMessage = currentMock.statusText || "OK";
|
|
409
|
-
const urlMatch = match(currentMock.url, { decode: decodeURIComponent })(
|
|
410
|
-
pathname
|
|
411
|
-
) || { params: {} };
|
|
412
|
-
const params = urlMatch.params || {};
|
|
413
|
-
req.body = reqBody;
|
|
414
|
-
req.query = query;
|
|
415
|
-
req.params = params;
|
|
416
|
-
res.setHeader("Content-Type", "application/json");
|
|
417
|
-
res.setHeader("X-Mock", "generate by vite:mock-dev-server");
|
|
418
|
-
if (currentMock.headers) {
|
|
419
|
-
const headers = isFunction(currentMock.headers) ? await currentMock.headers({
|
|
420
|
-
query,
|
|
421
|
-
body: reqBody,
|
|
422
|
-
params,
|
|
423
|
-
headers: req.headers
|
|
424
|
-
}) : currentMock.headers;
|
|
425
|
-
Object.keys(headers).forEach((key) => {
|
|
426
|
-
res.setHeader(key, headers[key]);
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
if (currentMock.body) {
|
|
430
|
-
let body;
|
|
431
|
-
if (isFunction(currentMock.body)) {
|
|
432
|
-
body = await currentMock.body({
|
|
433
|
-
query,
|
|
434
|
-
body: reqBody,
|
|
435
|
-
params,
|
|
436
|
-
headers: req.headers
|
|
437
|
-
});
|
|
438
|
-
} else {
|
|
439
|
-
body = currentMock.body;
|
|
440
|
-
}
|
|
441
|
-
res.end(JSON.stringify(body));
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
if (currentMock.response) {
|
|
445
|
-
await currentMock.response(
|
|
446
|
-
req,
|
|
447
|
-
res,
|
|
448
|
-
next
|
|
449
|
-
);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
res.end("");
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
function doesProxyContextMatchUrl(context, url) {
|
|
456
|
-
return context.startsWith("^") && new RegExp(context).test(url) || url.startsWith(context);
|
|
675
|
+
return baseMiddleware(loader.mockData, {
|
|
676
|
+
formidableOptions: options.formidableOptions,
|
|
677
|
+
proxies
|
|
678
|
+
});
|
|
457
679
|
}
|
|
458
680
|
|
|
459
681
|
// src/plugin.ts
|
|
460
|
-
var viteConfig = {};
|
|
461
682
|
function mockDevServerPlugin({
|
|
462
683
|
include = ["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],
|
|
463
684
|
exclude = [
|
|
@@ -468,8 +689,51 @@ function mockDevServerPlugin({
|
|
|
468
689
|
"**/.git/**",
|
|
469
690
|
"**/dist/**"
|
|
470
691
|
],
|
|
471
|
-
formidableOptions = {}
|
|
692
|
+
formidableOptions = {},
|
|
693
|
+
build: build3 = false
|
|
472
694
|
} = {}) {
|
|
695
|
+
const pluginOptions = {
|
|
696
|
+
include,
|
|
697
|
+
exclude,
|
|
698
|
+
formidableOptions: {
|
|
699
|
+
multiples: true,
|
|
700
|
+
...formidableOptions
|
|
701
|
+
},
|
|
702
|
+
build: build3 ? Object.assign(
|
|
703
|
+
{
|
|
704
|
+
serverPort: 8080,
|
|
705
|
+
dist: "mockServer"
|
|
706
|
+
},
|
|
707
|
+
typeof build3 === "object" ? build3 : {}
|
|
708
|
+
) : false
|
|
709
|
+
};
|
|
710
|
+
const plugins = [serverPlugin(pluginOptions)];
|
|
711
|
+
if (pluginOptions.build) {
|
|
712
|
+
plugins.push(buildPlugin(pluginOptions));
|
|
713
|
+
}
|
|
714
|
+
return plugins;
|
|
715
|
+
}
|
|
716
|
+
function buildPlugin(pluginOptions) {
|
|
717
|
+
let viteConfig = {};
|
|
718
|
+
return {
|
|
719
|
+
name: "vite-plugin-mock-dev-server-generator",
|
|
720
|
+
enforce: "post",
|
|
721
|
+
apply: "build",
|
|
722
|
+
configResolved(config) {
|
|
723
|
+
viteConfig = config;
|
|
724
|
+
config.logger.warn("");
|
|
725
|
+
},
|
|
726
|
+
async buildEnd(error) {
|
|
727
|
+
if (error)
|
|
728
|
+
return;
|
|
729
|
+
if (viteConfig.command !== "build")
|
|
730
|
+
return;
|
|
731
|
+
await generateMockServer(this, viteConfig, pluginOptions);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function serverPlugin(pluginOptions) {
|
|
736
|
+
let viteConfig = {};
|
|
473
737
|
return {
|
|
474
738
|
name: "vite-plugin-mock-dev-server",
|
|
475
739
|
enforce: "pre",
|
|
@@ -479,25 +743,19 @@ function mockDevServerPlugin({
|
|
|
479
743
|
config.logger.warn("");
|
|
480
744
|
},
|
|
481
745
|
async configureServer({ middlewares, config, httpServer }) {
|
|
482
|
-
const middleware = await mockServerMiddleware(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
...formidableOptions
|
|
488
|
-
}
|
|
489
|
-
});
|
|
746
|
+
const middleware = await mockServerMiddleware(
|
|
747
|
+
httpServer,
|
|
748
|
+
config,
|
|
749
|
+
pluginOptions
|
|
750
|
+
);
|
|
490
751
|
middlewares.use(middleware);
|
|
491
752
|
},
|
|
492
753
|
async configurePreviewServer({ middlewares, httpServer }) {
|
|
493
|
-
const middleware = await mockServerMiddleware(
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
...formidableOptions
|
|
499
|
-
}
|
|
500
|
-
});
|
|
754
|
+
const middleware = await mockServerMiddleware(
|
|
755
|
+
httpServer,
|
|
756
|
+
viteConfig,
|
|
757
|
+
pluginOptions
|
|
758
|
+
);
|
|
501
759
|
middlewares.use(middleware);
|
|
502
760
|
}
|
|
503
761
|
};
|
|
@@ -511,6 +769,7 @@ function defineMock(config) {
|
|
|
511
769
|
// src/index.ts
|
|
512
770
|
var src_default = mockDevServerPlugin;
|
|
513
771
|
export {
|
|
772
|
+
baseMiddleware,
|
|
514
773
|
src_default as default,
|
|
515
774
|
defineMock,
|
|
516
775
|
mockDevServerPlugin
|