vite-plugin-mock-dev-server 0.4.2 → 1.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 +53 -15
- package/README.zh-CN.md +48 -12
- package/dist/index.cjs +80 -45
- package/dist/index.d.ts +17 -13
- package/dist/index.js +81 -46
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<a href="https://www.npmjs.com/package/vite-plugin-mock-dev-server"><img alt="npm" src="https://img.shields.io/npm/v/vite-plugin-mock-dev-server?style=flat-square"></a>
|
|
12
12
|
<img alt="node-current" src="https://img.shields.io/node/v/vite-plugin-mock-dev-server?style=flat-square">
|
|
13
13
|
<img alt="npm peer dependency version" src="https://img.shields.io/npm/dependency-version/vite-plugin-mock-dev-server/peer/vite?style=flat-square">
|
|
14
|
-
<img alt="GitHub" src="https://img.shields.io/github/
|
|
14
|
+
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/pengzhanbo/vite-plugin-mock-dev-server/lint.yml?style=flat-square">
|
|
15
15
|
<img alt="npm" src="https://img.shields.io/npm/dm/vite-plugin-mock-dev-server?style=flat-square">
|
|
16
16
|
</p>
|
|
17
17
|
<br>
|
|
@@ -131,25 +131,29 @@ export default defineConfig({
|
|
|
131
131
|
|
|
132
132
|
- `options.prefix`
|
|
133
133
|
|
|
134
|
-
Type
|
|
134
|
+
**Type:** `string | string[]`
|
|
135
135
|
|
|
136
136
|
Configure custom matches rules for the mock server. Any requests that request path starts with that `prefix` will be proxied to that specified target. If the `prefix` starts with ^, it will be interpreted as a RegExp.
|
|
137
137
|
|
|
138
138
|
> In general, `server.proxy` is sufficient to meet the requirements, and this options is added to be compatible with some scenarios.
|
|
139
139
|
|
|
140
|
-
Default
|
|
140
|
+
**Default:** `[]`
|
|
141
141
|
|
|
142
142
|
- `option.include`
|
|
143
|
+
|
|
144
|
+
**Type:** `string | string[]`
|
|
143
145
|
|
|
144
146
|
Configure to read mock files, which can be a directory, glob, or array
|
|
145
147
|
|
|
146
|
-
Default
|
|
148
|
+
**Default:** `['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']` (relative for `process.cwd()`)
|
|
147
149
|
|
|
148
150
|
- `options.exclude`
|
|
151
|
+
|
|
152
|
+
**Type:** `string | string[]`
|
|
149
153
|
|
|
150
154
|
When you configure the mock files to be read, the files you want to exclude can be a directory, glob, or array
|
|
151
155
|
|
|
152
|
-
Default
|
|
156
|
+
**Default:**
|
|
153
157
|
```ts
|
|
154
158
|
[
|
|
155
159
|
'**/node_modules/**',
|
|
@@ -161,11 +165,21 @@ export default defineConfig({
|
|
|
161
165
|
]
|
|
162
166
|
```
|
|
163
167
|
|
|
168
|
+
- `options.reload`
|
|
169
|
+
|
|
170
|
+
**Type:** `boolean`
|
|
171
|
+
|
|
172
|
+
When mock resources are hot updated, only the data content is updated, but the page is not refreshed by default.
|
|
173
|
+
Turn this on when you want to refresh the page every time you modify the mock file.
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
**Default:** `false`
|
|
177
|
+
|
|
164
178
|
- `options.formidableOptions`
|
|
165
179
|
|
|
166
180
|
Configure to `formidable`,see [formidable options](https://github.com/node-formidable/formidable#options)
|
|
167
181
|
|
|
168
|
-
Default
|
|
182
|
+
**Default:** `{}`
|
|
169
183
|
|
|
170
184
|
example: Configure to file upload dir
|
|
171
185
|
```ts
|
|
@@ -180,9 +194,9 @@ export default defineConfig({
|
|
|
180
194
|
|
|
181
195
|
When building a small, independently deployable mock service.
|
|
182
196
|
|
|
183
|
-
Type
|
|
197
|
+
**Type:** `boolean | ServerBuildOptions`
|
|
184
198
|
|
|
185
|
-
Default
|
|
199
|
+
**Default:** `false`
|
|
186
200
|
|
|
187
201
|
```ts
|
|
188
202
|
interface ServerBuildOptions {
|
|
@@ -217,7 +231,7 @@ export default defineMock({
|
|
|
217
231
|
```ts
|
|
218
232
|
export default defineMock({
|
|
219
233
|
/**
|
|
220
|
-
* Address of request,support `/api/user/:id`
|
|
234
|
+
* Address of request,and support like `/api/user/:id`
|
|
221
235
|
*/
|
|
222
236
|
url: '/api/test',
|
|
223
237
|
/**
|
|
@@ -396,7 +410,7 @@ export default defineMock([
|
|
|
396
410
|
}
|
|
397
411
|
},
|
|
398
412
|
body: {
|
|
399
|
-
message: 'query.a
|
|
413
|
+
message: 'query.a == 1'
|
|
400
414
|
}
|
|
401
415
|
},
|
|
402
416
|
// Match /api/test?a=2
|
|
@@ -408,7 +422,16 @@ export default defineMock([
|
|
|
408
422
|
}
|
|
409
423
|
},
|
|
410
424
|
body: {
|
|
411
|
-
message: 'query.a
|
|
425
|
+
message: 'query.a == 2'
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
/**
|
|
430
|
+
* `?a=3` will resolve to `validator.query`
|
|
431
|
+
*/
|
|
432
|
+
url: '/api/test?a=3',
|
|
433
|
+
body: {
|
|
434
|
+
message: 'query.a == 3'
|
|
412
435
|
}
|
|
413
436
|
}
|
|
414
437
|
])
|
|
@@ -433,7 +456,22 @@ export default defineMock({
|
|
|
433
456
|
})
|
|
434
457
|
```
|
|
435
458
|
|
|
436
|
-
#### Example 8
|
|
459
|
+
#### Example 8:
|
|
460
|
+
Dynamic route matching
|
|
461
|
+
```ts
|
|
462
|
+
export default defineMock({
|
|
463
|
+
url: '/api/user/:userId',
|
|
464
|
+
body({ params }) {
|
|
465
|
+
return {
|
|
466
|
+
userId: params.userId,
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
})
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
The `userId` in the route will be resolved into the `request.params` object.
|
|
473
|
+
|
|
474
|
+
#### Example 9:
|
|
437
475
|
Use `mockjs`:
|
|
438
476
|
```ts
|
|
439
477
|
import Mock from 'mockjs'
|
|
@@ -448,7 +486,7 @@ export default defineMock({
|
|
|
448
486
|
```
|
|
449
487
|
You need installed `mockjs`
|
|
450
488
|
|
|
451
|
-
### Example
|
|
489
|
+
### Example 10:
|
|
452
490
|
Use `response` to customize the response
|
|
453
491
|
```ts
|
|
454
492
|
export default defineMock({
|
|
@@ -468,7 +506,7 @@ export default defineMock({
|
|
|
468
506
|
})
|
|
469
507
|
```
|
|
470
508
|
|
|
471
|
-
### Example
|
|
509
|
+
### Example 11:
|
|
472
510
|
Use json / json5
|
|
473
511
|
```json
|
|
474
512
|
{
|
|
@@ -480,7 +518,7 @@ Use json / json5
|
|
|
480
518
|
}
|
|
481
519
|
```
|
|
482
520
|
|
|
483
|
-
### Example
|
|
521
|
+
### Example 12:
|
|
484
522
|
|
|
485
523
|
multipart, upload file.
|
|
486
524
|
|
package/README.zh-CN.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<a href="https://www.npmjs.com/package/vite-plugin-mock-dev-server"><img alt="npm" src="https://img.shields.io/npm/v/vite-plugin-mock-dev-server?style=flat-square"></a>
|
|
14
14
|
<img alt="node-current" src="https://img.shields.io/node/v/vite-plugin-mock-dev-server?style=flat-square">
|
|
15
15
|
<img alt="npm peer dependency version" src="https://img.shields.io/npm/dependency-version/vite-plugin-mock-dev-server/peer/vite?style=flat-square">
|
|
16
|
-
<img alt="GitHub" src="https://img.shields.io/github/
|
|
16
|
+
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/pengzhanbo/vite-plugin-mock-dev-server/lint.yml?style=flat-square">
|
|
17
17
|
<img alt="npm" src="https://img.shields.io/npm/dm/vite-plugin-mock-dev-server?style=flat-square">
|
|
18
18
|
</p>
|
|
19
19
|
<br>
|
|
@@ -133,25 +133,29 @@ export default defineConfig({
|
|
|
133
133
|
|
|
134
134
|
- `options.prefix`
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
**类型:** `string | string[]`
|
|
137
137
|
|
|
138
138
|
为mock服务器配置自定义匹配规则。任何请求路径以 `prefix` 值开头的请求将被代理到对应的目标。如果 `prefix` 值以 ^ 开头,将被识别为 RegExp。
|
|
139
139
|
|
|
140
140
|
> 一般情况下, `server.proxy` 已经足够满足需求,添加此项是为了与某些场景兼容。
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
**默认值:** `[]`
|
|
143
143
|
|
|
144
144
|
- `option.include`
|
|
145
|
+
|
|
146
|
+
**类型:** `string | string[]`
|
|
145
147
|
|
|
146
148
|
配置读取 mock文件,可以是一个 目录,glob,或者一个数组
|
|
147
149
|
|
|
148
|
-
|
|
150
|
+
**默认值:** `['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']` (相对于根目录)
|
|
149
151
|
|
|
150
152
|
- `options.exclude`
|
|
153
|
+
|
|
154
|
+
**类型:** `string | string[]`
|
|
151
155
|
|
|
152
156
|
配置读取 mock文件时,需要排除的文件, 可以是一个 目录、glob、或者一个数组
|
|
153
157
|
|
|
154
|
-
|
|
158
|
+
**默认值:**
|
|
155
159
|
```ts
|
|
156
160
|
[
|
|
157
161
|
'**/node_modules/**',
|
|
@@ -163,11 +167,19 @@ export default defineConfig({
|
|
|
163
167
|
]
|
|
164
168
|
```
|
|
165
169
|
|
|
170
|
+
- `options.reload`
|
|
171
|
+
|
|
172
|
+
**Type:** `boolean`
|
|
173
|
+
|
|
174
|
+
mock资源热更新时,仅更新了数据内容,但是默认不重新刷新页面。当你希望每次修改mock文件都刷新页面时,可以打开此选项。
|
|
175
|
+
|
|
176
|
+
**Default:** `false`
|
|
177
|
+
|
|
166
178
|
- `options.formidableOptions`
|
|
167
179
|
|
|
168
180
|
配置 `formidable`,查看 [formidable options](https://github.com/node-formidable/formidable#options)
|
|
169
181
|
|
|
170
|
-
|
|
182
|
+
**默认值:** `{}`
|
|
171
183
|
|
|
172
184
|
示例: 配置文件上传的存放目录
|
|
173
185
|
```ts
|
|
@@ -182,9 +194,9 @@ export default defineConfig({
|
|
|
182
194
|
|
|
183
195
|
构建可独立部署的小型mock服务时配置。
|
|
184
196
|
|
|
185
|
-
|
|
197
|
+
**类型:** `boolean | ServerBuildOptions`
|
|
186
198
|
|
|
187
|
-
|
|
199
|
+
**默认值:**`false`
|
|
188
200
|
|
|
189
201
|
```ts
|
|
190
202
|
interface ServerBuildOptions {
|
|
@@ -413,6 +425,15 @@ export default defineMock([
|
|
|
413
425
|
body: {
|
|
414
426
|
message: 'query.a === 2'
|
|
415
427
|
}
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
/**
|
|
431
|
+
* `?a=3` 将会解析到 `validator.query`
|
|
432
|
+
*/
|
|
433
|
+
url: '/api/test?a=3',
|
|
434
|
+
body: {
|
|
435
|
+
message: 'query.a == 3'
|
|
436
|
+
}
|
|
416
437
|
}
|
|
417
438
|
])
|
|
418
439
|
```
|
|
@@ -436,7 +457,22 @@ export default defineMock({
|
|
|
436
457
|
})
|
|
437
458
|
```
|
|
438
459
|
|
|
439
|
-
#### 示例8
|
|
460
|
+
#### 示例8:
|
|
461
|
+
动态路由匹配
|
|
462
|
+
```ts
|
|
463
|
+
export default defineMock({
|
|
464
|
+
url: '/api/user/:userId',
|
|
465
|
+
body({ params }) {
|
|
466
|
+
return {
|
|
467
|
+
userId: params.userId,
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
路由中的 `userId`将会解析到 `request.params` 对象中.
|
|
474
|
+
|
|
475
|
+
#### 示例9:
|
|
440
476
|
使用 `mockjs` 生成响应数据:
|
|
441
477
|
```ts
|
|
442
478
|
import Mock from 'mockjs'
|
|
@@ -451,7 +487,7 @@ export default defineMock({
|
|
|
451
487
|
```
|
|
452
488
|
请先安装 `mockjs`
|
|
453
489
|
|
|
454
|
-
### 示例
|
|
490
|
+
### 示例10:
|
|
455
491
|
使用 `response` 自定义响应
|
|
456
492
|
```ts
|
|
457
493
|
export default defineMock({
|
|
@@ -471,7 +507,7 @@ export default defineMock({
|
|
|
471
507
|
})
|
|
472
508
|
```
|
|
473
509
|
|
|
474
|
-
### 示例
|
|
510
|
+
### 示例11:
|
|
475
511
|
使用 json / json5
|
|
476
512
|
```json
|
|
477
513
|
{
|
|
@@ -483,7 +519,7 @@ export default defineMock({
|
|
|
483
519
|
}
|
|
484
520
|
```
|
|
485
521
|
|
|
486
|
-
### Example
|
|
522
|
+
### Example 12:
|
|
487
523
|
|
|
488
524
|
multipart, 文件上传.
|
|
489
525
|
|
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ var import_vite = require("vite");
|
|
|
52
52
|
|
|
53
53
|
// package.json
|
|
54
54
|
var name = "vite-plugin-mock-dev-server";
|
|
55
|
-
var version = "0.
|
|
55
|
+
var version = "1.0.0";
|
|
56
56
|
|
|
57
57
|
// src/esbuildPlugin.ts
|
|
58
58
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
@@ -100,6 +100,7 @@ var import_node_fs = __toESM(require("fs"), 1);
|
|
|
100
100
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
101
101
|
var import_node_url = require("url");
|
|
102
102
|
var import_debug = __toESM(require("debug"), 1);
|
|
103
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
103
104
|
var isArray = (val) => Array.isArray(val);
|
|
104
105
|
var isFunction = (val) => typeof val === "function";
|
|
105
106
|
function sleep(timeout) {
|
|
@@ -116,6 +117,14 @@ var ensureArray = (thing) => {
|
|
|
116
117
|
return [];
|
|
117
118
|
return [thing];
|
|
118
119
|
};
|
|
120
|
+
var log = {
|
|
121
|
+
info(...args) {
|
|
122
|
+
console.info(import_picocolors.default.cyan("mock-dev-server: "), ...args);
|
|
123
|
+
},
|
|
124
|
+
error(...args) {
|
|
125
|
+
console.error("\n", import_picocolors.default.cyan("mock-dev-server: "), ...args, "\n");
|
|
126
|
+
}
|
|
127
|
+
};
|
|
119
128
|
function lookupFile(dir, formats, options) {
|
|
120
129
|
for (const format of formats) {
|
|
121
130
|
const fullPath = import_node_path2.default.join(dir, format);
|
|
@@ -319,6 +328,7 @@ async function buildMockEntry(inputFile, define) {
|
|
|
319
328
|
var import_node_url2 = require("url");
|
|
320
329
|
var import_http_status = __toESM(require("http-status"), 1);
|
|
321
330
|
var import_path_to_regexp = require("path-to-regexp");
|
|
331
|
+
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
322
332
|
|
|
323
333
|
// src/parseReqBody.ts
|
|
324
334
|
var import_co_body = __toESM(require("co-body"), 1);
|
|
@@ -404,7 +414,7 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
404
414
|
pathname
|
|
405
415
|
) || { params: {} };
|
|
406
416
|
const params2 = urlMatch2.params || {};
|
|
407
|
-
const
|
|
417
|
+
const request2 = {
|
|
408
418
|
query,
|
|
409
419
|
refererQuery,
|
|
410
420
|
params: params2,
|
|
@@ -412,9 +422,9 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
412
422
|
headers: req.headers
|
|
413
423
|
};
|
|
414
424
|
if (isFunction(mock.validator)) {
|
|
415
|
-
return mock.validator(
|
|
425
|
+
return mock.validator(request2);
|
|
416
426
|
} else {
|
|
417
|
-
return validate(
|
|
427
|
+
return validate(request2, mock.validator);
|
|
418
428
|
}
|
|
419
429
|
}
|
|
420
430
|
return hasMock;
|
|
@@ -431,47 +441,53 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
431
441
|
pathname
|
|
432
442
|
) || { params: {} };
|
|
433
443
|
const params = urlMatch.params || {};
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
444
|
+
const request = req;
|
|
445
|
+
request.body = reqBody;
|
|
446
|
+
request.query = query;
|
|
447
|
+
request.refererQuery = refererQuery;
|
|
448
|
+
request.params = params;
|
|
438
449
|
res.setHeader("Content-Type", "application/json");
|
|
439
450
|
res.setHeader("Cache-Control", "no-cache,max-age=0");
|
|
440
|
-
res.setHeader("X-Mock", "generate by vite:mock-dev-server");
|
|
451
|
+
res.setHeader("X-Mock", "generate by vite:plugin-mock-dev-server");
|
|
441
452
|
if (currentMock.headers) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
});
|
|
453
|
+
try {
|
|
454
|
+
const headers = isFunction(currentMock.headers) ? await currentMock.headers(request) : currentMock.headers;
|
|
455
|
+
Object.keys(headers).forEach((key) => {
|
|
456
|
+
res.setHeader(key, headers[key]);
|
|
457
|
+
});
|
|
458
|
+
} catch (e) {
|
|
459
|
+
log.error(`${import_picocolors2.default.red("[headers error]")} ${req.url}
|
|
460
|
+
`, e);
|
|
461
|
+
}
|
|
452
462
|
}
|
|
453
463
|
if (currentMock.body) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
body
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
464
|
+
try {
|
|
465
|
+
let body;
|
|
466
|
+
if (isFunction(currentMock.body)) {
|
|
467
|
+
body = await currentMock.body(request);
|
|
468
|
+
} else {
|
|
469
|
+
body = currentMock.body;
|
|
470
|
+
}
|
|
471
|
+
res.end(JSON.stringify(body));
|
|
472
|
+
} catch (e) {
|
|
473
|
+
log.error(`${import_picocolors2.default.red("[body error]")} ${req.url}
|
|
474
|
+
`, e);
|
|
475
|
+
res.statusCode = 500;
|
|
476
|
+
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
477
|
+
res.end("");
|
|
465
478
|
}
|
|
466
|
-
res.end(JSON.stringify(body));
|
|
467
479
|
return;
|
|
468
480
|
}
|
|
469
481
|
if (currentMock.response) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
482
|
+
try {
|
|
483
|
+
await currentMock.response(request, res, next);
|
|
484
|
+
} catch (e) {
|
|
485
|
+
log.error(`${import_picocolors2.default.red("[response error]")} ${req.url}
|
|
486
|
+
`, e);
|
|
487
|
+
res.statusCode = 500;
|
|
488
|
+
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
489
|
+
res.end("");
|
|
490
|
+
}
|
|
475
491
|
return;
|
|
476
492
|
}
|
|
477
493
|
res.end("");
|
|
@@ -534,12 +550,14 @@ var _MockLoader = class extends import_node_events.default {
|
|
|
534
550
|
return;
|
|
535
551
|
await this.loadMock(filepath);
|
|
536
552
|
this.updateMockList();
|
|
553
|
+
this.emit("mock:update-end");
|
|
537
554
|
});
|
|
538
555
|
this.on("mock:unlink", async (filepath) => {
|
|
539
556
|
if (!includeFilter(filepath))
|
|
540
557
|
return;
|
|
541
558
|
this.moduleCache.delete(filepath);
|
|
542
559
|
this.updateMockList();
|
|
560
|
+
this.emit("mock:update-end");
|
|
543
561
|
});
|
|
544
562
|
}
|
|
545
563
|
watchMockEntry() {
|
|
@@ -609,10 +627,19 @@ var _MockLoader = class extends import_node_events.default {
|
|
|
609
627
|
}
|
|
610
628
|
const mocks = {};
|
|
611
629
|
mockList.filter((mock) => mock.enabled || typeof mock.enabled === "undefined").forEach((mock) => {
|
|
612
|
-
|
|
613
|
-
|
|
630
|
+
const { pathname, query } = (0, import_node_url3.parse)(mock.url, true);
|
|
631
|
+
if (!mocks[pathname]) {
|
|
632
|
+
mocks[pathname] = [];
|
|
633
|
+
}
|
|
634
|
+
mock.url = pathname;
|
|
635
|
+
const list = mocks[pathname];
|
|
636
|
+
if (query && !isFunction(mock.validator)) {
|
|
637
|
+
mock.validator ?? (mock.validator = {});
|
|
638
|
+
mock.validator.query = Object.assign(
|
|
639
|
+
query,
|
|
640
|
+
mock.validator.query || {}
|
|
641
|
+
);
|
|
614
642
|
}
|
|
615
|
-
const list = mocks[mock.url];
|
|
616
643
|
mock.validator ? list.unshift(mock) : list.push(mock);
|
|
617
644
|
});
|
|
618
645
|
this._mockData = mocks;
|
|
@@ -733,7 +760,7 @@ var MockLoader = _MockLoader;
|
|
|
733
760
|
MockLoader.EXT_JSON = /\.json5?$/;
|
|
734
761
|
|
|
735
762
|
// src/mockMiddleware.ts
|
|
736
|
-
async function mockServerMiddleware(
|
|
763
|
+
async function mockServerMiddleware(config, options, httpServer, ws) {
|
|
737
764
|
const include = ensureArray(options.include);
|
|
738
765
|
const exclude = ensureArray(options.exclude);
|
|
739
766
|
const define = {};
|
|
@@ -750,6 +777,11 @@ async function mockServerMiddleware(httpServer, config, options) {
|
|
|
750
777
|
});
|
|
751
778
|
await loader.load();
|
|
752
779
|
httpServer == null ? void 0 : httpServer.on("close", () => loader.close());
|
|
780
|
+
loader.on("mock:update-end", () => {
|
|
781
|
+
if (options.reload) {
|
|
782
|
+
ws == null ? void 0 : ws.send({ type: "full-reload" });
|
|
783
|
+
}
|
|
784
|
+
});
|
|
753
785
|
const proxies = ensureProxies(config.server.proxy || {});
|
|
754
786
|
const prefix = ensureArray(options.prefix);
|
|
755
787
|
return baseMiddleware(loader, {
|
|
@@ -770,6 +802,7 @@ function mockDevServerPlugin({
|
|
|
770
802
|
"**/.git/**",
|
|
771
803
|
"**/dist/**"
|
|
772
804
|
],
|
|
805
|
+
reload = false,
|
|
773
806
|
formidableOptions = {},
|
|
774
807
|
build: build3 = false
|
|
775
808
|
} = {}) {
|
|
@@ -777,6 +810,7 @@ function mockDevServerPlugin({
|
|
|
777
810
|
prefix,
|
|
778
811
|
include,
|
|
779
812
|
exclude,
|
|
813
|
+
reload,
|
|
780
814
|
formidableOptions: {
|
|
781
815
|
multiples: true,
|
|
782
816
|
...formidableOptions
|
|
@@ -824,19 +858,20 @@ function serverPlugin(pluginOptions) {
|
|
|
824
858
|
viteConfig = config;
|
|
825
859
|
config.logger.warn("");
|
|
826
860
|
},
|
|
827
|
-
async configureServer({ middlewares, config, httpServer }) {
|
|
861
|
+
async configureServer({ middlewares, config, httpServer, ws }) {
|
|
828
862
|
const middleware = await mockServerMiddleware(
|
|
829
|
-
httpServer,
|
|
830
863
|
config,
|
|
831
|
-
pluginOptions
|
|
864
|
+
pluginOptions,
|
|
865
|
+
httpServer,
|
|
866
|
+
ws
|
|
832
867
|
);
|
|
833
868
|
middlewares.use(middleware);
|
|
834
869
|
},
|
|
835
870
|
async configurePreviewServer({ middlewares, httpServer }) {
|
|
836
871
|
const middleware = await mockServerMiddleware(
|
|
837
|
-
httpServer,
|
|
838
872
|
viteConfig,
|
|
839
|
-
pluginOptions
|
|
873
|
+
pluginOptions,
|
|
874
|
+
httpServer
|
|
840
875
|
);
|
|
841
876
|
middlewares.use(middleware);
|
|
842
877
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,13 @@ interface MockServerPluginOptions {
|
|
|
23
23
|
* @see https://github.com/micromatch/picomatch#globbing-features
|
|
24
24
|
*/
|
|
25
25
|
exclude?: string | string[];
|
|
26
|
+
/**
|
|
27
|
+
* mock资源热更新时,仅更新了数据内容,但是默认不重新刷新页面。
|
|
28
|
+
* 当你希望每次修改mock文件都刷新页面时,可以打开此选项。
|
|
29
|
+
*
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
reload?: boolean;
|
|
26
33
|
/**
|
|
27
34
|
* formidable options
|
|
28
35
|
* @see https://github.com/node-formidable/formidable#options
|
|
@@ -50,8 +57,9 @@ interface ServerBuildOption {
|
|
|
50
57
|
dist?: string;
|
|
51
58
|
}
|
|
52
59
|
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'TRACE' | 'OPTIONS';
|
|
60
|
+
type Headers = http.IncomingHttpHeaders;
|
|
53
61
|
type ResponseBody = Record<string, any> | any[] | string | number | null;
|
|
54
|
-
interface
|
|
62
|
+
interface ExtraRequest {
|
|
55
63
|
/**
|
|
56
64
|
* 请求地址中位于 `?` 后面的 queryString,已解析为 json
|
|
57
65
|
*/
|
|
@@ -69,17 +77,13 @@ interface ResponseReq {
|
|
|
69
77
|
*/
|
|
70
78
|
params: Record<string, any>;
|
|
71
79
|
/**
|
|
72
|
-
*
|
|
80
|
+
* 请求体中 headers
|
|
73
81
|
*/
|
|
74
|
-
headers:
|
|
75
|
-
}
|
|
76
|
-
interface ResponseBodyFn {
|
|
77
|
-
(request: ResponseReq): ResponseBody | Promise<ResponseBody>;
|
|
78
|
-
}
|
|
79
|
-
interface ResponseHeaderFn {
|
|
80
|
-
(request: ResponseReq): Headers | Promise<Headers>;
|
|
82
|
+
headers: Headers;
|
|
81
83
|
}
|
|
82
|
-
type
|
|
84
|
+
type MockRequest = ExtraRequest & http.IncomingMessage;
|
|
85
|
+
type ResponseBodyFn = (request: MockRequest) => ResponseBody | Promise<ResponseBody>;
|
|
86
|
+
type ResponseHeaderFn = (request: MockRequest) => Headers | Promise<Headers>;
|
|
83
87
|
interface MockOptionsItem {
|
|
84
88
|
/**
|
|
85
89
|
* 需要做mock的接口地址,
|
|
@@ -136,7 +140,7 @@ interface MockOptionsItem {
|
|
|
136
140
|
*
|
|
137
141
|
* 在 req 中,还可以拿到 query、params、body等已解析的请求信息
|
|
138
142
|
*/
|
|
139
|
-
response?: (req:
|
|
143
|
+
response?: (req: MockRequest, res: http.ServerResponse<http.IncomingMessage>, next: Connect.NextFunction) => void | Promise<void>;
|
|
140
144
|
/**
|
|
141
145
|
* 请求验证器
|
|
142
146
|
*
|
|
@@ -144,12 +148,12 @@ interface MockOptionsItem {
|
|
|
144
148
|
* 但全部都在单个 mock中的 body或者 response 中写,内容会很庞杂,不好管理,
|
|
145
149
|
* 验证器的功能,允许你同时配置多条相同url的mock,通过验证器来判断使哪个mock生效。
|
|
146
150
|
*/
|
|
147
|
-
validator?: Partial<
|
|
151
|
+
validator?: Partial<ExtraRequest> | ((request: ExtraRequest) => boolean);
|
|
148
152
|
}
|
|
149
153
|
type MockOptions = MockOptionsItem[];
|
|
150
154
|
type FormidableFile = formidable.File | formidable.File[];
|
|
151
155
|
|
|
152
|
-
declare function mockDevServerPlugin({ prefix, include, exclude, formidableOptions, build, }?: MockServerPluginOptions): Plugin[];
|
|
156
|
+
declare function mockDevServerPlugin({ prefix, include, exclude, reload, formidableOptions, build, }?: MockServerPluginOptions): Plugin[];
|
|
153
157
|
|
|
154
158
|
/**
|
|
155
159
|
* mock config helper
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { createFilter } from "vite";
|
|
|
9
9
|
|
|
10
10
|
// package.json
|
|
11
11
|
var name = "vite-plugin-mock-dev-server";
|
|
12
|
-
var version = "0.
|
|
12
|
+
var version = "1.0.0";
|
|
13
13
|
|
|
14
14
|
// src/esbuildPlugin.ts
|
|
15
15
|
import fsp from "fs/promises";
|
|
@@ -57,6 +57,7 @@ import fs from "fs";
|
|
|
57
57
|
import path2 from "path";
|
|
58
58
|
import { fileURLToPath } from "url";
|
|
59
59
|
import Debug from "debug";
|
|
60
|
+
import colors from "picocolors";
|
|
60
61
|
var isArray = (val) => Array.isArray(val);
|
|
61
62
|
var isFunction = (val) => typeof val === "function";
|
|
62
63
|
function sleep(timeout) {
|
|
@@ -73,6 +74,14 @@ var ensureArray = (thing) => {
|
|
|
73
74
|
return [];
|
|
74
75
|
return [thing];
|
|
75
76
|
};
|
|
77
|
+
var log = {
|
|
78
|
+
info(...args) {
|
|
79
|
+
console.info(colors.cyan("mock-dev-server: "), ...args);
|
|
80
|
+
},
|
|
81
|
+
error(...args) {
|
|
82
|
+
console.error("\n", colors.cyan("mock-dev-server: "), ...args, "\n");
|
|
83
|
+
}
|
|
84
|
+
};
|
|
76
85
|
function lookupFile(dir, formats, options) {
|
|
77
86
|
for (const format of formats) {
|
|
78
87
|
const fullPath = path2.join(dir, format);
|
|
@@ -276,6 +285,7 @@ async function buildMockEntry(inputFile, define) {
|
|
|
276
285
|
import { parse as urlParse } from "url";
|
|
277
286
|
import HTTP_STATUS from "http-status";
|
|
278
287
|
import { match, pathToRegexp } from "path-to-regexp";
|
|
288
|
+
import colors2 from "picocolors";
|
|
279
289
|
|
|
280
290
|
// src/parseReqBody.ts
|
|
281
291
|
import bodyParser from "co-body";
|
|
@@ -361,7 +371,7 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
361
371
|
pathname
|
|
362
372
|
) || { params: {} };
|
|
363
373
|
const params2 = urlMatch2.params || {};
|
|
364
|
-
const
|
|
374
|
+
const request2 = {
|
|
365
375
|
query,
|
|
366
376
|
refererQuery,
|
|
367
377
|
params: params2,
|
|
@@ -369,9 +379,9 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
369
379
|
headers: req.headers
|
|
370
380
|
};
|
|
371
381
|
if (isFunction(mock.validator)) {
|
|
372
|
-
return mock.validator(
|
|
382
|
+
return mock.validator(request2);
|
|
373
383
|
} else {
|
|
374
|
-
return validate(
|
|
384
|
+
return validate(request2, mock.validator);
|
|
375
385
|
}
|
|
376
386
|
}
|
|
377
387
|
return hasMock;
|
|
@@ -388,47 +398,53 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies }) {
|
|
|
388
398
|
pathname
|
|
389
399
|
) || { params: {} };
|
|
390
400
|
const params = urlMatch.params || {};
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
401
|
+
const request = req;
|
|
402
|
+
request.body = reqBody;
|
|
403
|
+
request.query = query;
|
|
404
|
+
request.refererQuery = refererQuery;
|
|
405
|
+
request.params = params;
|
|
395
406
|
res.setHeader("Content-Type", "application/json");
|
|
396
407
|
res.setHeader("Cache-Control", "no-cache,max-age=0");
|
|
397
|
-
res.setHeader("X-Mock", "generate by vite:mock-dev-server");
|
|
408
|
+
res.setHeader("X-Mock", "generate by vite:plugin-mock-dev-server");
|
|
398
409
|
if (currentMock.headers) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
});
|
|
410
|
+
try {
|
|
411
|
+
const headers = isFunction(currentMock.headers) ? await currentMock.headers(request) : currentMock.headers;
|
|
412
|
+
Object.keys(headers).forEach((key) => {
|
|
413
|
+
res.setHeader(key, headers[key]);
|
|
414
|
+
});
|
|
415
|
+
} catch (e) {
|
|
416
|
+
log.error(`${colors2.red("[headers error]")} ${req.url}
|
|
417
|
+
`, e);
|
|
418
|
+
}
|
|
409
419
|
}
|
|
410
420
|
if (currentMock.body) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
body
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
421
|
+
try {
|
|
422
|
+
let body;
|
|
423
|
+
if (isFunction(currentMock.body)) {
|
|
424
|
+
body = await currentMock.body(request);
|
|
425
|
+
} else {
|
|
426
|
+
body = currentMock.body;
|
|
427
|
+
}
|
|
428
|
+
res.end(JSON.stringify(body));
|
|
429
|
+
} catch (e) {
|
|
430
|
+
log.error(`${colors2.red("[body error]")} ${req.url}
|
|
431
|
+
`, e);
|
|
432
|
+
res.statusCode = 500;
|
|
433
|
+
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
434
|
+
res.end("");
|
|
422
435
|
}
|
|
423
|
-
res.end(JSON.stringify(body));
|
|
424
436
|
return;
|
|
425
437
|
}
|
|
426
438
|
if (currentMock.response) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
439
|
+
try {
|
|
440
|
+
await currentMock.response(request, res, next);
|
|
441
|
+
} catch (e) {
|
|
442
|
+
log.error(`${colors2.red("[response error]")} ${req.url}
|
|
443
|
+
`, e);
|
|
444
|
+
res.statusCode = 500;
|
|
445
|
+
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
446
|
+
res.end("");
|
|
447
|
+
}
|
|
432
448
|
return;
|
|
433
449
|
}
|
|
434
450
|
res.end("");
|
|
@@ -446,7 +462,7 @@ import EventEmitter from "events";
|
|
|
446
462
|
import fs3 from "fs";
|
|
447
463
|
import { createRequire } from "module";
|
|
448
464
|
import path4 from "path";
|
|
449
|
-
import { pathToFileURL } from "url";
|
|
465
|
+
import { pathToFileURL, parse as urlParse2 } from "url";
|
|
450
466
|
import chokidar from "chokidar";
|
|
451
467
|
import { build as build2 } from "esbuild";
|
|
452
468
|
import fastGlob from "fast-glob";
|
|
@@ -491,12 +507,14 @@ var _MockLoader = class extends EventEmitter {
|
|
|
491
507
|
return;
|
|
492
508
|
await this.loadMock(filepath);
|
|
493
509
|
this.updateMockList();
|
|
510
|
+
this.emit("mock:update-end");
|
|
494
511
|
});
|
|
495
512
|
this.on("mock:unlink", async (filepath) => {
|
|
496
513
|
if (!includeFilter(filepath))
|
|
497
514
|
return;
|
|
498
515
|
this.moduleCache.delete(filepath);
|
|
499
516
|
this.updateMockList();
|
|
517
|
+
this.emit("mock:update-end");
|
|
500
518
|
});
|
|
501
519
|
}
|
|
502
520
|
watchMockEntry() {
|
|
@@ -566,10 +584,19 @@ var _MockLoader = class extends EventEmitter {
|
|
|
566
584
|
}
|
|
567
585
|
const mocks = {};
|
|
568
586
|
mockList.filter((mock) => mock.enabled || typeof mock.enabled === "undefined").forEach((mock) => {
|
|
569
|
-
|
|
570
|
-
|
|
587
|
+
const { pathname, query } = urlParse2(mock.url, true);
|
|
588
|
+
if (!mocks[pathname]) {
|
|
589
|
+
mocks[pathname] = [];
|
|
590
|
+
}
|
|
591
|
+
mock.url = pathname;
|
|
592
|
+
const list = mocks[pathname];
|
|
593
|
+
if (query && !isFunction(mock.validator)) {
|
|
594
|
+
mock.validator ?? (mock.validator = {});
|
|
595
|
+
mock.validator.query = Object.assign(
|
|
596
|
+
query,
|
|
597
|
+
mock.validator.query || {}
|
|
598
|
+
);
|
|
571
599
|
}
|
|
572
|
-
const list = mocks[mock.url];
|
|
573
600
|
mock.validator ? list.unshift(mock) : list.push(mock);
|
|
574
601
|
});
|
|
575
602
|
this._mockData = mocks;
|
|
@@ -690,7 +717,7 @@ var MockLoader = _MockLoader;
|
|
|
690
717
|
MockLoader.EXT_JSON = /\.json5?$/;
|
|
691
718
|
|
|
692
719
|
// src/mockMiddleware.ts
|
|
693
|
-
async function mockServerMiddleware(
|
|
720
|
+
async function mockServerMiddleware(config, options, httpServer, ws) {
|
|
694
721
|
const include = ensureArray(options.include);
|
|
695
722
|
const exclude = ensureArray(options.exclude);
|
|
696
723
|
const define = {};
|
|
@@ -707,6 +734,11 @@ async function mockServerMiddleware(httpServer, config, options) {
|
|
|
707
734
|
});
|
|
708
735
|
await loader.load();
|
|
709
736
|
httpServer == null ? void 0 : httpServer.on("close", () => loader.close());
|
|
737
|
+
loader.on("mock:update-end", () => {
|
|
738
|
+
if (options.reload) {
|
|
739
|
+
ws == null ? void 0 : ws.send({ type: "full-reload" });
|
|
740
|
+
}
|
|
741
|
+
});
|
|
710
742
|
const proxies = ensureProxies(config.server.proxy || {});
|
|
711
743
|
const prefix = ensureArray(options.prefix);
|
|
712
744
|
return baseMiddleware(loader, {
|
|
@@ -727,6 +759,7 @@ function mockDevServerPlugin({
|
|
|
727
759
|
"**/.git/**",
|
|
728
760
|
"**/dist/**"
|
|
729
761
|
],
|
|
762
|
+
reload = false,
|
|
730
763
|
formidableOptions = {},
|
|
731
764
|
build: build3 = false
|
|
732
765
|
} = {}) {
|
|
@@ -734,6 +767,7 @@ function mockDevServerPlugin({
|
|
|
734
767
|
prefix,
|
|
735
768
|
include,
|
|
736
769
|
exclude,
|
|
770
|
+
reload,
|
|
737
771
|
formidableOptions: {
|
|
738
772
|
multiples: true,
|
|
739
773
|
...formidableOptions
|
|
@@ -781,19 +815,20 @@ function serverPlugin(pluginOptions) {
|
|
|
781
815
|
viteConfig = config;
|
|
782
816
|
config.logger.warn("");
|
|
783
817
|
},
|
|
784
|
-
async configureServer({ middlewares, config, httpServer }) {
|
|
818
|
+
async configureServer({ middlewares, config, httpServer, ws }) {
|
|
785
819
|
const middleware = await mockServerMiddleware(
|
|
786
|
-
httpServer,
|
|
787
820
|
config,
|
|
788
|
-
pluginOptions
|
|
821
|
+
pluginOptions,
|
|
822
|
+
httpServer,
|
|
823
|
+
ws
|
|
789
824
|
);
|
|
790
825
|
middlewares.use(middleware);
|
|
791
826
|
},
|
|
792
827
|
async configurePreviewServer({ middlewares, httpServer }) {
|
|
793
828
|
const middleware = await mockServerMiddleware(
|
|
794
|
-
httpServer,
|
|
795
829
|
viteConfig,
|
|
796
|
-
pluginOptions
|
|
830
|
+
pluginOptions,
|
|
831
|
+
httpServer
|
|
797
832
|
);
|
|
798
833
|
middlewares.use(middleware);
|
|
799
834
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-mock-dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"vite",
|
|
6
6
|
"plugin",
|
|
@@ -33,13 +33,14 @@
|
|
|
33
33
|
"chokidar": "^3.5.3",
|
|
34
34
|
"co-body": "^6.1.0",
|
|
35
35
|
"debug": "^4.3.4",
|
|
36
|
-
"esbuild": "^0.17.
|
|
36
|
+
"esbuild": "^0.17.11",
|
|
37
37
|
"fast-glob": "^3.2.12",
|
|
38
38
|
"formidable": "^2.1.1",
|
|
39
39
|
"http-status": "^1.6.2",
|
|
40
40
|
"is-core-module": "^2.11.0",
|
|
41
41
|
"json5": "^2.2.3",
|
|
42
|
-
"path-to-regexp": "^6.2.1"
|
|
42
|
+
"path-to-regexp": "^6.2.1",
|
|
43
|
+
"picocolors": "^1.0.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@pengzhanbo/eslint-config-ts": "^0.3.2",
|
|
@@ -48,16 +49,16 @@
|
|
|
48
49
|
"@types/debug": "^4.1.7",
|
|
49
50
|
"@types/formidable": "^2.0.5",
|
|
50
51
|
"@types/is-core-module": "^2.2.0",
|
|
51
|
-
"@types/node": "^18.
|
|
52
|
-
"bumpp": "^
|
|
52
|
+
"@types/node": "^18.14.6",
|
|
53
|
+
"bumpp": "^9.0.0",
|
|
53
54
|
"conventional-changelog-cli": "^2.2.2",
|
|
54
|
-
"eslint": "^8.
|
|
55
|
+
"eslint": "^8.35.0",
|
|
55
56
|
"mockjs": "^1.1.0",
|
|
56
|
-
"prettier": "^2.8.
|
|
57
|
+
"prettier": "^2.8.4",
|
|
57
58
|
"tsup": "^6.6.3",
|
|
58
59
|
"typescript": "^4.9.5",
|
|
59
|
-
"vite": "^4.1.
|
|
60
|
-
"vitepress": "1.0.0-alpha.
|
|
60
|
+
"vite": "^4.1.4",
|
|
61
|
+
"vitepress": "1.0.0-alpha.49",
|
|
61
62
|
"vue": "^3.2.47"
|
|
62
63
|
},
|
|
63
64
|
"peerDependencies": {
|