webpack实现具有热更新功能的mock接口服务

2,617 阅读2分钟

1. 前言

在前端进行开发的时候,一定会遇到和中后台进行接口连调。很多时候,中后台和前端开发是并行的,前端进行静态界面功能开发,后端进行接口业务功能开发,这个时候,中后台是无法提供有用的接口的。这个时候,需要有一个 mock 服务来提供模拟的接口数据,供前端来进行调试,这快加快前端开发,并减少后续的与中后台的连调时间。

这里有个前提,接口的路径和返回结果的结构及返回字段需要由中后台提供。mock 服务只在前期开发模式下使用,如果中后台提供了开发环境的接口,那么可以不再依赖 mock 服务。

SPA 前端项目基本上是由 webpack 进行打包,使用 webpack-dev-server 进行开发调试。所以可以使用 webpack-dev-server 来拦截请求,通过解析接口请求路径,并返回相应的模拟的接口数据。

2. 方案一: devServer.before 解析请求路径并返回接口数据

在 webpack 的 devServer 选项中,有个钩子方法 before,该方法会在服务器内部的所有其他中间件之前执行定制的功能。所以,在这个方法内,获取请求的路径,判断是否是接口请求,从而返回接口的 mock 数据。

devServer 的配置如下:

const {apiMocker} = require('../my-mock-server/index')

devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
    }, 
    hot: true, 
    host: '127.0.0.1',
    port: '9000',
    before: apiMocker
}

my-mock-server/index.js 文件内容:

const fs = require('fs')
const path = require('path')

const PREFIX = '/api/*'

function apiMocker(app, server) {
  app.get(PREFIX, handerAsyncRequest)
  app.post(PREFIX, handerAsyncRequest)
}

function handerAsyncRequest(req, res) {
  const reqPath = req.path.replace(/\/api/ig, '')
  const filePath = path.resolve(__dirname, `./mocks${reqPath}.js`)
  if (!fs.existsSync(filePath)) {
    res.send('文件不存在')
    return
  }

  let data = require(filePath)
  res.send(data)
}

module.exports = {
  apiMocker
}

如上代码,devServer 的 before 方法中,通过解析请求路径是否包含 /api 前缀来判断是否为接口请求来读取本地的 mock 数据,数据存放在本地的 my-mock-server/mocks/* 下。

本地开发环境服务启动后,比如 http://127.0.0.1:9000 ,mock 服务器会监听同一个地址和端口。在接口调用中,可以通过设置 baseURL 为 http://127.0.0.1:9000 来进行调用。

3. 方案二: 使用 express 提供 mock 服务器

方案一中,如果 mock 数据在使用中基本不变话,可以考虑使用。但一般情况下,开发过程中会反复的修改 mock 数据来创建一定的业务场景,这个时候,方案一需要重启服务来使修改生效。所以为了提供 mock 数据的热更新功能,有了第二个方案,即使用 express 来提供服务。

启动 express 服务仍然使用了 devServer.before,在该钩子方法内启动 express 服务。webpack 配置如下:

devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
    hot: true,
    host: '127.0.0.1',
    port: '9000',
    before(app, server) {
      if (process.env.MOCK === 'true') {
        const entry = path.resolve(__dirname, '../my-mock-server/index.js')

        // child_process 模块来创建子进程
        require('child_process').exec(`node-dev ${entry}`)
      }
    }
 }

my-mock-server/index.js 文件内容:

const fs = require('fs')
const path = require('path')
const cors = require('cors')
const express = require('express')

var app = express()
app.use(cors())

app.get('/api/demo1', function (req, res) {
  const reqPath = req.path.replace(/\/api/ig, '')
  const filePath = path.resolve(__dirname, `./mocks${reqPath}.js`)
  if (!fs.existsSync(filePath)) {
    res.send('文件不存在')
    return
  }

  let data = require(filePath)
  res.send(data)
})

var server = app.listen(9001, function () {
  var host = server.address().address
  var port = server.address().port

  console.log('应用实例,访问地址为 http://%s:%s', host, port)
})

启动开发环境后,express 会监听在 9001 端口。业务代码中的接口请求的 baseURL 需要使用 http://127.0.0.1:9001 。express 本身是不支持热更新的,这里使用了 node-dev 提供了热更新功能。

4. 总结

接口的mock对前端在开发过程中功能的实现,和后续与中后台的开发连调提供很好的帮助。Example Here