模块联邦本身是一个Webpack 插件 ModuleFederationPlugin,插件有几个重要参数:
- name 必须,唯一 ID,作为输出的模块名,使用的时通过 name/{name}/name/{expose} 的方式使用;。
- remotes 可以将其他项目的 name 映射到当前项目中,远程其他共享模块的加载地址。
- exposes 表示导出的模块,只有在此申明的模块才可以作为远程依赖被使用。
- shared 是非常重要的参数,制定了这个参数,可以让远程加载的模块对应依赖改为使用本地项目。
一、 创建应用app1
1.首先创建vue项目app1,新建webpack.config.js,进行模块联邦配置(注意VueLoaderPlugin的使用)
const path = require('path');
// vue-loader在15.*之后的版本都是 vue-loader的使用都是需要伴生 VueLoaderPlugin的,
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
devtool: false,
entry: './src/main.js',
mode: "development",
devServer: {
port: 3000,
contentBase: path.join(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 请确保引入这个插件!
new VueLoaderPlugin(),
new HTMLWebpackPlugin({
template: path.resolve(__dirname, './public/index.html')
}),
new ModuleFederationPlugin({
// 提供给其他服务加载的文件
filename: "remoteEntry.js",
// 唯一ID,用于标记当前服务
name: "app1",
library: { type: "var", name: "app1" },
// 需要暴露的模块,使用时通过 `${name}/${expose}` 引入
exposes: {
'./Button': "./src/components/Button.vue",
}
})
]
}
2.依赖安装
在配置模块联邦时遇到了很多兼容问题,比如babel版本冲突等,demo项目中package.json配置如下
{
"scripts": {
"start": "webpack serve",
"build": "webpack"
},
"devDependencies": {
"@babel/core": "7.9.6",
"babel-loader": "^8.1.0",
"html-webpack-plugin": "^4.5.0",
"vue-loader": "^15.9.3",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.0.0",
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"vue": "^2.6.12",
"webpack-cli": "^4.0.0"
}
}
二、创建应用app2
1.首先创建vue项目app2,新建webpack.config.js,进行模块联邦配置
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
devtool: false,
entry: './src/main.js',
mode: "development",
devServer: {
port: 3001,
contentBase: path.join(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 请确保引入这个插件!
new VueLoaderPlugin(),
new HTMLWebpackPlugin({
template: path.resolve(__dirname, './public/index.html')
}),
new ModuleFederationPlugin({
name: "app2",
remotes: {
app1: "app1@http://localhost:3000/remoteEntry.js",
}
})
]
}
2.依赖安装
{
"scripts": {
"start": "webpack serve",
"build": "webpack"
},
"devDependencies": {
"@babel/core": "7.9.6",
"babel-loader": "^8.1.0",
"html-webpack-plugin": "^4.5.0",
"vue-loader": "^15.9.3",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.0.0",
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"vue": "^2.6.12",
"webpack-cli": "^4.0.0"
}
}
三、在app2中调用app1
webpack配置好之后,我们通过地址访问可以看到http://localhost:3000/remoteEntry.js 中的文件已经被共享,在app2中直接以组件形式进行引用即可。
import("app1/Button")
会被解析大致为: loadScript("http://localhost:3000/remoteEntry.js").then(() => require('Content'))
<template>
<div id="app">
<h1>我是子应用</h1>
<p>我将使用主应用的共享组件</p>
<ul>
<li>
<Button />
</li>
</ul>
</div>
</template>
<script>
export default {
components: {
Button: () => import("app1/Button"),
},
};
</script>
【注:本篇文章是学习的时候看到的,转载过来做笔记记录。转自掘金作者:寇寇菌,原文链接:https://juejin.cn/post/6992374705890000927】