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 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/license/pengzhanbo/vite-plugin-mock-dev-server?style=flat-square">
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: `string | string[]`
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 `['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']` (relative for `process.cwd()`)
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 `boolean | ServerBuildOptions`
197
+ **Type:** `boolean | ServerBuildOptions`
184
198
 
185
- Default:`false`
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 === 1'
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 === 2'
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 9
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 10
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 11:
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/license/pengzhanbo/vite-plugin-mock-dev-server?style=flat-square">
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
- Type: `string | string[]`
136
+ **类型:** `string | string[]`
137
137
 
138
138
  为mock服务器配置自定义匹配规则。任何请求路径以 `prefix` 值开头的请求将被代理到对应的目标。如果 `prefix` 值以 ^ 开头,将被识别为 RegExp。
139
139
 
140
140
  > 一般情况下, `server.proxy` 已经足够满足需求,添加此项是为了与某些场景兼容。
141
141
 
142
- Default: `[]`
142
+ **默认值:** `[]`
143
143
 
144
144
  - `option.include`
145
+
146
+ **类型:** `string | string[]`
145
147
 
146
148
  配置读取 mock文件,可以是一个 目录,glob,或者一个数组
147
149
 
148
- 默认值: `['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']` (相对于根目录)
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
- 类型: `boolean | ServerBuildOptions`
197
+ **类型:** `boolean | ServerBuildOptions`
186
198
 
187
- 默认值:`false`
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
- ### 示例9
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
- ### 示例10
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 11:
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.4.2";
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 request = {
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(request);
425
+ return mock.validator(request2);
416
426
  } else {
417
- return validate(request, mock.validator);
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
- req.body = reqBody;
435
- req.query = query;
436
- req.refererQuery = refererQuery;
437
- req.params = params;
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
- const headers = isFunction(currentMock.headers) ? await currentMock.headers({
443
- query,
444
- refererQuery,
445
- body: reqBody,
446
- params,
447
- headers: req.headers
448
- }) : currentMock.headers;
449
- Object.keys(headers).forEach((key) => {
450
- res.setHeader(key, headers[key]);
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
- let body;
455
- if (isFunction(currentMock.body)) {
456
- body = await currentMock.body({
457
- query,
458
- refererQuery,
459
- body: reqBody,
460
- params,
461
- headers: req.headers
462
- });
463
- } else {
464
- body = currentMock.body;
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
- await currentMock.response(
471
- req,
472
- res,
473
- next
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
- if (!mocks[mock.url]) {
613
- mocks[mock.url] = [];
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(httpServer, config, options) {
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 ResponseReq {
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
- * 请求 中的 headers
80
+ * 请求体中 headers
73
81
  */
74
- headers: Record<string, any>;
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 Headers = Record<string, any>;
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: Connect.IncomingMessage & ResponseReq, res: http.ServerResponse<http.IncomingMessage>, next: Connect.NextFunction) => void | Promise<void>;
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<ResponseReq> | ((request: ResponseReq) => boolean);
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.4.2";
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 request = {
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(request);
382
+ return mock.validator(request2);
373
383
  } else {
374
- return validate(request, mock.validator);
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
- req.body = reqBody;
392
- req.query = query;
393
- req.refererQuery = refererQuery;
394
- req.params = params;
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
- const headers = isFunction(currentMock.headers) ? await currentMock.headers({
400
- query,
401
- refererQuery,
402
- body: reqBody,
403
- params,
404
- headers: req.headers
405
- }) : currentMock.headers;
406
- Object.keys(headers).forEach((key) => {
407
- res.setHeader(key, headers[key]);
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
- let body;
412
- if (isFunction(currentMock.body)) {
413
- body = await currentMock.body({
414
- query,
415
- refererQuery,
416
- body: reqBody,
417
- params,
418
- headers: req.headers
419
- });
420
- } else {
421
- body = currentMock.body;
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
- await currentMock.response(
428
- req,
429
- res,
430
- next
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
- if (!mocks[mock.url]) {
570
- mocks[mock.url] = [];
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(httpServer, config, options) {
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.4.2",
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.6",
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.11.19",
52
- "bumpp": "^8.2.1",
52
+ "@types/node": "^18.14.6",
53
+ "bumpp": "^9.0.0",
53
54
  "conventional-changelog-cli": "^2.2.2",
54
- "eslint": "^8.33.0",
55
+ "eslint": "^8.35.0",
55
56
  "mockjs": "^1.1.0",
56
- "prettier": "^2.8.3",
57
+ "prettier": "^2.8.4",
57
58
  "tsup": "^6.6.3",
58
59
  "typescript": "^4.9.5",
59
- "vite": "^4.1.1",
60
- "vitepress": "1.0.0-alpha.45",
60
+ "vite": "^4.1.4",
61
+ "vitepress": "1.0.0-alpha.49",
61
62
  "vue": "^3.2.47"
62
63
  },
63
64
  "peerDependencies": {