在webpack-dev-server内添加mock server

12,140 阅读3分钟

在开发基于api交互、前后端分离的网页应用时,经常会遇到几个问题:

  • 前端页面已经编排好了,但是后台接口还没准备好,或者是突然出现Bug,这样没办法进行对接测试。
  • 我们希望服务器返回特定类型的数据,以测试某页面在特定条件下是否存在问题,但作为前端我们一般不会接触到后端代码和数据库,每次都找后端添加模拟数据又很麻烦。

为解决这两个问题,最简单的解决办法就是搭建一个mock server,专门返回需要的模拟数据。

webpack-dev-server是我们开发vue、react时必备的工具,通过webpack-dev-serverbefore钩子,可以在webpack-dev-server上添加我们需要的mock server功能,而不需要另行搭建服务器。

在一通搜索后,我找到了这篇文章和这个webpack中间件webpack-api-mocker,只需要少许修改就能webpack-dev-server当做mock server来用,并且对同一URL下的GETPOSTPATCH等不同的HTTP METHOD做分别处理,支持热切换。

使用方法很简单,在webpack.dev.conf.jsdevServer中添加新钩子before,将所有请求交由apiMocker处理,然后当需要使用模拟数据时,只需要将请求的URL改为webpack服务器上既可。

npm install webpack-api-mocker --save-dev
const apiMocker = require('webpack-api-mocker')
config = {
  ...
  devServer: {
    before(app) { 
      apiMocker(app, path.resolve('mock/api.js'))
    }
  }
  ...
}

api.js

const fs = require('fs');

function fromJSONFile(filename) {
    return (req, res) => {
        const data = fs.readFileSync(`mock/data/${filename}.json`).toString();
        const json = JSON.parse(data);
        return res.json(json);
    };
}
const proxy = {
    'GET /app/user/profile': fromJSONFile('profile'),
};
module.exports = proxy;

修改URL

axios.get('user/info').then(...)
// 修改URL,加上前缀
axios.get('http://127.0.0.1:8080/' + 'user/info').then(...)

更进一步

经过上面的步骤,mock server已经基本能运行了,但还是有一些不友好。每次需要使用模拟数据时,都要修改项目源码,改写请求的URL,在测试完毕后还得再改回来,如果该请求在源码内有多处地方使用,那改动的地方就多了,比较麻烦。我们可以再进行一些改进。

改进的思路就是开启mock server后,将所有对api服务器的请求都发送到webpack server上,webpack server拦截并处理所有已定义有模拟数据的接口请求,而未定义的接口请求则转发到api服务器上。

上面说的那个项目作者已经合并了我的PR,下面这段可以不用理了,继续用上面那个webpack-api-mocker

首先,我们要对前面用到的那个中间件webpack-api-mocker进行改进,修改后的代码在我的github上,插件主要就一个文件index.js,复制下来直接使用即可。修改了那些内容可以看commit log

然后添加一个新的npm命令dev-mock,定义一个环境变量MOCK来控制是否开启mock server:

"script": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+   "dev-mock": "MOCK=true webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
}

webpack config中当MOCK变量存在时才开启mock server

config = {
  ...
  devServer: {
    if (process.env.MOCK) {
        before(app) {
          apiMocker(app, path.resolve('mock/api.js'), {
            proxy: {
              '/app//*': 'http://api.leaderlegend.com',
            }
          });
        }
    }
  }
  ...
}

为了在代码中使用环境变量MOCK,我们要在webpack config内传递该值。如何传值参考StackOverflow上的这个回答Passing environment-dependent variables in webpack

config = {
    ...
    devServer: ...
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: process.env.NODE_ENV,
                MOCK: process.env.MOCK,
            }
        }),
        ...
    ]
    ...
}

通过判断环境变量MOCK来确定api服务器地址,这里最好保持第一个path相同以更方便转发

const BASE_URL = process.env.MOCK ? 'http://127.0.0.1:8080/app/' : 'http://api.harlanluo.com/app/';

到此为止已经全部完成,需要使用模拟数据时,使用npm run dev-mock命令来运行,,不需要时则使用npm run dev,无需对项目源码对做任何修改。