Module Federation 与 SSR 中的模块化
本节目标
- 粗览「模块联邦(Module Federation)」解决什么(多应用共享模块)
- 理解 SSR 下「模块只该在服务端跑一次」的要点
- 建立「模块化不止浏览器,还跨应用/跨环境」的认知
模块联邦:让「多个独立部署的前端应用」能「运行时互相 import 对方的模块」,不用打包进自己包里。
// 运行环境:Webpack 5 配置示意(非直接运行的单文件)
// app1 暴露一个组件
// webpack.config.js -> new ModuleFederationPlugin({ name:'app1', exposes:{'./Button':'./src/Button.js'} })
// app2 远程引入
// import { Button } from 'app1@https://cdn/remoteEntry.js' // 运行时拉取 app1 的模块SSR(服务端渲染)里的模块化:Node 端 import 的模块在服务端进程里只加载一次(缓存)。注意:浏览器用的模块(含 window)不能不小心被 Node 端 import,否则报错。需用「条件导出」或「只 import 纯逻辑模块」隔离。
// 纯逻辑模块(服务端/浏览器都能用)
export const sum = (a, b) => a + b
// 带 window 的模块只在客户端 import,别让 SSR 入口碰它名词解释
模块联邦(Module Federation):Webpack 5 引入的能力,让多个「独立构建、独立部署」的前端应用,在运行时互相加载对方的模块(像 import 远程包)。它解决「微前端/多团队各自部署却要共享组件」的问题,避免每个应用都打包一份相同组件。
SSR(服务端渲染):在 Node 端把组件渲染成 HTML 再发给浏览器。此时「模块在 Node 进程里加载」,有缓存、也会因 window/document 不存在而崩。所以 SSR 项目要把「纯逻辑」和「只 browser 的代码」分开模块,避免 Node 端误 import 浏览器专属代码。
课后练习
练习 1:模块联邦和「npm 发包共享」有什么本质区别?
答案:npm 共享是「构建时」把依赖打进各自包(各自一份副本、要发版同步);模块联邦是「运行时」从一个已部署的应用拉取模块(同一份、实时更新、独立部署)。前者适合稳定库,后者适合「多应用共享且要独立迭代的组件」。
练习 2:SSR 里为什么不能让 Node 端 import 含 window 的模块?
答案:Node 没有
window/document,模块顶层一旦用到就抛ReferenceError,服务端渲染直接崩。所以要「环境隔离」:纯逻辑(无浏览器 API)模块两端共用;含window的模块只在客户端入口引入,Node 端绝不碰。
总结
模块化的视野不该停在「一个浏览器应用内」。我的观点:模块联邦和 SSR 代表了模块化的「两个延伸维度」——一个是「跨应用运行时共享」(微前端),一个是「跨环境(服务端/客户端)隔离」。它们共同提醒你:模块是有「部署边界」和「运行环境边界」的。设计模块时想清「它会在哪跑、被谁引」,才能避免 SSR 的 window 崩溃、或微前端的重复打包。初学者不必深抠配置,但要有这个心智:模块不是孤立的,它活在「环境 + 部署」的上下文里。