基于 Webpack 插件体系的 Mock 服务

前端 | 基于Webpack插件体系的Mock服务.png

背景

在软件研发流程中,对于前后端分离的架构体系而言,为了能够更快速、高效的实现功能的开发,研发团队通常来说会在产品原型阶段对前后端联调的数据接口进行结构设计及约定,进而可以分别同步进行对应功能的实现,提升研发速率。除了常见的研发流程提效之外,对于一些特殊的无法满足前后端联调场景下,也可在条件不允许的情况下进行 Mock 处理,等待条件满足后再进行真实的接口联调,如:网络不通、多地协同等。本文从前端研发过程中的 Mock 需求场景出发,结合前端业界通用的 Webpack 工程化的方案来提供 Mock 服务,以期能够给读者提供一些 Mock 工程化的实现方案借鉴。

架构

对于绝大多数业务开发而言,在目前成熟的生产实践中,前端开发团队仍然是以Webpack作为前端工程打包构建的主流工具。因而,对于前端 Mock 服务的工程化方案而言,前端工程架构基建团队提供适配Webpack体系的插件方案是一个不错的工程基建选择。虽然各方前端团队都以各大框架或者框架生态的脚手架方案进行构建,但大部分现有生态工程打包器底层仍然是以Webpack为主,如:@vue/cliumicreate-react-app等。

对于Webpack插件,其本质是一个类(ps:更准确的说是函数,JavaScript 中没有真正意义上的类),需要在类中定义apply方法,用于通过compiler对象挂载Webpack的事件钩子,该回调中可以获取到当前编译的compilation对象以及异步的callbackWebpack提供了丰富的插件入口,并通过tapable钩子事件系统,串联起整个Webpack钩子函数的生命周期流程。对于 Mock 服务而言,其实现的核心思路是在compiler的钩子watchRun进行 Mock 服务器的启动与监听,其 Mock 服务器可以是基于koa或者express的 node 服务器。

注意:在自定义 Webpack 插件时,Webpack4 和 Webpack5 中的守护进程模式、异步加载、定义全局变量、访问实例对象、事件监听器等方面均有所变化,需要开发者进行相应的兼容处理。

目录

├─ lib                                    // Mock服务的核心包
|   ├─ app.js
|   ├─ utils.js
├─ index.js                               // MockServiceWebpackPlugin插件导出

实践

对于项目工期较紧且某一时间段内无法进行前后端联调的场景下,业务开发下的实践可通过引入mock-service-webpack-plugin的插件进行前端 Mock。由于团队是基于 Vue 全家桶进行的业务开发,故而本实践案例以@vue/cli脚手架方案作为工程基建的底座来对业务中的某一个接口联调进行介绍。

在 Vue 脚手架配置中引入mock-service-webpack-plugin插件,对configureWebpack字段进行配置,代码如下:

const path = require("path");
const resolve = (dir) => path.join(__dirname, dir);const MockServiceWebpackPlugin = require("mock-service-webpack-plugin");const fs = require("fs");const mockUrl = "http://localhost:9009"; // 不要与proxy代理服务端口重合const filterPort = (url) => parseFloat(url.split(":").pop());const plugins = [],proxy = {"/api": {target: "http://localhost:8198", // 不要与mock服务端口重合ws: true,pathRewrite: {"^/api": "",},},};if (process.env.VUE_APP_MOCK) {plugins.push(new MockServiceWebpackPlugin({source: path.resolve(process.cwd(), "./src/mock"),port: filterPort(mockUrl),}));proxy["/mock"] = {target: mockUrl,ws: true,pathRewrite: {"^/mock": "",},};
}module.exports = {// webpack configconfigureWebpack: {plugins,},devServer: {// https: true,// 端口配置historyApiFallback: true,port: 8888,// 反向代理配置proxy,},
};

在项目结构中新建一个目录用于放置相关的 Mock 数据接口,其需要和上述vue.config.js中的 Mock 设置目录相同,结构如下:

├─ src
|   ├─ mock                               // mock目录
|   |    ├─ screenConfig.js
|   ├─ api                                // 真实接口目录
|   |    ├─ BigScreenConfig.js
├─ .env.dev                               // 环境配置
├─ vue.config.js                          // vue cli打包相关配置

注意:通常来说,为了能使用到Webpack的热更新机制,可将 Mock 目录放置到src下的某个目录中

以其中一个大屏自配置的 Mock 接口为例,代码如下:

// src/mock/screenConfig.jsmodule.exports = {path: "/sm/smJsonPnSetting/find",methods: "POST",data: {code: "0",success: true,msg: "成功",data: {settingId: "settingId-16943333",pnId: "pnId-12345678",title: "数字大屏",createTime: "2023-09-15 22:27:05",updateTime: "2023-09-15 22:27:05",isActived: "1",content: {charts: [{timeSize: "m15",edit: false,tabs: [{lineOptions: {chartType: "area",list: ["上传速率(最小)", "下载速率(最小)"],},edit: false,staticTypes: [{kpiEnAlias: "userUprateAvr",staticMethod: "Min",neType: 5104,},{kpiEnAlias: "userDownrateAvr",staticMethod: "Min",neType: 5104,},],title: "图表名称1",},],id: 1,title: "图表01",},],materials: {MaterialResource: {top: 900,left: 1300,},MaterialTimeDimension: {top: 58,left: 1200,},MaterialChangeView: {top: 100,left: 1900,},MaterialTraffic: {top: 900,left: 1600,},MaterialAlarm: {top: 900,left: 700,},MaterialSelectPn: {top: 65,left: 1400,},MaterialCard: {top: 900,left: 1000,},},logo: "cdn/screen/selfScreen3/default_logo.svg",conf: "大屏自配置",title: "数字大屏",layouts: [{draggable: false,y0: 1,x0: 1,y1: 2,x1: 2,id: "1",matchId: 1,content: "LayoutPerformanceIndex",},{draggable: false,y0: 1,x0: 2,y1: 4,x1: 6,id: "2",matchId: "",},{draggable: false,y0: 2,x0: 1,y1: 3,x1: 2,id: "4",matchId: "",},{draggable: false,y0: 3,x0: 1,y1: 4,x1: 2,id: "6",matchId: "",},],bottomTabs: [{itemid: 1,src: "img/traffic.png",checked: false,id: "MaterialTraffic",title: "本月流量",value: 0,},{itemid: 2,src: "img/resource.png",checked: false,id: "MaterialResource",title: "资源概况",value: 514,},{itemid: 6,src: "img/card.png",checked: true,id: "MaterialCard",title: "号卡详情",value: 5,},{itemid: 5,src: "img/alarm.png",checked: false,id: "MaterialAlarm",title: "设备告警",value: 0,},],},smVersion: "4",},},
};

对于是否开启 Mock 服务,可借助脚本通过.env变量进行控制,代码如下:

VUE_APP_MODE=dev
VUE_APP_MOCK=false

而在页面中对 Mock 与真实接口基于环境变量来进行切分,代码如下:

// api.js
import axios from "axios";let BaseAxios = axios.create({timeout: 60000,
});let APIGetFind = async function (params) {return await BaseAxios.post("api" + "/sm/smJsonPnSetting/find", params);
};let MockGetFind = async function (params) {return await BaseAxios.post("mock" + "/sm/smJsonPnSetting/find", params);
};// main.js
Vue.prototype.$mock = process.env.VUE_APP_MOCK;
<script>
import { APIGetFind, MockGetFind } from "@/api/BigScreenConfig";export default {data() {return {settingId: "",};},methods: {async useEffect() {console.log("this.settingId", this.settingId);const res = this.$mock? await MockGetFind({settingId: this.settingId,}): await APIGetFind({settingId: this.settingId,});console.log('res', res);},},
};
</script>

对于package.json中的脚本设置,代码如下:

{"scripts": {"serve": "vue-cli-service serve","serve:dev": "cross-env VUE_APP_MODE=dev npm run serve","serve:dev_mock": "cross-env VUE_APP_MODE=dev VUE_APP_MOCK=true npm run serve"}
}

源码

index.js

Webpack插件mock-service-webpack-plugin的入口,导出MockServiceWebpackPlugin类,使用进程间通信对 Mock 服务器和本地 Web 开发服务器进行响应,代码如下:

const path = require("path");
const fs = require("fs");
const { fork } = require("child_process");
class MockServiceWebpackPlugin {constructor(options) {this.options = options;}apply(compiler) {const { source, port = "9009" } = this.options;if (!source) {console.error(`Mock Directory did not exist. Please make sure your Mock Source Directory`);if (!fs.existsSync(source))console.error(`${source} did not exist. Please make sure your Source is Correct`);}let child;child = fork(path.resolve(__dirname, "./lib/app.js"), [], {encoding: "utf8",execArgv: process.execArgv,});child.send({ source, port });compiler.hooks.watchRun.tapAsync("MockServiceWebpackPlugin",(compilation, callback) => {console.log("compiler watching...");fs.watch(source, { recursive: true }, (eventType, filename) => {console.log("eventType:", eventType, "filename:", filename);child.kill("SIGKILL");child = fork(path.resolve(__dirname, "./lib/app.js"), [], {encoding: "utf8",execArgv: process.execArgv,});child.send({ source, port });});callback();});}
}module.exports = MockServiceWebpackPlugin;

lib

app.js

app.js是基于express启动的 Mock 服务器,也是实现 Mock 服务路由的核心,代码如下:

const express = require("express");
const bodyParser = require("body-parser");
const fs = require("fs");
const path = require("path");
const app = express();
const router = express.Router();const { createRoutes } = require("./utils");app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false,})
);process.on("message", ({ source, port }) => {console.log(`Options get From Parents`, source, port);createRoutes(router, source);app.use(router);app.listen(port, () => {console.log(`Mock Server Listen ${port} is Running`);});
});
utils.js

utils.js主要用于 HTTP 请求的相关处理,基于用户的 Mock 服务的 options 进行相应的路由动态生成,代码如下:

const fs = require("fs");
const path = require("path");const METHODS_MAP = {POST: "post",GET: "get",DELETE: "delete",PUT: "put",
};const createRoutes = (router, p) => {const stats = fs.statSync(p);if (stats.isDirectory()) {fs.readdirSync(p).forEach((item) => {createRoutes(router, `${p}/${item}`);});} else if (stats.isFile()) {const { path, methods, data } = require(`${p}`);if (!methods)console.error(`Methods did not exist. Please make sure your method is one of ${Object.keys(METHODS_MAP).join(" ")}`);if (!data)console.error(`Data did not exists. Please make sure your data is correct`);router[METHODS_MAP[`${methods}`]](path, (req, res) => {res.json(data);});}
};module.exports = {createRoutes,
};

总结

除了基于 Webpack 的前端工程化构建,对于RollupVite以及Gulp等其他前端打包构建工具也是现代化前端工程团队需要纳入考虑的工程基建范畴。对于完整的 Mock 服务,也可提供平台服务、IDE 插件等形式来帮助业务团队更好的提升效率及开发体验,工具从来都是服务的承载形式,重要的不是功能本身,而是体验带来的效率优化。

对于前端工程化而言,Mock 服务仅仅是开发流程中的一环,面对日益增加的成本及业务压力,如何有效的提升效率,实现工程效率才是前端工程师应该考虑的重中之重。不仅仅在于企业效益的间接贡献,更重要的是前端工程化实践也是平台工程乃至软件工程方向的重要组成部分,所有的工程能力的提升都是工程师应该一直致力于培养的重要能力,共勉!!!

ps: 最后,对于mock-service-webpack-plugin的实现感到不错的同学,欢迎点个小小的 star,您的 star,是我们最大的动力~~~

参考

  • Webpack 钩子函数
  • webpack 的自定义插件学习
  • 学 webpack 前先看看 tapable 吧
  • Webpack HMR 原理解析
  • Webpack 原理浅析
  • 前端该如何优雅地 Mock 数据
  • 详解如何优雅在 webpack 项目实现 mock 服务器
  • mock 服务搭建
  • Webpack 实战:本地 mock 开发模式实践
  • 基于 webpack-dev-server 搭建 mock 服务
  • 编写 webpack 插件-webpack-mock-service-plugin
  • 【webpack 插件篇】webpack-plugin-mock 一款 mockjs 的 webpack 插件,配置简单、易用
  • 从零开始搭建一个 mock 服务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/241565.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习 | 基础卷积神经网络

卷积神经网络是人脸识别、自动驾驶汽车等大多数计算机视觉应用的支柱。可以认为是一种特殊的神经网络架构&#xff0c;其中基本的矩阵乘法运算被卷积运算取代&#xff0c;专门处理具有网格状拓扑结构的数据。 1、全连接层的问题 1.1、全连接层的问题 “全连接层”的特点是每个…

kubernetes集群 应用实践 kafka部署

kubernetes集群 应用实践 kafka部署 零.1、环境说明 零.2、kafka架构说明 zookeeper在kafka集群中的作用 一、Broker注册 二、Topic注册 三、Topic Partition选主 四、生产者负载均衡 五、消费者负载均衡 一、持久化存储资源准备 1.1 创建共享目录 [rootnfsserver ~]# mkdir -…

锯齿云服务器租赁使用教程

首先登陆锯齿云账号 网盘上传数据集与代码 随后我们需要做的是将所需要的数据集与代码上传到网盘&#xff08;也可以直接在租用服务器后将数据集与代码传到服务器的硬盘上&#xff0c;但这样做会消耗大量时间&#xff0c;造成资源浪费&#xff09; 点击工作空间&#xff1a;…

谷粒商城-商品服务-新增商品功能开发(商品图片无法展示问题没有解决)

在网关配置路由 - id: member_routeuri: lb://gulimemberpredicates:- Path/api/gulimember/**filters:- RewritePath/api/(?<segment>.*),/$\{segment}并将所有逆向生成的工程调式出来 获取分类关联的品牌 例如&#xff1a;手机&#xff08;分类&#xff09;-> 品…

Python算法例26 落单的数Ⅳ

1. 问题描述 给定数组&#xff0c;除了一个数出现一次外&#xff0c;所有数都出现两次&#xff0c;并且所有出现两次的数都挨着&#xff0c;找出出现一次的数。 2. 问题示例 给出nums[3&#xff0c;3&#xff0c;2&#xff0c;2&#xff0c;4&#xff0c;5&#xff0c;5]&am…

ZooKeeper 使用介绍和原理详解

目录 1. 介绍 重要性 应用场景 2. ZooKeeper 架构 服务角色 数据模型 工作原理 3. 安装和配置 下载 ZooKeeper 安装和配置 启动 ZooKeeper 验证和管理 停止和关闭 4. ZooKeeper 数据模型 数据结构和层次命名空间&#xff1a; 节点类型和 Watcher 机制&#xff…

基于python的excel检查和读写软件

软件版本&#xff1a;python3.6 窗口和界面gui代码&#xff1a; class mygui:def _init_(self):passdef run(self):root Tkinter.Tk()root.title(ExcelRun)max_w, max_h root.maxsize()root.geometry(f500x500{int((max_w - 500) / 2)}{int((max_h - 300) / 2)}) # 居中显示…

【MySQL】MySQL的数据类型

MySQL的数据类型 一、数据类型分类二、数值类型1、整数类型2、bit类型3、小数类型 三、字符串类型四、时间日期类型五、enum和set类型enum和set查找 数据类型的作用&#xff1a; 决定了存储数据时应该开辟的空间大小和数据的取值范围。决定了如何识别一个特定的二进制序列。 …

AI创作系统ChatGPT系统源码,支持Midjourney绘画,GPT语音对话+DALL-E3文生图

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

R语言基础 | 安徽某高校《统计建模与R软件》期末复习

第一节 数字、字符与向量 1.1 向量的赋值 c<-(1,2,3,4,5) 1.2 向量的运算 对于向量&#xff0c;我们可以直接对其作加&#xff08;&#xff09;&#xff0c;减&#xff08;-&#xff09;&#xff0c;乘&#xff08;*&#xff09;&#xff0c;除&#xff08;/&#xff09…

【shell脚本实战学习笔记】#1

shell脚本实战学习笔记#1 脚本编写场景需求&#xff1a; 编写一个比较数据大小的shell脚本&#xff0c;要求判断用户只能输入两位数字&#xff0c;不能是字符或其他特殊字符&#xff1b;并且在shell脚本中需要用到函数来控制执行顺序。 知识点&#xff1a;shell函数&#xff…

科研学习|论文解读——面向电商内容安全风险管控的协同过滤推荐算法研究

【论文完整内容详见知网链接】&#xff1a; 面向电商内容安全风险管控的协同过滤推荐算法研究 - 中国知网 (cnki.net) 面向电商内容安全风险管控的协同过滤推荐算法研究* 摘 要&#xff1a;[目的/意义]随着电商平台商家入驻要求降低以及商品上线审核流程简化&#xff0c;内容安…

Centos安装vsftpd:centos配置vsftpd,ftp报200和227错误

一、centos下载安装vsftpd&#xff08;root权限&#xff09; 1、下载安装 yum -y install vsftpd 2、vsftpd的配置文件 /etc/vsftpd.conf 3、备份原来的配置文件 sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.backup 4、修改配置文件如下&#xff1a;vi /etc/vsftpd.conf …

体验一下 CodeGPT 插件

体验一下 CodeGPT 插件 0. 背景1. CodeGPT 插件安装2. CodeGPT 插件基本配置3. (可选)CodeGPT 插件预制提示词原始配置(英文)4. CodeGPT 插件预制提示词配置(中文)5. 简单验证一下 0. 背景 看到B站Up主 “wwwzhouhui” 一个关于 CodeGPT 的视频&#xff0c;感觉挺有意思&#…

SpringMVC:整合 SSM 中篇

文章目录 SpringMVC - 04整合 SSM 中篇一、优化二、总结三、说明注意&#xff1a; SpringMVC - 04 整合 SSM 中篇 一、优化 在 spring-dao.xml 中配置 dao 接口扫描&#xff0c;可以动态地实现 dao 接口注入到 Spring 容器中。 优化前&#xff1a;手动创建 SqlSessionTempl…

STM32实现三个小灯亮

led.c #include"led.h"void Led_Init(void) {GPIO_InitTypeDef GPIO_VALUE; //???RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//???GPIO_VALUE.GPIO_ModeGPIO_Mode_Out_PP;//???? ????GPIO_VALUE.GPIO_PinGPIO_Pin_1|GPIO_Pin_2|GPIO_P…

spring-validation实现分组校验

文章目录 前言实际开发可能会使用到分组校验maven添加依赖简单使用高级应用分组自定义分组组合分组 源码地址 前言 JSR 303中提出了Bean Validation&#xff0c;表示JavaBean的校验&#xff0c;Hibernate Validation是其具体实现&#xff0c;并对其进行了一些扩展&#xff0c;…

Arduino上U8g2库显示中文的经历

u8g2自带很多中文库&#xff1b;但是向u8g2_font_wqy12_t_chinese3 比较全的应该是u8g2_font_wqy12_t_gb2312 这个&#xff0c;只是我还没有调用成功 这个库&#xff0c;中文就显示不全&#xff1b;有些没有定义&#xff0c;如百家姓 #include <Arduino.h> #include <…

Java经典框架之Spring

Java经典框架之Spring Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring简介 2.…

HA启动Advanced SSH Web Terminal 提示附加组件似乎尚未准备就绪,它可能仍在启动。是否要再试一次?

环境&#xff1a; Home Assistant OS11.1 Advanced SSH & Web Terminal 17.0 问题描述&#xff1a; HA安装好SSH加载项&#xff0c;启动Advanced SSH & Web Terminal 提示附加组件似乎尚未准备就绪&#xff0c;它可能仍在启动。是否要再试一次&#xff1f; 解决方案…