webpack模块-精读《Webpack5新特性——模块联邦》

1 简介

先说一下推论:Webpack5模块联邦让Webpack达到了在线运行时的效果,让代码可以借助CDN直接在项目之间共享,无需在本地安装Npm包,构建和发布!

我们知道Webpack可以通过DLL或Externals来共享Common Chunk,但是不同应用程序和项目之间的这项任务是困难的,我们几乎很难实现项目之间的按需热交换。

模块联邦是Webpack5新推出的一个重要功能,它允许跨应用模块共享,所以本周让我们通过 webpack-5-module-federation-a-game-changer-in-javascript-architecture 文章来了解一下什么是模块联邦“模块联合”功能。

2 概述&精读 NPM Way 共享模块

想象一下共享模块的正常形式,是的,NPM。

如下图,正常的代码共享需要将依赖作为Lib安装到项目中,用Webpack构建打包,然后上线,如下图:

对于Home和Search项目,当需要共享模块时,最常见的方式是将其提取到公共依赖项中并将其安装到各自的项目中。

Monorepo虽然可以在一定程度上解决重复安装、修改困难的问题,但仍然需要本地编译。

UMD模式下的共享模块

Runtime的真实形态可能是UMD模式的共享代码模块,即将模块以Webpack UMD模式打包并导出到其他项目中。 这是一种非常常见的模块共享形式:

对于 Home 和 Search 项目webpack模块,模块直接与 UMD 包一起重用。 但这些技术方案的问​​题也很明显,即包体积难以达到本地编译的优化效果,且库容易出现冲突。

微后端形式的共享模块

微后端:微前端(MFE)也是最近流行的模块共享管理方式。 微后端是为了解决多项目共存的问题。 多项目共存最大的问题就是模块共享,不冲突。

由于微后端还需要考虑样式冲突和生命周期管理,因此本文仅关注资源加载形式。 微后端通常有两种封装形式:

子应用独立打包,模块前馈性更强,但公共依赖无法提取。

整个应用打包在一起,很好的解决了前面的问题,但是打包速度太慢,而且不具备水平扩展的能力。

模块联合形式

最后提到本文的主角,Federated Module,Webpack5内置的核心特性之一:

从图中可以看出,该方案是将一个应用程序的包直接应用到另一个应用程序中,同时具备将整个应用程序打包在一起的公共依赖提取能力。

让应用程序具备模块化输出能力webpack模块,实际上开辟了一种新的应用形态,即“中心应用”。 该中心应用用于在线动态分发Runtime子模块,并不直接提供给用户:

对于微后端来说,这张图是一个完美的主应用,因为所有子应用都可以通过Runtime的方式复用主应用的npm包和模块,更好的融入到主应用中。

模块联合的用法如下:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
name: "app_one_remote",
remotes: {
app_two: "app_two_remote",
app_three: "app_three_remote"
},
exposes: {
AppContainer: "./src/App"
},
shared: ["react", "react-dom", "react-router-dom"]
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"]
})
]
};

模块联合本身是一个普通的Webpack插件ModuleFederationPlugin。 该插件有几个重要参数:

name 当前应用程序的名称,需要全局唯一。

遥控器可以将其他项目的名称映射到当前项目。

Expose 代表导入的模块,只有这里声明的模块才可以用作远程依赖。

共享是一个非常重要的参数。 如果制定该参数,则可以将远程加载模块对应的依赖改为使用本地项目的React或ReactDOM。

例如,如果您设置遥控器:{ app_twp: "app_two_remote" },则可以使用以下形式直接从代码中的其他应用程序调用该模块:

import { Search } from "app_two/Search";

这个app_two/Search来自app_two的配置:

// app_two 的 webpack 配置
export default {
plugins: [
new ModuleFederationPlugin({
name: "app_two",
library: { type: "var", name: "app_two" },
filename: "remoteEntry.js",
exposes: {
Search: "./src/Search"
},
shared: ["react", "react-dom"]
})
]
};

正因为 Search 是在公开中导入的,所以我们可以使用 [name]/[exposes_name] 模块来实现此目的,它是引用应用程序的本地模块。

3 总结

模块联合为较小的后端应用程序提供了开箱即用的解决方案,并且已经被外部化为Webpack5的官方模块。 可以说是继Externals之后终极的运行时代码复用解决方案。

另外,Webpack5还具有大量的外部编译时缓存功能。 可以看到,无论是性能还是多项目组织,Webpack5都在努力给出自己最好的想法。 期待Webpack5的正式发布,前端工程将迈向新的阶段。