vite-plugin-mock-dev-server 1.1.0 → 1.1.2
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 +9 -5
- package/README.zh-CN.md +8 -5
- package/dist/index.cjs +27 -35
- package/dist/index.d.ts +157 -28
- package/dist/index.js +27 -35
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
- 🍕 Support `viteConfig.define` in mock file.
|
|
41
41
|
- ⚓️ Support `resolve.alias` in mock file.
|
|
42
42
|
- 📤 Support `multipart` content-type,mock upload file.
|
|
43
|
+
- 🍪 Support cookies
|
|
43
44
|
- 🌈 Support `vite preview` mode
|
|
44
45
|
- 🗂 Support building small independent deployable mock services.
|
|
45
46
|
|
|
@@ -193,6 +194,12 @@ export default defineConfig({
|
|
|
193
194
|
})
|
|
194
195
|
```
|
|
195
196
|
|
|
197
|
+
- `options.cookiesOptions`
|
|
198
|
+
|
|
199
|
+
Configure to `cookies`, see [cookies](https://github.com/pillarjs/cookies#new-cookiesrequest-response--options)
|
|
200
|
+
|
|
201
|
+
**Default:** `{}`
|
|
202
|
+
|
|
196
203
|
- `options.build`
|
|
197
204
|
|
|
198
205
|
Configuration needed to build a small, independently deployable mock service.
|
|
@@ -335,15 +342,12 @@ export default defineMock({
|
|
|
335
342
|
|
|
336
343
|
/**
|
|
337
344
|
* response cookies
|
|
338
|
-
* @type Record<string, string |
|
|
345
|
+
* @type Record<string, string | [value: string, option: CookieOption]>
|
|
339
346
|
* @see https://github.com/pillarjs/cookies#cookiessetname--values--options
|
|
340
347
|
*/
|
|
341
348
|
cookies: {
|
|
342
349
|
'your-cookie': 'your cookie value',
|
|
343
|
-
'cookie&option': {
|
|
344
|
-
value: 'cookie value',
|
|
345
|
-
option: { path: '/', httpOnly: true }
|
|
346
|
-
}
|
|
350
|
+
'cookie&option': ['cookie value', { path: '/', httpOnly: true }]
|
|
347
351
|
},
|
|
348
352
|
|
|
349
353
|
/**
|
package/README.zh-CN.md
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
- 🍕 支持在 mock文件中使用 `viteConfig.define`配置字段
|
|
42
42
|
- ⚓️ 支持 `resolve.alias`
|
|
43
43
|
- 📤 支持 multipart 类型,模拟文件上传
|
|
44
|
+
- 🍪 支持 cookies
|
|
44
45
|
- 🌈 支持 `vite preview` 模式
|
|
45
46
|
- 🗂 支持构建可独立部署的小型mock服务
|
|
46
47
|
|
|
@@ -189,6 +190,11 @@ export default defineConfig({
|
|
|
189
190
|
}
|
|
190
191
|
})
|
|
191
192
|
```
|
|
193
|
+
- `options.cookiesOptions`
|
|
194
|
+
|
|
195
|
+
配置 `cookies`, 查看 [cookies](https://github.com/pillarjs/cookies#new-cookiesrequest-response--options)
|
|
196
|
+
|
|
197
|
+
**默认值:** `{}`
|
|
192
198
|
|
|
193
199
|
- `options.build`
|
|
194
200
|
|
|
@@ -328,15 +334,12 @@ export default defineMock({
|
|
|
328
334
|
|
|
329
335
|
/**
|
|
330
336
|
* 响应体 cookies
|
|
331
|
-
* @type Record<string, string |
|
|
337
|
+
* @type Record<string, string | [value: string, option: CookieOption]>
|
|
332
338
|
* @see https://github.com/pillarjs/cookies#cookiessetname--values--options
|
|
333
339
|
*/
|
|
334
340
|
cookies: {
|
|
335
341
|
'your-cookie': 'your cookie value',
|
|
336
|
-
'cookie&option': {
|
|
337
|
-
value: 'cookie value',
|
|
338
|
-
option: { path: '/', httpOnly: true }
|
|
339
|
-
}
|
|
342
|
+
'cookie&option': ['cookie value', { path: '/', httpOnly: true }]
|
|
340
343
|
},
|
|
341
344
|
|
|
342
345
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -54,7 +54,7 @@ var import_vite = require("vite");
|
|
|
54
54
|
|
|
55
55
|
// package.json
|
|
56
56
|
var name = "vite-plugin-mock-dev-server";
|
|
57
|
-
var version = "1.1.
|
|
57
|
+
var version = "1.1.2";
|
|
58
58
|
|
|
59
59
|
// src/esbuildPlugin.ts
|
|
60
60
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
@@ -436,65 +436,53 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies, cookiesOp
|
|
|
436
436
|
const mockUrl = Object.keys(mockData).find((key) => {
|
|
437
437
|
return (0, import_path_to_regexp2.pathToRegexp)(key).test(pathname);
|
|
438
438
|
});
|
|
439
|
-
if (!mockUrl)
|
|
439
|
+
if (!mockUrl)
|
|
440
440
|
return next();
|
|
441
|
-
}
|
|
442
441
|
const reqBody = await parseReqBody(req, formidableOptions);
|
|
443
|
-
const cookies = new import_cookies.default(req, res, cookiesOptions);
|
|
444
442
|
const method = req.method.toUpperCase();
|
|
445
|
-
const
|
|
443
|
+
const mock = fineMock(mockData[mockUrl], pathname, method, {
|
|
446
444
|
query,
|
|
447
445
|
refererQuery,
|
|
448
446
|
body: reqBody,
|
|
449
447
|
headers: req.headers
|
|
450
448
|
});
|
|
451
|
-
if (!
|
|
449
|
+
if (!mock)
|
|
452
450
|
return next();
|
|
453
451
|
debug("middleware: ", method, pathname);
|
|
452
|
+
const cookies = new import_cookies.default(req, res, cookiesOptions);
|
|
454
453
|
const request = req;
|
|
455
454
|
const response = res;
|
|
456
455
|
request.body = reqBody;
|
|
457
456
|
request.query = query;
|
|
458
457
|
request.refererQuery = refererQuery;
|
|
459
|
-
request.params = parseParams(
|
|
458
|
+
request.params = parseParams(mock.url, pathname);
|
|
460
459
|
request.getCookie = cookies.get.bind(cookies);
|
|
461
460
|
response.setCookie = cookies.set.bind(cookies);
|
|
462
|
-
|
|
463
|
-
await
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (
|
|
461
|
+
responseStatus(response, mock.status, mock.statusText);
|
|
462
|
+
await provideHeaders(request, response, mock.headers);
|
|
463
|
+
await provideCookies(request, response, mock.cookies);
|
|
464
|
+
const { body, delay, response: responseFn } = mock;
|
|
465
|
+
if (body) {
|
|
467
466
|
try {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
} else {
|
|
472
|
-
body = currentMock.body;
|
|
473
|
-
}
|
|
474
|
-
await realDelay(startTime, currentMock.delay);
|
|
475
|
-
res.end(JSON.stringify(body));
|
|
467
|
+
const result = isFunction(body) ? await body(request) : mock.body;
|
|
468
|
+
await realDelay(startTime, delay);
|
|
469
|
+
res.end(JSON.stringify(result));
|
|
476
470
|
} catch (e) {
|
|
477
471
|
log.error(`${import_picocolors2.default.red("[body error]")} ${req.url}
|
|
478
472
|
`, e);
|
|
479
|
-
|
|
480
|
-
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
473
|
+
responseStatus(response, 500);
|
|
481
474
|
res.end("");
|
|
482
475
|
}
|
|
483
476
|
return;
|
|
484
477
|
}
|
|
485
|
-
if (
|
|
478
|
+
if (responseFn) {
|
|
486
479
|
try {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
realDelay(startTime, currentMock.delay).then(() => end(...args));
|
|
490
|
-
return response;
|
|
491
|
-
};
|
|
492
|
-
await currentMock.response(request, response, next);
|
|
480
|
+
await realDelay(startTime, delay);
|
|
481
|
+
await responseFn(request, response, next);
|
|
493
482
|
} catch (e) {
|
|
494
483
|
log.error(`${import_picocolors2.default.red("[response error]")} ${req.url}
|
|
495
484
|
`, e);
|
|
496
|
-
|
|
497
|
-
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
485
|
+
responseStatus(response, 500);
|
|
498
486
|
res.end("");
|
|
499
487
|
}
|
|
500
488
|
return;
|
|
@@ -522,6 +510,10 @@ function fineMock(mockList, pathname, method, request) {
|
|
|
522
510
|
return hasMock;
|
|
523
511
|
});
|
|
524
512
|
}
|
|
513
|
+
function responseStatus(response, status = 200, statusText) {
|
|
514
|
+
response.statusCode = status;
|
|
515
|
+
response.statusMessage = statusText || getHTTPStatusText(status);
|
|
516
|
+
}
|
|
525
517
|
async function provideHeaders(req, res, headersOption) {
|
|
526
518
|
res.setHeader("Content-Type", "application/json");
|
|
527
519
|
res.setHeader("Cache-Control", "no-cache,max-age=0");
|
|
@@ -545,11 +537,11 @@ async function provideCookies(req, res, cookiesOption) {
|
|
|
545
537
|
const cookies = isFunction(cookiesOption) ? await cookiesOption(req) : cookiesOption;
|
|
546
538
|
Object.keys(cookies).forEach((key) => {
|
|
547
539
|
const optional = cookies[key];
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
} else {
|
|
551
|
-
const { value, options } = optional;
|
|
540
|
+
if (isArray(optional)) {
|
|
541
|
+
const [value, options] = optional;
|
|
552
542
|
res.setCookie(key, value, options);
|
|
543
|
+
} else {
|
|
544
|
+
res.setCookie(key, optional);
|
|
553
545
|
}
|
|
554
546
|
});
|
|
555
547
|
} catch (e) {
|
package/dist/index.d.ts
CHANGED
|
@@ -7,57 +7,72 @@ import chokidar from 'chokidar';
|
|
|
7
7
|
|
|
8
8
|
interface MockServerPluginOptions {
|
|
9
9
|
/**
|
|
10
|
+
* To configure the path matching rules for mock services,
|
|
11
|
+
* any request path starting with prefix will be intercepted and proxied.
|
|
12
|
+
* If the prefix starts with `^`, it will be recognized as a `RegExp`.
|
|
13
|
+
*
|
|
10
14
|
* 为 mock 服务配置 路径匹配规则,任何请求路径以 prefix 开头的都将被拦截代理。
|
|
11
15
|
* 如果 prefix 以 `^` 开头,将被识别为 `RegExp`。
|
|
12
|
-
*
|
|
13
16
|
* @default []
|
|
17
|
+
* @example ['^/api']
|
|
14
18
|
*/
|
|
15
19
|
prefix?: string | string[];
|
|
16
20
|
/**
|
|
21
|
+
* glob string matching mock includes files
|
|
22
|
+
*
|
|
17
23
|
* glob 字符串匹配 mock 包含的文件
|
|
18
|
-
* @see https://github.com/micromatch/picomatch#globbing-features
|
|
24
|
+
* @see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
|
|
19
25
|
* @default []
|
|
20
26
|
*/
|
|
21
27
|
include?: string | string[];
|
|
22
28
|
/**
|
|
23
|
-
* glob
|
|
24
|
-
*
|
|
29
|
+
* glob string matching mock excluded files
|
|
30
|
+
*
|
|
31
|
+
* glob 字符串匹配 mock 排除的文件
|
|
32
|
+
* @see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
|
|
25
33
|
*/
|
|
26
34
|
exclude?: string | string[];
|
|
27
35
|
/**
|
|
36
|
+
* When the mock resource is hot updated, only the data content is updated,
|
|
37
|
+
* but the page is not refreshed by default.
|
|
38
|
+
* If you want to refresh the page every time you modify a mock file,
|
|
39
|
+
* you can open this option.
|
|
40
|
+
*
|
|
28
41
|
* mock资源热更新时,仅更新了数据内容,但是默认不重新刷新页面。
|
|
29
42
|
* 当你希望每次修改mock文件都刷新页面时,可以打开此选项。
|
|
30
|
-
*
|
|
31
43
|
* @default false
|
|
32
44
|
*/
|
|
33
45
|
reload?: boolean;
|
|
34
46
|
/**
|
|
35
47
|
* formidable options
|
|
36
|
-
* @see https://github.com/node-formidable/formidable#options
|
|
48
|
+
* @see [formidable](https://github.com/node-formidable/formidable#options)
|
|
37
49
|
*/
|
|
38
50
|
formidableOptions?: formidable.Options;
|
|
39
51
|
/**
|
|
40
52
|
* cookies options
|
|
41
|
-
* @see https://github.com/pillarjs/cookies#new-cookiesrequest-response--options
|
|
53
|
+
* @see [cookies](https://github.com/pillarjs/cookies#new-cookiesrequest-response--options)
|
|
42
54
|
*/
|
|
43
55
|
cookiesOptions?: Cookies.Option;
|
|
44
56
|
/**
|
|
45
|
-
*
|
|
57
|
+
* When you need to build a small mock service, you can configure this option.
|
|
46
58
|
*
|
|
59
|
+
* 当需要构建一个小型mock服务时,可配置此项
|
|
47
60
|
* @default false
|
|
48
61
|
*/
|
|
49
62
|
build?: boolean | ServerBuildOption;
|
|
50
63
|
}
|
|
51
64
|
interface ServerBuildOption {
|
|
52
65
|
/**
|
|
53
|
-
*
|
|
66
|
+
* Service startup port
|
|
54
67
|
*
|
|
68
|
+
* 服务启动端口
|
|
55
69
|
* @default 8080
|
|
56
70
|
*/
|
|
57
71
|
serverPort?: number;
|
|
58
72
|
/**
|
|
59
|
-
*
|
|
73
|
+
* Service application output directory
|
|
60
74
|
*
|
|
75
|
+
* 服务应用输出目录
|
|
61
76
|
* @default 'dist/mockServer'
|
|
62
77
|
*/
|
|
63
78
|
dist?: string;
|
|
@@ -67,107 +82,221 @@ type Headers = http.IncomingHttpHeaders;
|
|
|
67
82
|
type ResponseBody = Record<string, any> | any[] | string | number | null;
|
|
68
83
|
interface ExtraRequest {
|
|
69
84
|
/**
|
|
85
|
+
* The query string located after `?` in the request address has been parsed into JSON.
|
|
86
|
+
*
|
|
70
87
|
* 请求地址中位于 `?` 后面的 queryString,已解析为 json
|
|
71
88
|
*/
|
|
72
89
|
query: Record<string, any>;
|
|
73
90
|
/**
|
|
91
|
+
* The queryString located after `?` in the referer request has been parsed as JSON.
|
|
92
|
+
*
|
|
74
93
|
* 请求 referer 中位于 `?` 后面的 queryString,已解析为 json
|
|
75
94
|
*/
|
|
76
95
|
refererQuery: Record<string, any>;
|
|
77
96
|
/**
|
|
97
|
+
* Body data in the request
|
|
98
|
+
*
|
|
78
99
|
* 请求体中 body 数据
|
|
79
100
|
*/
|
|
80
101
|
body: Record<string, any>;
|
|
81
102
|
/**
|
|
82
|
-
*
|
|
103
|
+
* The params parameter parsed from the `/api/id/:id` in the request address.
|
|
104
|
+
*
|
|
105
|
+
* 请求地址中,`/api/id/:id` 解析后的 params 参数
|
|
83
106
|
*/
|
|
84
107
|
params: Record<string, any>;
|
|
85
108
|
/**
|
|
109
|
+
* headers data in the request
|
|
86
110
|
* 请求体中 headers
|
|
87
111
|
*/
|
|
88
112
|
headers: Headers;
|
|
89
113
|
}
|
|
90
114
|
type MockRequest = Connect.IncomingMessage & ExtraRequest & {
|
|
115
|
+
/**
|
|
116
|
+
* @see [cookies](https://github.com/pillarjs/cookies#cookiesgetname--options)
|
|
117
|
+
*/
|
|
91
118
|
getCookie: (name: string, option?: Cookies.GetOption) => string | undefined;
|
|
92
119
|
};
|
|
93
120
|
type MockResponse = http.ServerResponse<http.IncomingMessage> & {
|
|
121
|
+
/**
|
|
122
|
+
* @see [cookies](https://github.com/pillarjs/cookies#cookiessetname--values--options)
|
|
123
|
+
*/
|
|
94
124
|
setCookie: (name: string, value?: string | null, option?: Cookies.SetOption) => void;
|
|
95
125
|
};
|
|
96
126
|
type ResponseBodyFn = (request: MockRequest) => ResponseBody | Promise<ResponseBody>;
|
|
97
127
|
type ResponseHeaderFn = (request: MockRequest) => Headers | Promise<Headers>;
|
|
98
|
-
type CookieValue = string |
|
|
99
|
-
value: string;
|
|
100
|
-
options?: Cookies.SetOption;
|
|
101
|
-
};
|
|
128
|
+
type CookieValue = string | [string, Cookies.SetOption];
|
|
102
129
|
type ResponseCookies = Record<string, CookieValue>;
|
|
103
130
|
type ResponseCookiesFn = (request: MockRequest) => ResponseCookies | Promise<ResponseCookies>;
|
|
104
131
|
interface MockOptionsItem {
|
|
105
132
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
133
|
+
* The interface address that needs to be mocked,
|
|
134
|
+
* supported by `path-to-regexp` for path matching.
|
|
135
|
+
*
|
|
136
|
+
* 需要进行 mock 的接口地址, 由 `path-to-regexp` 提供路径匹配支持
|
|
137
|
+
* @see [path-to-regexp](https://github.com/pillarjs/path-to-regexp)
|
|
138
|
+
* @example
|
|
139
|
+
* ```txt
|
|
140
|
+
* /api/login
|
|
141
|
+
* /api/post/:id
|
|
142
|
+
* /api/post/:id
|
|
143
|
+
* ```
|
|
108
144
|
*/
|
|
109
145
|
url: string;
|
|
110
146
|
/**
|
|
111
|
-
*
|
|
147
|
+
* The interface allows request methods, and by default allows both GET and POST.
|
|
112
148
|
*
|
|
149
|
+
* 该接口允许的 请求方法,默认同时支持 GET 和 POST
|
|
113
150
|
* @default ['POST','GET']
|
|
114
151
|
*/
|
|
115
152
|
method?: Method | Method[];
|
|
116
153
|
/**
|
|
154
|
+
* Whether to enable mock for this interface.
|
|
155
|
+
* In most scenarios, we only need to mock some interfaces instead of all requests that
|
|
156
|
+
* have been configured with mock.
|
|
157
|
+
* Therefore, it is important to be able to configure whether to enable it or not.
|
|
158
|
+
*
|
|
117
159
|
* 是否启动对该接口的mock,在多数场景下,我们进需要对部分接口进行 mock,
|
|
118
160
|
* 而不是对所有配置了mock的请求进行全量mock,所以是否能够配置是否启用很重要
|
|
119
|
-
*
|
|
120
161
|
* @default true
|
|
121
162
|
*/
|
|
122
163
|
enabled?: boolean;
|
|
123
164
|
/**
|
|
124
|
-
*
|
|
165
|
+
* Configure the response body headers
|
|
125
166
|
*
|
|
126
|
-
*
|
|
167
|
+
* 配置响应体 headers
|
|
168
|
+
* @default
|
|
169
|
+
* ```json
|
|
170
|
+
* { "Content-Type": "application/json" }
|
|
171
|
+
* ```
|
|
127
172
|
*/
|
|
128
173
|
headers?: Headers | ResponseHeaderFn;
|
|
129
174
|
/**
|
|
130
|
-
*
|
|
175
|
+
* Configure Response Header Status Code
|
|
131
176
|
*
|
|
177
|
+
* 配置 响应头状态码
|
|
132
178
|
* @default 200
|
|
133
179
|
*/
|
|
134
180
|
status?: number;
|
|
135
181
|
/**
|
|
136
|
-
*
|
|
182
|
+
* Configure response header status text
|
|
137
183
|
*
|
|
184
|
+
* 配置响应头状态文本
|
|
138
185
|
* @default 'OK'
|
|
139
186
|
*/
|
|
140
187
|
statusText?: string;
|
|
141
188
|
/**
|
|
142
|
-
*
|
|
189
|
+
* Configure response delay time, unit: `ms`
|
|
143
190
|
*
|
|
191
|
+
* 配置响应延迟时间, 单位: `ms`
|
|
144
192
|
* @default 0
|
|
145
193
|
*/
|
|
146
194
|
delay?: number;
|
|
147
195
|
/**
|
|
196
|
+
* Configure response body cookies
|
|
197
|
+
*
|
|
148
198
|
* 设置响应体 cookies
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* export default {
|
|
202
|
+
* cookies: {
|
|
203
|
+
* 'token1': '1234567',
|
|
204
|
+
* 'token2': ['1234567', { path: '/' }],
|
|
205
|
+
* },
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* export default {
|
|
211
|
+
* cookies: function (request) {
|
|
212
|
+
* return {
|
|
213
|
+
* 'token1': '1234567',
|
|
214
|
+
* 'token2': ['1234567', { path: '/' }],
|
|
215
|
+
* }
|
|
216
|
+
* },
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
149
219
|
*/
|
|
150
220
|
cookies?: ResponseCookies | ResponseCookiesFn;
|
|
151
221
|
/**
|
|
152
|
-
*
|
|
222
|
+
* Configure response body data content
|
|
153
223
|
*
|
|
154
|
-
*
|
|
224
|
+
* 配置响应体数据内容
|
|
225
|
+
* @default ''
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* export default {
|
|
229
|
+
* body: { a: 1 },
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
* @example
|
|
233
|
+
* ```ts
|
|
234
|
+
* export default {
|
|
235
|
+
* body: function(request) {
|
|
236
|
+
* return { a: 1, query: request.query }
|
|
237
|
+
* },
|
|
238
|
+
* }
|
|
239
|
+
* ```
|
|
155
240
|
*/
|
|
156
241
|
body?: ResponseBody | ResponseBodyFn;
|
|
157
242
|
/**
|
|
243
|
+
* If you need to set complex response content, you can use the response method,
|
|
244
|
+
* which is a middleware. Here, you can get information such as req
|
|
245
|
+
* and res of the http request,
|
|
246
|
+
* and then return response data through res.write() | res.end().
|
|
247
|
+
* Otherwise, you need to execute next() method.
|
|
248
|
+
* In `req`, you can also get parsed request information such as
|
|
249
|
+
* `query`, `params`, `body` and `refererQuery`.
|
|
250
|
+
*
|
|
158
251
|
* 如果需要设置复杂的响应内容,可以使用 response 方法,
|
|
159
252
|
* 该方法是一个 middleware,你可以在这里拿到 http 请求的 req、res等信息,
|
|
160
|
-
* 然后通过 res.write() | res.end() 返回响应数据,
|
|
253
|
+
* 然后通过 res.write() | res.end() 返回响应数据, 否则需要执行 next() 方法。
|
|
254
|
+
* 在 `req` 中,还可以拿到 query、params、body, refererQuery 等已解析的请求信息。
|
|
255
|
+
*
|
|
256
|
+
* @see [connect](https://github.com/senchalabs/connect#appusefn)
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* export default {
|
|
260
|
+
* response(req, res) {
|
|
261
|
+
* res.setHeader('Content-Type', 'application/json')
|
|
262
|
+
* res.end(JSON.stringify({ a: 1 }))
|
|
263
|
+
* },
|
|
264
|
+
* }
|
|
265
|
+
* ```
|
|
161
266
|
*
|
|
162
|
-
* 在 req 中,还可以拿到 query、params、body等已解析的请求信息
|
|
163
267
|
*/
|
|
164
268
|
response?: (req: MockRequest, res: MockResponse, next: Connect.NextFunction) => void | Promise<void>;
|
|
165
269
|
/**
|
|
270
|
+
* Request Validator
|
|
271
|
+
*
|
|
272
|
+
* Sometimes, for the same API request, data needs to be returned based
|
|
273
|
+
* on different request parameters.
|
|
274
|
+
* However, if all of this is written in a single mock's body or response,
|
|
275
|
+
* the content can become cumbersome and difficult to manage.
|
|
276
|
+
* The function of a validator allows you to configure multiple mocks with
|
|
277
|
+
* the same URL simultaneously and determine which mock should be used through validation.
|
|
278
|
+
*
|
|
166
279
|
* 请求验证器
|
|
167
280
|
*
|
|
168
281
|
* 有时候,一个相同的API请求,需要根据不同的请求参数,来决定返回数据,
|
|
169
282
|
* 但全部都在单个 mock中的 body或者 response 中写,内容会很庞杂,不好管理,
|
|
170
283
|
* 验证器的功能,允许你同时配置多条相同url的mock,通过验证器来判断使哪个mock生效。
|
|
284
|
+
* @example
|
|
285
|
+
* ```ts
|
|
286
|
+
* export default {
|
|
287
|
+
* validator: {
|
|
288
|
+
* query: { id: 123 }
|
|
289
|
+
* }
|
|
290
|
+
* }
|
|
291
|
+
* ```
|
|
292
|
+
* @example
|
|
293
|
+
* ```ts
|
|
294
|
+
* export default {
|
|
295
|
+
* validator: function(request) {
|
|
296
|
+
* return request.query.id === 123
|
|
297
|
+
* }
|
|
298
|
+
* }
|
|
299
|
+
* ```
|
|
171
300
|
*/
|
|
172
301
|
validator?: Partial<ExtraRequest> | ((request: ExtraRequest) => boolean);
|
|
173
302
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { createFilter, normalizePath } from "vite";
|
|
|
9
9
|
|
|
10
10
|
// package.json
|
|
11
11
|
var name = "vite-plugin-mock-dev-server";
|
|
12
|
-
var version = "1.1.
|
|
12
|
+
var version = "1.1.2";
|
|
13
13
|
|
|
14
14
|
// src/esbuildPlugin.ts
|
|
15
15
|
import fsp from "fs/promises";
|
|
@@ -391,65 +391,53 @@ function baseMiddleware(mockLoader, { formidableOptions = {}, proxies, cookiesOp
|
|
|
391
391
|
const mockUrl = Object.keys(mockData).find((key) => {
|
|
392
392
|
return pathToRegexp(key).test(pathname);
|
|
393
393
|
});
|
|
394
|
-
if (!mockUrl)
|
|
394
|
+
if (!mockUrl)
|
|
395
395
|
return next();
|
|
396
|
-
}
|
|
397
396
|
const reqBody = await parseReqBody(req, formidableOptions);
|
|
398
|
-
const cookies = new Cookies(req, res, cookiesOptions);
|
|
399
397
|
const method = req.method.toUpperCase();
|
|
400
|
-
const
|
|
398
|
+
const mock = fineMock(mockData[mockUrl], pathname, method, {
|
|
401
399
|
query,
|
|
402
400
|
refererQuery,
|
|
403
401
|
body: reqBody,
|
|
404
402
|
headers: req.headers
|
|
405
403
|
});
|
|
406
|
-
if (!
|
|
404
|
+
if (!mock)
|
|
407
405
|
return next();
|
|
408
406
|
debug("middleware: ", method, pathname);
|
|
407
|
+
const cookies = new Cookies(req, res, cookiesOptions);
|
|
409
408
|
const request = req;
|
|
410
409
|
const response = res;
|
|
411
410
|
request.body = reqBody;
|
|
412
411
|
request.query = query;
|
|
413
412
|
request.refererQuery = refererQuery;
|
|
414
|
-
request.params = parseParams(
|
|
413
|
+
request.params = parseParams(mock.url, pathname);
|
|
415
414
|
request.getCookie = cookies.get.bind(cookies);
|
|
416
415
|
response.setCookie = cookies.set.bind(cookies);
|
|
417
|
-
|
|
418
|
-
await
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (
|
|
416
|
+
responseStatus(response, mock.status, mock.statusText);
|
|
417
|
+
await provideHeaders(request, response, mock.headers);
|
|
418
|
+
await provideCookies(request, response, mock.cookies);
|
|
419
|
+
const { body, delay, response: responseFn } = mock;
|
|
420
|
+
if (body) {
|
|
422
421
|
try {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
} else {
|
|
427
|
-
body = currentMock.body;
|
|
428
|
-
}
|
|
429
|
-
await realDelay(startTime, currentMock.delay);
|
|
430
|
-
res.end(JSON.stringify(body));
|
|
422
|
+
const result = isFunction(body) ? await body(request) : mock.body;
|
|
423
|
+
await realDelay(startTime, delay);
|
|
424
|
+
res.end(JSON.stringify(result));
|
|
431
425
|
} catch (e) {
|
|
432
426
|
log.error(`${colors2.red("[body error]")} ${req.url}
|
|
433
427
|
`, e);
|
|
434
|
-
|
|
435
|
-
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
428
|
+
responseStatus(response, 500);
|
|
436
429
|
res.end("");
|
|
437
430
|
}
|
|
438
431
|
return;
|
|
439
432
|
}
|
|
440
|
-
if (
|
|
433
|
+
if (responseFn) {
|
|
441
434
|
try {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
realDelay(startTime, currentMock.delay).then(() => end(...args));
|
|
445
|
-
return response;
|
|
446
|
-
};
|
|
447
|
-
await currentMock.response(request, response, next);
|
|
435
|
+
await realDelay(startTime, delay);
|
|
436
|
+
await responseFn(request, response, next);
|
|
448
437
|
} catch (e) {
|
|
449
438
|
log.error(`${colors2.red("[response error]")} ${req.url}
|
|
450
439
|
`, e);
|
|
451
|
-
|
|
452
|
-
res.statusMessage = getHTTPStatusText(res.statusCode);
|
|
440
|
+
responseStatus(response, 500);
|
|
453
441
|
res.end("");
|
|
454
442
|
}
|
|
455
443
|
return;
|
|
@@ -477,6 +465,10 @@ function fineMock(mockList, pathname, method, request) {
|
|
|
477
465
|
return hasMock;
|
|
478
466
|
});
|
|
479
467
|
}
|
|
468
|
+
function responseStatus(response, status = 200, statusText) {
|
|
469
|
+
response.statusCode = status;
|
|
470
|
+
response.statusMessage = statusText || getHTTPStatusText(status);
|
|
471
|
+
}
|
|
480
472
|
async function provideHeaders(req, res, headersOption) {
|
|
481
473
|
res.setHeader("Content-Type", "application/json");
|
|
482
474
|
res.setHeader("Cache-Control", "no-cache,max-age=0");
|
|
@@ -500,11 +492,11 @@ async function provideCookies(req, res, cookiesOption) {
|
|
|
500
492
|
const cookies = isFunction(cookiesOption) ? await cookiesOption(req) : cookiesOption;
|
|
501
493
|
Object.keys(cookies).forEach((key) => {
|
|
502
494
|
const optional = cookies[key];
|
|
503
|
-
if (
|
|
504
|
-
|
|
505
|
-
} else {
|
|
506
|
-
const { value, options } = optional;
|
|
495
|
+
if (isArray(optional)) {
|
|
496
|
+
const [value, options] = optional;
|
|
507
497
|
res.setCookie(key, value, options);
|
|
498
|
+
} else {
|
|
499
|
+
res.setCookie(key, optional);
|
|
508
500
|
}
|
|
509
501
|
});
|
|
510
502
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-mock-dev-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"vite",
|
|
6
6
|
"plugin",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"vite": ">=3.0.0"
|
|
68
68
|
},
|
|
69
|
-
"packageManager": "pnpm@
|
|
69
|
+
"packageManager": "pnpm@8.3.1",
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": "^14.18.0 || >=16"
|
|
72
72
|
},
|