利用装饰器实现mock和api的局部分离切换

前言

在通常的前端开发中,咱们通常会利用mock产生数据来过渡到正式api实现之间的真空期,当正式api实现后,再把mock地址切换为正式api地址。前端

本文就是利用ES7的装饰器来实现mock和api地址之间的切换。vue

项目背景

  • vue-cli搭建的单页项目
  • axios

核心技术

项目架构

具体实现

以用户登陆为例

  • service 层
...
    async login (params) {
        await Api.member.login(params)
    }
...
复制代码
  • api 层
import axios from 'axios'
...
  // mock api地址,正式api实现以后,将其删除便可
  @Mock({
    method: 'post',
    url: '/members/login'
  })
  async login (params) {
    await axios.post('/members/login', params) #正式api地址
  }
...
复制代码
  • mock装饰器
设置axios的baseURl为/mock
import axios from 'axios'
axios.defaults.baseURL = '/mock'
/** * mock装饰器类的初步实现,未作优化判断 */
function Mock (params) {
  const {method, url} = params

  return function (target, name, descriptor) {
    descriptor.value = async function () {
      const result = await axios({
        method,
        url,
        params: arguments[0]
      })
      return result
    }
    return descriptor
  }
}
export default Mock

复制代码
  • dev代理
利用dev代理将以/mock开头的地址代理到mock服务器
proxyTable: {
      '/mock':{
        target:'http://mock.server.url',
        changeOrigin: true,
        pathRewrite: {
          '^/mock': '/api'
        }
      },
    },
复制代码

其余

  • babel插件
"babel-plugin-transform-decorators-legacy": "^1.3.4",
复制代码
  • 当正式api接口完成后,将mock装饰器删除便可。

升级优化

存在的问题

通过一晚的反复思考,发现上述实现存在一些问题webpack

  • 使用比较繁琐
  • 内部实现不够优雅,本质就是重写了一个api接口。
  • 发布线上版本时,还需手动删除mock装饰器。

优化

因此,针对上述问题作了一些优化。ios

  • api类
// 增长属性
  constructor () {
    this.baseUrl = '/members'
  }
  
  // 修改成
  @Mock()
  async login (params) {
    await axios.post(`${this.baseUrl}/login`, params) #正式api地址
  }
复制代码
  • mock装饰器
return function (target, name, descriptor) {
    // 初始化目标实例
    const targetInstance = new target.constructor()

    //根据环境变量判断并修改实例的baseUrl
    targetInstance.baseUrl = process.env.ENABLE_MOCK === 'true'
      ? `${process.env.MOCK_URL}${targetInstance.baseUrl}`
      : targetInstance.baseUrl

    const oldValue = descriptor.value

    // 目标方法
    descriptor.value = async function () {
      // 执行原方法
      
      const result = await oldValue.apply(targetInstance, arguments)
      return result
    }
    // 返回
    return descriptor
  }
复制代码
  • dev环境变量
// 增长mock配置
  ENABLE_MOCK: '"true"',
  MOCK_URL: '"/mock"'
复制代码

后续展望

  • 研究可否经过webpack打包时,自动去掉装饰器。