vite-plugin-mock-dev-server 1.1.5 → 1.1.6
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 +114 -10
- package/README.zh-CN.md +114 -12
- package/dist/index.cjs +26 -17
- package/dist/index.d.ts +66 -18
- package/dist/index.js +26 -17
- package/package.json +4 -2
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="npm" src="https://img.shields.io/npm/
|
|
14
|
+
<img alt="npm" src="https://img.shields.io/npm/dt/vite-plugin-mock-dev-server?style=flat-square">
|
|
15
15
|
<br>
|
|
16
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
|
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fpengzhanbo%2Fvite-plugin-mock-dev-server?ref=badge_shield"><img alt="fossa status" src="https://app.fossa.com/api/projects/git%2Bgithub.com%2Fpengzhanbo%2Fvite-plugin-mock-dev-server.svg?type=shield"></a>
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
- 🌈 Support `vite preview` mode.
|
|
44
44
|
- 📤 Support `multipart` content-type,mock upload file.
|
|
45
45
|
- 📥 Support mock download file.
|
|
46
|
+
- ⚜️ Support `WebSocket Mock`
|
|
46
47
|
- 🗂 Support building small independent deployable mock services.
|
|
47
48
|
|
|
48
49
|
|
|
@@ -148,6 +149,18 @@ export default defineConfig({
|
|
|
148
149
|
|
|
149
150
|
**Default:** `[]`
|
|
150
151
|
|
|
152
|
+
- `options.wsPrefix`
|
|
153
|
+
|
|
154
|
+
**类型:** `string | string[]`
|
|
155
|
+
|
|
156
|
+
Configure the matching rules for WebSocket service. Any request path starting with the value of `wsPrefix` and using the `ws/wss` protocol will be proxied to the corresponding target.
|
|
157
|
+
|
|
158
|
+
If the value of `wsPrefix` starts with `^`, it will be recognized as a RegExp.
|
|
159
|
+
|
|
160
|
+
> Different from using `viteConfig.server.proxy` by default for http mock, `websocket mock` does not use the ws-related configuration in `viteConfig.server.proxy`. Also, rules configured in `wsPrefix` cannot be configured simultaneously in `viteConfig.server.proxy`, as it will cause conflicts when starting the vite server because multiple instances of WebSocketServer cannot be implemented for the same request.
|
|
161
|
+
> This conflict is neither a problem with Vite nor with the plugin; it belongs to a reasonable error type. When switching between WebSocket Mock and WebSocket Proxy, please pay attention to avoid duplicate configurations that may cause conflicts.
|
|
162
|
+
|
|
163
|
+
|
|
151
164
|
- `option.include`
|
|
152
165
|
|
|
153
166
|
**Type:** `string | string[]`
|
|
@@ -162,14 +175,7 @@ export default defineConfig({
|
|
|
162
175
|
|
|
163
176
|
When reading mock files for configuration, the files that need to be excluded can be a directory, glob, or an array.
|
|
164
177
|
|
|
165
|
-
**Default:**
|
|
166
|
-
```ts
|
|
167
|
-
[
|
|
168
|
-
'**/node_modules/**',
|
|
169
|
-
'**/.vscode/**',
|
|
170
|
-
'**/.git/**',
|
|
171
|
-
]
|
|
172
|
-
```
|
|
178
|
+
**Default:** `['**/node_modules/**','**/.vscode/**','**/.git/**']`
|
|
173
179
|
|
|
174
180
|
- `options.reload`
|
|
175
181
|
|
|
@@ -258,6 +264,7 @@ export default defineApiMock({
|
|
|
258
264
|
## Mock Configuration
|
|
259
265
|
|
|
260
266
|
```ts
|
|
267
|
+
// Configure the http mock
|
|
261
268
|
export default defineMock({
|
|
262
269
|
/**
|
|
263
270
|
* Request address, supports the `/api/user/:id` format.
|
|
@@ -380,7 +387,32 @@ export default defineMock({
|
|
|
380
387
|
res.end()
|
|
381
388
|
}
|
|
382
389
|
})
|
|
383
|
-
|
|
390
|
+
```
|
|
391
|
+
```ts
|
|
392
|
+
// Configure the WebSocket mock
|
|
393
|
+
export default defineMock({
|
|
394
|
+
/**
|
|
395
|
+
* Request address, supports the `/api/user/:id` format.
|
|
396
|
+
* The plugin matches the path through `path-to-regexp`.
|
|
397
|
+
* @see https://github.com/pillarjs/path-to-regexp
|
|
398
|
+
*/
|
|
399
|
+
url: '/api/test',
|
|
400
|
+
/**
|
|
401
|
+
* Value must be explicitly specified as `true`.
|
|
402
|
+
* The plugin needs to make a judgment based on this field.
|
|
403
|
+
*/
|
|
404
|
+
ws: true,
|
|
405
|
+
/**
|
|
406
|
+
* Configure the WebSocketServer
|
|
407
|
+
* @see https://github.com/websockets/ws/blob/master/doc/ws.md#class-websocketserver
|
|
408
|
+
*/
|
|
409
|
+
setup(wss) {
|
|
410
|
+
wss.on('connection', (ws, request) => {
|
|
411
|
+
ws.on('message', (rawData) => {})
|
|
412
|
+
ws.send('data')
|
|
413
|
+
})
|
|
414
|
+
}
|
|
415
|
+
})
|
|
384
416
|
```
|
|
385
417
|
|
|
386
418
|
### Request/Response Enhance
|
|
@@ -650,6 +682,78 @@ export default defineMock({
|
|
|
650
682
|
})
|
|
651
683
|
```
|
|
652
684
|
|
|
685
|
+
**exp:** Graphql
|
|
686
|
+
```ts
|
|
687
|
+
import { buildSchema, graphql } from 'graphql'
|
|
688
|
+
const schema = buildSchema(`
|
|
689
|
+
type Query {
|
|
690
|
+
hello: String
|
|
691
|
+
}
|
|
692
|
+
`)
|
|
693
|
+
const rootValue = { hello: () => 'Hello world!' }
|
|
694
|
+
|
|
695
|
+
export default defineMock({
|
|
696
|
+
url: '/api/graphql',
|
|
697
|
+
method: 'POST',
|
|
698
|
+
body: async (request) => {
|
|
699
|
+
const source = request.body.source
|
|
700
|
+
const { data } = await graphql({ schema, rootValue, source })
|
|
701
|
+
return data
|
|
702
|
+
},
|
|
703
|
+
})
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
```ts
|
|
707
|
+
fetch('/api/graphql', {
|
|
708
|
+
method: 'POST',
|
|
709
|
+
body: JSON.stringify({ source: '{ hello }' })
|
|
710
|
+
})
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
**exp:** WebSocket Mock
|
|
714
|
+
```ts
|
|
715
|
+
// ws.mock.ts
|
|
716
|
+
export default defineMock({
|
|
717
|
+
url: '/socket.io',
|
|
718
|
+
ws: true,
|
|
719
|
+
setup(wss) {
|
|
720
|
+
const wsMap = new Map()
|
|
721
|
+
wss.on('connection', (ws, req) => {
|
|
722
|
+
const token = req.getCookie('token')
|
|
723
|
+
wsMap.set(token, ws)
|
|
724
|
+
ws.on('message', (raw) => {
|
|
725
|
+
const data = JSON.parse(String(raw))
|
|
726
|
+
if (data.type === 'ping') return
|
|
727
|
+
// Broadcast
|
|
728
|
+
for (const [_token, _ws] of wsMap.entires()) {
|
|
729
|
+
if (_token !== token)
|
|
730
|
+
_ws.send(raw)
|
|
731
|
+
}
|
|
732
|
+
})
|
|
733
|
+
})
|
|
734
|
+
wss.on('error', (err) => {
|
|
735
|
+
console.error(err)
|
|
736
|
+
})
|
|
737
|
+
return () => {
|
|
738
|
+
wsMap.clear()
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
})
|
|
742
|
+
```
|
|
743
|
+
```ts
|
|
744
|
+
// app.ts
|
|
745
|
+
const ws = new WebSocket('ws://localhost:5173/socket.io')
|
|
746
|
+
ws.addEventListener('open', () => {
|
|
747
|
+
setInterval(() => {
|
|
748
|
+
// heartbeat
|
|
749
|
+
ws.send({ type: 'ping' })
|
|
750
|
+
}, 1000)
|
|
751
|
+
}, { once: true })
|
|
752
|
+
ws.addEventListener('message', (raw) => {
|
|
753
|
+
console.log(raw)
|
|
754
|
+
})
|
|
755
|
+
```
|
|
756
|
+
|
|
653
757
|
## Mock Services
|
|
654
758
|
|
|
655
759
|
In some scenarios, it may be necessary to use the data provided by mock services for display purposes, but the project may have already been packaged, built and deployed without support from `vite` and this plugin's mock service. Since this plugin supports importing various `node` modules in mock files at the design stage, the mock file cannot be inline into client build code.
|
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="npm" src="https://img.shields.io/npm/
|
|
16
|
+
<img alt="npm" src="https://img.shields.io/npm/dt/vite-plugin-mock-dev-server?style=flat-square">
|
|
17
17
|
<br>
|
|
18
18
|
<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">
|
|
19
19
|
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fpengzhanbo%2Fvite-plugin-mock-dev-server?ref=badge_shield"><img alt="fossa status" src="https://app.fossa.com/api/projects/git%2Bgithub.com%2Fpengzhanbo%2Fvite-plugin-mock-dev-server.svg?type=shield"></a>
|
|
@@ -37,13 +37,14 @@
|
|
|
37
37
|
- 🎨 可选择你喜欢的任意用于生成mock数据库,如 `mockjs`,或者不使用其他库
|
|
38
38
|
- 📥 路径规则匹配,请求参数匹配
|
|
39
39
|
- ⚙️ 随意开启或关闭对某个接口的 mock配置
|
|
40
|
-
-
|
|
40
|
+
- 📀 支持多种响应体数据类型,包括 `text/json/buffer/stream`.
|
|
41
41
|
- ⚖️ 使用 `server.proxy` 配置
|
|
42
42
|
- 🍕 支持在 mock文件中使用 `viteConfig.define`配置字段
|
|
43
43
|
- ⚓️ 支持在 mock文件中使用 `viteConfig.resolve.alias` 路径别名
|
|
44
44
|
- 🌈 支持 `vite preview` 模式
|
|
45
45
|
- 📤 支持 multipart 类型,模拟文件上传
|
|
46
46
|
- 📥 支持模拟文件下载
|
|
47
|
+
- ⚜️ 支持模拟 `WebSocket`
|
|
47
48
|
- 🗂 支持构建可独立部署的小型mock服务
|
|
48
49
|
|
|
49
50
|
|
|
@@ -140,12 +141,22 @@ export default defineConfig({
|
|
|
140
141
|
|
|
141
142
|
**类型:** `string | string[]`
|
|
142
143
|
|
|
143
|
-
为mock服务器配置自定义匹配规则。任何请求路径以 `prefix` 值开头的请求将被代理到对应的目标。如果 `prefix` 值以
|
|
144
|
+
为mock服务器配置自定义匹配规则。任何请求路径以 `prefix` 值开头的请求将被代理到对应的目标。如果 `prefix` 值以 `^` 开头,将被识别为 RegExp。
|
|
144
145
|
|
|
145
146
|
> 一般情况下, `server.proxy` 已经足够满足需求,添加此项是为了与某些场景兼容。
|
|
146
147
|
|
|
147
148
|
**默认值:** `[]`
|
|
148
149
|
|
|
150
|
+
- `options.wsPrefix`
|
|
151
|
+
|
|
152
|
+
**类型:** `string | string[]`
|
|
153
|
+
|
|
154
|
+
配置 webSocket 服务 匹配规则。任何请求路径以 `wsPrefix` 值开头的 `ws/wss` 协议请求,将被代理到对应的目标。
|
|
155
|
+
如果`wsPrefix`值以 `^` 开头,将被识别为 RegExp。
|
|
156
|
+
|
|
157
|
+
> 与 http mock 默认使用 `viteConfig.server.proxy` 不同的是,`websocket mock` 不会使用 `viteConfig.server.proxy` 中的 ws 相关的配置,且配置在 `wsPrefix` 中的规则,不能同时配置在 `viteConfig.server.proxy`中,因为会导致在 vite 在启动服务时产生冲突,因为不能对同一个请求实现多个的 `WebSocketServer`实例。
|
|
158
|
+
> 该冲突既不是 `vite` 的问题,也不是插件的问题,这属于合理的错误类型。在进行 `WebSocket Mock`和 `WebSocket Proxy` 切换时,请注意配置不要出现重复导致冲突。
|
|
159
|
+
|
|
149
160
|
- `option.include`
|
|
150
161
|
|
|
151
162
|
**类型:** `string | string[]`
|
|
@@ -160,14 +171,7 @@ export default defineConfig({
|
|
|
160
171
|
|
|
161
172
|
配置读取 mock文件时,需要排除的文件, 可以是一个 目录、glob、或者一个数组
|
|
162
173
|
|
|
163
|
-
**默认值:**
|
|
164
|
-
```ts
|
|
165
|
-
[
|
|
166
|
-
'**/node_modules/**',
|
|
167
|
-
'**/.vscode/**',
|
|
168
|
-
'**/.git/**',
|
|
169
|
-
]
|
|
170
|
-
```
|
|
174
|
+
**默认值:** `['**/node_modules/**', '**/.vscode/**', '**/.git/**']`
|
|
171
175
|
|
|
172
176
|
- `options.reload`
|
|
173
177
|
|
|
@@ -254,6 +258,7 @@ export default defineApiMock({
|
|
|
254
258
|
## Mock 配置
|
|
255
259
|
|
|
256
260
|
```ts
|
|
261
|
+
// 配置 http mock
|
|
257
262
|
export default defineMock({
|
|
258
263
|
/**
|
|
259
264
|
* 请求地址,支持 `/api/user/:id` 格式
|
|
@@ -376,7 +381,32 @@ export default defineMock({
|
|
|
376
381
|
res.end()
|
|
377
382
|
}
|
|
378
383
|
})
|
|
379
|
-
|
|
384
|
+
```
|
|
385
|
+
```ts
|
|
386
|
+
// 配置 WebSocket mock
|
|
387
|
+
export default defineMock({
|
|
388
|
+
/**
|
|
389
|
+
* 请求地址,支持 `/api/user/:id` 格式
|
|
390
|
+
* 插件通过 `path-to-regexp` 匹配路径
|
|
391
|
+
* @see https://github.com/pillarjs/path-to-regexp
|
|
392
|
+
*/
|
|
393
|
+
url: '/api/test',
|
|
394
|
+
/**
|
|
395
|
+
* 必须显式的指定值为 `true`
|
|
396
|
+
* 插件内部需要根据此值进行判断
|
|
397
|
+
*/
|
|
398
|
+
ws: true,
|
|
399
|
+
/**
|
|
400
|
+
* 配置 WebSocketServer
|
|
401
|
+
* @see https://github.com/websockets/ws/blob/master/doc/ws.md#class-websocketserver
|
|
402
|
+
*/
|
|
403
|
+
setup(wss) {
|
|
404
|
+
wss.on('connection', (ws, request) => {
|
|
405
|
+
ws.on('message', (rawData) => {})
|
|
406
|
+
ws.send('data')
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
})
|
|
380
410
|
```
|
|
381
411
|
|
|
382
412
|
### Request/Response 增强
|
|
@@ -645,6 +675,78 @@ export default defineMock({
|
|
|
645
675
|
})
|
|
646
676
|
```
|
|
647
677
|
|
|
678
|
+
**exp:** Graphql
|
|
679
|
+
```ts
|
|
680
|
+
import { buildSchema, graphql } from 'graphql'
|
|
681
|
+
const schema = buildSchema(`
|
|
682
|
+
type Query {
|
|
683
|
+
hello: String
|
|
684
|
+
}
|
|
685
|
+
`)
|
|
686
|
+
const rootValue = { hello: () => 'Hello world!' }
|
|
687
|
+
|
|
688
|
+
export default defineMock({
|
|
689
|
+
url: '/api/graphql',
|
|
690
|
+
method: 'POST',
|
|
691
|
+
body: async (request) => {
|
|
692
|
+
const source = request.body.source
|
|
693
|
+
const { data } = await graphql({ schema, rootValue, source })
|
|
694
|
+
return data
|
|
695
|
+
},
|
|
696
|
+
})
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
```ts
|
|
700
|
+
fetch('/api/graphql', {
|
|
701
|
+
method: 'POST',
|
|
702
|
+
body: JSON.stringify({ source: '{ hello }' })
|
|
703
|
+
})
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**exp:** WebSocket Mock
|
|
707
|
+
```ts
|
|
708
|
+
// ws.mock.ts
|
|
709
|
+
export default defineMock({
|
|
710
|
+
url: '/socket.io',
|
|
711
|
+
ws: true,
|
|
712
|
+
setup(wss) {
|
|
713
|
+
const wsMap = new Map()
|
|
714
|
+
wss.on('connection', (ws, req) => {
|
|
715
|
+
const token = req.getCookie('token')
|
|
716
|
+
wsMap.set(token, ws)
|
|
717
|
+
ws.on('message', (raw) => {
|
|
718
|
+
const data = JSON.parse(String(raw))
|
|
719
|
+
if (data.type === 'ping') return
|
|
720
|
+
// Broadcast
|
|
721
|
+
for (const [_token, _ws] of wsMap.entires()) {
|
|
722
|
+
if (_token !== token)
|
|
723
|
+
_ws.send(raw)
|
|
724
|
+
}
|
|
725
|
+
})
|
|
726
|
+
})
|
|
727
|
+
wss.on('error', (err) => {
|
|
728
|
+
console.error(err)
|
|
729
|
+
})
|
|
730
|
+
return () => {
|
|
731
|
+
wsMap.clear()
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
})
|
|
735
|
+
```
|
|
736
|
+
```ts
|
|
737
|
+
// app.ts
|
|
738
|
+
const ws = new WebSocket('ws://localhost:5173/socket.io')
|
|
739
|
+
ws.addEventListener('open', () => {
|
|
740
|
+
setInterval(() => {
|
|
741
|
+
// heartbeat
|
|
742
|
+
ws.send({ type: 'ping' })
|
|
743
|
+
}, 1000)
|
|
744
|
+
}, { once: true })
|
|
745
|
+
ws.addEventListener('message', (raw) => {
|
|
746
|
+
console.log(raw)
|
|
747
|
+
})
|
|
748
|
+
```
|
|
749
|
+
|
|
648
750
|
## 独立部署的小型mock服务
|
|
649
751
|
|
|
650
752
|
在一些场景中,可能会需要使用mock服务提供的数据支持,用于展示,但可能项目已完成打包构建部署,已脱离 `vite` 和本插件提供的 mock服务支持。由于本插件在设计之初,支持在mock文件中引入各种 `node` 模块,所以不能将 mock文件打包内联到客户端构建代码中。
|
package/dist/index.cjs
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`,
|
|
3
|
-
`)}};function
|
|
1
|
+
"use strict";var Ve=Object.create;var q=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var et=Object.getPrototypeOf,tt=Object.prototype.hasOwnProperty;var ot=(e,o)=>{for(var t in o)q(e,t,{get:o[t],enumerable:!0})},ye=(e,o,t,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of Ze(o))!tt.call(e,s)&&s!==t&&q(e,s,{get:()=>o[s],enumerable:!(r=Ye(o,s))||r.enumerable});return e};var u=(e,o,t)=>(t=e!=null?Ve(et(e)):{},ye(o||!e||!e.__esModule?q(t,"default",{value:e,enumerable:!0}):t,e)),rt=e=>ye(q({},"__esModule",{value:!0}),e);var jt={};ot(jt,{baseMiddleware:()=>ae,createDefineMock:()=>wt,default:()=>Ot,defineMock:()=>xt,mockDevServerPlugin:()=>ge,mockWebSocket:()=>fe,transformMockData:()=>pe});module.exports=rt(jt);var st=()=>typeof document>"u"?new URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href,x=st();var Ce=u(require("fs"),1),_=u(require("fs/promises"),1),E=u(require("path"),1),Ee=require("esbuild"),We=u(require("fast-glob"),1),Ie=u(require("is-core-module"),1),V=require("vite");var ve="vite-plugin-mock-dev-server",Me="1.1.6";var oe=u(require("fs/promises"),1),be=u(require("path"),1),xe=u(require("json5"),1),A={name:"externalize-deps",setup(e){e.onResolve({filter:/.*/},({path:o})=>{if(o[0]!=="."&&!be.default.isAbsolute(o))return{external:!0}})}},B={name:"json5-loader",setup(e){e.onLoad({filter:/\.json5$/},async({path:o})=>{let t=await oe.default.readFile(o,"utf-8");return{contents:`export default ${JSON.stringify(xe.default.parse(t))}`,loader:"js"}})}},J={name:"json-loader",setup(e){e.onLoad({filter:/\.json$/},async({path:o})=>({contents:`export default ${await oe.default.readFile(o,"utf-8")}`,loader:"js"}))}},z=e=>({name:"alias-plugin",setup(o){o.onResolve({filter:/.*/},async({path:t})=>{let r=e.find(({find:c})=>nt(c,t));if(!r)return null;let{find:s,replacement:n}=r;return{path:(await o.resolve(t.replace(s,n),{kind:"import-statement",resolveDir:n,namespace:"file"})).path,external:!1}})}});function nt(e,o){return e instanceof RegExp?e.test(o):o.length<e.length?!1:o===e?!0:o.startsWith(`${e}/`)}var G=u(require("fs"),1),Q=u(require("path"),1),we=require("url"),Oe=u(require("debug"),1),je=require("path-to-regexp"),re=u(require("picocolors"),1),j=e=>Array.isArray(e),R=e=>typeof e=="function",it=e=>Object.prototype.toString.call(e)==="[object Object]",Pe=e=>it(e)&&Object.keys(e).length===0,ct=e=>e!==null&&typeof e=="object"&&typeof e.pipe=="function",Se=e=>ct(e)&&e.readable!==!1&&typeof e._read=="function"&&typeof e._readableState=="object";function Re(e){return new Promise(o=>setTimeout(o,e))}function De(e){return Q.default.dirname((0,we.fileURLToPath)(e))}var D=(0,Oe.default)("vite:plugin-mock-dev-server"),P=e=>j(e)?e:e==null?[]:[e],T={info(...e){console.info(re.default.cyan("mock-dev-server: "),...e)},error(...e){console.error(`
|
|
2
|
+
`,re.default.cyan("mock-dev-server: "),...e,`
|
|
3
|
+
`)}};function $(e,o,t){for(let s of o){let n=Q.default.join(e,s);if(G.default.existsSync(n)&&G.default.statSync(n).isFile()){let i=t!=null&&t.pathOnly?n:G.default.readFileSync(n,"utf-8");if(!(t!=null&&t.predicate)||t.predicate(i))return i}}let r=Q.default.dirname(e);if(r!==e&&(!(t!=null&&t.rootDir)||r.startsWith(t==null?void 0:t.rootDir)))return $(r,o,t)}var X=(e={})=>{let o=[],t=[];return Object.keys(e).forEach(r=>{var n,i;let s=e[r];typeof s=="string"||!s.ws&&!((n=s.target)!=null&&n.toString().startsWith("ws:"))&&!((i=s.target)!=null&&i.toString().startsWith("wss:"))?o.push(r):t.push(r)}),{httpProxies:o,wsProxies:t}};function K(e,o){return e[0]==="^"&&new RegExp(e).test(o)||o.startsWith(e)}function H(e,o){return((0,je.match)(e,{decode:decodeURIComponent})(o)||{params:{}}).params||{}}async function Te(e,o,t){let r=P(t.include),s=P(t.exclude),n={};if(o.define)for(let f in o.define){let d=o.define[f];n[f]=typeof d=="string"?d:JSON.stringify(d)}let{httpProxies:i}=X(o.server.proxy||{});i.push(...P(t.prefix));let c=P(t.wsPrefix),a={};try{let f=$(o.root,["package.json"]);f&&(a=JSON.parse(f))}catch{}let p=t.build.dist,m=await ut(process.cwd(),r,s),l=E.default.join(o.root,`mock-data-${Date.now()}.js`);await _.default.writeFile(l,m,"utf-8");let{code:M,deps:b}=await mt(l,n,o.resolve.alias),h=at(b);await _.default.unlink(l);let g=[{filename:E.default.join(p,"mock-data.js"),source:M},{filename:E.default.join(p,"index.js"),source:lt(i,c,t.cookiesOptions,t.build.serverPort)},{filename:E.default.join(p,"package.json"),source:pt(a,h)}];try{if(E.default.isAbsolute(p)){await _.default.rm(p,{recursive:!0}),Ce.default.mkdirSync(p,{recursive:!0});for(let{filename:f,source:d}of g)await _.default.writeFile(f,d,"utf-8")}else for(let{filename:f,source:d}of g)e.emitFile({type:"asset",fileName:f,source:d})}catch{}}function at(e){let o=new Set,t=[ve,"connect","cors"];return Object.keys(e).forEach(r=>{e[r].imports.filter(n=>n.external).map(n=>n.path).forEach(n=>{!t.includes(n)&&!(0,Ie.default)(n)&&o.add(n)})}),Array.from(o)}function pt(e,o){let{dependencies:t={},devDependencies:r={}}=e,s={...t,...r},n={name:"mock-server",type:"module",scripts:{start:"node index.js"},dependencies:{connect:"^3.7.0","vite-plugin-mock-dev-server":`^${Me}`,cors:"^2.8.5"},pnpm:{peerDependencyRules:{ignoreMissing:["vite"]}}};return o.forEach(i=>{n.dependencies[i]=s[i]||"latest"}),JSON.stringify(n,null,2)}function lt(e,o,t={},r=8080){return`import { createServer } from 'node:http';
|
|
4
|
+
import connect from 'connect';
|
|
4
5
|
import corsMiddleware from 'cors';
|
|
5
|
-
import { baseMiddleware } from 'vite-plugin-mock-dev-server';
|
|
6
|
+
import { baseMiddleware, mockWebSocket } from 'vite-plugin-mock-dev-server';
|
|
6
7
|
import mockData from './mock-data.js';
|
|
7
8
|
|
|
8
9
|
const app = connect();
|
|
10
|
+
const server = createServer(app);
|
|
11
|
+
const httpProxies = ${JSON.stringify(e)};
|
|
12
|
+
const wxProxies = ${JSON.stringify(o)}
|
|
13
|
+
const cookiesOptions = ${JSON.stringify(t)};
|
|
14
|
+
|
|
15
|
+
mockWebSocket({ mockData }, server, wxProxies, cookiesOptions)
|
|
16
|
+
|
|
9
17
|
app.use(corsMiddleware());
|
|
10
18
|
app.use(baseMiddleware({ mockData }, {
|
|
11
19
|
formidableOptions: { multiples: true },
|
|
12
|
-
proxies:
|
|
13
|
-
cookiesOptions
|
|
20
|
+
proxies: httpProxies,
|
|
21
|
+
cookiesOptions,
|
|
14
22
|
}));
|
|
15
|
-
app.listen(${e});
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
server.listen(${r});
|
|
25
|
+
|
|
26
|
+
console.log('listen: http://localhost:${r}');
|
|
27
|
+
`}async function ut(e,o,t){let r=await(0,We.default)(o,{cwd:e}),s=(0,V.createFilter)(o,t,{resolve:!1}),n=r.filter(s),i="",c="";return n.forEach((a,p)=>{let m=(0,V.normalizePath)(E.default.join(e,a));i+=`import * as m${p} from '${m}';
|
|
28
|
+
`,c+=`m${p}, `}),`import { transformMockData } from 'vite-plugin-mock-dev-server';
|
|
20
29
|
${i}
|
|
21
|
-
const exporters = [${
|
|
30
|
+
const exporters = [${c}];
|
|
22
31
|
const mockList = exporters.map((raw) => raw && raw.default
|
|
23
32
|
? raw.default
|
|
24
33
|
: Object.keys(raw || {}).map((key) => raw[key])
|
|
25
34
|
)
|
|
26
35
|
export default transformMockData(mockList);
|
|
27
|
-
`}async function
|
|
28
|
-
`,
|
|
29
|
-
`,
|
|
30
|
-
`,
|
|
31
|
-
`,
|
|
32
|
-
`,r)}}function
|
|
36
|
+
`}async function mt(e,o,t){var r;try{let s=await(0,Ee.build)({entryPoints:[e],outfile:"out.js",write:!1,target:["node14.18","node16"],platform:"node",bundle:!0,metafile:!0,format:"esm",define:o,plugins:[z(t),A,B,J]});return{code:s.outputFiles[0].text,deps:((r=s.metafile)==null?void 0:r.inputs)||{}}}catch(s){console.error(s)}return{code:"",deps:{}}}var ne=require("buffer"),ie=require("url"),_e=u(require("cookies"),1),Ue=u(require("http-status"),1),U=u(require("mime-types"),1),ce=require("path-to-regexp"),F=u(require("picocolors"),1);var Y=u(require("co-body"),1),Fe=u(require("formidable"),1);async function Le(e,o){var s;let t=e.method.toUpperCase();if(["GET","DELETE","HEAD"].includes(t))return;let r=((s=e.headers["content-type"])==null?void 0:s.toLocaleLowerCase())||"";try{if(r.startsWith("application/json"))return await Y.default.json(e);if(r.startsWith("application/x-www-form-urlencoded"))return await Y.default.form(e);if(r.startsWith("text/plain"))return await Y.default.text(e);if(r.startsWith("multipart/form-data"))return await dt(e,o)}catch(n){console.error(n)}}async function dt(e,o){let t=(0,Fe.default)(o);return new Promise((r,s)=>{t.parse(e,(n,i,c)=>{if(n){s(n);return}r({...i,...c})})})}function $e(e,o){return W(e.headers,o.headers)&&W(e.body,o.body)&&W(e.params,o.params)&&W(e.query,o.query)&&W(e.refererQuery,o.refererQuery)}function W(e,o){if(!o)return!0;for(let t in o)if(o[t]!==e[t])return!1;return!0}function ae(e,{formidableOptions:o={},proxies:t,cookiesOptions:r}){return async function(s,n,i){let c=Date.now(),{query:a,pathname:p}=(0,ie.parse)(s.url,!0);if(!p||t.length===0||!t.some(S=>K(S,s.url)))return i();let m=e.mockData,l=Object.keys(m).find(S=>(0,ce.pathToRegexp)(S).test(p));if(!l)return i();let{query:M}=(0,ie.parse)(s.headers.referer||"",!0),b=await Le(s,o),h=new _e.default(s,n,r),g=h.get.bind(h),f=s.method.toUpperCase(),d=ft(m[l],{pathname:p,method:f,request:{query:a,refererQuery:M,body:b,headers:s.headers,getCookie:g}});if(!d)return i();D("middleware: ",f,s.url);let v=s,y=n;v.body=b,v.query=a,v.refererQuery=M,v.params=H(d.url,p),v.getCookie=g,y.setCookie=h.set.bind(h);let{body:w,delay:k,type:O="json",response:L,status:te=200,statusText:Ke}=d;if(se(y,te,Ke),await kt(v,y,d),await gt(v,y,d),w){try{let S=R(w)?await w(v):w;await He(c,k),yt(y,S,O)}catch(S){T.error(`${F.default.red("[body error]")} ${s.url}
|
|
37
|
+
`,S),se(y,500),n.end("")}return}if(L){try{await He(c,k),await L(v,y,i)}catch(S){T.error(`${F.default.red("[response error]")} ${s.url}
|
|
38
|
+
`,S),se(y,500),n.end("")}return}n.end("")}}function ft(e,{pathname:o,method:t,request:r}){return e.find(s=>{if(!o||!s||!s.url||s.ws===!0||!(s.method?j(s.method)?s.method:[s.method]:["GET","POST"]).includes(t))return!1;let i=(0,ce.pathToRegexp)(s.url).test(o);if(i&&s.validator){let c=H(s.url,o);if(R(s.validator))return s.validator({params:c,...r});try{return $e({params:c,...r},s.validator)}catch(a){return T.error(`${F.default.red("[validator error]")} ${o}
|
|
39
|
+
`,a),!1}}return i})}function se(e,o=200,t){e.statusCode=o,e.statusMessage=t||ht(o)}async function kt(e,o,{headers:t,type:r="json"}){let s=U.contentType(r)||U.contentType(U.lookup(r)||"");if(s&&o.setHeader("Content-Type",s),o.setHeader("Cache-Control","no-cache,max-age=0"),o.setHeader("X-Mock","generate by vite:plugin-mock-dev-server"),!!t)try{let n=R(t)?await t(e):t;Object.keys(n).forEach(i=>{o.setHeader(i,n[i])})}catch(n){T.error(`${F.default.red("[headers error]")} ${e.url}
|
|
40
|
+
`,n)}}async function gt(e,o,{cookies:t}){if(t)try{let r=R(t)?await t(e):t;Object.keys(r).forEach(s=>{let n=r[s];if(j(n)){let[i,c]=n;o.setCookie(s,i,c)}else o.setCookie(s,n)})}catch(r){T.error(`${F.default.red("[cookies error]")} ${e.url}
|
|
41
|
+
`,r)}}function yt(e,o,t){if(Se(o))o.pipe(e);else if(ne.Buffer.isBuffer(o))e.end(t==="text"||t==="json"?o.toString("utf-8"):o);else{let r=typeof o=="string"?o:JSON.stringify(o);e.end(t==="buffer"?ne.Buffer.from(r):r)}}async function He(e,o){if(!o||o<=0)return;let t=Date.now()-e,r=o-t;r>0&&await Re(r)}function ht(e){return Ue.default[e]||"Unknown"}var Ae=u(require("events"),1),Z=u(require("fs"),1),Be=require("module"),le=u(require("path"),1),Je=require("url"),ue=u(require("chokidar"),1),ze=require("esbuild"),Ge=u(require("fast-glob"),1),C=require("vite");var Ne=require("url"),qe=u(require("lodash.sortby"),1);function pe(e){let o=[];for(let[,r]of e.entries())r&&(j(r)?o.push(...r):o.push(r));let t={};return o.filter(r=>(r.enabled||typeof r.enabled>"u")&&r.url).forEach(r=>{let{pathname:s,query:n}=(0,Ne.parse)(r.url,!0),i=t[s]??(t[s]=[]),c={...r,url:s};if(c.ws!==!0){let a=c.validator;Pe(n)||(R(a)?c.validator=function(p){return W(p.query,n)&&a(p)}:a?(c.validator={...a},c.validator.query=c.validator.query?{...n,...c.validator.query}:n):c.validator={query:n})}i.push(c)}),Object.keys(t).forEach(r=>{t[r]=(0,qe.default)(t[r],s=>{if(s.ws===!0)return 0;let{validator:n}=s;if(!n)return 1;if(R(n))return 0;let{query:i,params:c,headers:a,body:p,refererQuery:m}=n;return 1/(N(i)+N(c)+N(a)+N(p)+N(m))})}),t}function N(e){return e?Object.keys(e).length:0}var vt=De(x),I=(0,Be.createRequire)(vt),ee=class extends Ae.default{constructor(t){super();this.options=t;this.moduleCache=new Map;this.moduleDeps=new Map;this.moduleType="cjs";this._mockData={};this.cwd=t.cwd||process.cwd();try{let r=$(this.cwd,["package.json"]);this.moduleType=r&&JSON.parse(r).type==="module"?"esm":"cjs"}catch{}}get mockData(){return this._mockData}async load(){let{include:t,exclude:r}=this.options,s=await(0,Ge.default)(t,{cwd:this.cwd}),n=(0,C.createFilter)(t,r,{resolve:!1});this.watchMockEntry(),this.watchDeps();for(let c of s.filter(n))await this.loadMock(c);this.updateMockList();let i=null;this.on("mock:update",async c=>{n(c)&&(await this.loadMock(c),i&&clearTimeout(i),i=setTimeout(()=>{this.updateMockList(),this.emit("mock:update-end",c),i=null},0))}),this.on("mock:unlink",async c=>{n(c)&&(this.moduleCache.delete(c),this.updateMockList(),this.emit("mock:update-end",c))})}watchMockEntry(){let{include:t}=this.options,[r,...s]=t,n=ue.default.watch(r,{ignoreInitial:!0,cwd:this.cwd});s.length>0&&s.forEach(i=>n.add(i)),n.on("add",async i=>{i=(0,C.normalizePath)(i),this.emit("mock:update",i),D("watcher:add",i)}),n.on("change",async i=>{i=(0,C.normalizePath)(i),this.emit("mock:update",i),D("watcher:change",i)}),n.on("unlink",async i=>{i=(0,C.normalizePath)(i),this.emit("mock:unlink",i),D("watcher:unlink",i)}),this.mockWatcher=n}watchDeps(){let t=[];this.depsWatcher=ue.default.watch([],{ignoreInitial:!0,cwd:this.cwd}),this.depsWatcher.on("change",r=>{r=(0,C.normalizePath)(r);let s=this.moduleDeps.get(r);s&&s.forEach(n=>{this.emit("mock:update",n)})}),this.depsWatcher.on("unlink",r=>{r=(0,C.normalizePath)(r),this.moduleDeps.delete(r)}),this.on("update:deps",()=>{let r=[];for(let[n]of this.moduleDeps.entries())r.push(n);let s=r.filter(n=>!t.includes(n));s.length>0&&this.depsWatcher.add(s)})}close(){var t,r;(t=this.mockWatcher)==null||t.close(),(r=this.depsWatcher)==null||r.close()}updateMockList(){this._mockData=pe(this.moduleCache)}updateModuleDeps(t,r){Object.keys(r).forEach(s=>{r[s].imports.map(i=>i.path).forEach(i=>{this.moduleDeps.has(i)||this.moduleDeps.set(i,new Set),this.moduleDeps.get(i).add(t)})}),this.emit("update:deps")}async loadMock(t){if(!t)return;let r=!1;/\.m[jt]s$/.test(t)?r=!0:/\.c[jt]s$/.test(t)?r=!1:r=this.moduleType==="esm";let{code:s,deps:n}=await this.transformWithEsbuild(t,r);try{let i=await this.loadFromCode(t,s,r),c=i&&i.default?i.default:Object.keys(i||{}).map(a=>i[a]);j(c)?c.forEach(a=>a.__filepath__=t):c.__filepath__=t,this.moduleCache.set(t,c),this.updateModuleDeps(t,n)}catch(i){console.error(i)}}async loadFromCode(t,r,s){if(s){let n=`${t}.timestamp-${Date.now()}`,i=`${n}.mjs`,c=`${(0,Je.pathToFileURL)(n)}.mjs`;await Z.default.promises.writeFile(i,r,"utf8");try{return await import(c)}finally{try{Z.default.unlinkSync(i)}catch{}}}else{t=le.default.resolve(this.cwd,t);let n=le.default.extname(t),i=Z.default.realpathSync(t),c=n in I.extensions?n:".js",a=I.extensions[c];I.extensions[c]=(m,l)=>{l===i?m._compile(r,l):a(m,l)},delete I.cache[I.resolve(t)];let p=I(t);return I.extensions[c]=a,p.__esModule?p:{default:p}}}async transformWithEsbuild(t,r){var s;try{let n=await(0,ze.build)({entryPoints:[t],outfile:"out.js",write:!1,target:["node14.18","node16"],platform:"node",bundle:!0,metafile:!0,format:r?"esm":"cjs",define:this.options.define,plugins:[z(this.options.alias),A,J,B]});return{code:n.outputFiles[0].text,deps:((s=n.metafile)==null?void 0:s.inputs)||{}}}catch(n){console.error(n)}return{code:"",deps:{}}}};var me=require("url"),Qe=u(require("cookies"),1),de=require("path-to-regexp"),Xe=require("ws");function fe(e,o,t,r){var c;let s=new Set,n=new Map,i=new Map;(c=e.on)==null||c.call(e,"mock:update-end",a=>{if(!s.has(a))return;let p={};for(let[m,l]of i.entries())e.mockData[m].forEach(M=>{M.__filepath__===a&&M.ws&&l.forEach(({pathname:b,req:h,ws:g})=>{p[b]??(p[b]={mock:M,list:[],mockUrl:m}),p[b].list.push({req:h,ws:g}),g.removeAllListeners()})});Object.keys(p).forEach(m=>{var g,f;let l=n.get(m),{mock:M,list:b,mockUrl:h}=p[m];l.wss.removeAllListeners(),(g=l.cancel)==null||g.call(l),l.cancel=(f=M.setup)==null?void 0:f.call(M,l.wss),l.wss.on("close",()=>{n.delete(m)}),b.forEach(({req:d,ws:v})=>{l.wss.emit("connection",v,d),v.on("close",()=>{let y=i.get(h),w=(y==null?void 0:y.findIndex(k=>k.ws===v))||-1;w>=0&&(y==null||y.splice(w,1))})})})}),o==null||o.on("upgrade",(a,p,m)=>{var w;let{pathname:l,query:M}=(0,me.parse)(a.url,!0);if(!l||t.length===0||!t.some(k=>K(k,a.url)))return;let b=e.mockData,h=Object.keys(b).find(k=>(0,de.pathToRegexp)(k).test(l));if(!h)return;let g=b[h].find(k=>k.url&&k.ws&&(0,de.pathToRegexp)(k.url).test(l));if(!g)return;s.add(g.__filepath__);let f=n.get(l);if(!f){let k=new Xe.WebSocketServer({noServer:!0}),O=(w=g.setup)==null?void 0:w.call(g,k);k.on("close",()=>{n.delete(l)}),f={wss:k,cancel:O},n.set(l,f)}let d=a,v=new Qe.default(a,a,r),{query:y}=(0,me.parse)(a.headers.referer||"",!0);d.query=M,d.refererQuery=y,d.params=H(h,l),d.getCookie=v.get.bind(v),f.wss.handleUpgrade(d,p,m,k=>{D(`websocket-mock: ${a.url} connected`),f.wss.emit("connection",k,d);let O=i.get(h);O||(O=[],i.set(h,O)),O.push({req:d,ws:k,pathname:l}),k.on("close",()=>{let L=O.findIndex(te=>te.ws===k);L>=0&&O.splice(L,1)})})}),o==null||o.on("close",()=>{n.forEach(({wss:a,cancel:p})=>{p==null||p(),a.close()}),n.clear(),s.clear(),i.clear()})}async function ke(e,o,t,r){let s=P(o.include),n=P(o.exclude),i={};if(e.define)for(let m in e.define){let l=e.define[m];i[m]=typeof l=="string"?l:JSON.stringify(l)}let c=new ee({include:s,exclude:n,define:i,alias:e.resolve.alias});await c.load(),c.on("mock:update-end",()=>{o.reload&&(r==null||r.send({type:"full-reload"}))}),t==null||t.on("close",()=>c.close());let{httpProxies:a}=X(e.server.proxy||{}),p=P(o.prefix);return fe(c,t,P(o.wsPrefix),o.cookiesOptions),ae(c,{formidableOptions:o.formidableOptions,proxies:[...p,...a],cookiesOptions:o.cookiesOptions})}function ge({prefix:e=[],wsPrefix:o=[],include:t=["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],exclude:r=["**/node_modules/**","**/.vscode/**","**/.git/**"],reload:s=!1,formidableOptions:n={},build:i=!1,cookiesOptions:c={}}={}){let a={prefix:e,wsPrefix:o,include:t,exclude:r,reload:s,cookiesOptions:c,formidableOptions:{multiples:!0,...n},build:i?Object.assign({serverPort:8080,dist:"mockServer"},typeof i=="object"?i:{}):!1},p=[bt(a)];return a.build&&p.push(Mt(a)),p}function Mt(e){let o={};return{name:"vite-plugin-mock-dev-server-generator",enforce:"post",apply:"build",configResolved(t){o=t,t.logger.warn("")},async buildEnd(t){t||o.command==="build"&&await Te(this,o,e)}}}function bt(e){let o={};return{name:"vite-plugin-mock-dev-server",enforce:"pre",apply:"serve",configResolved(t){o=t,t.logger.warn("")},async configureServer({middlewares:t,config:r,httpServer:s,ws:n}){let i=await ke(r,e,s,n);t.use(i)},async configurePreviewServer({middlewares:t,httpServer:r}){let s=await ke(o,e,r);t.use(s)}}}function xt(e){return e}function wt(e){return t=>(j(t)?t=t.map(r=>e(r)||r):t=e(t)||t,t)}var Ot=ge;0&&(module.exports={baseMiddleware,createDefineMock,defineMock,mockDevServerPlugin,mockWebSocket,transformMockData});
|
package/dist/index.d.ts
CHANGED
|
@@ -3,21 +3,35 @@ import http from 'node:http';
|
|
|
3
3
|
import { Readable } from 'node:stream';
|
|
4
4
|
import Cookies from 'cookies';
|
|
5
5
|
import formidable from 'formidable';
|
|
6
|
+
import { WebSocketServer } from 'ws';
|
|
6
7
|
import EventEmitter from 'node:events';
|
|
7
8
|
import chokidar from 'chokidar';
|
|
8
9
|
|
|
9
10
|
interface MockServerPluginOptions {
|
|
10
11
|
/**
|
|
11
|
-
* To configure the path matching rules for mock services,
|
|
12
|
+
* To configure the path matching rules for http mock services,
|
|
12
13
|
* any request path starting with prefix will be intercepted and proxied.
|
|
13
14
|
* If the prefix starts with `^`, it will be recognized as a `RegExp`.
|
|
14
15
|
*
|
|
15
|
-
* 为 mock 服务配置 路径匹配规则,任何请求路径以 prefix 开头的都将被拦截代理。
|
|
16
|
+
* 为 http mock 服务配置 路径匹配规则,任何请求路径以 prefix 开头的都将被拦截代理。
|
|
16
17
|
* 如果 prefix 以 `^` 开头,将被识别为 `RegExp`。
|
|
17
18
|
* @default []
|
|
18
19
|
* @example ['^/api']
|
|
19
20
|
*/
|
|
20
21
|
prefix?: string | string[];
|
|
22
|
+
/**
|
|
23
|
+
* Configure path matching rules for WebSocket mock service.
|
|
24
|
+
* Any ws/wss requests with a request path starting with wsPrefix
|
|
25
|
+
* will be intercepted by the proxy.
|
|
26
|
+
* If wsPrefix starts with `^`, it will be recognized as a `RegExp`.
|
|
27
|
+
*
|
|
28
|
+
* 为 websocket mock 服务配置 路径匹配规则, 任何请求路径以 wsPrefix 开头的 ws/wss请求,
|
|
29
|
+
* 都将被代理拦截。
|
|
30
|
+
* 如果 wsPrefix 以 `^` 开头,将被识别为 `RegExp`。
|
|
31
|
+
* @default []
|
|
32
|
+
* @example ['/socket.io']
|
|
33
|
+
*/
|
|
34
|
+
wsPrefix?: string | string[];
|
|
21
35
|
/**
|
|
22
36
|
* glob string matching mock includes files
|
|
23
37
|
*
|
|
@@ -128,7 +142,7 @@ type ResponseHeaderFn = (request: MockRequest) => Headers | Promise<Headers>;
|
|
|
128
142
|
type CookieValue = string | [string, Cookies.SetOption];
|
|
129
143
|
type ResponseCookies = Record<string, CookieValue>;
|
|
130
144
|
type ResponseCookiesFn = (request: MockRequest) => ResponseCookies | Promise<ResponseCookies>;
|
|
131
|
-
interface
|
|
145
|
+
interface MockBaseItem {
|
|
132
146
|
/**
|
|
133
147
|
* The interface address that needs to be mocked,
|
|
134
148
|
* supported by `path-to-regexp` for path matching.
|
|
@@ -144,23 +158,33 @@ interface MockOptionsItem {
|
|
|
144
158
|
*/
|
|
145
159
|
url: string;
|
|
146
160
|
/**
|
|
147
|
-
*
|
|
161
|
+
* Enable WebSocket interface simulation
|
|
148
162
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
163
|
+
* 开启 websocket 接口模拟
|
|
164
|
+
*
|
|
165
|
+
* @default false
|
|
151
166
|
*/
|
|
152
|
-
|
|
167
|
+
ws?: boolean;
|
|
153
168
|
/**
|
|
154
169
|
* Whether to enable mock for this interface.
|
|
155
170
|
* In most scenarios, we only need to mock some interfaces instead of all requests that
|
|
156
171
|
* have been configured with mock.
|
|
157
172
|
* Therefore, it is important to be able to configure whether to enable it or not.
|
|
158
173
|
*
|
|
159
|
-
* 是否启动对该接口的mock
|
|
174
|
+
* 是否启动对该接口的mock,在多数场景下,我们仅需要对部分接口进行 mock,
|
|
160
175
|
* 而不是对所有配置了mock的请求进行全量mock,所以是否能够配置是否启用很重要
|
|
161
176
|
* @default true
|
|
162
177
|
*/
|
|
163
178
|
enabled?: boolean;
|
|
179
|
+
}
|
|
180
|
+
interface MockHttpItem extends MockBaseItem {
|
|
181
|
+
/**
|
|
182
|
+
* The interface allows request methods, and by default allows both GET and POST.
|
|
183
|
+
*
|
|
184
|
+
* 该接口允许的 请求方法,默认同时支持 GET 和 POST
|
|
185
|
+
* @default ['POST','GET']
|
|
186
|
+
*/
|
|
187
|
+
method?: Method | Method[];
|
|
164
188
|
/**
|
|
165
189
|
* Configure the response body headers
|
|
166
190
|
*
|
|
@@ -330,11 +354,35 @@ interface MockOptionsItem {
|
|
|
330
354
|
* ```
|
|
331
355
|
*/
|
|
332
356
|
validator?: Partial<Omit<ExtraRequest, 'getCookie'>> | ((request: ExtraRequest) => boolean);
|
|
357
|
+
ws?: false;
|
|
358
|
+
}
|
|
359
|
+
type MockWebsocketServerDestroy = (() => void) | void;
|
|
360
|
+
interface MockWebsocketItem extends MockBaseItem {
|
|
361
|
+
ws: true;
|
|
362
|
+
/**
|
|
363
|
+
* Configure Websocket Server
|
|
364
|
+
*
|
|
365
|
+
* 配置 Websocket Server
|
|
366
|
+
* @example
|
|
367
|
+
* ```ts
|
|
368
|
+
* export default {
|
|
369
|
+
* ws: true
|
|
370
|
+
* setup: (wss) => {
|
|
371
|
+
* wss.on('connection', (ws,req) => {
|
|
372
|
+
* ws.on('message', (raw) => console.log(raw))
|
|
373
|
+
* ws.send(JSON.stringify({ type: 'connected' }))
|
|
374
|
+
* })
|
|
375
|
+
* wss.on('error', (error) => console.error(error))
|
|
376
|
+
* }
|
|
377
|
+
* }
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
setup: (wss: WebSocketServer) => MockWebsocketServerDestroy;
|
|
333
381
|
}
|
|
334
|
-
type MockOptions =
|
|
382
|
+
type MockOptions = (MockHttpItem | MockWebsocketItem)[];
|
|
335
383
|
type FormidableFile = formidable.File | formidable.File[];
|
|
336
384
|
|
|
337
|
-
declare function mockDevServerPlugin({ prefix, include, exclude, reload, formidableOptions, build, cookiesOptions, }?: MockServerPluginOptions): Plugin[];
|
|
385
|
+
declare function mockDevServerPlugin({ prefix, wsPrefix, include, exclude, reload, formidableOptions, build, cookiesOptions, }?: MockServerPluginOptions): Plugin[];
|
|
338
386
|
|
|
339
387
|
/**
|
|
340
388
|
* mock config helper
|
|
@@ -351,8 +399,9 @@ declare function mockDevServerPlugin({ prefix, include, exclude, reload, formida
|
|
|
351
399
|
* })
|
|
352
400
|
* ```
|
|
353
401
|
*/
|
|
354
|
-
declare function defineMock(config:
|
|
402
|
+
declare function defineMock(config: MockHttpItem): MockHttpItem;
|
|
355
403
|
declare function defineMock(config: MockOptions): MockOptions;
|
|
404
|
+
declare function defineMock(config: MockWebsocketItem): MockWebsocketItem;
|
|
356
405
|
/**
|
|
357
406
|
* 返回一个自定义的 defineMock 函数,用于支持对 mock config 的预处理。
|
|
358
407
|
*
|
|
@@ -360,7 +409,7 @@ declare function defineMock(config: MockOptions): MockOptions;
|
|
|
360
409
|
*
|
|
361
410
|
* @param transformer preprocessing function
|
|
362
411
|
*/
|
|
363
|
-
declare function createDefineMock(transformer: (mock:
|
|
412
|
+
declare function createDefineMock(transformer: (mock: MockHttpItem | MockWebsocketItem) => MockHttpItem | MockWebsocketItem | void): typeof defineMock;
|
|
364
413
|
|
|
365
414
|
interface MockLoaderOptions {
|
|
366
415
|
cwd?: string;
|
|
@@ -374,8 +423,7 @@ interface MockLoaderOptions {
|
|
|
374
423
|
*/
|
|
375
424
|
declare class MockLoader extends EventEmitter {
|
|
376
425
|
options: MockLoaderOptions;
|
|
377
|
-
|
|
378
|
-
moduleCache: Map<string, MockOptions | MockOptionsItem>;
|
|
426
|
+
moduleCache: Map<string, MockOptions | MockHttpItem | MockWebsocketItem>;
|
|
379
427
|
moduleDeps: Map<string, Set<string>>;
|
|
380
428
|
cwd: string;
|
|
381
429
|
mockWatcher: chokidar.FSWatcher;
|
|
@@ -395,8 +443,6 @@ declare class MockLoader extends EventEmitter {
|
|
|
395
443
|
private updateMockList;
|
|
396
444
|
private updateModuleDeps;
|
|
397
445
|
private loadMock;
|
|
398
|
-
private loadJson;
|
|
399
|
-
private loadModule;
|
|
400
446
|
private loadFromCode;
|
|
401
447
|
private transformWithEsbuild;
|
|
402
448
|
}
|
|
@@ -408,6 +454,8 @@ interface BaseMiddlewareOptions {
|
|
|
408
454
|
}
|
|
409
455
|
declare function baseMiddleware(mockLoader: MockLoader, { formidableOptions, proxies, cookiesOptions }: BaseMiddlewareOptions): Connect.NextHandleFunction;
|
|
410
456
|
|
|
411
|
-
declare function
|
|
457
|
+
declare function mockWebSocket(loader: MockLoader, httpServer: http.Server | null, proxies: string[], cookiesOptions: MockServerPluginOptions['cookiesOptions']): void;
|
|
458
|
+
|
|
459
|
+
declare function transformMockData(mockList: Map<string, MockHttpItem | MockWebsocketItem | MockOptions> | (MockHttpItem | MockWebsocketItem | MockOptions)[]): Record<string, MockOptions>;
|
|
412
460
|
|
|
413
|
-
export { BaseMiddlewareOptions, FormidableFile, MockOptions,
|
|
461
|
+
export { BaseMiddlewareOptions, FormidableFile, MockHttpItem, MockOptions, MockRequest, MockServerPluginOptions, MockWebsocketItem, baseMiddleware, createDefineMock, mockDevServerPlugin as default, defineMock, mockDevServerPlugin, mockWebSocket, transformMockData };
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
import Fe from"fs";import
|
|
2
|
-
`,
|
|
3
|
-
`)}};function
|
|
1
|
+
import Fe from"fs";import G from"fs/promises";import I from"path";import{build as Le}from"esbuild";import $e from"fast-glob";import He from"is-core-module";import{createFilter as _e,normalizePath as Ue}from"vite";var re="vite-plugin-mock-dev-server",se="1.1.6";import ne from"fs/promises";import Se from"path";import Re from"json5";var N={name:"externalize-deps",setup(t){t.onResolve({filter:/.*/},({path:o})=>{if(o[0]!=="."&&!Se.isAbsolute(o))return{external:!0}})}},q={name:"json5-loader",setup(t){t.onLoad({filter:/\.json5$/},async({path:o})=>{let e=await ne.readFile(o,"utf-8");return{contents:`export default ${JSON.stringify(Re.parse(e))}`,loader:"js"}})}},A={name:"json-loader",setup(t){t.onLoad({filter:/\.json$/},async({path:o})=>({contents:`export default ${await ne.readFile(o,"utf-8")}`,loader:"js"}))}},B=t=>({name:"alias-plugin",setup(o){o.onResolve({filter:/.*/},async({path:e})=>{let r=t.find(({find:c})=>De(c,e));if(!r)return null;let{find:n,replacement:s}=r;return{path:(await o.resolve(e.replace(n,s),{kind:"import-statement",resolveDir:s,namespace:"file"})).path,external:!1}})}});function De(t,o){return t instanceof RegExp?t.test(o):o.length<t.length?!1:o===t?!0:o.startsWith(`${t}/`)}import K from"fs";import V from"path";import{fileURLToPath as Ce}from"url";import Ee from"debug";import{match as We}from"path-to-regexp";import ie from"picocolors";var P=t=>Array.isArray(t),R=t=>typeof t=="function",Ie=t=>Object.prototype.toString.call(t)==="[object Object]",ce=t=>Ie(t)&&Object.keys(t).length===0,Te=t=>t!==null&&typeof t=="object"&&typeof t.pipe=="function",ae=t=>Te(t)&&t.readable!==!1&&typeof t._read=="function"&&typeof t._readableState=="object";function pe(t){return new Promise(o=>setTimeout(o,t))}function le(t){return V.dirname(Ce(t))}var D=Ee("vite:plugin-mock-dev-server"),j=t=>P(t)?t:t==null?[]:[t],W={info(...t){console.info(ie.cyan("mock-dev-server: "),...t)},error(...t){console.error(`
|
|
2
|
+
`,ie.cyan("mock-dev-server: "),...t,`
|
|
3
|
+
`)}};function F(t,o,e){for(let n of o){let s=V.join(t,n);if(K.existsSync(s)&&K.statSync(s).isFile()){let i=e!=null&&e.pathOnly?s:K.readFileSync(s,"utf-8");if(!(e!=null&&e.predicate)||e.predicate(i))return i}}let r=V.dirname(t);if(r!==t&&(!(e!=null&&e.rootDir)||r.startsWith(e==null?void 0:e.rootDir)))return F(r,o,e)}var J=(t={})=>{let o=[],e=[];return Object.keys(t).forEach(r=>{var s,i;let n=t[r];typeof n=="string"||!n.ws&&!((s=n.target)!=null&&s.toString().startsWith("ws:"))&&!((i=n.target)!=null&&i.toString().startsWith("wss:"))?o.push(r):e.push(r)}),{httpProxies:o,wsProxies:e}};function z(t,o){return t[0]==="^"&&new RegExp(t).test(o)||o.startsWith(t)}function L(t,o){return(We(t,{decode:decodeURIComponent})(o)||{params:{}}).params||{}}async function ue(t,o,e){let r=j(e.include),n=j(e.exclude),s={};if(o.define)for(let m in o.define){let d=o.define[m];s[m]=typeof d=="string"?d:JSON.stringify(d)}let{httpProxies:i}=J(o.server.proxy||{});i.push(...j(e.prefix));let c=j(e.wsPrefix),a={};try{let m=F(o.root,["package.json"]);m&&(a=JSON.parse(m))}catch{}let p=e.build.dist,u=await Be(process.cwd(),r,n),l=I.join(o.root,`mock-data-${Date.now()}.js`);await G.writeFile(l,u,"utf-8");let{code:v,deps:M}=await Je(l,s,o.resolve.alias),y=Ne(M);await G.unlink(l);let k=[{filename:I.join(p,"mock-data.js"),source:v},{filename:I.join(p,"index.js"),source:Ae(i,c,e.cookiesOptions,e.build.serverPort)},{filename:I.join(p,"package.json"),source:qe(a,y)}];try{if(I.isAbsolute(p)){await G.rm(p,{recursive:!0}),Fe.mkdirSync(p,{recursive:!0});for(let{filename:m,source:d}of k)await G.writeFile(m,d,"utf-8")}else for(let{filename:m,source:d}of k)t.emitFile({type:"asset",fileName:m,source:d})}catch{}}function Ne(t){let o=new Set,e=[re,"connect","cors"];return Object.keys(t).forEach(r=>{t[r].imports.filter(s=>s.external).map(s=>s.path).forEach(s=>{!e.includes(s)&&!He(s)&&o.add(s)})}),Array.from(o)}function qe(t,o){let{dependencies:e={},devDependencies:r={}}=t,n={...e,...r},s={name:"mock-server",type:"module",scripts:{start:"node index.js"},dependencies:{connect:"^3.7.0","vite-plugin-mock-dev-server":`^${se}`,cors:"^2.8.5"},pnpm:{peerDependencyRules:{ignoreMissing:["vite"]}}};return o.forEach(i=>{s.dependencies[i]=n[i]||"latest"}),JSON.stringify(s,null,2)}function Ae(t,o,e={},r=8080){return`import { createServer } from 'node:http';
|
|
4
|
+
import connect from 'connect';
|
|
4
5
|
import corsMiddleware from 'cors';
|
|
5
|
-
import { baseMiddleware } from 'vite-plugin-mock-dev-server';
|
|
6
|
+
import { baseMiddleware, mockWebSocket } from 'vite-plugin-mock-dev-server';
|
|
6
7
|
import mockData from './mock-data.js';
|
|
7
8
|
|
|
8
9
|
const app = connect();
|
|
10
|
+
const server = createServer(app);
|
|
11
|
+
const httpProxies = ${JSON.stringify(t)};
|
|
12
|
+
const wxProxies = ${JSON.stringify(o)}
|
|
13
|
+
const cookiesOptions = ${JSON.stringify(e)};
|
|
14
|
+
|
|
15
|
+
mockWebSocket({ mockData }, server, wxProxies, cookiesOptions)
|
|
16
|
+
|
|
9
17
|
app.use(corsMiddleware());
|
|
10
18
|
app.use(baseMiddleware({ mockData }, {
|
|
11
19
|
formidableOptions: { multiples: true },
|
|
12
|
-
proxies:
|
|
13
|
-
cookiesOptions
|
|
20
|
+
proxies: httpProxies,
|
|
21
|
+
cookiesOptions,
|
|
14
22
|
}));
|
|
15
|
-
app.listen(${e});
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
server.listen(${r});
|
|
25
|
+
|
|
26
|
+
console.log('listen: http://localhost:${r}');
|
|
27
|
+
`}async function Be(t,o,e){let r=await $e(o,{cwd:t}),n=_e(o,e,{resolve:!1}),s=r.filter(n),i="",c="";return s.forEach((a,p)=>{let u=Ue(I.join(t,a));i+=`import * as m${p} from '${u}';
|
|
28
|
+
`,c+=`m${p}, `}),`import { transformMockData } from 'vite-plugin-mock-dev-server';
|
|
20
29
|
${i}
|
|
21
|
-
const exporters = [${
|
|
30
|
+
const exporters = [${c}];
|
|
22
31
|
const mockList = exporters.map((raw) => raw && raw.default
|
|
23
32
|
? raw.default
|
|
24
33
|
: Object.keys(raw || {}).map((key) => raw[key])
|
|
25
34
|
)
|
|
26
35
|
export default transformMockData(mockList);
|
|
27
|
-
`}async function
|
|
28
|
-
`,
|
|
29
|
-
`,
|
|
30
|
-
`,
|
|
31
|
-
`,s)}}async function
|
|
32
|
-
`,
|
|
36
|
+
`}async function Je(t,o,e){var r;try{let n=await Le({entryPoints:[t],outfile:"out.js",write:!1,target:["node14.18","node16"],platform:"node",bundle:!0,metafile:!0,format:"esm",define:o,plugins:[B(e),N,q,A]});return{code:n.outputFiles[0].text,deps:((r=n.metafile)==null?void 0:r.inputs)||{}}}catch(n){console.error(n)}return{code:"",deps:{}}}import{Buffer as fe}from"buffer";import{parse as ke}from"url";import Qe from"cookies";import Xe from"http-status";import*as $ from"mime-types";import{pathToRegexp as ye}from"path-to-regexp";import H from"picocolors";import Y from"co-body";import ze from"formidable";async function de(t,o){var n;let e=t.method.toUpperCase();if(["GET","DELETE","HEAD"].includes(e))return;let r=((n=t.headers["content-type"])==null?void 0:n.toLocaleLowerCase())||"";try{if(r.startsWith("application/json"))return await Y.json(t);if(r.startsWith("application/x-www-form-urlencoded"))return await Y.form(t);if(r.startsWith("text/plain"))return await Y.text(t);if(r.startsWith("multipart/form-data"))return await Ge(t,o)}catch(s){console.error(s)}}async function Ge(t,o){let e=ze(o);return new Promise((r,n)=>{e.parse(t,(s,i,c)=>{if(s){n(s);return}r({...i,...c})})})}function me(t,o){return C(t.headers,o.headers)&&C(t.body,o.body)&&C(t.params,o.params)&&C(t.query,o.query)&&C(t.refererQuery,o.refererQuery)}function C(t,o){if(!o)return!0;for(let e in o)if(o[e]!==t[e])return!1;return!0}function he(t,{formidableOptions:o={},proxies:e,cookiesOptions:r}){return async function(n,s,i){let c=Date.now(),{query:a,pathname:p}=ke(n.url,!0);if(!p||e.length===0||!e.some(S=>z(S,n.url)))return i();let u=t.mockData,l=Object.keys(u).find(S=>ye(S).test(p));if(!l)return i();let{query:v}=ke(n.headers.referer||"",!0),M=await de(n,o),y=new Qe(n,s,r),k=y.get.bind(y),m=n.method.toUpperCase(),d=Ke(u[l],{pathname:p,method:m,request:{query:a,refererQuery:v,body:M,headers:n.headers,getCookie:k}});if(!d)return i();D("middleware: ",m,n.url);let h=n,g=s;h.body=M,h.query=a,h.refererQuery=v,h.params=L(d.url,p),h.getCookie=k,g.setCookie=y.set.bind(y);let{body:w,delay:f,type:O="json",response:T,status:X=200,statusText:je}=d;if(Z(g,X,je),await Ve(h,g,d),await Ye(h,g,d),w){try{let S=R(w)?await w(h):w;await ge(c,f),Ze(g,S,O)}catch(S){W.error(`${H.red("[body error]")} ${n.url}
|
|
37
|
+
`,S),Z(g,500),s.end("")}return}if(T){try{await ge(c,f),await T(h,g,i)}catch(S){W.error(`${H.red("[response error]")} ${n.url}
|
|
38
|
+
`,S),Z(g,500),s.end("")}return}s.end("")}}function Ke(t,{pathname:o,method:e,request:r}){return t.find(n=>{if(!o||!n||!n.url||n.ws===!0||!(n.method?P(n.method)?n.method:[n.method]:["GET","POST"]).includes(e))return!1;let i=ye(n.url).test(o);if(i&&n.validator){let c=L(n.url,o);if(R(n.validator))return n.validator({params:c,...r});try{return me({params:c,...r},n.validator)}catch(a){return W.error(`${H.red("[validator error]")} ${o}
|
|
39
|
+
`,a),!1}}return i})}function Z(t,o=200,e){t.statusCode=o,t.statusMessage=e||et(o)}async function Ve(t,o,{headers:e,type:r="json"}){let n=$.contentType(r)||$.contentType($.lookup(r)||"");if(n&&o.setHeader("Content-Type",n),o.setHeader("Cache-Control","no-cache,max-age=0"),o.setHeader("X-Mock","generate by vite:plugin-mock-dev-server"),!!e)try{let s=R(e)?await e(t):e;Object.keys(s).forEach(i=>{o.setHeader(i,s[i])})}catch(s){W.error(`${H.red("[headers error]")} ${t.url}
|
|
40
|
+
`,s)}}async function Ye(t,o,{cookies:e}){if(e)try{let r=R(e)?await e(t):e;Object.keys(r).forEach(n=>{let s=r[n];if(P(s)){let[i,c]=s;o.setCookie(n,i,c)}else o.setCookie(n,s)})}catch(r){W.error(`${H.red("[cookies error]")} ${t.url}
|
|
41
|
+
`,r)}}function Ze(t,o,e){if(ae(o))o.pipe(t);else if(fe.isBuffer(o))t.end(e==="text"||e==="json"?o.toString("utf-8"):o);else{let r=typeof o=="string"?o:JSON.stringify(o);t.end(e==="buffer"?fe.from(r):r)}}async function ge(t,o){if(!o||o<=0)return;let e=Date.now()-t,r=o-e;r>0&&await pe(r)}function et(t){return Xe[t]||"Unknown"}import rt from"events";import ee from"fs";import{createRequire as st}from"module";import Me from"path";import{pathToFileURL as nt}from"url";import be from"chokidar";import{build as it}from"esbuild";import ct from"fast-glob";import{createFilter as at,normalizePath as U}from"vite";import{parse as tt}from"url";import ot from"lodash.sortby";function ve(t){let o=[];for(let[,r]of t.entries())r&&(P(r)?o.push(...r):o.push(r));let e={};return o.filter(r=>(r.enabled||typeof r.enabled>"u")&&r.url).forEach(r=>{let{pathname:n,query:s}=tt(r.url,!0),i=e[n]??(e[n]=[]),c={...r,url:n};if(c.ws!==!0){let a=c.validator;ce(s)||(R(a)?c.validator=function(p){return C(p.query,s)&&a(p)}:a?(c.validator={...a},c.validator.query=c.validator.query?{...s,...c.validator.query}:s):c.validator={query:s})}i.push(c)}),Object.keys(e).forEach(r=>{e[r]=ot(e[r],n=>{if(n.ws===!0)return 0;let{validator:s}=n;if(!s)return 1;if(R(s))return 0;let{query:i,params:c,headers:a,body:p,refererQuery:u}=s;return 1/(_(i)+_(c)+_(a)+_(p)+_(u))})}),e}function _(t){return t?Object.keys(t).length:0}var pt=le(import.meta.url),E=st(pt),Q=class extends rt{constructor(e){super();this.options=e;this.moduleCache=new Map;this.moduleDeps=new Map;this.moduleType="cjs";this._mockData={};this.cwd=e.cwd||process.cwd();try{let r=F(this.cwd,["package.json"]);this.moduleType=r&&JSON.parse(r).type==="module"?"esm":"cjs"}catch{}}get mockData(){return this._mockData}async load(){let{include:e,exclude:r}=this.options,n=await ct(e,{cwd:this.cwd}),s=at(e,r,{resolve:!1});this.watchMockEntry(),this.watchDeps();for(let c of n.filter(s))await this.loadMock(c);this.updateMockList();let i=null;this.on("mock:update",async c=>{s(c)&&(await this.loadMock(c),i&&clearTimeout(i),i=setTimeout(()=>{this.updateMockList(),this.emit("mock:update-end",c),i=null},0))}),this.on("mock:unlink",async c=>{s(c)&&(this.moduleCache.delete(c),this.updateMockList(),this.emit("mock:update-end",c))})}watchMockEntry(){let{include:e}=this.options,[r,...n]=e,s=be.watch(r,{ignoreInitial:!0,cwd:this.cwd});n.length>0&&n.forEach(i=>s.add(i)),s.on("add",async i=>{i=U(i),this.emit("mock:update",i),D("watcher:add",i)}),s.on("change",async i=>{i=U(i),this.emit("mock:update",i),D("watcher:change",i)}),s.on("unlink",async i=>{i=U(i),this.emit("mock:unlink",i),D("watcher:unlink",i)}),this.mockWatcher=s}watchDeps(){let e=[];this.depsWatcher=be.watch([],{ignoreInitial:!0,cwd:this.cwd}),this.depsWatcher.on("change",r=>{r=U(r);let n=this.moduleDeps.get(r);n&&n.forEach(s=>{this.emit("mock:update",s)})}),this.depsWatcher.on("unlink",r=>{r=U(r),this.moduleDeps.delete(r)}),this.on("update:deps",()=>{let r=[];for(let[s]of this.moduleDeps.entries())r.push(s);let n=r.filter(s=>!e.includes(s));n.length>0&&this.depsWatcher.add(n)})}close(){var e,r;(e=this.mockWatcher)==null||e.close(),(r=this.depsWatcher)==null||r.close()}updateMockList(){this._mockData=ve(this.moduleCache)}updateModuleDeps(e,r){Object.keys(r).forEach(n=>{r[n].imports.map(i=>i.path).forEach(i=>{this.moduleDeps.has(i)||this.moduleDeps.set(i,new Set),this.moduleDeps.get(i).add(e)})}),this.emit("update:deps")}async loadMock(e){if(!e)return;let r=!1;/\.m[jt]s$/.test(e)?r=!0:/\.c[jt]s$/.test(e)?r=!1:r=this.moduleType==="esm";let{code:n,deps:s}=await this.transformWithEsbuild(e,r);try{let i=await this.loadFromCode(e,n,r),c=i&&i.default?i.default:Object.keys(i||{}).map(a=>i[a]);P(c)?c.forEach(a=>a.__filepath__=e):c.__filepath__=e,this.moduleCache.set(e,c),this.updateModuleDeps(e,s)}catch(i){console.error(i)}}async loadFromCode(e,r,n){if(n){let s=`${e}.timestamp-${Date.now()}`,i=`${s}.mjs`,c=`${nt(s)}.mjs`;await ee.promises.writeFile(i,r,"utf8");try{return await import(c)}finally{try{ee.unlinkSync(i)}catch{}}}else{e=Me.resolve(this.cwd,e);let s=Me.extname(e),i=ee.realpathSync(e),c=s in E.extensions?s:".js",a=E.extensions[c];E.extensions[c]=(u,l)=>{l===i?u._compile(r,l):a(u,l)},delete E.cache[E.resolve(e)];let p=E(e);return E.extensions[c]=a,p.__esModule?p:{default:p}}}async transformWithEsbuild(e,r){var n;try{let s=await it({entryPoints:[e],outfile:"out.js",write:!1,target:["node14.18","node16"],platform:"node",bundle:!0,metafile:!0,format:r?"esm":"cjs",define:this.options.define,plugins:[B(this.options.alias),N,A,q]});return{code:s.outputFiles[0].text,deps:((n=s.metafile)==null?void 0:n.inputs)||{}}}catch(s){console.error(s)}return{code:"",deps:{}}}};import{parse as xe}from"url";import lt from"cookies";import{pathToRegexp as we}from"path-to-regexp";import{WebSocketServer as ut}from"ws";function Oe(t,o,e,r){var c;let n=new Set,s=new Map,i=new Map;(c=t.on)==null||c.call(t,"mock:update-end",a=>{if(!n.has(a))return;let p={};for(let[u,l]of i.entries())t.mockData[u].forEach(v=>{v.__filepath__===a&&v.ws&&l.forEach(({pathname:M,req:y,ws:k})=>{p[M]??(p[M]={mock:v,list:[],mockUrl:u}),p[M].list.push({req:y,ws:k}),k.removeAllListeners()})});Object.keys(p).forEach(u=>{var k,m;let l=s.get(u),{mock:v,list:M,mockUrl:y}=p[u];l.wss.removeAllListeners(),(k=l.cancel)==null||k.call(l),l.cancel=(m=v.setup)==null?void 0:m.call(v,l.wss),l.wss.on("close",()=>{s.delete(u)}),M.forEach(({req:d,ws:h})=>{l.wss.emit("connection",h,d),h.on("close",()=>{let g=i.get(y),w=(g==null?void 0:g.findIndex(f=>f.ws===h))||-1;w>=0&&(g==null||g.splice(w,1))})})})}),o==null||o.on("upgrade",(a,p,u)=>{var w;let{pathname:l,query:v}=xe(a.url,!0);if(!l||e.length===0||!e.some(f=>z(f,a.url)))return;let M=t.mockData,y=Object.keys(M).find(f=>we(f).test(l));if(!y)return;let k=M[y].find(f=>f.url&&f.ws&&we(f.url).test(l));if(!k)return;n.add(k.__filepath__);let m=s.get(l);if(!m){let f=new ut({noServer:!0}),O=(w=k.setup)==null?void 0:w.call(k,f);f.on("close",()=>{s.delete(l)}),m={wss:f,cancel:O},s.set(l,m)}let d=a,h=new lt(a,a,r),{query:g}=xe(a.headers.referer||"",!0);d.query=v,d.refererQuery=g,d.params=L(y,l),d.getCookie=h.get.bind(h),m.wss.handleUpgrade(d,p,u,f=>{D(`websocket-mock: ${a.url} connected`),m.wss.emit("connection",f,d);let O=i.get(y);O||(O=[],i.set(y,O)),O.push({req:d,ws:f,pathname:l}),f.on("close",()=>{let T=O.findIndex(X=>X.ws===f);T>=0&&O.splice(T,1)})})}),o==null||o.on("close",()=>{s.forEach(({wss:a,cancel:p})=>{p==null||p(),a.close()}),s.clear(),n.clear(),i.clear()})}async function te(t,o,e,r){let n=j(o.include),s=j(o.exclude),i={};if(t.define)for(let u in t.define){let l=t.define[u];i[u]=typeof l=="string"?l:JSON.stringify(l)}let c=new Q({include:n,exclude:s,define:i,alias:t.resolve.alias});await c.load(),c.on("mock:update-end",()=>{o.reload&&(r==null||r.send({type:"full-reload"}))}),e==null||e.on("close",()=>c.close());let{httpProxies:a}=J(t.server.proxy||{}),p=j(o.prefix);return Oe(c,e,j(o.wsPrefix),o.cookiesOptions),he(c,{formidableOptions:o.formidableOptions,proxies:[...p,...a],cookiesOptions:o.cookiesOptions})}function Pe({prefix:t=[],wsPrefix:o=[],include:e=["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],exclude:r=["**/node_modules/**","**/.vscode/**","**/.git/**"],reload:n=!1,formidableOptions:s={},build:i=!1,cookiesOptions:c={}}={}){let a={prefix:t,wsPrefix:o,include:e,exclude:r,reload:n,cookiesOptions:c,formidableOptions:{multiples:!0,...s},build:i?Object.assign({serverPort:8080,dist:"mockServer"},typeof i=="object"?i:{}):!1},p=[mt(a)];return a.build&&p.push(dt(a)),p}function dt(t){let o={};return{name:"vite-plugin-mock-dev-server-generator",enforce:"post",apply:"build",configResolved(e){o=e,e.logger.warn("")},async buildEnd(e){e||o.command==="build"&&await ue(this,o,t)}}}function mt(t){let o={};return{name:"vite-plugin-mock-dev-server",enforce:"pre",apply:"serve",configResolved(e){o=e,e.logger.warn("")},async configureServer({middlewares:e,config:r,httpServer:n,ws:s}){let i=await te(r,t,n,s);e.use(i)},async configurePreviewServer({middlewares:e,httpServer:r}){let n=await te(o,t,r);e.use(n)}}}function qo(t){return t}function Ao(t){return e=>(P(e)?e=e.map(r=>t(r)||r):e=t(e)||e,e)}var Go=Pe;export{he as baseMiddleware,Ao as createDefineMock,Go as default,qo as defineMock,Pe as mockDevServerPlugin,Oe as mockWebSocket,ve as transformMockData};
|
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.6",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"vite",
|
|
6
6
|
"plugin",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"lodash.sortby": "^4.7.0",
|
|
44
44
|
"mime-types": "^2.1.35",
|
|
45
45
|
"path-to-regexp": "^6.2.1",
|
|
46
|
-
"picocolors": "^1.0.0"
|
|
46
|
+
"picocolors": "^1.0.0",
|
|
47
|
+
"ws": "^8.13.0"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@pengzhanbo/eslint-config-ts": "^0.3.4",
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
"@types/lodash.sortby": "^4.7.7",
|
|
57
58
|
"@types/mime-types": "^2.1.1",
|
|
58
59
|
"@types/node": "^18.16.1",
|
|
60
|
+
"@types/ws": "^8.5.4",
|
|
59
61
|
"bumpp": "^9.1.0",
|
|
60
62
|
"conventional-changelog-cli": "^2.2.2",
|
|
61
63
|
"eslint": "^8.39.0",
|