vue3 vite mock实践
前段时间在将两个不同的业务分支合并时(可参考一套vue代码根据环境变量实现不同环境功能定制化——案例分享),发现mock文件夹下面有大量差异的json内容,看了一眼提交记录为21
年,最近这两年该文件夹内容都没有变更。
查寻资料发现mock是用于前端模拟后端响应,往往用于前后端分离开发,前端和后端并行开发用。
考虑团队从22
年开始就强推全栈开发,往往一个人包揽前后端开发,平时调试时一般直接调用本地接口或线上测试环境接口,或许前端的mock功能渐渐就被弃用了。
考虑到最近几篇博客围绕的前端项目hello_vue3都会涉及到后端接口的调用(见vue3配置代理实现axios请求本地接口返回PG库数据【前后端实操】),读者还需要维护一个本地后端,比较繁琐,计划引入mock技术,对于部分页面提供调用mock和本地接口开关
,实现单纯前端也能进行初步调试,本文主要说明vue3 + vite + ts 环境下mock搭建、使用、以及遇到的问题 。
效果showCase
代码仓
https://gitee.com/pinetree-cpu/hello_vue3
mock环境搭建
安装依赖
npm install vite-plugin-mock mockjs --save-dev
# 或者
yarn add vite-plugin-mock mockjs -D
配置 vite.config.ts
关注viteMockServe()
内部配置
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import { viteMockServe } from 'vite-plugin-mock'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
viteMockServe({
mockPath: 'src/mock', // mock文件存放目录
enable: true,
logger: true, // 是否在控制台显示请求日志
watchFiles: true // 监视文件更改
})
],
server: {
proxy: {
'/asset': { // 以 '/asset' 开头的请求会被代理
target: 'http://localhost:8888', // 后端服务器地址
changeOrigin: true, // 允许跨域
rewrite: (path) => path.replace(/^\/asset/, '') // 重写路径,去掉 '/asset'
}
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
创建mock文件
在项目根目录下创建 mock 文件夹,创建assetInfo_mock.ts
,本文主要mockvue3配置代理实现axios请求本地接口返回PG库数据【前后端实操】)中的资产信息
定义mock VO类型
在src/types/index.ts
中添加
// mock资产表单
export interface MockAssetFormData {
assetNumber: string;
assetStatus: string;
extAttribute1: string;
extAttribute2: string;
extAttribute3: string;
extAttribute4: string;
extAttribute5: string;
extAttribute6: string;
extAttribute7: string;
extAttribute8: string;
extAttribute9: string;
extAttribute10: string;
bizId: string;
}
// 响应VO
export interface ResultVO<T = any> {
code: number;
isSuccess: boolean;
message: String;
data: T;
}
定义mock数据响应逻辑逻辑
import { MockMethod } from 'vite-plugin-mock'
import type { MockAssetFormData, ResultVO} from "@/types";
const assetInfoMockList: MockAssetFormData[] = [
{
"bizId": "0777c40218114c35a29b0d4d84355668",
"assetNumber": "0777c40218114c35a29b0d4d8435520e",
"assetStatus": "10",
"extAttribute1": "mock_ext_attribute1",
"extAttribute2": "mock_ext_attribute2",
"extAttribute3": "mock_ext_attribute3",
"extAttribute4": "mock_ext_attribute4",
"extAttribute5": "mock_ext_attribute5",
"extAttribute6": "mock_ext_attribute6",
"extAttribute7": "mock_ext_attribute7",
"extAttribute8": "mock_ext_attribute8",
"extAttribute9": "mock_ext_attribute9",
"extAttribute10": "mock_ext_attribute10",
},
{
"bizId": "0777c40218114c35a29b0d4d84355668",
"assetNumber": "2d72bf99ebcad018297aed761b5dee8d",
"assetStatus": "10",
"extAttribute1": "mock_ext_attribute1",
"extAttribute2": "mock_ext_attribute2",
"extAttribute3": "mock_ext_attribute3",
"extAttribute4": "mock_ext_attribute4",
"extAttribute5": "mock_ext_attribute5",
"extAttribute6": "mock_ext_attribute6",
"extAttribute7": "mock_ext_attribute7",
"extAttribute8": "mock_ext_attribute8",
"extAttribute9": "mock_ext_attribute9",
"extAttribute10": "mock_ext_attribute10",
},
{
"bizId": "0777c40218114c35a29b0d4d84355998",
"assetNumber": "good-giao",
"assetStatus": "10",
"extAttribute1": "mock_ext_attribute1",
"extAttribute2": "mock_ext_attribute2",
"extAttribute3": "mock_ext_attribute3",
"extAttribute4": "mock_ext_attribute4",
"extAttribute5": "mock_ext_attribute5",
"extAttribute6": "mock_ext_attribute6",
"extAttribute7": "mock_ext_attribute7",
"extAttribute8": "mock_ext_attribute8",
"extAttribute9": "mock_ext_attribute9",
"extAttribute10": "mock_ext_attribute10",
}
]
export default [
{
url: '/mock/asset/assetInfo',
method: 'post',
response: (body): ResultVO<Map<String, Array<MockAssetFormData>>> => {
console.log('body', body)
const bizId = body.body.bizId
console.log('bizId', bizId)
const matchAssetInfo = assetInfoMockList.filter(item => item.bizId === bizId)
const dataMap = new Map<String, Array<MockAssetFormData>>
dataMap.set('assetInfoList', matchAssetInfo)
console.log('dataMap', dataMap)
const dataObj = Object.fromEntries(dataMap)
console.log('dataObj', dataObj)
return {
code: matchAssetInfo.length > 0 ? 300 : 404,
data: dataObj,
isSuccess: matchAssetInfo.length > 0,
message: matchAssetInfo.length > 0 ? 'success' : 'asset not found'
}
}
}
] as MockMethod[]
请求mock数据
// 请求mock数据
await axios.post('/mock/asset/assetInfo', { bizId }).then(result => {
const assetInfoList: Array<AssetFormData> = result?.data?.data?.assetInfoList
console.log('assetInfoList', assetInfoList)
tabs.value = []
assetInfoList.forEach((asset, idx) => {
const newTabName = `表单 ${idx + 1}`
tabs.value.push({
label: newTabName,
name: newTabName,
insertForm: asset
})
activeTab.value = newTabName
})
})
遇到的问题汇总
mock里面console.log和debugger没有效果
例如下方代码块内容,不会在浏览器控制台输出
export default [
{
url: '/mock/asset/assetInfo',
method: 'post',
response: (body): ResultVO<Map<String, Array<MockAssetFormData>>> => {
console.log('body', body)
const bizId = body.body.bizId
console.log('bizId', bizId)
const matchAssetInfo = assetInfoMockList.filter(item => item.bizId === bizId)
const dataMap = new Map<String, Array<MockAssetFormData>>
dataMap.set('assetInfoList', matchAssetInfo)
console.log('dataMap', dataMap)
const dataObj = Object.fromEntries(dataMap)
console.log('dataObj', dataObj)
return {
code: matchAssetInfo.length > 0 ? 300 : 404,
data: dataObj,
isSuccess: matchAssetInfo.length > 0,
message: matchAssetInfo.length > 0 ? 'success' : 'asset not found'
}
}
}
] as MockMethod[]
问题根因:
Mock 代码通常运行在 Node.js 环境或特殊的中间件层,而不是浏览器上下文
表现:
console.log 输出会出现在终端/服务器日志中,而不是浏览器控制台
debugger 语句在服务端环境中无法触发浏览器调试器
解决措施:
在Node终端查看
返回Map对象时为空
根据bizId成功获取到matchAssetInfo
后,计划按照后端接口返回的格式进行组装成dataMap
,console.log显示存在数据,但是返回的data
为一个空对象
问题根因:
Map不是JSON原生支持的数据类型,序列化时会丢失其特殊结构
Map键可以是任意类型(对象、函数等),而 JSON 只支持字符串键
解决措施:
使用Object.fromEntries() 将一个键值对列表(entries)转换成一个普通对象
const dataMap = new Map<String, Array<MockAssetFormData>>
dataMap.set('assetInfoList', matchAssetInfo)
console.log('dataMap', dataMap)
const dataObj = Object.fromEntries(dataMap)
console.log('dataObj', dataObj)
return {
code: matchAssetInfo.length > 0 ? 300 : 404,
data: dataObj,
isSuccess: matchAssetInfo.length > 0,
message: matchAssetInfo.length > 0 ? 'success' : 'asset not found'
}
本文转成dataObj进行返回,能够正常返回Map数据
总结
mock技术把请求后端接口返回json数据调整成请求mock服务返回json数据,mock服务返回的数据一般个人或团队内部维护,能够提高开发效率、避免对外部接口的依赖阻塞开发进度。也存在一些不足:如测试数据存在局限性,不能全面反应出真实的数据、维护成本的增加,若调用外部接口调整了,相应的mock规则也需要跟着调整。