记一次前端Vue3+Vite+TS项目中使用Mock.js + vite-plugin-mock插件发布到生产(线上)环境填坑汇总

该文章已生成可运行项目,

一、关于 Mock 数据

Mock:在前端开发中通常指模拟后端接口和数据。

开发过程中,一般都是前后端同时开发,尤其是某些后台系统开发时,很多前端同学分分钟就可以做完静态页面的开发,然后就是摸鱼时间,等待后端的接口。如果你的后端同事非常配合,愿意在设计数据库的时候顺便定好返回的数据结构和字段,并且联调时间很紧张的时候,这时候你应该考虑着手去做一下前端 mock,为联调争取时间。

Mock 优点

  1. 简单: 不需要复杂的配置和部署过程,可以快速地创建和管理模拟数据;
  2. 灵活: 可以满足不同的开发需求,例如支持不同的请求类型、不同的请求方式等;
  3. 真实: 能够生成更接近真实的数据,可以模拟不同的数据类型、格式和结构;
  4. 可维护: 可以方便地更新和修改模拟数据;
  5. 共享: 可以在团队内方便的共享模拟数据。

二、Mock 数据使用

1. 安装依赖 mockjs、vite-plugin-mock

vite 的数据模拟插件,是基于 vite.js 开发的。 支持本地环境和生产环境服务。

npm i mockjs vite-plugin-mock --save-dev

2. vite.config.ts 文件中配置

// vite.config.ts
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'

export default defineConfig(({ command }) => {
  return {
  	// 插件
    plugins: [
      viteMockServe({
        mockPath: "./mock/", // 目录位置
        logger: true, //  是否在控制台显示请求日志
        supportTs: true, // 是否读取ts文件模块
        localEnabled: env.VITE_APP_OPEN_MOCK === "true", // 设置是否启用本地mock文件
        prodEnabled: env.VITE_APP_OPEN_MOCK === "true", // 设置打包是否启用mock功能
        // 这样可以控制关闭mock的时候不让mock打包到最终代码内
        injectCode: `
            import { setupProdMockServer } from './mockProdServer';
            setupProdMockServer();
        `
      }),
    ],
    // 省略其它配置...
  }
})

3. 开发环境使用

  1. 在根目录下创建 mock 文件夹,用于存放本地 mock 文件,内部创建 user.ts

    // mock/user.ts
    
    const createUserList = () => {
        return [
            {
                userId: 1,
                avatar: 'https://pic1.zhimg.com/80/v2-083faf550543c1e9f134b56b3322ee3c_720w.webp',
                username: 'admin',
                password: '123456789',
                desc: '下船不谈船里事',
                roles: ['平台管理员'],
                buttons: ['cuser.detail'],
                routes: ['home'],
                token: 'Admin Token'
            },
            {
                userId: 2,
                avatar: 'https://pic1.zhimg.com/80/v2-e1427f6a21122ac163ff98d24f55d372_720w.webp',
                username: 'system',
                password: '123456789',
                desc: '旧人不谈近况,新人不讲过往',
                roles: ['系统管理员'],
                buttons: ['cuser.detail', 'cuser.user'],
                routes: ['home'],
                token: 'Admin Token'
            }
        ]
    }
    export default [
        // 获取用户信息接口
        {
            url: '/api/user/info',
            method: 'get',
            response: (request: any) => {
                // 获取请求头携带的 token
                const token = request.headers.token
                // 查看用户信息数据中是否包含有此 token 的用户
                const checkUser = createUserList().find((item) => item.token === token)
                // 没有就返回失败信息
                if (!checkUser) {
                    return {
                        code: 201,
                        data: {
                            message: '获取用户信息失败'
                        }
                    }
                }
                // 有就返回成功信息
                return {
                    code: 200,
                    data: {
                        checkUser
                    }
                }
            }
        }
    ]
    
  2. src文件夹下新建 utils/request.ts

    // utils/request.ts
    import axios from "axios";
    
    //创建一个axios实例
    const request = axios.create({
        baseURL: '/api',
        timeout: 20000,
    });
    
    
    // 添加请求拦截器
    request.interceptors.request.use(
        function (config) {
            // 请求地址携带时间戳
            const _t = new Date().getTime()
            config.url += `?${_t}`
            
            // 请求头携带token
            config.headers['token'] = localStorage.getItem('token') || ''
    
            // 在发送请求之前做些什么
            // console.log('我要准备请求啦------')
            // console.log(config, '请求配置')
            
            return config;
        },
        function (error) {
            // 对请求错误做些什么
            return Promise.reject(error);
        }
    );
    
    // 添加响应拦截器
    request.interceptors.response.use(
        function (response) {
            // 对响应数据做点什么
            // console.log('我接收到响应数据啦------')
            // console.log(response, '响应配置')
            if (response.status === 200) {
                return Promise.resolve(response.data)
            } else {
                return Promise.reject(response)
            }
        },
        function (error) {
            // 对响应错误做点什么
            if (error && error.response) {
                switch (error.response.status) {
                    case 400:
                        error.message = '错误请求';
                        break;
                    case 401:
                        error.message = '未授权,请重新登录';
                        break;
                    case 403:
                        error.message = '拒绝访问';
                        break;
                    case 404:
                        error.message = '请求错误,未找到该资源';
                        break;
                    case 405:
                        error.message = '请求方法未允许';
                        break;
                    case 408:
                        error.message = '请求超时';
                        break;
                    case 500:
                        error.message = '服务器端出错';
                        break;
                    case 501:
                        error.message = '网络未实现';
                        break;
                    case 502:
                        error.message = '网络错误';
                        break;
                    case 503:
                        error.message = '服务不可用';
                        break;
                    case 504:
                        error.message = '网络超时';
                        break;
                    case 505:
                        error.message = 'http版本不支持该请求';
                        break;
                    default:
                        error.message = `未知错误${error.response.status}`;
                }
            } else {
                error.message = "连接到服务器失败";
            }
            return Promise.reject(error);
        }
    );
    
    /*
     *  get请求:从服务器端获取数据
     *  url:请求地址
     *  params:参数
     * */
    export function get(url:string, params = {}) {
        return new Promise((resolve, reject) => {
            request({
                url: url,
                method: 'get',
                params: params
            }).then(response => {
                resolve(response);
            }).catch(error => {
                reject(error);
            });
        });
    }
    
    /*
     *  post请求:向服务器端提交数据
     *  url:请求地址
     *  params:参数
     * */
    export function post(url:string, params = {}) {
        return new Promise((resolve, reject) => {
            request({
                url: url,
                method: 'post',
                data: params
            }).then(response => {
                resolve(response);
            }).catch(error => {
                reject(error);
            });
        });
    }
    
    // 对外暴露请求方法
    export default {
        get,
        post
    }
    
  3. src文件夹下新建 api/user.ts

    // api/user.ts
    
    import { get, post } from './request';
    
    const api = {
        users: '/api/user/info'
    }
    
    //获取用户信息
    export const getUserInfo = () => {
        const token = localStorage.getItem('token');
        if (!token) return Promise.reject(new Error('用户未登录'));
        return get(api.users);
    }
    
  4. 业务使用

    // App.vue
    import { onBeforeMount } from 'vue'
    import { getUserInfo } from "./api/user"
    
    onBeforeMount(async () => {
      // 获取用户信息
      const users = await getUserInfo()
      console.log(users)
    })
    

三、在生产(线上)环境中的使用(填坑)

1. 配置 vite.config.ts

// vite.config.ts
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'

export default defineConfig(({ command }) => {
  return {
  	// 插件
    plugins: [
      viteMockServe({
        mockPath: "./mock/", // 目录位置
        logger: true, //  是否在控制台显示请求日志
        supportTs: true, // 是否读取ts文件模块
        localEnabled: env.VITE_APP_OPEN_MOCK === "true", // 设置是否启用本地mock文件
        prodEnabled: env.VITE_APP_OPEN_MOCK === "true", // 设置打包是否启用mock功能
        // 这样可以控制关闭mock的时候不让mock打包到最终代码内
        injectCode: `
            import { setupProdMockServer } from './mockProdServer';
            setupProdMockServer();
        `
      }),
    ],
    // 省略其它配置...
  }
})

填坑一、prodEnabled需要配置成true才能在生产环境打包mock

2. 创建 mockProdServer.ts 文件

在根目录下新建文件 mockProdServer.ts

// mockProdServer.ts
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';

// 导入所有的 mock 模块
const modules = import.meta.globEager('./mock/*.ts');
const mockModules: any[] = [];

Object.keys(modules).forEach((key) => {
  if (key.includes('/_')) {
    return;
  }
  mockModules.push(...modules[key].default);
});

export function setupProdMockServer() {
  createProdMockServer(mockModules);
}
填坑二、 这里 import.meta.globEager() 引入的文件路径可以使用通配符,需要注意书写格式,要能够成功引入这些ts才行,引入不成功,也不会报错,打包后在生产环境非常难以debug

3. main.ts 中引用上面这个模块的 setupProdMockServer() 并调用

// src/main.ts
import { setupProdMockServer } from '../mockProdServer'
setupProdMockServer()
填坑三、这里一定要调用否则发布到生产的时候就无法访问接口,接口会返回405,404的错误

4. 打包

"scripts":{
    "build:pro": "vite build --mode pro"
}
填坑四、通过本地打开会出现空白页面的情况,是因为里面接口或者文件返回会出现跨域。构建完成后可以通过vscode中的LiveServer这个扩展打开,或者通过 npx serve dist 打开
填坑五、调用接口的时候控制台的NetWork中无法看到,这是因为这里没有真正的服务器的,是通过mockjs对接口进行拦截处理的。 但是 如果mockjs在生产环境没有打包好,或者上面的配置有问题的话,则会正常调用接口,并且会报405,404的错误,因为mock拦截没成功,请求正常触发找不到资源就会报错
本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八了个戒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值