Vite API Mock 插件: vite-plugin-mock-dev-server

在vite 开发环境中注入 mock-dev-server, 模拟请求和数据响应。

特性

  • ⚡️ 轻量,灵活,快速
  • 🧲 非注入式,对客户端代码无侵入
  • 💡 ESModule/commonjs
  • 🦾 Typescript
  • 🏷 支持 json / json5 编写 mock 数据
  • 📦 自动加载 mock 文件
  • 🎨 可选择你喜欢的任意用于生成mock数据库,如 mockjs,或者不使用其他库
  • 📥 路径规则匹配,请求参数匹配
  • ⚙️ 随意开启或关闭对某个接口的 mock配置
  • 🔥 热更新
  • ⚖️ 使用 server.proxy 配置
  • 🍕 支持在 mock文件中使用 viteConfig.define配置字段
  • ⚓️ 支持 resolve.alias
  • 📤 支持 multipart 类型,模拟文件上传
  • 🌈 支持 vite preview 模式
  • 🗂 支持构建可独立部署的小型mock服务

文档

查看 Documentation 了解更多。

查看 github 仓库

使用

安装

# npm
npm i -D vite-plugin-mock-dev-server
# yarn 
yarn add vite-plugin-mock-dev-server
# pnpm
pnpm add -D vite-plugin-mock-dev-server

配置

vite.config.ts

import { defineConfig } from 'vite'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'

export default defineConfig({
  plugins: [
    mockDevServerPlugin(),
  ],
  // 这里定义的字段,在mock中也能使用
  define: {},
  server: {
    proxy: {
      '^/api': {
        target: 'http://example.com'
      }
    }
  }
})

插件会读取 server.proxyoptions.prefix 的配置,对匹配的 url 启用mock 匹配。

插件也会读取 define 配置, 支持在 mock 文件中直接使用。

因为一般场景下,我们只需要对有代理的url进行mock,这样才能通过 vite 提供的 http 服务进行 代理和 mock,
但你也可以使用 options.prefix配置 mock

编写mock文件

默认配置,在你的项目根目录的 mock 目录中编写mock数据:

mock/api.mock.ts :

import { defineMock } from 'vite-plugin-mock-dev-server'

export default defineMock({
  url: '/api/test',
  body: {
    a: 1,
    b: 2,
  }
})

方法

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

    类型: string | string[]

    为mock服务器配置自定义匹配规则。任何请求路径以 prefix 值开头的请求将被代理到对应的目标。如果 prefix 值以 ^ 开头,将被识别为 RegExp。

    一般情况下, server.proxy 已经足够满足需求,添加此项是为了与某些场景兼容。

    默认值: []

  • option.include

    类型: string | string[]

    配置读取 mock文件,可以是一个 目录,glob,或者一个数组

    默认值: ['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}'] (相对于根目录)

  • options.exclude

    类型: string | string[]

    配置读取 mock文件时,需要排除的文件, 可以是一个 目录、glob、或者一个数组

    默认值:

    [
      '**/node_modules/**',
      '**/.vscode/**',
      '**/.git/**',
    ]
    
  • options.reload

    Type: boolean

    mock资源热更新时,仅更新了数据内容,但是默认不重新刷新页面。当你希望每次修改mock文件都刷新页面时,可以打开此选项。

    Default: false

  • options.formidableOptions

    配置 formidable,查看 formidable options

    默认值: {}

    示例: 配置文件上传的存放目录

    MockDevServerPlugin({
      formidableOptions: {
        uploadDir: path.join(process.cwd(), 'uploads'),
      }
    })
    
  • options.build

    需要构建可独立部署的小型mock服务时配置。

    类型: boolean | ServerBuildOptions

    默认值:false

    interface ServerBuildOptions {
      /**
       * 服务端口
       * @default 8080
       */
      serverPort?: number
      /**
       * 构建输出目录
       @default 'mockServer'
       */
      dist?: string
    }
    

defineMock(config)

mock 配置帮助函数,提供类型检查帮助

import { defineMock } from 'vite-plugin-mock-dev-server'

export default defineMock({
  url: '/api/test',
  body: {}
})

createDefineMock(transformer)

返回一个自定义的 defineMock 函数,用于支持对 mock config 的预处理。

import path from 'path'
import { createDefineMock } from 'vite-plugin-mock-dev-server'

// 预处理 mock url
const defineAPIMock = createDefineMock((mock) => {
  mock.url = path.join('/api', mock.url)
})

export default defineApiMock({
  url: '/test' // 补全为 '/api/test'
})

Mock 配置

export default defineMock({
  /**
   * 请求地址,支持 `/api/user/:id` 格式 
   */
  url: '/api/test',
  /**
   * 接口支持的请求方法
   * 
   * @type string | string[]
   * @default ['POST','GET']
   * 
   */
  method: ['GET', 'POST'],
  /**
   * 是否启用当前 mock请求
   * 
   * 在实际场景中,我们一般只需要某几个mock接口生效,
   * 而不是所以mock接口都启用。
   * 对当前不需要mock的接口,可设置为 false
   * 
   * @default true
   */
  enable: true,
  /**
   * 设置接口响应延迟, 单位:ms
   * 
   * @default 0
   */
  delay: 1000,
  /**
   * 响应状态码
   * 
   * @default 200
   */
  status: 200,
  /**
   * 响应状态文本
   */
  statusText: 'OK',
  /**
   * 请求验证器,通过验证器则返回 mock数据,否则不使用当前mock。
   * 这对于一些场景中,某个接口需要通过不同的入参来返回不同的数据,
   * 验证器可以很好的解决这一类问题,将同个 url 分为多个 mock配置,
   * 根据 验证器来判断哪个mock配置生效。
   * 
   * @type { headers?: object; body?: object; query?: object; params?: object; refererQuery?: object  }
   * 
   * 如果 validator 传入的是一个对象,那么验证方式是严格比较 请求的接口
   * 中,headers/body/query/params 的各个`key`的`value`是否全等,
   * 全等则校验通过
   * 
   * @type ({ headers: object; body: object; query: object; params: object; refererQuery: object }) => boolean
   * 如果 validator 传入的是一个函数,那么会讲 请求的接口相关数据作为入参,提供给使用者进行自定义校验,并返回一个 boolean
   * 
   */
  validator: {
    headers: {},
    body: {},
    query: {},
    params: {},
    /**
     * refererQuery 验证了请求来源页面 URL 中的查询参数,
     * 这使得可以直接在浏览器地址栏中修改参数以获取不同的模拟数据。
     */
    refererQuery: {}
  },
  /**
   * 
   * 响应状态 headers
   * 
   * @type Record<string, any>
   * 
   * @type (({ query, body, params, headers }) => Record<string, any>)
   * 入参部分为 请求相关信息
   */
  headers: {
    'Content-Type': 'application/json'
  },

  /**
   * 响应体数据
   * 定义返回的响应体数据内容。
   * 在这里,你可以直接返回JavaScript支持的数据类型如 `string/number/array/object` 等
   * 同时,你也可以使用如 `mockjs` 等库来生成数据内容
   * 
   * @type string | number | array | object
   *  直接返回定义的数据
   * 
   * @type (request: { headers, query, body, params }) => any | Promise<any>
   * 如果传入一个函数,那么可以更加灵活的定义返回响应体数据
   */
  body: {},

  /**
   * 如果通过 body 配置不能解决mock需求,
   * 那么可以通过 配置 response,暴露http server 的接口,
   * 实现完全可控的自定义配置
   * 
   * 在 req参数中,已内置了 query、body、params 的解析,
   * 你可以直接使用它们
   * 
   * 别忘了,需要通过 `res.end()` 返回响应体数据,
   * 或者需要跳过mock,那么别忘了调用 `next()`
   */
  response(req, res, next) {
    res.end()
  }
})

注意:

如果使用 json/json5 编写 mock文件,则不支持使用 response 方法,以及不支持使用其他字段的函数形式。

mock/**/*.mock.{ts,js,mjs,cjs,json,json5}

查看更多示例: example

示例1:

命中 /api/test 请求,并返回一个 数据为空的响应体内容

export default defineMock({
  url: '/api/test',
})

示例2:

命中 /api/test 请求,并返回一个固定内容数据

export default defineMock({
  url: '/api/test',
  body: {
    a: 1
  }
})

示例3:

限定只允许 GET 请求

export default defineMock({
  url: '/api/test',
  method: 'GET'
})

示例4:

在返回的响应头中,添加自定义header

export default defineMock({
  url: '/api/test',
  headers: {
    'X-Custom': '12345678'
  }
})
export default defineMock({
  url: '/api/test',
  headers({ query, body, params, headers }) {
    return {
      'X-Custom': query.custom
    }
  }
})

示例5:

定义多个相同url请求mock,并使用验证器匹配生效规则

export default defineMock([
  // 命中 /api/test?a=1
  {
    url: '/api/test',
    validator: {
      query: {
        a: 1
      }
    },
    body: {
      message: 'query.a === 1'
    }
  },
  // 命中 /api/test?a=2
  {
    url: '/api/test',
    validator: {
      query: {
        a: 2
      }
    },
    body: {
      message: 'query.a === 2'
    }
  },
  {
    /**
     * `?a=3` 将会解析到 `validator.query`
     */
    url: '/api/test?a=3',
    body: {
      message: 'query.a == 3'
    }
  }
])

示例6:

延迟接口响应:

export default defineMock({
  url: '/api/test',
  delay: 6000, // 延迟 6秒
})

示例7:

使接口请求失败

export default defineMock({
  url: '/api/test',
  status: 504,
  statusText: 'Bad Gateway'
})

示例8:

动态路由匹配

export default defineMock({
  url: '/api/user/:userId',
  body({ params }) {
    return {
      userId: params.userId,
    }
  }
})

路由中的 userId将会解析到 request.params 对象中.

示例9:

使用 mockjs 生成响应数据:

import Mock from 'mockjs'
export default defineMock({
  url: '/api/test',
  body: Mock.mock({
    'list|1-10': [{
      'id|+1': 1
    }]
  })
})

请先安装 mockjs

示例10:

使用 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,
    }))
  }
})

示例11:

使用 json / json5

{
  // 支持 comment
  "url": "/api/test",
  "body": {
    "a": 1
  }
}

Example 12:

multipart, 文件上传.

通过 formidable 支持。

<form action="/api/upload" method="post" enctype="multipart/form-data">
    <p>
      <span>file: </span>
      <input type="file" name="files" multiple />
    </p>
    <p>
      <span>name:</span>
      <input type="text" name="name" value="mark">
    </p>
    <p>
      <input type="submit" value="submit">
    </p>
  </form>

fields files 映射为 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),
    }
  },
})

独立部署的小型mock服务

在一些场景中,可能会需要使用mock服务提供的数据支持,用于展示,但可能项目已完成打包构建部署,已脱离 vite 和本插件提供的 mock服务支持。由于本插件在设计之初,支持在mock文件中引入各种 node 模块,所以不能将 mock文件打包内联到客户端构建代码中。

为了能够满足这类场景,插件一方面提供了 vite preview 下的支持,同时还提供了在 vite build 时,也构建一个可独立部署的 小型mock服务应用,可以将这个应用部署到相关的环境,后通过其他http服务器如nginx做代理转发到实际端口实现mock支持。

构建默认输出到 dist/mockServer 目录中,并生成如下文件:

./mockServer
├── index.js
├── mock-data.js
└── package.json

在该目录下,执行 npm install 安装依赖后,执行 npm start 即可启动 mock server。
默认端口为 8080
可通过 localhost:8080/ 访问相关的 mock 接口。

Archives

awesome-vite

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容