npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rspack-plugin-mock

v2.1.0

Published

inject api mock server to development server

Readme

rspack-plugin-mock

Rspack and Rsbuild 中注入 API mock 服务。

rspackrsbuild 中实现与 vite-plugin-mock-dev-server 完全一致的模拟开发服务。

[!IMPORTANT] 从插件 2.0 版本开始,仅支持 [email protected] 版本 和 [email protected] 版本.

如果您使用的是 [email protected][email protected] 版本,请使用 [email protected] 版本.

特性

  • ⚡️ 轻量,灵活,快速
  • 🧲 非注入式,对客户端代码无侵入
  • 💡 ESModule
  • 🦾 Typescript
  • 🔥 热更新
  • 🏷 支持 .[cm]?js/ .ts / json / json5 编写 mock 数据
  • 📦 自动加载 mock 文件
  • 🎨 可选择你喜欢的任意用于生成mock数据库,如 mockjs,或者不使用其他库
  • 📥 路径规则匹配,请求参数匹配
  • ⚙️ 随意开启或关闭对某个接口的 mock配置
  • 📀 支持多种响应体数据类型,包括 text/json/buffer/stream.
  • ⚖️ rspack 中使用 devServer.proxy 配置, rsbuild 中使用 server.proxy 配置
  • 🍕 支持在 mock 文件中使用 define配置
  • ⚓️ 支持在 mock 文件中使用 resolve.alias 路径别名
  • 📤 支持 multipart 类型,模拟文件上传
  • 📥 支持模拟文件下载
  • ⚜️ 支持模拟 WebSocketServer-Sent Events
  • 📝 支持 请求录制请求回放
  • 🗂 支持构建可独立部署的小型mock服务

安装

# npm
npm i -D rspack-plugin-mock
# yarn
yarn add rspack-plugin-mock
# pnp
pnpm add -D rspack-plugin-mock

使用

In Rspack

// rspack.config.js
import { MockServerPlugin } from 'rspack-plugin-mock'

export default {
  devServer: {
    // 插件将会读取 `proxy` 配置
    proxy: [
      { context: '/api', target: 'http://example.com' },
    ],
  },
  plugins: [
    new MockServerPlugin(/* pluginOptions */),
  ]
}

In Rsbuild

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core'
import { pluginMockServer } from 'rspack-plugin-mock/rsbuild'

export default defineConfig({
  server: {
    // 插件将会读取 `proxy` 配置
    proxy: {
      '/api': 'http://example.com',
    },
  },
  plugins: [
    pluginMockServer(/* pluginOptions */),
  ],
})

编写 mock 配置文件

插件默认会读取 项目根目录的 mock 目录:

mock/**/*.mock.ts :

import { defineMock } from 'rspack-plugin-mock/helper'

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

你可以使用 .js, .mjs, .cjs, .ts, .json, .json5 文件格式来编写 mock 配置。

方法

MockServerPlugin(pluginOptions)

rspack mock 服务插件。

插件将会读取 devServer.proxy 配置,然后在 @rspack/dev-server 中注入中间件。

import { MockServerPlugin } from 'rspack-plugin-mock'

export default {
  devServer: {
    // 插件将会读取 `proxy` 配置
    proxy: [
      { context: '/api', target: 'http://example.com' },
    ],
  },
  plugins: [
    new MockServerPlugin(/* 插件配置 */),
  ]
}

pluginMockServer(pluginOptions)

rsbuild mock 服务插件. 仅适用于 rsbuild.

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core'
import { pluginMockServer } from 'rspack-plugin-mock/rsbuild'

export default defineConfig({
  server: {
    // 插件将会读取 `proxy` 配置
    proxy: {
      '/api': 'http://example.com',
    },
  },
  plugins: [
    pluginMockServer(/* 插件配置 */),
  ],
})

defineMock(options)

mock 配置类型帮助函数

import { defineMock } from 'rspack-plugin-mock/helper'

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

createDefineMock(transformer)

  • transformer: (mock: MockOptions) => MockOptions

返回一个自定义的 defineMock 函数,以支持对 mock 配置进行预处理。

import { createDefineMock } from 'rspack-plugin-mock/helper'

const definePostMock = createDefineMock((mock) => {
  mock.url = `/api/post/${mock.url}`
})

export default definePostMock({
  url: 'list', // => '/api/post/list'
  body: [{ title: '1' }, { title: '2' }],
})

createSSEStream(req, res)

创建一个 Server-sent events 写入流,用于支持模拟 EventSource

import { createSSEStream, defineMock } from 'rspack-plugin-mock/helper'

export default defineMock({
  url: '/api/sse',
  response: (req, res) => {
    const sse = createSSEStream(req, res)
    sse.write({ event: 'message', data: { message: 'hello world' } })
    sse.end()
  }
})

插件配置

  • 类型: boolean

  • 默认值: true

  • 详情:

    是否开启 mock 服务。如果设置为 false,插件将不会生效。

prefix

  • 类型: string | string[]

  • 详情:

    为 http mock 服务配置 路径匹配规则,任何请求路径以 prefix 开头的都将被拦截代理。 如果 prefix 以 ^ 开头,将被识别为 RegExp

wsPrefix

  • 类型: string | string[]

  • 详情:

    为 websocket mock 服务配置 路径匹配规则, 任何请求路径以 wsPrefix 开头的 ws/wss请求,都将被代理拦截。 如果 wsPrefix 以 ^ 开头,将被识别为 RegExp

    请避免在 devServer.proxy / server.proxy 中出现 wsPrefix 配置中相同的规则,因为这可能会导致规则冲突。

cwd

  • 类型: string

  • 默认值: process.cwd()

  • 详情:

    配置 includeexclude 的匹配上下文。

dir

  • 类型: string

  • 默认值: mock (相对于 cwd)

  • 详情:

    配置 mock 包的输出目录,相对于 cwd

include

  • 类型: string | string[]

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

  • 详情:

    glob 字符串匹配 mock 包含的文件。 查看 picomatch

exclude

  • 类型: string | string[]

  • 默认值: [] (相对于 dir)

  • 详情:

    glob 字符串匹配 mock 排除的文件。 查看 picomatch

log

  • 类型: boolean | 'info' | 'warn' | 'error' | 'silent' | 'debug'

  • 默认值: info

  • 详情:

    开启日志,或配置 日志级别

reload

  • 类型: boolean

  • 默认值: false

  • 详情:

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

activeScene

  • 类型: string | string[]

  • 默认值: ''

  • 详情:

    当前激活的场景,用于过滤 mock。

    只有 scene 与此有交集的 mock(或未配置 scene 的 mock)才会被考虑匹配。可通过 X-Mock-Scene 请求头按请求覆盖。

cors

  • 类型: boolean | CorsOptions

  • 默认值: true

  • 详情:

    配置 cors

formidableOptions

  • 类型: FormidableOptions

  • 默认值: { multiples: true }

  • 详情:

    配置 formidable

cookiesOptions

  • 类型: CookiesOptions

  • 详情:

    配置 cookies

bodyParserOptions

  • 类型: BodyParserOptions

  • 详情:

    配置 co-body

build

  • 类型: boolean | ServerBuildOption

    interface ServerBuildOption {
      /**
       * 服务启动端口
       * @default 8080
       */
      serverPort?: number
      /**
       * 构建输出目录,相对于 rspack/rsbuild 构建输出目录
       * @default 'mockServer'
       */
      dist?: string
    
      /**
       * 服务日志级别
       * @default 'error'
       */
      log?: LogLevel
    }
  • 默认值: false

  • 详情:

    当需要构建一个小型mock服务时,可配置此项。插件会在构建生产包时,额外生成一个可部署的node mock 服务包。

record

  • 类型: false | RecordOptions

  • 默认值: false

  • 详情:

    是否开启请求录制功能。开启后,插件会记录所有请求数据,用于后续的请求回放。

    插件在 proxy 的基础上,记录被 http-proxy 代理的请求数据。 在获得响应后,插件会将请求数据和响应数据记录到指定的目录中。

    interface RecordOptions {
      /**
       * 是否启用录制功能
       * - true: 启用,自动录制 proxy 响应
       * - false: 禁用(默认)
       * @default false
       */
      enabled?: boolean
      /**
       * 过滤要录制的请求
       * - 函数:自定义过滤函数,返回 true 表示录制
       * - 对象:包含/排除模式,支持 glob 或 path-to-regexp 模式
       * @example
       * ```ts
       * // Record all requests
       * filter: (req) => true
       * // Record requests using glob pattern
       * filter: { mode: 'glob', include: '/api/**' }
       * // Record requests using path-to-regexp pattern
       * filter: { mode: 'path-to-regexp', include: '/api/:id' }
       * ```
       */
      filter?: ((req: RecordedReq) => boolean) | {
        /**
         * 包含需要录制的请求链接
         *
         * glob 模式或 path-to-regexp 模式
         * (使用 mode 选项设置模式,默认为 glob)
         */
        include?: string | string[]
        /**
         * 排除不需要录制的请求链接
         *
         * glob 模式或 path-to-regexp 模式
         * (使用 mode 选项设置模式,默认为 glob)
         */
        exclude?: string | string[]
        /**
         * 包含/排除模式的匹配模式
         * - 'glob': glob 模式匹配(默认)
         * - 'path-to-regexp': path-to-regexp 模式匹配
         */
        mode: 'glob' | 'path-to-regexp'
      }
      /**
       * 录制数据存储目录
       * 相对于项目根目录
       * @default 'mock/.recordings'
       */
      dir?: string
    
      /**
       * 是否覆盖已有录制数据
       * - true: 相同请求覆盖旧数据(默认)
       * - false: 保留旧数据,不录制新数据
       * @default true
       */
      overwrite?: boolean
      /**
       * 录制数据过期时间(秒)
       * - 0: 永不过期(默认)
       * - 正数:指定秒数后过期
       * @default 0
       */
      expires?: number
    
      /**
       * 要录制的状态码
       * - 为空数组时记录所有状态码(默认)
       * - 指定一个或多个状态码进行过滤
       * @default []
       */
      status?: number | number[]
    
      /**
       * 是否在录制目录中添加 .gitignore
       * - true: 添加(默认)
       * - false: 不添加
       * @default true
       */
      gitignore?: boolean
    }

replay

  • 类型: boolean

  • 默认值: false

  • 详情:

    是否开启请求回放功能。开启后,插件会根据记录的请求数据,模拟响应。

priority

  • 类型: MockMatchPriority

  • 详情:

    自定义 路径匹配规则优先级。查看更多

    默认值: undefined

Mock 配置

http mock

import { defineMock } from 'rspack-plugin-mock/helper'
export default defineMock({
  url: '/api/test',
  body: { message: 'hello world' }
})

websocket mock

import { defineMock } from 'rspack-plugin-mock/helper'

export default defineMock({
  url: '/socket.io',
  ws: true,
  setup(wss) {
    wss.on('connection', (ws, req) => {
      console.log('connected')
    })
  }
})

options.url

  • 类型: string

  • 详情:

    需要进行 mock 的接口地址, 由 path-to-regexp 提供路径匹配支持。

options.enabled

  • 类型: boolean

  • 默认值: true

  • 详情:

    是否启动对该接口的mock,在多数场景下,我们仅需要对部分接口进行 mock, 而不是对所有配置了mock的请求进行全量mock,所以是否能够配置是否启用很重要

options.scene

  • 类型: string | string[]

  • 默认值: ''

  • 详情:

    该 mock 的场景标识。

    未配置时,该 mock 为全场景通用,不受 activeScene 限制。 配置后,只有 scene 中任意一项与 activeScene 中任意一项匹配时,该 mock 才会激活。

options.method

  • 类型: Method | Method[]

    type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'
  • 默认值: ['GET', 'POST']

  • 详情:

    该接口允许的 请求方法,默认同时支持 GET 和 POST

options.type

  • 类型: 'text' | 'json' | 'buffer' | string

  • 详情:

    响应体数据类型。 还支持 mime-db 中的包含的类型。

    当响应体返回的是一个文件,而你不确定应该使用哪个类型时,可以将文件名作为值传入, 插件内部会根据文件名后缀查找匹配的content-type

options.headers

  • 类型: object | (request: MockRequest) => object | Promise<object>

  • 默认值: { 'Content-Type': 'application/json' }

  • 详情:

    配置响应体 headers

options.status

  • 类型: number

  • 默认值: 200

  • 详情:

    配置 响应头状态码

options.statusText

  • 类型: string

  • 默认值: "OK"

  • 详情:

    配置响应头状态文本

options.delay

  • 类型: number | [number, number]

  • 默认值: 0

  • 详情:

    配置响应延迟时间, 如果传入的是一个数组,则代表延迟时间的范围。

    单位: ms

options.body

  • 类型: Body | (request: MockRequest) => Body | Promise<Body>

    type Body = string | object | Buffer | Readable
  • 详情:

    配置响应体数据内容 body 优先级高于 response.

options.response

  • 类型: (req: MockRequest, res: MockResponse, next: (err?: any) => void) => void | Promise<void>

  • 详情:

    如果需要设置复杂的响应内容,可以使用 response 方法, 该方法是一个 middleware,你可以在这里拿到 http 请求的 req、res等信息, 然后通过 res.write() | res.end() 返回响应数据, 否则需要执行 next() 方法。 在 req 中,还可以拿到 query、params、body, refererQuery 等已解析的请求信息。

options.cookies

  • 类型: CookiesOptions | (request: MockRequest) => CookiesOptions | Promise<CookiesOptions>

    type CookiesOptions = Record<string, CookieValue>
    
    type CookieValue = string | [string, SetCookie]
  • 详情:

    配置响应体 cookies

options.validator

  • 类型: Validator | (request: MockRequest) => boolean

    interface Validator {
      /**
       * 请求地址中位于 `?` 后面的 queryString,已解析为 json
       */
      query: Record<string, any>
      /**
       * 请求 referer 中位于 `?` 后面的 queryString
       */
      refererQuery: Record<string, any>
      /**
       * 请求体中 body 数据
       */
      body: Record<string, any>
      /**
       * 请求地址中,`/api/id/:id` 解析后的 params 参数
       */
      params: Record<string, any>
      /**
       * 请求体中 headers
       */
      headers: Headers
    }
  • 详情:

    请求验证器

    有时候,一个相同的API请求,需要根据不同的请求参数,来决定返回数据, 但全部都在单个 mock中的 body或者 response 中写,内容会很庞杂,不好管理, 验证器的功能,允许你同时配置多条相同url的mock,通过验证器来判断使哪个mock生效。

options.ws

  • 类型: boolean

  • 默认值: false

  • 详情:

    配置是否开启 WebSocket Mock

options.setup

  • 类型: (wss: WebSocketServer, ctx: WebSocketSetupContext) => void

  • 详情:

    配置 Websocket Server

interface WebSocketSetupContext {
  /**
   * 当你在定义 WSS 时,可能会执行一些自动任务或循环任务,
   * 但是当热更新时,插件内部会重新执行 setup() ,
   * 这可能导致出现 重复注册监听事件 和 循环任务如 `setTimeout` 等。
   * 通过 `onCleanup()` 可以来清除这些自动任务或循环任务。
   */
  onCleanup: (cleanup: () => void) => void
}

options.error

  • 类型: MockErrorConfig | undefined

  • 详情:

    配置错误模拟,包括错误概率、错误状态码、错误状态文本、以及自定义错误响应体。

interface MockErrorConfig {
  /**
   * 错误概率(0-1),默认 0.5
   * @default 0.5
   */
  probability?: number
  /**
   * 错误状态码,默认 500
   * @default 500
   */
  status?: number
  /**
   * 错误状态文本
   */
  statusText?: string
  /**
   * 自定义错误响应体,适用于 status 为 200,但响应体需要模拟错误场景
   * @example
   * { code: 500, msg: 'Internal Server Error', result: null }
   */
  body?: ResponseBody | ResponseBodyFn
}

Request/Response 增强

当你配置 headers, body, and response 的函数形式时, 插件在参数 requestresponse 添加了新的内容用于帮助获取必要的数据.

Request:

request的原始数据类型是Connect.IncomingMessage. 插件在此基础上,增加了 query, params, body, refererQuery,以及 getCookie(name) 方法用于获取cookie信息。

type Request = Connect.IncomingMessage & {
  query: object
  params: object
  body: any
  refererQuery: object
  getCookie: (name: string, option?: Cookies.GetOption) => string | undefined
}

Response:

response 的原始数据类型是http.ServerResponse<http.IncomingMessage>. 插件在此基础上增加了 setCookie(name, value) 方法用于设置cookie

type Response = http.ServerResponse<http.IncomingMessage> & {
  setCookie: (
    name: string,
    value?: string | null,
    option?: Cookies.SetOption,
  ) => void
}

注意:

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

共享 Mock 数据

由于每个mock文件都是作为独立的入口进行编译,其依赖的本地文件也编译在内, 且每个mock文件拥有独立的作用域,这使得即使多个 mock文件共同依赖某一个data.ts文件,也无法共享数据。 某个 mock 文件对 data.ts 中的数据进行修改,其它mock文件不会获取到修改后的数据。

为此,插件提供了一个 defineMockData 函数,用于在 mock 文件中使用 data.ts 作为共享数据源。

type defineMockData<T> = (
  key: string, // 数据唯一标识符
  initialData: T, // 初始化数据
  options?: {
    persistOnHMR?: boolean // 是否在热更新时保持数据状态
  } // 可选配置
) => [getter, setter] & { value: T }

用法

data.ts

import { defineMockData } from 'rspack-plugin-mock/helper'

export default defineMockData('posts', [
  { id: '1', title: 'title1', content: 'content1' },
  { id: '2', title: 'title2', content: 'content2' },
])

*.mock.ts

import { defineMock } from 'rspack-plugin-mock/helper'
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 }
    }
  }
])

注意:

defineMockData 仅是基于 memory 提供的共享数据支持, 如果需要做 mock 数据持久化,建议使用 nosql, 如 lowdblevel 等。

自定义匹配优先级

自定义规则仅影响包含动态参数的链接,如: /api/user/:id

插件内置的路径匹配规则优先级,已经能够满足大部分需求,但如果你需要更加灵活的自定义匹配规则优先级, 可以使用 priority 参数。

示例:

import { MockServerPlugin } from 'rspack-plugin-mock'

export default {
  plugins: [
    new MockServerPlugin({
      priority: {
        // 匹配规则优先级, 全局生效。声明在该选项中的规则将优先于默认规则生效。
        // 规则在数组越靠前的位置,优先级越高。
        global: ['/api/:a/b/c', '/api/a/:b/c', '/api/a/b/:c'],
        // 对于一些特殊情况,需要调整部分规则的优先级,可以使用此选项。
        // 比如一个请求同时命中了规则 A 和 B,且 A 比 B 优先级高, 但期望规则 B 生效时。
        special: {
          // 当请求同时命中 [key] 和 rules 中的任意一个时,优先匹配 [key] 。
          // when 用于进一步约束具体是哪些请求需要调整优先级。
          '/api/:a/:b/c': {
            rules: ['/api/a/:b/:c', '/api/a/b/:c'],
            when: ['/api/a/b/c']
          },
          // 如果不需要 when, 则表示命中规则的请求都需要调整优先级。
          // 可以简写为 [key]: [...rules]
          '/api/:a/b': ['/api/a/:b'],
        }
      }
    })
  ]
}

注意:

priority 虽然可以调整优先级,但大多数时候,你都没有必要这么做。 对于一些特殊情况的请求,可以使用 静态规则来替代 priority,静态规则总是拥有最高优先级。

Example

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

查看更多示例: example

export default defineMock({
  url: '/api/test',
})
export default defineMock({
  url: '/api/test',
  body: { a: 1 },
})
export default defineMock({
  url: '/api/test',
  body: () => ({ a: 1 })
})
export default defineMock({
  url: '/api/test',
  method: 'GET'
})
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' }
  }
})
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' },
  },
  // 命中 POST /api/test 请求,且 请求体中,字段 a 为数组,且数组包含值为 1, 2 的项
  {
    url: '/api/test',
    method: ['POST'],
    validator: { body: { a: [1, 2] } }
  }
])
export default defineMock({
  url: '/api/test',
  delay: 6000, // 延迟 6秒
})
export default defineMock({
  url: '/api/test',
  status: 502,
  statusText: 'Bad Gateway'
})
export default defineMock({
  url: '/api/user/:userId',
  body({ params }) {
    return { userId: params.userId }
  }
})

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

import { Buffer } from 'node:buffer'

// 由于 type 默认值是 json,虽然在传输过程中body使用buffer,
// 但是 content-type 还是为 json
export default defineMock({
  url: 'api/buffer',
  body: Buffer.from(JSON.stringify({ a: 1 }))
})
// 当 type 为 buffer 时,content-type 为 application/octet-stream,
// body 传入的数据会被转为 buffer
export default defineMock({
  url: 'api/buffer',
  type: 'buffer',
  // 内部使用 Buffer.from(body) 进行转换
  body: { a: 1 }
})

模拟文件下载,传入文件读取流

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">下载文件</a>
import Mock from 'mockjs'

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

请先安装 mockjs

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,
    }))
  }
})
{
  "url": "/api/test",
  "body": {
    "a": 1
  }
}

通过 formidable 支持。

<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 映射为 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),
    }
  },
})
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 }' })
})
// ws.mock.ts
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
        // Broadcast
        for (const [_token, _ws] of wsMap.entires()) {
          if (_token !== token)
            _ws.send(raw)
        }
      })
    })
    wss.on('error', (err) => {
      console.error(err)
    })
    onCleanup(() => wsMap.clear())
  }
})
// app.ts
const ws = new WebSocket('ws://localhost:5173/socket.io')
ws.addEventListener('open', () => {
  setInterval(() => {
    // heartbeat
    ws.send(JSON.stringify({ type: 'ping' }))
  }, 1000)
}, { once: true })
ws.addEventListener('message', (raw) => {
  console.log(raw)
})
// sse.mock.ts
import { createSSEStream, defineMock } from 'rspack-plugin-mock/helper'

export default defineMock({
  url: '/api/sse',
  response(req, res) {
    const sse = createSSEStream(req, res)
    let count = 0
    const timer = setInterval(() => {
      sse.write({
        event: 'count',
        data: { count: ++count },
      })
      if (count >= 10) {
        sse.end()
        clearInterval(timer)
      }
    }, 1000)
  },
})
// app.js
const es = new EventSource('/api/sse')

es.addEventListener('count', (e) => {
  console.log(e.data)
})

独立部署的小型mock服务

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

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

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

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

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

Links

License

rspack-plugin-mock is licensed under the MIT License