前言
在一般的前端开发中,我们一般会利用mock产生数据来过渡到正式api实现之间的真空期,当正式api实现后,再把mock地址切换为正式api地址。
本文就是利用ES7的装饰器来实现mock和api地址之间的切换。
项目背景
- 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装饰器删除即可。
升级优化
存在的问题
经过一晚的反复思考,发现上述实现存在一些问题
- 使用比较繁琐
- 内部实现不够优雅,本质就是重写了一个api接口。
- 发布线上版本时,还需手动删除mock装饰器。
优化
所以,针对上述问题做了一些优化。
- 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打包时,自动去掉装饰器。