前言
在一般的前端开发中,我们一般会利用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打包时,自动去掉装饰器。