Code Monkey home page Code Monkey logo

pengzhanbo / vite-plugin-mock-dev-server Goto Github PK

View Code? Open in Web Editor NEW
125.0 1.0 9.0 1.04 MB

🚀mock-dev-server is injected into the vite development environment to simulate requests and data responses.在vite 开发环境中注入 mock-dev-server, 模拟请求和数据响应

Home Page: https://vite-plugin-mock-dev-server.netlify.app

License: MIT License

HTML 1.30% TypeScript 97.01% JavaScript 1.69%
mock mock-server vite vite-plugin vitejs mockjs typescript fakerjs graphql websocket

vite-plugin-mock-dev-server's Introduction

vite-plugin-mock-dev-server



Vite Plugin for API mock dev server.


npm node-current npm peer dependency version npm
GitHub Workflow Status fossa status


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.

Netlify Status

Usage

Install

# 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

Configuration

vite.config.ts

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

export default defineConfig({
  plugins: [
    mockDevServerPlugin(),
  ],
  // The fields defined here can also be used in mock.
  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 {
      /**
       * server port
       * @default 8080
       */
      serverPort?: number
      /**
       * build output dir
       * @default 'mockServer'
       */
      dist?: string
      /**
       * log level
       * @default 'error'
       */
      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'

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

export default defineApiMock({
  url: '/test' // Complete as '/api/test'
})

Mock Configuration

// Configure the http mock
export default defineMock({
  /**
   * Request address, supports the `/api/user/:id` format.
   * The plugin matches the path through `path-to-regexp`.
   * @see https://github.com/pillarjs/path-to-regexp
   */
  url: '/api/test',
  /**
   * Supported request methods of the interface.
   * @type string | string[]
   * @default ['POST','GET']
   *
   */
  method: ['GET', 'POST'],
  /**
   * In practical scenarios,
   * we usually only need certain mock interfaces to take effect,
   * rather than enabling all mock interfaces.
   * For interfaces that do not currently require mocking,
   * they can be set to false.
   *
   * @default true
   */
  enabled: true,
  /**
   * Set interface response delay, if an array is passed in,
   * it represents the range of delay time.
   * unit: ms.
   * @default 0
   */
  delay: 1000,
  /**
   * response status
   * @default 200
   */
  status: 200,
  /**
   * response status text
   */
  statusText: 'OK',
  /**
   * response headers
   * @type Record<string, any>
   * @type (({ query, body, params, headers }) => Record<string, any>)
   */
  headers: {
    'Content-Type': 'application/json'
  },

  /**
   * response cookies
   * @type Record<string, string | [value: string, option: CookieOption]>
   * @see https://github.com/pillarjs/cookies#cookiessetname--values--options
   */
  cookies: {
    'your-cookie': 'your cookie value',
    'cookie&option': ['cookie value', { path: '/', httpOnly: true }]
  },
  /**
   * Response body data type, optional values include `text, json, buffer`.
   * And also support types included in `mime-db`.
   * When the response body returns a file and you are not sure which type to use,
   * you can pass the file name as the value. The plugin will internally search for matching
   * `content-type` based on the file name suffix.
   * However, if it is a TypeScript file such as `a.ts`, it may not be correctly matched
   * as a JavaScript script. You need to modify `a.ts` to `a.js` as the value passed
   * in order to recognize it correctly.
   * @see https://github.com/jshttp/mime-db
   * @default 'json'
   */
  type: 'json',

  /**
   * Response Body
   * Support `string/number/array/object/buffer/ReadableStream`
   * You can also use libraries such as' mockjs' to generate data content
   * @type string | number | array | object | ReadableStream | buffer
   * @type (request: { headers, query, body, params, refererQuery, getCookie }) => any | Promise<any>
   */
  body: '',

  /**
   * If the mock requirement cannot be solved through `body` configuration,
   * then it can be achieved by configuring response and exposing the interface of http server
   * to realize fully controllable custom configuration in req parameters.
   * The parsing of query, body and params has been built-in, so you can use them directly.
   * Don't forget to return response data through `res.end()` or skip mock by calling `next()`.
   */
  response(req, res, next) {
    res.end()
  },
  /**
   * Request validator, return mock data if validated, otherwise do not use current mock.
   * This is useful in scenarios where an interface needs to return different data based
   * on different input parameters.
   * Validators can solve this type of problem well by dividing the same URL into multiple
   * mock configurations and determining which one is effective based on the validator.
   *
   * @type { headers, body, query, params, refererQuery }
   * If the validator passed in is an object,
   * then the validation method is to deeply compare whether
   * `headers/body/query/params/refererQuery` of the requested interface contain
   * the `key-value` of the validator.
   *
   * @type (request) => boolean
   * If the validator passed in is a function,
   * then the data related to the requested interface will be provided as input parameters
   * for users to perform custom validation and return a boolean.
   *
   */
  validator: {
    headers: {},
    body: {},
    query: {},
    params: {},
    /**
     * refererQuery validates the query parameters in the URL of the request source page,
     * which allows for direct modification of parameters in the browser address bar
     * to obtain different simulated data.
     */
    refererQuery: {}
  },
})
// Configure the WebSocket mock
export default defineMock({
  /**
   * Request address, supports the `/api/user/:id` format.
   * The plugin matches the path through `path-to-regexp`.
   * @see https://github.com/pillarjs/path-to-regexp
   */
  url: '/api/test',
  /**
   * Value must be explicitly specified as `true`.
   * The plugin needs to make a judgment based on this field.
   */
  ws: true,
  /**
   * Configure the WebSocketServer
   * @see https://github.com/websockets/ws/blob/master/doc/ws.md#class-websocketserver
   * If there are some additional automatically executed tasks or loop
   * tasks in the setup function,a callback needs to be passed in
   * `onCleanup()` to clear these tasks.
   * This is because when the plugin is hot updated,
   * it needs to re-execute setup and clear previous tasks; otherwise,
   * duplicate tasks may cause conflicts.
   * `onCleanup()` can be called multiple times within setup.
   * @type `(wss: WebSocketServer, context: SetupContext) => void`
   */
  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, // key
  initialData: T, // initial data
) => [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: {
        // The priority of matching rules is global.
        // The rules declared in this option will take priority over the default rules.
        // The higher the position of the rule in the array, the higher the priority.
        global: ['/api/:a/b/c', '/api/a/:b/c', '/api/a/b/:c'],
        // For some special cases where the priority of certain rules needs to be adjusted,
        // this option can be used. For example, when a request matches both Rule A and Rule B,
        // and Rule A has a higher priority than Rule B, but it is desired for Rule B to take effect.
        special: {
          // When both A and B or C match, and B or C is at the top of the sort order,
          // insert A into the top position.
          // The `when` option is used to further constrain the priority adjustment to
          // be effective only for certain requests.
          '/api/:a/:b/c': {
            rules: ['/api/a/:b/:c', '/api/a/b/:c'],
            when: ['/api/a/b/c']
          },
          // If no `when` is specified, it means that all requests matching the rules need to have their priorities adjusted. It can be abbreviated as `[key]: [...rules]`
          '/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([
  // Match /api/test?a=1
  {
    url: '/api/test',
    validator: {
      query: { a: 1 },
    },
    body: { message: 'query.a == 1' },
  },
  // Match /api/test?a=2
  {
    url: '/api/test',
    validator: {
      query: { a: 2 },
    },
    body: { message: 'query.a == 2' },
  },
  {
    // `?a=3` will resolve to `validator.query`
    url: '/api/test?a=3',
    body: { message: 'query.a == 3' }
  },
  // Hitting the POST /api/test request, and in the request body,
  // field a is an array that contains items with values of 1 and 2.
  {
    url: '/api/test',
    method: ['POST'],
    validator: { body: { a: [1, 2] } }
  }
])

exp: Response Delay

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

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'

// Since the default value of type is json,
// although buffer is used for body during transmission,
// the content-type is still json.
export default defineMock({
  url: 'api/buffer',
  body: Buffer.from(JSON.stringify({ a: 1 }))
})
// When the type is buffer, the content-type is application/octet-stream.
// The data passed in through body will be converted to a buffer.
export default defineMock({
  url: 'api/buffer',
  type: 'buffer',
  // Convert using Buffer.from(body) for internal use
  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',
  // When you are unsure of the type, you can pass in the file name for internal parsing by the plugin.
  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

// 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)
})

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

All Contributors

pengzhanbo
pengzhanbo

📖 🤔 💡 💻
jiadesen
jiadesen

🤔 🐛
yogibaba
yogibaba

💻
pfdgithub
pfdgithub

💻 🐛

LICENSE

MIT

FOSSA Status

vite-plugin-mock-dev-server's People

Contributors

allcontributors[bot] avatar fossabot avatar jiadesen avatar pengzhanbo avatar pfdgithub avatar yogibaba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

vite-plugin-mock-dev-server's Issues

raw html response from file

Hello!

Is that possible to respond with raw html file from an actual file? My goal is to emulate response delays while adding some specific response headers when dev server is pointed to few specific locations.

p.s. Thanks for the interesting plugin!

请求验证器扩展:支持 referer query 验证

对于同一个页面中发起的 api 请求,可以根据特定的 referer query 加载不同的 mock 数据,例:

localhost/index.html?mock=张三
localhost/index.html?mock=李四

支持的场景:

可以不侵入业务源码,通过在页面 url 中添加特定标识,便可控制页面中一些接口响应所需的 mock 数据

"[ERROR] Invalid define value (must be an entity name or valid JSON syntax)"... when JSON object is the value

hi there 👋

thanks for this great tool and apologies for the english here 🙏

with a vite configuring like this:

define: {
    'import.meta.env.__X__': JSON.stringify({ my: 'object' )),
},

i get an error:

✘ [ERROR] Invalid define value (must be an entity name or valid JSON syntax): {"BASE_URL":"/","MODE":"development","DEV":true,"PROD":false,"__X__":{\"my\":\"object\}"}

Error: Build failed with 1 error:
error: Invalid define value (must be an entity name or valid JSON syntax): {"BASE_URL":"/","MODE":"development","DEV":true,"PROD":false,"__X__":{\"my\":\"object\}"}
    at failureErrorWithLog (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:1651:15)
    at /Users/me/code/my-app/node_modules/esbuild/lib/main.js:1059:25
    at runOnEndCallbacks (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:1486:45)
    at buildResponseToResult (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:1057:7)
    at /Users/me/code/my-app/node_modules/esbuild/lib/main.js:1086:16
    at responseCallbacks.<computed> (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:704:9)
    at handleIncomingPacket (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:764:9)
    at Socket.readFromStdout (/Users/me/code/my-app/node_modules/esbuild/lib/main.js:680:7)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:545:12) {
  errors: [Getter/Setter],
  warnings: [Getter/Setter]
}

naively, i think the issue is caused by re-writing the user define entries (here). in cases where the parsed value is an object, esbuild errors.

ideally user defines wouldn't be edited, just passed thru as they were set.

also see: #31

Invalid define value (must be an entity name or valid JSON syntax): {"BASE_URL":"./","MODE":"production","DEV":false,"PROD":true,"LEGACY":__VITE_IS_LEGACY__}

[email protected]@vitejs/[email protected]下,启用 options.build 配置后,执行npm run build会报错:

Invalid define value (must be an entity name or valid JSON syntax): {"BASE_URL":"./","MODE":"production","DEV":false,"PROD":true,"LEGACY":__VITE_IS_LEGACY__}

生成了mockServer目录和文件,但mock-data.js文件中是空的。

可能与 babelrollup 版本有关?没往下查,可参考:
vitejs/vite#2442
babel/babel#13017
rollup/plugins#838

热更新和参数问题

1、环境:v0.4.0 + vue 2.7.14 + vite 4.1.3
2、问题
1)开发环境,修改***.mock.ts文件接口数据,好像无法热更新
2)是否可支持属性同义词配置,比如,axios中 params 表示 url后的参数,data表示body体的参数,但实际mock接口接收后,query、params、body无法对应,是否可支持同义词配置?alias : { body:'data', query: 'params'}

build报错

1、版本:1.0.4 ,环境: vite - 4.1.4
2、插件配置:

export function initMockDevServerPlugin() {
  return mockDevServerPlugin({
    prefix: 'mock',
    include: 'mock/**/*.{ts,js,cjs,mjs,json,json5}',
    formidableOptions: {
      // 配置上传资源存放目录
      uploadDir: resolve(process.cwd(), 'uploads'),
      // 可修改上传资源名称
      filename: (name, ext, part) => {
        return part.originalFilename!
      },
    },
    build: {
      serverPort: 6666,
      dist: 'mockServer',
    },
  })
}

3、pnpm build 后报错信息(项目本身正常打包完成)

    mock-data-1678971238074.js:2:43:
      2 │ import * as m0 from 'E:\0WorkSpace\VsCode\app\mock\api.ts';
        ╵                                            ^


 ERROR  Build failed with 1 error:                                                                                                                           20:53:58  
mock-data-1678971238074.js:2:43: ERROR: Syntax error "i"

  mock-data-1678971238074.js:2:43: ERROR: Syntax error "i"
  at failureErrorWithLog (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:1636:15)
  at node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:1048:25
  at runOnEndCallbacks (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:1471:45)
  at buildResponseToResult (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:1046:7)
  at node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:1075:16
  at responseCallbacks.<computed> (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:697:9)
  at handleIncomingPacket (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:752:9)
  at Socket.readFromStdout (node_modules\.pnpm\[email protected]\node_modules\esbuild\lib\main.js:673:7)
  at Socket.emit (node:events:512:28)
  at addChunk (node:internal/streams/readable:324:12)
  at readableAddChunk (node:internal/streams/readable:297:9)
  at Readable.push (node:internal/streams/readable:234:10)
  at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)

4、mock/api.ts

import { defineMock } from 'vite-plugin-mock-dev-server'
export default defineMock([
  {
    url: '/mock/caseCache/getData',
    body: (res) => {
      const { query, params, body } = res
      return {
        data: {
          query,
          params,
          body,
          isLogin: false,
        },
        message: '成功',
        code: '200',
      }
    },
  },
  {
    url: '/mock/casePackage/initData',
    body: () => {
      return {
        data: {
          sectionOptions: [
            { value: '0-1', label: '测试1' },
          ],
          phyunitOptions: [
            { value: '0-2', label: '测试2' },
          ],
        },
        message: '成功',
        code: '200',
      }
    },
  },
])

5、说明,感觉跟文件无关,删除mock/api.ts后,报错内容一样,不过换成其它mock文件
6、开发环境下,mock测试接口,都可以访问

请求体过大报错

Bug 描述

如题,在请求时传了个很大的body后,raw-body解析request时报
PayloadTooLargeError: request entity too large
因为co-body默认的limit1mb,建议在传入一个很大的limit配置,具体数值看你掐指一算

系统环境

- OS: macOS 13.6.5
- Node: 18
- packageManager: yarn
- vite: ^4.4.5
- vite-plugin-mock-dev-server: ^1.4.7

Logs

PayloadTooLargeError: request entity too large
at readStream (node_modules/raw-body/index.js:163:17)
at executor (node_modules/raw-body/index.js:120:5)
at new Promise ()
at getRawBody (node_modules/raw-body/index.js:119:10)
at module.exports [as json] (node_modules/co-body/lib/json.js:39:21)
at parseReqBody (file://node_modules/vite-plugin-mock-dev-server/dist/index.js:656:31)
at file://node_modules/vite-plugin-mock-dev-server/dist/index.js:775:27
at call (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50689:7)
at next (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50633:5)
at cors (node_modules/cors/lib/index.js:188:7)
at node_modules/cors/lib/index.js:224:17
at originCallback (node_modules/cors/lib/index.js:214:15)
at node_modules/cors/lib/index.js:219:13
at optionsCallback (node_modules/cors/lib/index.js:199:9)
at corsMiddleware (node_modules/cors/lib/index.js:204:7)
at file://node_modules/vite-plugin-mock-dev-server/dist/index.js:1534:22
at call (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50689:7)
at next (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50633:5)
at Function.handle (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50636:3)
at Server.app (file://node_modules/vite/dist/node/chunks/dep-52909643.js:50501:37)
at Server.emit (node:events:517:28)
at parserOnIncoming (node:_http_server:1123:12)
at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17) {
expected: 2003701,
length: 2003701,
limit: 1048576,
type: 'entity.too.large'
}

mockServer 独立部署安装和启动报错

安装报错

yarn install v1.22.19
warning package.json: No license field
warning mock-server: No license field
[1/4] Resolving packages...
error An unexpected error occurred: "https://registry.npmmirror.com/@%2ftypes: [NOT_FOUND] /@%2ftypes not found".
info If you think this is a bug, please open a bug report with the information provided in "D:\\MyProject\\nanke-web\\dist\\mockServer\\yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

查询原因是 package.json 中的依赖 "@/types": "latest" 导致的。将之删除后,进行 yarn start,出现启动报错

启动报错

$ node index.js
file:///D:/MyProject/nanke-web/dist/mockServer/node_modules/vite-plugin-mock-dev-server/dist/index.js:1329
  (_a = loader.on) == null ? void 0 : _a.call(loader, "mock:update-end", (filepath) => {
               ^

TypeError: Cannot read properties of undefined (reading 'on')
    at mockWebSocket (file:///D:/MyProject/nanke-web/dist/mockServer/node_modules/vite-plugin-mock-dev-server/dist/index.js:1329:16)
    at file:///D:/MyProject/nanke-web/dist/mockServer/index.js:14:1
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
    at async loadESM (node:internal/process/esm_loader:91:5)
    at async handleMainPromise (node:internal/modules/run_main:65:12)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

@pengzhanbo

如何设置mock 接口支持跨域?或如何 全局设置 mockConfig

结合微前端时,需要设置支持跨域,

子项目为vite 已经配置过跨域了,但mock 接口还是提示跨域

想每一个mock 接口都 增加 以下header 配置,如何在一个地方全局增加这个配置呢


headers: {
    'access-control-allow-credentials': 'true',
    'access-control-allow-origin': '*',
    'access-control-allow-headers': 'X-Requested-With,Content-Type',
    'access-control-allow-methods': '*'
  },

多个mock模块如何公用一套数据?

做示例数据时需要多个*.mock.ts同时公用一套数据,但是用单例类模式也会在每个mock模块中重新生成数据,导致列表和编辑不是一条数据

在mock中使用vite.config.ts中定义的路径别名@时,会引发错误

首先非常感谢vite-plugin-mock-dev-server的贡献。

以下是我在使用过程中遇到的问题。
插件版本:1.0.6
vite版本:4.1.4
vue版本:3.2.41
node版本:18.14.1

在mock中使用vite.config.ts中定义的路径别名@时,会引发以下错误

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@/api' imported from E:\vue_work\cms-client\mock\user.mock.ts.timestamp-1679469726707.mjs
at new NodeError (node:internal/errors:399:5)
at packageResolve (node:internal/modules/esm/resolve:889:9)
at moduleResolve (node:internal/modules/esm/resolve:938:20)
at defaultResolve (node:internal/modules/esm/resolve:1153:11)
at nextResolve (node:internal/modules/esm/loader:163:28)
at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
at link (node:internal/modules/esm/module_job:76:36) {
    code: 'ERR_MODULE_NOT_FOUND'
}

使用@别名的情况为:在mock文件中使用了api请求中定义的url枚举类。或者导入定义的type类型
以下是项目代码

//mock/user.mock.ts

import {defineMock} from 'vite-plugin-mock-dev-server';
import {UserApiUrl} from "@/api/user";

export default defineMock([
	{
		url: UserApiUrl.login,
		body(req) {
			return {token: "1111"};
		}
	},
]);


//src/api/user

export enum UserApiUrl {
	login = '/user/login',
}

如果我在mock中将@别名改为/src时,如果引入的文件中又使用@别名引入了其他文件,同样会引发此错误。
所以我不太清除是插件不支持在mock文件中使用别名,还是我哪里配置有问题。

还请大佬们不吝赐教。

是否可以支持测试环境部署?

大佬好项目前期可能只是想简单的纯前端部署展示,不想涉及后端,比如打包后部署到nginx上,通过mock数据进行简单的展示是否可以提供对该场景的支持?

[ERROR] The entry point "mock/table.ts.timestamp-1710847630001.mjs" cannot be marked as external

Bug 描述

当我通过pnpm run dev 启动项目时,偶尔(大概率)会报错,但是项目能正常运行起来

✘ [ERROR] The entry point "mock/table.ts.timestamp-1710847630001.mjs" cannot be marked as external

Error: Build failed with 1 error:
error: The entry point "mock/table.ts.timestamp-1710847630001.mjs" cannot be marked as external
    at failureErrorWithLog (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1651:15)
    at /Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1059:25
    at runOnEndCallbacks (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1486:45)
    at buildResponseToResult (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1057:7)
    at /Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1086:16
    at responseCallbacks.<computed> (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:704:9)
    at handleIncomingPacket (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:764:9)
    at Socket.readFromStdout (/Users/sun/Code/Vue/WebDevPractice/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:680:7)
    at Socket.emit (node:events:517:28)
    at addChunk (node:internal/streams/readable:368:12) {
  errors: [Getter/Setter],
  warnings: [Getter/Setter]

系统环境

- OS:MacOS M1
- Node:v18.19.1
- packageManager:pnpm
- vite:^5.0.12
- vite-plugin-mock-dev-server:^1.4.7

Logs

/mock/table.ts

import { defineMock } from "vite-plugin-mock-dev-server";
import { faker } from "@faker-js/faker";

const data = [
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
  {
    date: faker.date.past(),
    name: faker.internet.userName(),
    address: faker.location.city(),
  },
];
export default defineMock({
  url: "/api/table",
  body: ({ body: { page, pageSize } }) => {
    return {
      total: data.length,
      data: data.slice((page - 1) * pageSize, page * pageSize),
    };
  },
  delay: 1000,
});

功能请求:希望可以对所有MockOptionsItem中的字段url添加前缀

希望的api:

1.在vite.config.js中的mockDevServerPlugin中新增加配置选项urlPrefix,用于指定mock的url前缀
或者在mockDevServerPlugin中新增加配置选项urlRewrite,用于指定mock的url重写规则
或是直接读取vite.config.js中的server.proxy中的rewrite规则

export default defineConfig({
	plugins: [
		mockDevServerPlugin({
		    urlPrefix:'/api',
		    //或者
		    urlRewrite: (path) => path.replace(/^\/api/, ''),
		})
	],
	server: {
		proxy: {
			'/api': {
				target: "http://example.com",
				rewrite: (path) => path.replace(/^\/api/, ''),
			}
		}
	}
})

2.改造defineMock,添加第二个参数,用于指定MockOptionsItem的url前缀

defineMock([{
    url:'/login'
    ...
},{
    url:'/logout'
    ...
}], {
    urlPrefix:'/api/user'
})

解决的问题

1.proxy中的key一般情况下并不是直接存在于api的url中,而是用户为了统一代理而添加的一个自定义前缀,比如/api,/api2,/api3等等
但是在mock中如果每一项都添加一个/api的话,会导致mock的url和真实的url看起来不一致,而且麻烦,所以希望能够统一指定一个前缀
2.在同一个mock文件中,一般都是同一类的api,例如user相关的api,一般都会以/user开始。

以上只是部分使用场景的举例,我感觉如果将此功能加入后,会更加方便,也更加灵活。

争议点

当defineMock中的urlPrefix选项和mockDevServerPlugin中的urlPrefix或urlRewrite都存在时,应该以哪个为准? 或者是同时生效?

关于mock前置拦截功能

环境:
vite3+vue3

问题描述:
我不想频繁操作vite.config文件,看到您官网上有一个【enable】属性,但是写了enable属性后,会导致ts报错如下:
image
并且,只要写了enable之后不管写true还是false都不走mock了

期望:
1、有一个拦截函数,类似于下面格式
const mockEnable = false
export default mockFilter({ url, params, body, query, xxx }) :Boolean => {})
export default defineMock({ xxxxxxx })
2.修复enable功能
3.修复ts报错

希望可以显式定义 *.mock.ts 文件加载顺序,以便于控制不同文件中 mock 规则优先级。

我的场景是,需要在一个单独的文件中定义一些通用 mock 规则,并在其他文件中定义专用规则,希望能优先匹配专用规则。
看到之前的 issue 中有类似的问题,插件文档中也没有相关的描述,希望能添加支持。

#27 (comment)

另外在本次排查中,还发现一个 bug,不确定是否跟你的问题有关联。大概跟你描述下。

当mock配置中有以下两个类似的配置文件时时:

// a.mock.ts
export default defineMock({
  url: '/api/post/:postId'
})
// b.mock.ts
export default defineMock({
  url: '/api/post/list'
})

如果 a.mock.ts 优先于 b.mock.ts 被解析加载,那么客户端发起的 /api/post/list 的请求,会总是命中 a.mock.ts 中的配置,而不是命中期望的b.mock.ts的配置,这是由于 /api/post/list 也是符合 /api/post/:postId 的解析匹配的。

这个问题也可能会导致对 b.mock.ts 的配置使用 enabled ,也不会有预期表现。

mock配置中的方法执行错误,导致 vite开发服务终止

Originally posted by @kenixFog in #15 (comment)

遇到个新"问题",但是不晓得能不能从插件层面进行容错~~

body: (res, query, params, body) => {   ❌

这个修改的时候,我改错了,我写成了

(body: (res,  {query, params, body} ) => {)

然后导致程序直接退出


E:\0WorkSpace\app\mock\api.mock.ts:30
   body: (res, { query, params, body }) => {
                 ^

TypeError: Cannot destructure property 'query' of 'undefined' as it is undefined.
   at Object.body (E:\0WorkSpace\app\mock\api.mock.ts:30:19)
   at E:\0WorkSpace\app\node_modules\.pnpm\[email protected][email protected]\node_modules\vite-plugin->mock-dev-server\dist\index.cjs:456:34
   at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v19.6.0
ELIFECYCLE  Command failed with exit code 1.

这个写法肯定有问题,但万一手抖,改错了。。重新启动,时间成本略微有点高~

文件上传接口报错

Error: Unsupported content-type: multipart/form-data; boundary=----WebKitFormBoundaryJBADTbzOOrlYZerZ

[bug:]Cannot start service: Host version "0.19.8" does not match binary version "0.18.17"

Version

  • Vite: 4.4.9
  • vite-plugin-mock-dev-server: 1.4.0
  • esbuild: 0.18.17&0.19.8

Reason

Maybe the incompatible esbuild version cause this problem.[I'm not sure now]

Would you mind set esbuild to peerDep or other ways to keep esbuild's version unique in project

I found the 4.x vite was still use 0.18.x esbuild

"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
"rollup": "^3.27.1"
},

希望 `mockDevServerPlugin` 添加一个 `base_url` 配置

希望 mockDevServerPlugin 添加一个 base_url 配置:

// vite.config.ts
mockDevServerPlugin({
  base_url: '/api/v1',
}),


// user.mock.ts
export default defineMock({
  url: '/users', // => 等价于 /api/v1/users
  body: {
    data: [],
  },
})

避免写很多

export default defineMock({
  url: `${BASE_URL}/xxx`, 
})

或者当前有什么方法可以拦截统一加一个前缀?

export const prefixDefineMock = ({url, ...rest}) => defineMock({ url: `${BASE_URL}/${url}`, ...rest})

这样对 js/ts 可以,对 json 就不行了

mock文件夹下的空文件会导致异常

vite正常运行,在mock下创建.ts空文件,会导致vite异常终止,或者mock下存在空的ts文件,vite无法启动

node:internal/errors:490
    ErrorCaptureStackTrace(err);
    ^

TypeError: The "url" argument must be of type string. Received undefined
    at new NodeError (node:internal/errors:399:5)
    at validateString (node:internal/validators:163:11)
    at Url.parse (node:url:175:3)
    at urlParse (node:url:146:13)
    at E:\0WorkSpace\VsCode\xianhuo\dlsc-app-naiveUI\node_modules\.pnpm\[email protected][email protected]\node_modules\vite-plugin-mock-dev-server\dist\index.cjs:645:62
    at Array.forEach (<anonymous>)
    at _MockLoader.updateMockList (E:\0WorkSpace\VsCode\xianhuo\dlsc-app-naiveUI\node_modules\.pnpm\[email protected][email protected]\node_modules\vite-plugin-mock-dev-server\dist\index.cjs:644:84)
    at _MockLoader.<anonymous> (E:\0WorkSpace\VsCode\xianhuo\dlsc-app-naiveUI\node_modules\.pnpm\[email protected][email protected]\node_modules\vite-plugin-mock-dev-server\dist\index.cjs:567:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'ERR_INVALID_ARG_TYPE'
}

js同步异步导致的问题

这个问题,应该不算插件本身的问题,但实际使用中遇到了,不晓得有没有好的解决思路,两个mock请求,对应的响应方法:
响应A:但是其中一个通过while循环,时间判断10秒后,再返回结果,
响应B:直接返回

按钮A对应响应A,按钮B对应响应B,直接先点击B,再点击A,由于同步机制,会导致A需要等待B响应完成后才能返回,这也就意味着,mock情况下,如果方法是前后按序触发,只能按序执行,当然实际后台请求都是异步,不会存在这种情况

针对这种现象,插件是否可以统一规避掉?

next() 无法将 POST 请求转交给 Vite 默认代理中间件

使用 response(req, res, next) 自定义处理时,对于 POST 请求,无法通过 next() 方式将请求转交给下一个中间件(Vite 默认代理转发)处理 。浏览器 Network 一直处于 pending 状态,直至超时后 canceled 状态。
对于 GET 请求不受影响,可被 Vite 默认代理转发至目标服务器。应该是因为 mock 插件提取 body 时,消耗了 request 流,造成 post 请求无法转交给后续处理器。

这个链接可以参考一下:
https://github.com/pfdgithub/scaffold-webpack/blob/react/cfg/devServer.js#L63


vite.config.js

{
  server: {
    proxy: {
        "/api": {
          target: "http://1.2.3.4:5"
        },
    }
  }
}

_.mock.js

export default defineMock([
  {
    url: "/api/(.*)",
    response: async (req, res, next) => {
      console.log(req.method, req.url);
      next();
    },
  },
]);

Network
image
image
image

是否可以支持mock数据低优先级

很多时候随着项目的迭代,大部分接口都是通过后台的接口获取,mock数据的常见情况是在新的需求中,后台接口未实现之前。
目前绝大部分的mock插件都是本地数据优先。

能否做到优先匹配server.proxy中的地址,如果返回404再走mock接口,
或者开放函数接口,由开发人员自行决定返回值
考虑以下方案:

mockDevServerPlugin({
priority:'before'|'after'
})

vite4.x版本中使用别名导致随机性的导入一些方法失败

我在vite4.x版本中,配置了针对于mock的别名,然后进行一些方法的导入。如果是冷启动的时候,该方法必然会被提示找不到:
image
如果我在修改代码后,该导入又是正常的。

这个问题让我很困惑,希望得到解决一下,否则在嵌套层数过深的地方,很不友好。

mockServer 正常启动,但是接口进 mockServer 服务后报错,和一些实验性建议

错误信息 1

服务正常启动,但是请求进来后报错,并且造成服务中止。报错如下:

$ node index.js
listen: http://localhost:3002
node:internal/errors:478
    ErrorCaptureStackTrace(err);
    ^

TypeError [ERR_HTTP_INVALID_HEADER_VALUE]: Invalid value "undefined" for header "X-File-Path"
    at ServerResponse.setHeader (node:_http_outgoing:647:3)
    at provideHeaders (file:///D:/MyProject/nanke-web/dist/mockServer/node_modules/vite-plugin-mock-dev-server/dist/index.js:934:7)
    at file:///D:/MyProject/nanke-web/dist/mockServer/node_modules/vite-plugin-mock-dev-server/dist/index.js:836:11
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  code: 'ERR_HTTP_INVALID_HEADER_VALUE'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

根据报错可知,是一个 JS 常见的 undefined 错误。进入 dist/index.js 临时修改代码

-934 res.setHeader("X-File-Path", filepath);
+934 res.setHeader("X-File-Path", filepath || ''); 

可临时解决问题

建议 1

是否可以支持:打印输出请求进来的 info 信息,这样可以明确知道请求确实是到了这里,而不是开发者手动去检查

建议2

是否可以支持:打包的 mockServer 在 dist 目录外面。这导致每次进行打包需要重新进入 mockServer 进行 installstart

建议3

是否可以支持:将 mockServer 复制到 vite 项目之外时,能够正常启动。
我将 mockServer 复制到 vite 项目之外后,启动报错:

$ node index.js
node:internal/errors:478
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite' imported from D:\MyProject\mockServer\node_modules\vite-plugin-mock-dev-server\dist\index.js
    at new NodeError (node:internal/errors:387:5)
    at packageResolve (node:internal/modules/esm/resolve:852:9)
    at moduleResolve (node:internal/modules/esm/resolve:901:20)
    at defaultResolve (node:internal/modules/esm/resolve:1115:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:841:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

生产环境下作为临时的数据来源,确实有这个需求:与 vite 项目打包的 dist 目录进行解耦

WebSocket mocking issues when ws request contains query params

Describe the bug

The plugin works great for mocking REST endpoints but I cannot get WebSocket mocking working. I can proxy to local WebSocket server running on another port so its the mocking itself that does not seem to match requests.

The browser ws request remains pending, e.g.

ws://localhost:5173/foo/ws?id=123&bar=456

The relevant code is:

vite.config.js

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

const rootPath = `/foo`;

export default defineConfig({
  plugins: [
    mockDevServerPlugin({
      log: "debug",
      wsPrefix: `/${rootPath}/ws`,
    }),
  ],
  server: {
    proxy: {
      [`${rootPath}/user`]: "",
      [`${rootPath}/resources`]: ""
    }
  },
  base: `/${rootPath}/web`,
});

mock/ws.mock.js

import { defineMock } from "vite-plugin-mock-dev-server";
import mockData from "../mock-data.json";

const rootPath = `/foo`;

export default defineMock({
  url: `/${rootPath}/ws`,
  ws: true,
  setup(wss) {
    wss.on("connection", (ws) => {
      ws.on('error', console.error);

      ws.on('message', (data) => {
        console.log('received: %s', data);
      });
    
      mockData.messages.forEach(msg => {
        ws.send(JSON.stringify(msg));
      });
    })
  },
})

My only thought is that path-to-regex is not matching requests with query params.

Environment

- OS: MacOS 14.3
- Node: 20.11.0
- packageManager: npm 10.2.4
- vite: 5.1.1 (with plain JS)
- vite-plugin-mock-dev-server: 1.4.7

Logs

vite console log

3:12:45 PM [vite] server restarted.
3:12:45 PM [vite:mock] GET /foo/user  (mock/user.mock.js)
3:12:45 PM [vite:mock] DEBUG /foo/user  matches: [ /foo/user ]

3:12:45 PM [vite:mock] GET /foo/resources  (mock/resources.mock.js)
3:12:45 PM [vite:mock] DEBUG /foo/resources  matches: [ /foo/resources ]

未配置 vite 的 proxy 参数和插件的 prefix 参数,应输出警告信息。

随便配置一个无效的 proxy 就能继续走后续 mock 流程了,期望插件本身不强依赖于 proxy 配置。
虽然可以通过插件的 prefix 配置绕过,但是用起来总是有些奇怪。而如果不配置 prefix 又无法区分哪些是接口请求,哪些是资源请求,等于是允许在 *.mock.js 文件中拦截全部请求,也不太合适。
有没有什么好办法支持这种场景呢?🤔

也许应该在检测到 proxy 和 prefix 都未配置时,打印一个警告提醒一下用户?

BUG(response error): appendHeader is not a function

My code like this:

{
    url: `${BASE_URL}/xxx`,
    method: ['POST'],
    response: (req, res) => {
      const { username, password } = req.body
      if (xxx === 'xxx' && yyy === 'yyy') {
        res.statusCode = 200
        res.setHeader('Content-Type', 'application/json')
        res.appendHeader('Set-Cookie', 'xxx=xxx; Path=/; HttpOnly')
        res.end(
            .....
        )   
      }eles if(...){
        ...
      }
    }
}

Error message:

mock-dev-server:  [response error] /mock-api/xx/xx 
 file: mock/test.mock.ts TypeError: res.appendHeader is not a function
    at response (/home/xx/Desktop/xx/mock/test.mock.ts:54:13)
    at /home/xx/Desktop/xx/node_modules/.pnpm/[email protected][email protected]/node_modules/vite-plugin-mock-dev-server/dist/index.cjs:46:105
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

It was working fine the last commit

version

node -v
v16.16.0
pnpm -v
8.3.1
vite-plugin-mock-dev-server
1.1.13
typescript
5.0.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.