Module Federation 模块联邦 在Vue3中使用Vue2搭建的微服务
前言:
备注:本文基于对webpack Module Federation有一定了解的情况下
一般情况下使用模块联邦都是会使用相同的版本,如Vue2的组件时在Vue2中使用,但我为什么会在Vue3项目中去使用Vue2的组件呢,其实是因为历史原因。好几个老的核心的项目都是使用Vue2来写的,在中期以及空闲的时候团队是有机会使用Vue3去重构,但是并没有这样做,到了现在这个阶段已经太晚了,项目变得庞大,人员也减少了。
最近在维护一个项目,被折磨得不行,比如一个.vue文件有3千行代码,框架设计不合理,不易于维护,更不易于多人维护。所以,我决定抽空去重构。
Vue3相对于Vue2的好处不言而喻,故索性使用Vue3 + ts + pinia + element-plus + webpack,由于要使用module federation,所以使用webpack,因为Vite 对module federation支持还是不太好
一、如何使用:
虽然webpack官网并没有介绍,但是在GitHub中找到了Module Federation demo,传送门。
首先,我们把demo跑起来。
1.将代码拉下来:https://github.com/module-federation/module-federation-examples.git
2.在最外层目录安装依赖
yarn
3.进入vue2-in-vue3这个目录,执行命令启动
```shell
yarn start
```
这时候会启动两个服务,其中vue3使用了vue2的Button组件:
- 使用方HOST (vue3): [localhost:3002](http://localhost:3002/)
- 提供方REMOTE (vue2): [localhost:3001](http://localhost:3001/)
webpack相关配置:
vue2 webpack配置
plugins: [
...
new ModuleFederationPlugin({
name: 'vue2App',
filename: 'remoteEntry.js',
library: { type: 'var', name: 'vue2App' },
exposes: {
'./vue2': './node_modules/vue/dist/vue', // 注意点:这里需要把vue暴露出去,原因后面讲
'./Button': './src/components/Button',
},
}),
...
],
vue3 webpack配置
plugins: [
...
new ModuleFederationPlugin({
name: 'vue3',
filename: 'remoteEntry.js',
remotes: {
vue2App: 'vue2App@http://localhost:3001/remoteEntry.js',
},
}),
...
],
vue3项目 App.vue文件
<template>
<div>
<h3>Vue3 App</h3>
<Content :count="count"/>
<!--这里跟我们使用普通组件有一点区别
1、正常情况我们只需要这样写: <Button @btnClick="inc"/>
2、而这里则需要使用一个元素来将挂载组件
-->
<div id="vue2Button"></div>
<vue2-button @btnClick="inc"/>
</div>
</template>
<script>
import { ref } from "vue";
import Content from "./components/Content";
import { vue2ToVue3 } from './utils';
import Button from 'vue2App/Button';
export default {
components: {
Content,
// 通过一个方法,将vue2的组件转为vue3的组件,并挂载在id为'vue2Button'的元素上
vue2Button: vue2ToVue3(Button, 'vue2Button'),
},
setup() {
const count = ref(0);
const inc = () => {
count.value++;
};
return {
count,
inc,
};
}
};
</script>
utils.js,核心在于使用vue2ToVue3方法,使用vue2渲染函数将vue2组件挂载到指定元素
import Vue2 from 'vue2App/vue2';
function bindSlotContext(target = {}, context) {
return Object.keys(target).map(key => {
const vnode = target[key];
vnode.context = context;
return vnode;
});
}
/* 核心
* Transform vue2 components to DOM.(官方注释)
* 理解:这里通过使用vue2的渲染函数,将导入的组件挂载在指定的节点上,巧妙地让vue2的组件能在vue3中使用
* * 确实解决了问题,但是在使用的时候会有一些弊端:
* * 1、存在弊端:每使用一个组件就需要写一个元素去承载,在使用比较频繁的组件中,如:button、input 等常用组件,
* 一个页面可能使用非常多个,那么在书写的时候就需要创建很多元素去承载,所以在这种场景下不太适合使用
* * 2、使用场景:使用频率低,有交互的、稍微复杂一点的组件
*/
export function vue2ToVue3(WrapperComponent, wrapperId) {
let vm;
return {
mounted() {
const slots = bindSlotContext(this.$slots, this.__self);
vm = new Vue2({
render: createElement => {
return createElement(
WrapperComponent,
{
on: this.$attrs,
attrs: this.$attrs,
props: this.$props,
scopedSlots: this.$scopedSlots,
},
slots,
);
},
});
vm.$mount(`#${wrapperId}`);
},
props: WrapperComponent.props,
render() {
vm && vm.$forceUpdate();
},
};
}
vue2项目,Button.vue, 注意点:
<template>
<button @click="click">vue2 button click</button>
</template>
<script>
export default {
methods: {
click() {
this.$emit("btnClick");
// vue3 事件命名需要使用大驼峰,并且前以on开头
this.$emit("onBtnClick");
}
}
}
</script>
二、常见问题:
一、Uncaught Error: Shared module is not available for eager consumption
其实webpack官方是有给出解决方法的,详情见这里
官方给出的解决方法:新建一个bootstrap.js ,将main.js的内容放到bootstrap.js中,在主入口异步去加载bootstrap.js
// bootstrap.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
// 程序入口:main.js 有的是叫做 index.js
import ('./bootstrap.js')
按照故事情节发展,这个问题就解决了,但是这时候我依旧还是报这个错。在以前的其它项目中,我也是使用这种方式解决这个问题,为什么这一次不行了?
经过排查,我定位到了原因:
1、由于我是使用vue-cli创建的,vue-cli中默认2个环境变量 NODE_ENV='development'和 NODE_ENV='production',但是不满足我使用,我增加了一个 NODE_ENV='test',自定义了 --mode,如下:
package.json
"serve:test": "vue-cli-service serve --mode test",
// 在根目录中使用了三个环境变量文件
|_.env.development
|_.env.production
|_.env.test
.env.development代码:
NODE_ENV = 'development'
VUE_APP_API_ENV = 'dev'
.env.production:
NODE_ENV = 'production'
VUE_APP_API_ENV = 'prod'
.env.test:
NODE_ENV = 'test'
VUE_APP_API_ENV = 'test'
问题就出现在.env.test中,如果NODE_ENV = 'test'的话则会报错“Shared module is not available for eager consumption”
我把.env.test改为如下就好了:
NODE_ENV = 'development' # 这里要改为development
VUE_APP_API_ENV = 'test'
改正这样其实对于我的项目也没有影响,因为本来项目就只有正式和开发两个环境,我定义多了一个环境变量用来表示接口的环境,有时候可以给后端在本地调试使用,当然大家也可以使用cross-env的方式。
二、在vue2微服务中,使用了vue3不支持的第三方库,element-ui 在vue3中不能使用,需要使用element-plus
在我的vue2组件库中,有一部分组件对element-ui进行了二次封装,在vue3使用模块联邦去使用的时候就报错了,如:无法找到el-table 等。
测试element-plus在项目中是正常使用的,那我就导入element-ui看看能不能用,当然是不可用的,如果支持vue3的话,就不用弄一个element-plus了。
当然,除了这种情况以外,微服务暴露的工具函数,或者自己手写的组件,都是可以使用的。
总结:
1、首先,本人不太推荐使用这种方式,万不得已不要用
2、Model Federation 在vue3中去使用vue2的组件,会有很多坑,以及不方便的地方,建议有精力的话把组件库改为vue3的,或者vue2 、 vue3通用的
Module Federation 模块联邦 在Vue3中使用Vue2搭建的微服务的更多相关文章
- 032 搭建搜索微服务01----向ElasticSearch中导入数据--通过Feign实现微服务之间的相互调用
1.创建搜索服务 创建module: Pom文件: <?xml version="1.0" encoding="UTF-8"?> <proje ...
- .NET Core 中的 Swagger 应用与微服务场景下的Swagger Api 集成显示
Swagger 与 OpenAPI 的历史来源: Swagger 项目于 2015 年捐赠给 OpenAPI Initiative,此后被称为 OpenAPI.这两个名称可以互换使用.但是," ...
- 在django中如何从零开始搭建一个mock服务
mock概念 mock 就是模拟接口返回的一系列数据,用自定义的数据替换接口实际需要返回的数据,通过自定义的数据来实现对下级接口模块的测试.这里分为两类测试:一类是前端对接口的mock,一类是后端单元 ...
- docker微服务部署之:四、安装docker、docker中安装mysql和jdk1.8、手动构建镜像、部署项目
docker微服务部署之:三,搭建Zuul微服务项目 1.Centos7安装Docker 详见:Centos7安装Docker 2.Docker中安装jdk1.8 详见:使用Docker构建jdk1. ...
- 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务
在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...
- PACT 在微服务架构中的用途是什么?
PACT 是一个开源工具,允许测试服务提供者和消费者之间的交互,与合同隔离, 从而提高微服务集成的可靠性. 微服务中的用法 用于在微服务中实现消费者驱动的合同. 测试微服务的消费者和提供者之间的消费者 ...
- Module Federation原理剖析
[转自团队掘金原文: https://juejin.im/post/6895324456668495880] 为什么需要学习webpack5 module Federation原理呢?因为EMP微前端 ...
- 【设计模式】module(模块)模式
写在前面 最近刚接触到设计模式, <head first设计模式>里有一篇文章,是说使用模式的心智, 1.初学者"心智" :"我要为HELLO WORLD找个 ...
- 安卓与Unity交互之-Android Studio创建Module库模块教程
安卓开发工具创建Module库 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...
随机推荐
- git常见问题及解决方法
简介 由于在git使用过程中会出现各种各样的问题,因此本文将常见的问题记录下来并提供相应的解决方案,方便后续查找. git pull问题: There is no tracking informati ...
- 可以级联的以太网远程IO模块的优点与适用场景
可以级联的以太网远程IO模块的优点与具体的适用场景 对于数据采集控制点是按照线性分布的场景,比如智慧园区的路灯.桥梁.路灯.数字化工厂.停车场车位监测.智慧停车场.智能停车架.楼宇自动控制系统等场景, ...
- Selenium自动化测试之Selenium IDE
简介 Selenium IDE 是实现Web自动化的一种便捷工具,本质上它是一种浏览器插件.该插件支持Chrome和Firefox浏览器,拥有录制.编写及回放操作等功能,能够快速实现Web的自动化测试 ...
- 163_技巧_Power BI 一键批量建立自定义字段参数
163_技巧_Power BI 一键批量建立自定义字段参数 一.背景 在 2022 年 5 月开始,Power BI 新增了一个非常有用的功能字段参数.再也不用写一串的 SWITCH 了.字段参数的效 ...
- 两天时间学习的html的知识笔记
坚持努力背 特殊字符: 空格符 < 小于号 <> 大于号 >& 和号 &¥ 人民币 ¥ 版权 ©R 注册商标 ®. 摄氏度 ° 正负号 ±X 乘号 × 除号 ...
- 基于图像二维熵的视频信号丢失检测(Signal Loss Detection)
1 图像二维熵 图像二维熵作为一种特征评价尺度能够反映出整个图像所含平均信息量的高低,熵值(H)越大则代表图像所包含的信息越多,反之熵值(H)越小,则图像包含的信息越少.对于图像信息量,可以简单地认 ...
- 【Harmony OS】【ArkUI】ets开发 简易视频播放器
前言:这一次我们来使用ets的Swiper组件.List组件和Video组件制作一个简易的视频播放器.本篇是以HarmonyOS官网的codelab简易视频播放器(eTS)为基础进行编写.本篇最主要 ...
- 深入理解Aarch64内存管理
本文是对learn_the_architecture_-_aarch64_memory_management的部分翻译和个人注解.个人英文水平有限,若有翻译不当,欢迎加我私人微信LinuxDriver ...
- 让 DolphinScheduler 1.3.4 开启 Netty 日志打印,解决流程实例一直在运行中的问题
关于新一代大数据任务调度 - Apache DolphinScheduler Apache DolphinScheduler(incubator) 于 17 年在易观数科立项, 19 年 8 月进 ...
- 持久化-DLL劫持
持久化-DLL劫持 原理 通过篡改.替换和代理原dll文件来达到劫持. 原理演示 假定演练流程 假定我们要劫持的目标是 c:\temp\legit.dll 获取 c:\temp\legit.dll 所 ...