关于 ModuleFederation 和前端跨工程模块化方面的实践
前端跨工程模块化,是随着前端应用越来越复杂,大部分具有一定规模的企业都会面临不同产品线开发的功能(前端业务模块)如何在不同工程中复用的问题。
就目前前端技术的发展来看,跨工程方面的技术尚处于发展期,和单体工程不同,跨工程之间的代码复用方案在前端技术领域还不够成熟。
再展开跨工程方面的问题之前,我们先来简单的回顾下前端工程化的发展历程。
根据我这些年的经验,我对前端工程化的发展大致分为如下几个阶段。
- 手工管理代码文件的阶段
- 主要以文件管理为主,文件的加载合并基本都已手工为主
- 自动化工具和单一的模块加载器开始出现,但处理单位依然以文件为主
- 以工程为单位对前端代码进行管理
- 各种包管理工具开始出现,围绕代码包的管理,加载,整合,让前端有了工程概念
- 但管理方式和处理对象以单体工程为主和 spa 类应用的兴起相符合,同时期的移动端应用也多为单体应用
- 多工程管理阶段
-
这一阶段的问题变得更加复杂,前端工程需要继续保持之前单体工程化的能力,独立发布部署和维护,但构建后的代码又要集成到同一个运行环境中。
-
目前前端工程化在大部分成规模的公司都处于这一阶段,而大部分中小企业则尚处于上一阶段,跨工程的问题开始出现但不普世。
-
这一阶段诞生了一些新的技术,例如以容器化的各种微前端框架,微前端主要解决多个应用集成后的环境冲突问题,但相比这个问题更容易出现在大型且有一定的历史的企业,而 webpack5 的 module federation 则更聚焦大多数前端会面临的问题,即不同工程内的模块如何共享的问题。
-
针对上述阶段我们不过多展开,本文主要想讨论的是跨工程间模块复用的问题,目前这一领域据我所知仅有 module federation 一项。
但 mf 有一些比较致命的问题
- 不支持 webpack5 以前的版本
- 不支持其他打包工具或者无构建的纯 JS 模块
总体来说 mf 是一个很有创意的方案,但它和 webpack5 过度耦合的设计和实现影响了这一技术的发展,以及其成为标准的可能
说了这么多,现在来讨论下在跨工程模块共享技术上我们的实践,如果你也遇到同类的问题,或许可以参考我们的方案
首先我们设想的跨工程模块的使用场景和 webpack5 的 mf 类似
import { create } from '@rdeco/core'
create({
name:"foo",
exports:{
send(msg, next){
console.log(msg) // 'hello'
next('world')
}
}
})
// localhost:3000/bar.js
import { foo } from 'remote://foo'
const res = await foo.send('hello')
console.log(res) // world
// babel.config.js
module.exports = {
plugins:[['rdeco',{
moduleMap:{
foo:'http://localhost:3001/foo.js'
}
}]]
}
这是我们使用 rdeco 实现的一个可用的版本,相比 mf,这套方案更有优势
- 和构建工具无关,可以实现任意 webpack 版本的 mf,因为是一套运行时的方案,因此无论什么构建工具都可以支持。
- 基于事件驱动,不需要关心模块是否就绪的问题
- 不依赖 npm,rdeco 模块不是标准的 es6 模块,但这一点我认为现行的 es6 模块标准很难解决跨工程模块引用的问题。
总体而言在我们的实践过程中,这套方案足够轻量,并且独立工程输出的模块在不同工程间也非常易于调试,几乎和单体工程下的模块在开发体验上几乎是一致的。
基于这套方案,即使只有 2 - 3 个人的超小型前端团队也可以实现独立的工程架构设计,将不同类型的组件合理的划分到不同的工程中,然后很容易的在运行环境对他们进行整合
这套方案中的技术已经开源,如果你感兴趣可以自行搜索。
转载自:https://juejin.cn/post/7057140429036355615