背景介绍
在我们平常开发过程中,我们项目多数是前后端分离的项目,就需要和服务进行前后联调,需要服务给接口文档,然后我们再根据给的结构文档mock数据,在这之前呢我都是直接在页面中写死数据来进行模拟的,这不最近看了vite-plugin-mock这个插件。
插件功能介绍
vite-plugin-mock 是vbean团队开发的一个插件,目的就是在开发时拦截发送的请求,然后返回模拟的数据。用法就是 pnpm add vite-plugin-vite mockjs 两个库,vite-plugin-mock是强依赖mockjs库的。然后配置vite.config.js文件,然后在指定的mock文件夹下进行api的编写。
- 配置vite.config.js文件
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { viteMockServe } from 'vite-plugin-mock';
// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
console.log('command, mode:', command, mode);
return {
plugins: [
vue(),
ViteAliases({
prefix: '@',
}),
viteMockServe({ // vite-plugin-mock的配置项
mockPath: 'mock',
enable: true,
}),
],
};
});
viteMockServe 参数如下:
其中常用的就是mockPath和ignore,两个的默认值分别是mockPath='mock', ignore=true
{
mockPath?: string; //mock的文件夹路径
ignore?: RegExp | ((fileName: string) => boolean); //自动读取模拟.ts文件时,忽略指定格式的文件
watchFiles?: boolean;//设置是否监视 mock .ts 文件中的更改
enable?: boolean;//是否开启模拟
ignoreFiles?: string[];
configPath?: string;
}
2. 在创建mockPath指定的js文件(user.js),是相对于当前项目根目录的哈,然后在user.js中模拟网络请求,返回数据即可。
export default [
{
url: '/api/createUser',
method: 'post',
response: (req, res) => {
console.log('body>>>>>>>>', req);
return {
code: 0,
message: 'ok',
data: null,
};
},
},
];
- 运行网络进行请求该地址数据,最终得到模拟数据。当然在user.js文件中也可以使用mockjs来进行数据的创建。
插件原理介绍
- 直接请求
axios.get('/api/createUser')是会请求开发服务器的地址的,即:http://localhost:5174/api/createUser,如果没有匹配上的就返回当前根地址页面。 - 插件进行拦截开发服务器的请求,然后将mockPath下创建的模拟请求数据读取,然后进行匹配,如果有匹配上的就返回对应的数据,没用就返回默认内容。
插件复现
在完成插件复现之前我们要理清楚完成这个插件需要做哪些准备:
- 我们需要一个
函数/api去匹配开发服务器发送的请求。所以我们需要了解vite 插件api:configureServer用于配置开发服务器的钩子。 - 我们需要在插件中实现动态js文件的导入。导入mock目录(mockPath指定的路径)下的js文件。
- 重新熟悉 fs、path模块。
configureServer 函数 插件 API | Vite 官方中文文档
是用于配置开发服务器的钩子。最常见的用例是在内部 connect 应用程序中添加自定义中间件:
// 写法一
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 自定义请求处理...
})
},
})
//写法二
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
// 返回一个在内部中间件安装后
// 被调用的后置钩子
return () => {
server.middlewares.use((req, res, next) => {
// 自定义请求处理...
})
}
},
})
其中server.middlewares.use函数类似于express/koa中的中间件,参数也是req、res、next。
复现代码
import fs from 'fs';
import path from 'path';
import { pathToFileURL } from 'url';
export default function customMockPlugin(options = {}) {
const { enable = true, mockPath = 'mock' } = options;
return {
name: 'vite-plugin-custom-mock',
async configureServer(server) {
if (!enable) return; // 如果插件禁用,直接返回
// 加载 mock 数据
const mockData = await loadMockData(mockPath);
if (mockData.length === 0) {
console.warn('[vite-plugin-custom-mock] 没有找到 mock 数据');
return;
}
// 拦截请求
server.middlewares.use((req, res, next) => {
const url = req.url.split('?')[0]; // 去掉查询参数
const method = req.method.toLowerCase();
// 查找匹配的 mock 数据
const mock = mockData.find(
item => item.url === url && item.method === method
);
if (mock) {
console.log(`[vite-plugin-custom-mock] 拦截请求: ${method} ${url}`);
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(mock.response(req, res)));
return;
}
next(); // 如果没有匹配的 mock 数据,继续下一个中间件
});
},
};
}
// 加载 mock 数据
async function loadMockData(mockPath) {
const mockDir = path.resolve(process.cwd(), mockPath);
if (!fs.existsSync(mockDir)) {
console.warn(`[vite-plugin-custom-mock] mock 文件夹不存在: ${mockDir}`);
return [];
}
const mockFiles = fs
.readdirSync(mockDir)
.filter(file => file.endsWith('.js'));
const mockData = [];
for (const file of mockFiles) {
const filePath = path.join(mockDir, file);
const fileUrl = pathToFileURL(filePath).href; // 转换为 file: 协议的 URL
const module = await import(fileUrl); // 动态引入
mockData.push(module.default);
}
return mockData.flat(Infinity);
}
上述代码实现的原理就是在指定的mockPath下将请求的api地址和模拟的数据进行匹配,如果匹配到了就调用其response函数,返回数据。具体项目工程截图如下:
上图是大概的内容,然后再ViteMock函数中就是复现的代码了,就是上面的
ViteMock.js代码片段。我的这个插件是写在plugins目录下的,在vite.config.js文件中啊需要将其引入哦。
知识点总结
- fs模块:
- existsSync函数:是一个同步函数,返回boolean。判断一个路径是否存在。
- readdirSync函数:是一个同步函数,返回一个数组。返回文件夹下的内容(文件和文件夹)
- path模块:
- resolve函数:是一个地址路径拼接函数,功能类似于linux中的cd命令。
- join函数:是一个地址路径拼接函数,就是一个简单的拼接地址的函数(类似于字符串的拼接)。
- url对象:
- pathToFileURL函数(非常有用):是 Node.js 提供的一个工具函数,用于将文件路径转换为
file:协议的 URL。它在处理文件路径时非常有用,尤其是在需要将路径传递给支持 URL 的 API(如import())时。- 例子(
动态加载项目本地文件):
import { pathToFileURL } from 'url'; import path from 'path'; async function loadFile() { const filePath = path.resolve(process.cwd(), 'src', 'example.js'); // 解析为绝对路径 const fileUrl = pathToFileURL(filePath).href; // 转换为 file: 协议的 URL const module = await import(fileUrl); // 动态引入 console.log(module.default.message); // 输出: Hello from example.js! } loadFile(); - 例子(
- pathToFileURL函数(非常有用):是 Node.js 提供的一个工具函数,用于将文件路径转换为
- process.cwd() 函数:返回当前执行进程的目录(即项目的根目录),在写第三方插件的时候推荐用这个路径。
- configureServer函数:用于配置配置开发服务器的钩子函数。