简易的 webpack + vue 完成本地化数据 mock

日常业务开发,会频繁请求接口,非常耽误功夫。一个简单的方法是把数据缓存起来,然而我并不想每次提交前还要关心缓存数据是否被移除。

所以,要实现:

  1. 将数据复制到项目文件夹中,名字就叫 apiMock.js,不限文件个数和位置;
  2. 无侵入、不影响打包;

项目环境(重要)

vue-cli3、webapck4

webpack require.context

require.context 是一个非常有用但经常被忽略的 api,可以用它来加载任意模块:

// 1. 获取 src 文件夹下所有的 apiMock.js 文件
const mockDataContext = require.context("@src", true, /apiMock.js$/);

// 2. 获取所有文件的内容,并保存到 mockDataMap 对象中
const mockDataMap = mockDataContext.keys().reduce((map, key) => {
   Object.assign(map, mockDataContext(key).default);
   return map;
}, {});

terser vue-cli3 所用的 js 解析、混淆、压缩器

terser 默认可以删除 unreachable code,譬如,对于如下代码:

var a = 1
if (false) {
  a = 2
}

经过 terser 处理后,if 代码块会被移除,只剩下var a = 1

实施

有了上面的铺垫,实施起来就比价容易了。

首先,在项目最外层文件夹新建 .env.local 文件(它会被 git 忽略),添加:VUE_APP_MOCk=1;

然后,修改 vue.config.js:

...
configureWebpack: {
 plugins: [
   new webpack.DefinePlugin({
     VUE_APP_MOCK: !!process.env.VUE_APP_MOCk
   })
 ]
},
...
```

最后包装项目的 fetch/axios:
````js
import request from "axios";

export const fetch = (() => {
  let requestFlight = request;

  // 全局注入进来的
  if (VUE_APP_MOCK) {
    const mockDataContext = require.context("@src", true, /apiMock.js$/);

    // mockDataMap 包含了所有存在 apiMock.js 文件中的数据
    const mockDataMap = mockDataContext.keys().reduce((map, key) => {
      Object.assign(map, mockDataContext(key).default);
      return map;
    }, {});

    requestFlight = (params, ...args) => {
      // 【注意!!!】
      // 这里会得到本地文件的数据,具体存取策略需要结合项目综合考量
      const data = mockDataMap["r" + params.pid];
      if (!data) return request(params, ...args);

      return new Promise(resolve => {
        setTimeout(() => {
          resolve(data);
        }, 1000);
      });
    };
  }
  return requestFlight;
})();

使用

apiMock.js

export default {
  r4507: {res: {...}}
}
fetch({pid: "4507"})
  .then(res => {
    // res 为本地数据
    console.log(res)
  })
fetch({pid: "4508"})
  .then(res => {
    // 本地没有 4508 的缓存,所以 res 为接口返回的数据
    console.log(res)
  })