基于 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.rhkb.cn/news/226942.html

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

相关文章

WPF+Halcon 培训项目实战(8):WPF+Halcon初次开发

前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只做笔记分享&#xff0c;想要源码或者教学视频可以和他联系一下。 相关链接 微软系列技术教程 WPF 年度公益课程 Halcon开发 CSD…

uniapp中uview组件库丰富的Calendar 日历用法

目录 基本使用 #日历模式 #单个日期模式 #多个日期模式 #日期范围模式 #自定义主题颜色 #自定义文案 #日期最大范围 #是否显示农历 #默认日期 基本使用 通过show绑定一个布尔变量用于打开或收起日历弹窗。通过mode参数指定选择日期模式&#xff0c;包含单选/多选/范围…

【JS笔记】JavaScript语法 《基础+重点》 知识内容,快速上手(二)

数组 什么是数组&#xff1f; 字面理解就是 数字的组合 其实不太准确&#xff0c;准确的来说数组是一个 数据的集合 也就是我们把一些数据放在一个盒子里面&#xff0c;按照顺序排好 [1, 2, 3, hello, true, false]这个东西就是一个数组&#xff0c;存储着一些数据的集合 …

复数值神经网络可能是深度学习的未来

一、说明 复数这种东西,在人的头脑中似乎抽象、似乎复杂,然而,对于计算机来说,一点也不抽象,不复杂,那么,将复数概念推广到神经网络会是什么结果呢?本篇介绍国外的一些同行的尝试实践,请我们注意观察他们的进展。

C语言 volatile关键字

volatile关键字介绍 volatile 是一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是易变的&#xff0c;即可能在任何时候被意外地改变。在多线程编程中&#xff0c;当多个线程同时访问同一个变量时&#xff0c;由于线程之间的交互和优化&#xff0c;可能会导致变量的…

手机怎么下载python并安装,如何在手机上下载python

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;如何在手机上下载python 3.7版本&#xff0c;手机怎么下载python并安装&#xff0c;现在让我们一起来看看吧&#xff01; 如何在手机上下载python 应用市场内搜索下载下载Python在您开始之前&#xff0c;在你的计算机将…

Linux性能优化全景指南

Part1 Linux性能优化 1、性能优化性能指标 高并发和响应快对应着性能优化的两个核心指标&#xff1a;吞吐和延时 应用负载角度&#xff1a;直接影响了产品终端的用户体验系统资源角度&#xff1a;资源使用率、饱和度等 性能问题的本质就是系统资源已经到达瓶颈&#xff0c;但…

Vue3设计目标和优化

vue3.0的设计目标是什么&#xff1f;做了哪些优化&#xff1f; Vue3的设计目标&#xff1a;更小、更快、更友好、优化方案 一、设计目标 Vue3之前我们会面临的许多问题&#xff1a; 随着功能的增长&#xff0c;复杂组件的代码变得越来越难以维护起来缺少一种比较【干净】的…

苹果电脑Dock栏优化软件 mac功能亮点

hyperdock mac是一款Dock优化软件&#xff0c;hyperdock支持使用窗口自动排列功能&#xff0c;您可以直接通过将窗口拖拉至屏幕上方来快速最大化至全屏&#xff0c;又或者拖动到左右来进行左分屏和右分屏。而且Dock优化软件还有一个特色便是对Dock的强大管理哪里能力&#xff0…

需求分析 :不得不重新去面对的一关。

软件需求分析 背景 深入需求产生的背景明确项目目标了解用户群体 需求优先级 需求的分类与整理明确需求优先级让团队成员都参与到需求分析中来&#xff0c;增加团队合作能力与效率 编写需求文档 整理好的需求编写成详细的需求文档包括需求的描述、输入/输出格式、功能流程…

elasticsearch 笔记三:查询建议介绍、Suggester、自动完成

一、查询建议介绍 1. 查询建议是什么&#xff1f; 查询建议&#xff0c;为用户提供良好的使用体验。主要包括&#xff1a; 拼写检查&#xff1b; 自动建议查询词&#xff08;自动补全&#xff09; 拼写检查如图&#xff1a; 自动建议查询词&#xff08;自动补全&#xff09;…

学习Vue的key作用和原理

今天主要学习了列表渲染和key的作用和原理&#xff0c;先来说说列表渲染&#xff0c;顾名思义想要渲染列表最快的方式就是使用for循环&#xff0c;我们要学习的就是Vue中对标签实现for循环的语法&#xff0c;它和我们传统的js语法有些不同&#xff0c;它是先要有Vue实例中data的…

We are a team - 华为OD统一考试

OD统一考试 题解&#xff1a; Java / Python / C 题目描述 总共有 n 个人在机房&#xff0c;每个人有一个标号 (1<标号<n) &#xff0c;他们分成了多个团队&#xff0c;需要你根据收到的 m 条消息判定指定的两个人是否在一个团队中&#xff0c;具体的: 消息构成为 a b …

C/C++转WebAssembly及微信小程序调用

上一篇文章讲了C/C如何转WebAssembly&#xff0c;并测试了在Web端调用。本篇内容和上篇一样&#xff0c;介绍C/C包转的.wasm包如何在小程序中调用。 说明 本篇是在上一篇步骤1-4的基础上&#xff0c;再做修改&#xff0c;供微信小程序端调用的方法和步骤。 本篇操作手册可以…

Vue - 实现文件导出文件保存下载

1 文件导出&#xff1a;使用XLSX插件 需求背景&#xff1a;纯前端导出&#xff0c;如 在前端页面勾选部分表格数据&#xff0c;点击"导出"按钮导出Excel文件。 实现思路&#xff1a; 1.通过XLSX插件的 XLSX.utils.book_new()方法&#xff0c;创建excel工作蒲对象wb…

云计算:OpenStack 配置云主机实例的存储挂载并实现外网互通

目录 一、实验 1. 环境 2.配置存储挂载 3.云主机实例连接外部网络&#xff08;SNAT&#xff09; 4.外部网络连接云主机实例&#xff08;DNAT&#xff09; 二、问题 1.云主机 ping 不通外部网络 2.nova list 查看云主机列表报错 3.nova list 与 virsh list --all有何区…

o2o生活通全开源尊享版+多城市切换+企业付款+交友IM+平台快报

搭建教程 1.把 pigo2ov282.sql 文件里面的网址 test.souho.net 全部批量替换为你的自己的 2.使用 phpmyadmin 导入 pigo2ov282.sql 到你的数据库&#xff08;直接访问/phpmyadmin 即可&#xff09; 3.修改数据库文件/conf/db.php 里的数据库连接信息&#xff08;请勿使用记事本…

【51单片机系列】DS1302时钟模块扩展实验之与EEPROM结合使用只进行一次初始化工作

本文是关于时钟芯片DS1302的扩展实验。 文章目录 一、实验分析二、proteus仿真原理图三、软件设计及结果 本实验实现的目的&#xff1a;利用AT24C02掉电不丢失的功能&#xff0c;存储数据用来辨别DS1302时钟是否已经初始化&#xff0c;如果初始化就不执行DS1302初始化函数。 一…

无需翻墙|Stable Diffusion WebUI 安装|AI绘画

前言 最近终于有机会从围墙里往外看&#xff0c;了解到外面的世界已经有了天翻地覆的变化&#xff0c;感叹万千&#xff0c;笔者在本地mac&#xff0c;windows&#xff0c;linux&#xff0c;docker部署了不下20遍后&#xff0c;整理出来的linux极简避坑安装方案&#xff0c;供…

鸿鹄电子招投标系统:基于Spring Boot、Mybatis、Redis和Layui的企业电子招采平台源码与立项流程

在数字化时代&#xff0c;企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台&#xff0c;涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…