目前很多公司的业务都涉及到多个端的开发,有PC端/小程序/原生客户端等,而不同端都有对应的一个或几个独立的项目,而这些不同的项目之间都有一些可复用的业务逻辑,开发者往往需要在不同的项目中维护相同的逻辑。因此,为了节省维护成本,都会考虑跨项目模块复用,了解到 webpack5 的模块联邦特性,做了一下调研。
Module Federation,中文翻译为"模块联邦"
,是 webpack5 中的一个号称 改变JavaScript架构的游戏规则
的功能。其文档中定义的使用目的为:
多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署它们。这通常被称为微前端,但并不仅限于此。
简单说,MF 实际上就是可以把多个无单独依赖的、单独部署的应用合为一个。或者说不止是应用,MF 支持的粒度更细。它可以把多个模块、多个npm包合为一个。
而 MF 模块是可以在项目中直接导出某个模块,单独打包的,如下图:
这样就很灵活,在复用逻辑的时候可以做到尽可能对现有项目少改造,快速导出。
首先,这是webpack5的能力,所以当然要用webpack5来构建,怕配置麻烦的同学,可以直接看我的demo,demo我已经上传到github上了,地址为:https://github.com/LuckyWinty/vue2-module-federation/tree/master
导出方配置:
// home webpack.config.js
new ModuleFederationPlugin({
name: "home",
filename: "remoteEntry.js",
exposes: {
"./Content": "./src/components/Content",
"./Button": "./src/components/Button",
"./VueDemo": "./src/components/VueDemo", // 组件
"./Utils": "./src/utils", // 纯函数
},
}),
使用方配置:
// layout webpack.config.js
new ModuleFederationPlugin({
name: "layout",
filename: "remoteEntry.js",
remotes: {
home: "home@http://localhost:3002/remoteEntry.js",//cdn地址
},
exposes: {},
}),
// layout main.js
import Vue from "vue";
import Layout from './Layout.vue';
const Content = () => import("home/Content");
const Button = () => import("home/Button");
const VueDemo = () => import("home/VueDemo");
(async () => {
const { sayHi } = await import("home/Utils");
sayHi();
})();
Vue.component("content-element", Content);
Vue.component("button-element", Button);
Vue.component("vue-demo", VueDemo);
new Vue({
render: h => h(Layout),
}).$mount('#app')
通过以上配置,我们对 MF 有了一个初步的认识,即如果要使用 MF,需要配置好几个重要的属性:
字段名 | 类型 | 含义 |
---|---|---|
name | string | 必传值,即输出的模块名 |
library | object | 声明全局变量的方式,name为umd的name |
filename | string | 构建输出的文件名 |
remotes | object | 远程引用的应用名及其别名的映射,使用时以key值作为name |
exposes | object | 被远程引用时可暴露的资源路径及其别名 |
shared | object | 与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖 |
由此可见,该方案可以在项目间共享模块且使用方式与正常引入无太大区别。其基本原理为,将独立导出的模块打包为一个单独的包,然后使用方通过CDN地址的方式引用,这样就可以同步更新不同项目间的同一模块逻辑且节约了代码构建成本,维护成本等。
建议可以自行跑一下demo来感受一下它的作用。
小程序由于需要在上线前将所有代码打包好,然后送审通过后才能上线。因此无法做到按需动态CDN加载对应的模块。为了兼容小程序的这点,我们可以通过脚本拉取CDN地址的代码到小程序项目指定目录,然后小程序再引用。
Module Federation 和 qiankun/icestark 等框架在微前端应用上的一些差别:
模块
,qiankun/icestark 等框架基于 应用
,也就是说MF是由多个互相独立的模块聚合而成的应用,框架是由多个互相独立的应用聚合而成的应用。JS代码片段
,这种代码片段一般称为chunk。因此,模块的聚合,实际上是chunk的聚合。框架应用本质上是HTML
,而在SPA中,HTML又是main.js进行填充的。因此,应用的聚合,实际上是main.js的聚合。两者只不过微的粒度以及使用场景不同罢了,都可以成为微前端。
MF 有很多想象空间,值得继续探索和留意。MF 不是银弹,还是需要结合场景去选择。篇幅限制,先到这里。下次再聊聊 MF 的详细实现原理~