走进 Webpack 5 的模块联邦世界
2023-12-01 01:14:33
踏入 Webpack 5 的模块化新篇章,我们共同启航,去探索模块联邦的奥妙。
模块联邦,顾名思义,就是模块化的联合体,它允许在不同的应用程序间模块化的使用和管理。Webpack 5 携手模块联邦,为我们带来了资源模块化的无限可能,打破了应用程序间的藩篱,让资源流动如涓涓细流。
模块联邦架构下,应用程序不再是孤立的堡垒,它们可以像亲密的盟友,在单向数据流中互相扶持,取长补短。异步加载技术的加持,更是如虎添翼,让资源按需加载,优化了应用程序的加载效率。
模块联邦的魅力,还在于它灵活多变的特性,它能适应各种应用程序场景,无论是大型还是小型,无论是单一应用程序还是多应用程序,它都能游刃自如,为我们带来最佳的模块化方案。
Webpack 5 的模块联邦,就像一扇开启了模块化新世界的魔法之门,它的到来,不仅宣告了传统模块化思想的落幕,更预示着一个资源无界、合作共赢的崭新时代。
下面,我将带领大家,亲手搭建一个基于 Webpack 5 的模块联邦 demo,拆解模块联邦的内在逻辑,让它在不同的单页应用程序中大放异彩。
配置 Webpack 5 的模块联邦
首先,我们分别初始化两份 Webpack 5 配置文件,一份用于打包第一个单页应用程序(App1,index.html 为入口文件,src/index.js 为模块文件);另一份用于打包第二个单页应用程序(App2,index.html 为入口文件,src/index.js 为模块文件):
App1 的 Webpack 配置(app1.js)
const path = require('path');
const webpack = require('filepath/to/latest/of/modular-federation-umd.js');
const baseConfig = require('filepath/to/your/own/config.js'); // 如果有
module.exports = {
...baseConfig,
output: {
publicPath: 'path/to/app1/', // App1 打包后的 publicPath
},
devServer: {
port: 9001, // 启动 App1 服务的端口
},
experiments: {
outputModule: {
type: 'module', // webpack 5.x 采用原生 ESM
},
// 启用模块联邦 API
topLevelExports: true,
outputModule: true,
},
// 将 App1 中 src/index.js 导出的内容暴露给模块联邦
module: {
...baseConfig.module,
// 使用 AMD / UMD 格式化打包
// 以便于在模块联邦中使用
// 注意:Webapack 4.x 以前的版本需要
// 使用 webpack.commonjsModule.js 配置
loaders: [
{
test: /\.js$/,
loader: 'file-loader',
options: {
name: '[name].[hash].js',
publicPath: 'src/',
},
},
],
},
};
App2 的 Webpack 配置(app2.js)
// 与 App1 的 Webpack 配置大致相同,但端口号和 publicPath 需做相应调整
const path = require('path');
const webpack = require('filepath/to/latest/of/modular-federation-umd.js');
const baseConfig = require('filepath/to/your/own/config.js'); // 如果有
module.exports = {
...baseConfig,
output: {
publicPath: 'path/to/app2/', // App2 打包后的 publicPath
},
devServer: {
port: 9002, // 启动 App2 服务的端口
},
experiments: {
outputModule: {
type: 'module', // webpack 5.x 采用原生 ESM
},
// 启用模块联邦 API
topLevelExports: true,
outputModule: true,
},
// 将 App2 中 src/index.js 导出的内容暴露给模块联邦
module: {
...baseConfig.module,
loaders: [
{
test: /\.js$/,
loader: 'file-loader',
options: {
name: '[name].[hash].js',
publicPath: 'src/',
},
},
],
},
};
搭建模块联邦
1. 创建模块联邦配置文件(federation.json)
{
"name": "my-federation",
"remotes": {
"app1": "app1@http://path/to/app1/src/index.js"
}
}
说明 :
- "name": 指定模块联邦的唯一性名字
- "remotes": 指定远程模块的名字和对应的入口文件路径
2. 使用模块联邦 API
在 App2 的入口文件(index.js)中,加载来自模块联邦的远程模块:
// 加载来自 my-federation 的 app1 远程模块
const remoteContainer = document.getElementById('container');
const { getModule } = require('module-federation');
getModule('app1')
.then((module) => {
// 异步加载 app1 导出的模块
const App1 = module.get('App1');
// 创建来自 App1 的组件并渲染到容器中
const app1Component = App1.createElement();
container.append(app1Component);
})
.catch((error) => {
console.log(error);
});
3. 启动应用程序
运行 webpack 命令分别打包 App1 及其模块、App2 及其模块,并在各自端口启动服务:
// 打包 App1
> webpack --config app1.js
// 打包 App2
> webpack --config app2.js
// 启动 App1 服务
> npm run start:app1
// 启动 App2 服务
> npm run start:app2
说明 :
- webpack 命令用于打包应用程序及其模块
- npm start:app1 命令用于在端口 9001 启动 App1 服务
- npm start:app2 命令用于在端口 9002 启动 App2 服务
验证模块联邦
1. 访问 App2 页面(http://127.0.0.1)
2. 观察 App2 页面中,来自 App1 的组件
恭喜你,你已经踏入模块联邦的世界。
总结
模块联邦,在应用程序间资源模块化的道路上,为我们带来了无限可能,让不同的应用程序不再割裂孤立,打破藩篱,在单向数据流中,携手共赢,共创辉煌。
Webpack 5 携手模块联邦,为我们赋能,助力我们在资源模块化的新篇章中大显身手,谱写下一个传奇。