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

1 引言

先说结论:Webpack5 模块联邦让 Webpack 达到了线上 Runtime 的效果,让代码直接在项目间利用 CDN 直接共享,再也不须要本地安装 Npm 包、构建再发布了!javascript

咱们知道 Webpack 能够经过 DLL 或者 Externals 作代码共享时 Common Chunk,但不一样应用和项目间这个任务就变得困难了,咱们几乎没法在项目之间作到按需热插拔。html

模块联邦是 Webpack5 新内置的一个重要功能,可让跨应用间真正作到模块共享,因此这周让咱们经过 webpack-5-module-federation-a-game-changer-in-javascript-architecture 这篇文章了解什么是 “模块联邦” 功能。前端

2 概述 & 精读

NPM 方式共享模块

想象一下正常的共享模块方式,对,就是 NPM。java

以下图所示,正常的代码共享须要将依赖做为 Lib 安装到项目,进行 Webpack 打包构建再上线,以下图:react

对于项目 Home 与 Search,须要共享一个模块时,最多见的办法就是将其抽成通用依赖并分别安装在各自项目中。webpack

虽然 Monorepo 能够必定程度解决重复安装和修改困难的问题,但依然须要走本地编译。git

UMD 方式共享模块

真正 Runtime 的方式多是 UMD 方式共享代码模块,即将模块用 Webpack UMD 模式打包,并输出到其余项目中。这是很是广泛的模块共享方式:github

对于项目 Home 与 Search,直接利用 UMD 包复用一个模块。但这种技术方案问题也很明显,就是包体积没法达到本地编译时的优化效果,且库之间容易冲突。web

微前端方式共享模块

微前端:micro-frontends (MFE) 也是最近比较火的模块共享管理方式,微前端就是要解决多项目并存问题,多项目并存的最大问题就是模块共享,不能有冲突。前端工程化

因为微前端还要考虑样式冲突、生命周期管理,因此本文只聚焦在资源加载方式上。微前端通常有两种打包方式:

  1. 子应用独立打包,模块更解耦,但没法抽取公共依赖等。
  2. 总体应用一块儿打包,很好解决上面的问题,但打包速度实在是太慢了,不具有水平扩展能力。

模块联邦方式

终于提到本文的主角了,做为 Webpack5 内置核心特性之一的 Federated Module:

从图中能够看到,这个方案是直接将一个应用的包应用于另外一个应用,同时具有总体应用一块儿打包的公共依赖抽取能力。

让应用具有模块化输出能力,其实开辟了一种新的应用形态,即 “中心应用”,这个中心应用用于在线动态分发 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,插件有几个重要参数:

  1. name 当前应用名称,须要全局惟一。
  2. remotes 能够将其余项目的 name 映射到当前项目中。
  3. exposes 表示导出的模块,只有在此申明的模块才能够做为远程依赖被使用。
  4. shared 是很是重要的参数,制定了这个参数,可让远程加载的模块对应依赖改成使用本地项目的 React 或 ReactDOM。

好比设置了 remotes: { 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"]
    })
  ]
};
复制代码

正是由于 Searchexposes 被导出,咱们所以可使用 [name]/[exposes_name] 这个模块,这个模块对于被引用应用来讲是一个本地模块。

3 总结

模块联邦为更大型的前端应用提供了开箱解决方案,并已经做为 Webpack5 官方模块内置,能够说是继 Externals 后最终的运行时代码复用解决方案。

另外 Webpack5 还内置了大量编译时缓存功能,能够看到,不管是性能仍是多项目组织,Webpack5 都在尝试给出本身的最佳思路,期待 Webpack5 正式发布,前端工程化会迈向一个新的阶段。

讨论地址是:精读《Webpack5 新特性 - 模块联邦》 · Issue #239 · dt-fe/weekly

若是你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

关注 前端精读微信公众号

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证

相关文章
相关标签/搜索