vite-plugin-mock-dev-server
Vite Plugin for API mock dev server.
English | 简体中文
Feature
- ⚡️ Lightweight, Flexible, Fast.
- 🧲 Not injection-based, non-intrusive to client code.
- 💡 ESModule/commonjs.
- 🦾 Typescript.
- 🔥 HMR
- 🏷 Support
json
/ json5
. - 📦 Auto import mock file.
- 🎨 Support any lib, like
mockjs
, or do not use it. - 📥 Path rule matching, request parameter matching.
- ⚙️ Support Enabled/Disabled any one of the API mock.
- 📀 Supports response body content type such as
text/json/buffer/stream
. - ⚖️ Use
server.proxy
- 🍕 Support
viteConfig.define
and env
in the mock file. - ⚓️ Support
viteConfig.resolve.alias
in the mock file. - 🌈 Support
vite preview
mode. - 📤 Support
multipart
content-type, mock upload file. - 📥 Support mock download file.
- ⚜️ Support
WebSocket Mock
- 🗂 Support building small independent deployable mock services.
Documentation
See the documentation to learn more.
Usage
Install
npm i -D vite-plugin-mock-dev-server
yarn add vite-plugin-mock-dev-server
pnpm add -D vite-plugin-mock-dev-server
Configuration
vite.config.ts
import { defineConfig } from 'vite'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin(),
],
define: {},
server: {
proxy: {
'^/api': { target: 'http://example.com' }
}
}
})
The plugin will read the configuration of server.proxy
or options.prefix
, and enable mock matching for matched URLs.
The plugin will also read the define
configuration, which supports direct use in mock files.
Because in general scenarios, we only need to mock URLs with proxies so that we can use the proxy and mock services provided by Vite's HTTP service.
However, you can also configure mocks using options.prefix
.
Edit Mock File
By default, write mock data in the mock
directory of your project's root directory:
mock/**/*.mock.ts
:
import { defineMock } from 'vite-plugin-mock-dev-server'
export default defineMock({
url: '/api/test',
body: { a: 1, b: 2 }
})
Methods
mockDevServerPlugin(options)
Vite plugin
vite.config.ts
import { defineConfig } from 'vite'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin(),
]
})
options
-
options.prefix
Type: string | string[]
Configure custom matching rules for the mock server. Any request path starting with the value of prefix
will be proxied to the corresponding target. If the prefix
value starts with ^, it will be recognized as a RegExp.
In general, server.proxy
is sufficient to meet the needs. Adding this item is for compatibility with certain scenarios.
Default: []
-
options.wsPrefix
Type: string | string[]
Configure the matching rules for the WebSocket service. Any request path starting with the value of wsPrefix
and using the ws/wss
protocol will be proxied to the corresponding target.
If the value of wsPrefix
starts with ^
, it will be recognized as a RegExp.
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.
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.
-
option.include
Type: string | string[]
Configure to read mock files, which can be a directory, glob, or an array.
Default: ['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']
(Relative to the root directory.)
-
options.exclude
Type: string | string[]
When reading mock files for configuration, the files that need to be excluded can be a directory, glob, or array.
Default: ['**/node_modules/**','**/.vscode/**','**/.git/**']
-
options.reload
Type: boolean
When the mock resource is hot updated, only the data content is updated, but the page is not refreshed by default. If you want to refresh the page every time you modify the mock file, you can open this option.
-
options.cors
Type: boolean | CorsOptions
Enable by default.
Configure to cors
, see cors
Default: true
-
options.log
Type: boolean | 'info' | 'warn' | 'error' | 'silent'
Enable log and configure log level.
-
options.formidableOptions
Configure to formidable
, see formidable options
Default: {}
example: Configure to file upload dir
MockDevServerPlugin({
formidableOptions: {
uploadDir: path.join(process.cwd(), 'uploads'),
}
})
-
options.cookiesOptions
Configure to cookies
, see cookies
Default: {}
-
options.bodyParserOptions
Configure to co-body
, see co-body
Default: {}
-
options.build
The configuration needed to build a small, independently deployable mock service.
Type: boolean | ServerBuildOptions
Default: false
interface ServerBuildOptions {
serverPort?: number
dist?: string
log?: LogLevel
}
-
options.priority
Custom path matching rule priority。read more
Default: undefined
defineMock(config)
Mock Type Helper
import { defineMock } from 'vite-plugin-mock-dev-server'
export default defineMock({
url: '/api/test',
body: {}
})
createDefineMock(transformer)
Return a custom defineMock function to support preprocessing of mock config.
import path from 'node:path'
import { createDefineMock } from 'vite-plugin-mock-dev-server'
const defineAPIMock = createDefineMock((mock) => {
mock.url = path.join('/api', mock.url)
})
export default defineApiMock({
url: '/test'
})
Mock Configuration
export default defineMock({
url: '/api/test',
method: ['GET', 'POST'],
enabled: true,
delay: 1000,
status: 200,
statusText: 'OK',
headers: {
'Content-Type': 'application/json'
},
cookies: {
'your-cookie': 'your cookie value',
'cookie&option': ['cookie value', { path: '/', httpOnly: true }]
},
type: 'json',
body: '',
response(req, res, next) {
res.end()
},
validator: {
headers: {},
body: {},
query: {},
params: {},
refererQuery: {}
},
})
export default defineMock({
url: '/api/test',
ws: true,
setup(wss, { onCleanup }) {
wss.on('connection', (ws, request) => {
ws.on('message', (rawData) => {})
const timer = setInterval(() => ws.send('data'), 1000)
onCleanup(() => clearInterval(timer))
})
}
})
Request/Response Enhance
When defining methods using headers
, body
, and response
, the plugin adds new content to the request
and response
parameters.
In Request:
The original type of request
is Connect.IncomingMessage
. The plugin adds data such as query
, params
, body
, refererQuery
, and the getCookie(name)
method for obtaining cookie information on this basis.
type Request = Connect.IncomingMessage & {
query: object
params: object
body: any
refererQuery: object
getCookie: (name: string, option?: Cookies.GetOption) => string | undefined
}
In Response:
The original type of response
is http.ServerResponse<http.IncomingMessage>
. The plugin adds setCookie(name, value)
method for configuration cookies on this basis.
type Response = http.ServerResponse<http.IncomingMessage> & {
setCookie: (
name: string,
value?: string | null,
option?: Cookies.SetOption,
) => void
}
Tips:
If you write mock files using json/json5,
the 'response' method is not supported,
as is the function form that uses other fields.
Share Mock Data
Due to each mock
file being compiled as a separate entry point, the local files they depend on are also compiled within. Additionally, each mock file has an independent scope. This means that even if multiple mock files collectively depend on a data.ts
file, they cannot share data. If one mock file modifies the data in data.ts
, other mock files will not receive the updated data.
To address this, the plugin offers a defineMockData
function, which allows using data.ts
as a shared data source within mock files.
type defineMockData<T> = (
key: string,
initialData: T,
) => [getter, setter] & { value: T }
Exp
data.ts
import { defineMockData } from 'vite-plugin-mock-dev-server'
export default defineMockData('posts', [
{ id: '1', title: 'title1', content: 'content1' },
{ id: '2', title: 'title2', content: 'content2' },
])
*.mock.ts
import { defineMock } from 'vite-plugin-mock-dev-server'
import posts from './data'
export default defineMock([
{
url: '/api/posts',
body: () => posts.value
},
{
url: '/api/posts/delete/:id',
body: (params) => {
const id = params.id
posts.value = posts.value.filter(post => post.id !== id)
return { success: true }
}
}
])
Tips:
The defineMockData
function relies solely on the shared data support provided by memory
.
If persistent mock data is required, it is recommended to use a nosql
database like lowdb
or level
.
Custom-Path-Matching-Priority
Custom rules only affect links with dynamic parameters, such as: /api/user/:id
The priority of the path matching rules built into the plugin can already meet most needs, but if you need more flexible customization of the matching rule priority, you can use the priority
parameter.
Exp:
import { defineConfig } from 'vite'
import mockPlugin from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockPlugin({
priority: {
global: ['/api/:a/b/c', '/api/a/:b/c', '/api/a/b/:c'],
special: {
'/api/:a/:b/c': {
rules: ['/api/a/:b/:c', '/api/a/b/:c'],
when: ['/api/a/b/c']
},
'/api/:a/b': ['/api/a/:b'],
}
}
})
]
})
Tip:
priority
although it can adjust the priority,
most of the time you do not need to do so. For some special requests,
you can use static rules instead of priority
,
as static rules always have the highest priority.
Example
mock/**/*.mock.{ts,js,mjs,cjs,json,json5}
See more examples: example
exp: Match /api/test
, And returns a response body content with empty data
export default defineMock({
url: '/api/test',
})
exp: Match /api/test
, And returns a static content data
export default defineMock({
url: '/api/test',
body: { a: 1 },
})
exp: Only Support GET
Method
export default defineMock({
url: '/api/test',
method: 'GET'
})
exp: In the response header, add a custom header and cookie
export default defineMock({
url: '/api/test',
headers: { 'X-Custom': '12345678' },
cookies: { 'my-cookie': '123456789' },
})
export default defineMock({
url: '/api/test',
headers({ query, body, params, headers }) {
return { 'X-Custom': query.custom }
},
cookies() {
return { 'my-cookie': '123456789' }
}
})
exp: Define multiple mock requests for the same URL and match valid rules with validators
export default defineMock([
{
url: '/api/test',
validator: {
query: { a: 1 },
},
body: { message: 'query.a == 1' },
},
{
url: '/api/test',
validator: {
query: { a: 2 },
},
body: { message: 'query.a == 2' },
},
{
url: '/api/test?a=3',
body: { message: 'query.a == 3' }
},
{
url: '/api/test',
method: ['POST'],
validator: { body: { a: [1, 2] } }
}
])
exp: Response Delay
export default defineMock({
url: '/api/test',
delay: 6000,
})
exp: The interface request failed
export default defineMock({
url: '/api/test',
status: 502,
statusText: 'Bad Gateway'
})
exp: Dynamic route matching
export default defineMock({
url: '/api/user/:userId',
body({ params }) {
return { userId: params.userId }
}
})
The userId
in the route will be resolved into the request.params
object.
exp:** Use the buffer to respond data
import { Buffer } from 'node:buffer'
export default defineMock({
url: 'api/buffer',
body: Buffer.from(JSON.stringify({ a: 1 }))
})
export default defineMock({
url: 'api/buffer',
type: 'buffer',
body: { a: 1 }
})
exp: Response file type
Simulate file download, and pass in the file reading stream.
import { createReadStream } from 'node:fs'
export default defineMock({
url: '/api/download',
type: 'my-app.dmg',
body: () => createReadStream('./my-app.dmg')
})
<a href="/api/download" download="my-app.dmg">Download File</a>
exp: Use mockjs
:
import Mock from 'mockjs'
export default defineMock({
url: '/api/test',
body: Mock.mock({
'list|1-10': [{
'id|+1': 1
}]
})
})
You need install mockjs
exp: Use response
to customize the response
export default defineMock({
url: '/api/test',
response(req, res, next) {
const { query, body, params, headers } = req
console.log(query, body, params, headers)
res.status = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({
query,
body,
params,
}))
}
})
exp: Use json / json5
{
"url": "/api/test",
"body": {
"a": 1
}
}
exp: multipart, upload files.
use formidable
to support.
<form action="/api/upload" method="post" enctype="multipart/form-data">
<p>
<span>file: </span>
<input type="file" name="files" multiple="multiple">
</p>
<p>
<span>name:</span>
<input type="text" name="name" value="mark">
</p>
<p>
<input type="submit" value="submit">
</p>
</form>
fields files
mapping to formidable.File
export default defineMock({
url: '/api/upload',
method: 'POST',
body(req) {
const body = req.body
return {
name: body.name,
files: body.files.map((file: any) => file.originalFilename),
}
},
})
exp: Graphql
import { buildSchema, graphql } from 'graphql'
const schema = buildSchema(`
type Query {
hello: String
}
`)
const rootValue = { hello: () => 'Hello world!' }
export default defineMock({
url: '/api/graphql',
method: 'POST',
body: async (request) => {
const source = request.body.source
const { data } = await graphql({ schema, rootValue, source })
return data
},
})
fetch('/api/graphql', {
method: 'POST',
body: JSON.stringify({ source: '{ hello }' })
})
exp: WebSocket Mock
export default defineMock({
url: '/socket.io',
ws: true,
setup(wss, { onCleanup }) {
const wsMap = new Map()
wss.on('connection', (ws, req) => {
const token = req.getCookie('token')
wsMap.set(token, ws)
ws.on('message', (raw) => {
const data = JSON.parse(String(raw))
if (data.type === 'ping')
return
for (const [_token, _ws] of wsMap.entires()) {
if (_token !== token)
_ws.send(raw)
}
})
})
wss.on('error', (err) => {
console.error(err)
})
onCleanup(() => wsMap.clear())
}
})
const ws = new WebSocket('ws://localhost:5173/socket.io')
ws.addEventListener('open', () => {
setInterval(() => {
ws.send(JSON.stringify({ type: 'ping' }))
}, 1000)
}, { once: true })
ws.addEventListener('message', (raw) => {
console.log(raw)
})
Mock Services
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.
To meet such scenarios, on one hand, the plugin provides support under vite preview
, and on the other hand, it also builds a small independent mock service application that can be deployed to relevant environments during vite build
. This can then be forwarded through other HTTP servers like Nginx to actual ports for mock support.
The default output is built into the directory dist/mockServer
, generating files as follows:
./mockServer
├── index.js
├── mock-data.js
└── package.json
In this directory, execute npm install
to install dependencies, and then execute npm start
to start the mock server.
The default port is 8080
.
You can access related mock
interfaces through localhost:8080/
.
Archives
awesome-vite
Contributors
LICENSE
MIT