hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
模块联邦之缘起
自谷歌chrome
浏览器异军突起,并在2008年9月2号 正式官宣发布 v8
js引擎之后,它以极高的运行效率席卷了网络世界,同时也捕获了大量用户,这种不可阻挡的势头让其他各大科技公司(apple、moliza、microsoft)感受到了巨大的杀气, 随即大家都开始招兵买马、磨刀赫赫准备杀出一条血路,从此js引擎进入了军备竞赛时期,这其中微软甚至不惜自废IE
并开始力推背后携带了微软无数心血的全新js引擎 Chakra
的edge
浏览器,可想而知大家对js引擎这块蛋糕的重视程度有多高,而v8
的诞生催化了大量的著名开源作品,让js生态一直保持着非常强劲的活力,这其中最著名的就是 2009 年诞生的nodejs
,一个基于v8
的服务端js运行时,让js这门语言开始从前台到后台遍地生花,以至于以下一句很早诞生的调侃话语至今还在流传:
Any application that can be written in JavaScript, willeventually be written in JavaScript.
模块化规范
nodejs
将commonjs
模块化带到了服务器端,让大型js工程组织起来更加有条不紊,同时也带了npm
这个超级杀手锏,让模块分发与共享效率提高到了前所未有的高度。
而前端应用也随着网络应用的复杂度成倍提升,导致进入代码体积进入了高速膨胀时期,这个时候急需一个有效的模块化方案来解决如何优雅拆分模块,如何提高代码复用性和可维护性等一系列问题。
此时两大主流模块化方案amd
和cmd
开始在前端这里竞相角逐并最后各自站稳了一份很大的地盘,他们的代表实现分别是requirejs
和seajs
,相信不少小伙伴都了解或使用过。
工程化体系
尽管requirejs
和seajs
为前端带来了模块化规范的实现并给大型js工程注入了稳固的根基,但是仅靠模块化规范,依然不能解决如何和npm
生态互通,如何管理日趋复杂的模块依赖关系,如果兼容新的js特性等一系列问题,归根结底,这里面涉及到一个关键词工程化体系,之后webpack
和babel
便诞生了,他们目标非常明确,解决了以下图中的4大问题
随即成为了前端开始工程化体系开发的事实上的基建标配。
webpack
依靠优秀的插件和加载器机制,让其围绕它的生态得以不停地做大做强,干掉了过程其他更偏向于工具的gulp
,grunt
等一众对手
npm 的魔咒
webpack
和npm
几乎形成了完美搭档的状态,但前端原本从cdn
获取的资源改由打包工具合并到一个包体里带来了致命的更新和部署效率问题。
在某些需要需要动态更新的场景,这种all in one
的打包机制让包体的部署效率大打折扣,这本不是webpack
和npm
的问题,而是人们天生对web环境需要快速迭代、快递实验的高要求带来的典型场景需求。
注:externals 本身不能彻底解决动态更新的诉求,只适合于将底层公关依赖包体外链到cdn
bundless 来袭
同时webpack
随着项目体积日趋庞大,新的问题诸如开发体验差(热更新慢)、包体加大、构建速度慢(node\_modules黑洞)等问题也诞生了,此时新生代的开发工具snow
和vite
以不打包的名义开始蚕食webpack
的市场。
他们都利用了浏览器的原生模块化能力esm
,跳过webpack
的需要的依赖分析和打包流程,在此设计下做到了毫秒级的调试启动。
但它们带来的极致快体验并不能动摇整个webpack
生态的深厚围城,事实上大家都是处于调试基于vite
而生产打包还是用webpack
的双擎驱动模式,毕竟esm
普及还需要时间。
模块联邦吹响反攻号角
既然大家都吐槽wepack
构建慢,那么可不可以有一种方式既能跳过构建步骤又能让用户可以按自己的方式组合多层次依赖模块呢?
当然有的,那就是走预构建这条道路
模块联邦
因此诞生了,它的伟大之处在于保持当前前端开发模块化、组件化、工程化的高效率体系下,允许模块独立开发、独立部署,通过 CDN 直接共享,从而挣脱npm包体无法动态更新的桎梏,从而推动整个前端界开发和运行体验上升到一个新高度。
只要有越多的模块能提升到联邦里,本地启动速度将越快!
而且联邦模块天生具有双重身份,即可以是模块消费者,也可以是模块提供者,这让模块联邦应用之间形成了天然的网格关系,模块分发效率、部署效率、共享效率都得到了前所未有的提升!
模块联邦的阿喀琉斯之踵
webpack 5
或者其他工具带来的模块联邦实现真的完美了吗?它的确解决了免构建
、动态更新
、跨项目共享模块
的问题
但基于现有的编译时插件化机制去实现,无法规避工具链强绑定
,编译时确定才能远程模块消费关系
的难题
试想一下,你需要使用模块联邦这么技术,需要做的前置条件有多重,需要升级真个工具链!而且不同工具链之前的联邦模块是互相不通的!模块的流通性绑定在了你选择的工具链上。
模块联邦新革命
破除这两大难题的唯一解就是将其sdk化
,这是hel-micro
对模块联邦实现的全新思考,也是发起模块联邦新革命的秘密武器。
sdk化
后,任何技术栈、任何工具链均可无损、无痛接入模块联邦技术。
运行时的模块消费关系
从工具链回归到js语言本身,意味着模块消费关系从编译时提升到运行时,将极大提高动态载入远程模块的灵活性,为更复杂的业务赋能。
降维打击
对比依赖工具插件实现的模块联邦,hel-micro
从语言层面的实现将对其他模块联邦实现造成降维打击。
相比传统的npm共享方式,hel-micro
也具有更高效的代码共享能力(运行时共享)
解密 sdk 化核心实现
要实现sdk化,意味着我么必须挖掘出js语言本身的隐含能力,并跳出传统的打包流程思维,才能达到我们的最终目标
异步impor暗藏的能力
通常我们都会在头文件使用import
关键字静态导入其他模块,但其实import
可以作为函数调用,异步的导入一个模块,并返回一个promise对象
const mod = await import('./some-mod');
所以我么可以通过微调模块的加载顺序,来达到为一个模块被其他模块静态导入之前能够为它注入新代码的效果
而这个异步import带来的提前注入效果成为了hel-micro
为模块代理对象注入远程运行时代码的关键实现点,让hel-micro
可以位用户提供懒加载和预加载两种加载方式。
上图里两个核心接口:libReady
接口负责暴露模块,preFetchLib
接口负责拉取模块,通过调用接口的行为让每一个模块都表现为提供方或者消费者。
运行时依赖分析
hel-micro
通过内部维护的事件总线
、模块池
、样式池
、元数据池
四个数据结构,让有多级依赖层次的远程模块得以高效并安全有序的加载。
其中模块池
能保证模块不被重复加载并被上层各方调用者重复使用。
元数据-模块的灵魂
模块的实质是构建产物文件的集合,hel-micro
通过提供构建时的插件,收集好产物的网络路径并按sdk规定的协议存储起来,得以后续可以在网络让sdk可以下载并执行所有的远程模块。
双构建机制
hel-micro
使用rollup
打包本地可静态导入的代理文件,使用webpack
打包远程注入的实际运行代码,来达成可以本地静态导入node_modules
里的代理模块对象得到完整的类型提示,让用户能得到像使用本地模块一样地使用远程模块的极致开发体验
内定了4个目录hel_dist
,hel_proxy
,hel_proxy_es
,hel_bundle
来承载不同的产物,供package.json
配置不同的入口。
其中hel_proxy
,hel_proxy_es
目录下的文件是就是我么说到的模块代理对象的入口文件,我么可以看到该文件近乎一个空壳,所以它对模块使用方的打包体积大小影响几乎可以省略不计。
平台与生态
hel-mirco sdk主要依靠规范化的元数据格式来做远程模块加载,所以只要任意用户按照规范格式提供模块的元数据,即可被hel-micro
加载,这将极有利于围绕hel-micro的上层生态的建设与发展。
支持模块任意部署
sdk与平台是解耦的,我么默认提供了和hel pack
与npm unpkg
的支持,但允许你可以将模块发布到网络上的任意文件服务,仅需知道其部署地址即可。
如用户将 hel-meta.json
元数据保存到后台数据库(可结合devops流水线),就可很快搭出一个类似hel pack
的中心化的模块管控平台
中心化的模块管控平台对模块实施版本预览、灰度放量、秒级回滚等工作会特别方便,但它不妨碍sdk以去中性化的方式加载多平台包体,因为sdk天生支持同时从多个不同的平台拉取远程模块并使用,例如同时加载来自unpkg 和 hel pack2个平台的模块,平台值会被当做命名空间来隔离不同平台可能重名的模块。
上层生态建设
hel-micro
本身只提供远程模块加载的能力,具体的ui适配层还需要上层封装库区实现,目前的规划如下图
以 hel-micro-react
为例,提供以react
钩子函数的形式懒加载远程组件,并同时提供shadow dom样式隔离功能
何时采用hel-micro
当前时刻当你遇到以下任意一种情形时,采用hel-micro
都绝对值得你投入去尝试。
roadmap 2022~2023
结语
模块联邦对于搭建超大型js工程能到如虎添翼的作用,巨型应用的模块部署效率、共享效率都将迎刃而解,同时搭配微容器
相关框架(如wujie、rame)等,为你的隔离运行需求保驾护航,欢迎 star hel-micro,了解并使用。
_
我的其他开源作品友链(欢迎关注与了解):
concent,一个自带依赖收集、提供setup特性的react数据流方案
limu,一个比immer更高效的js不可变操作库