腾讯开源的 hel 提供了加载远程模块的能力,谈谈它的实现原理
腾讯开源的 hel,提供了一种运行时引入远程模块的能力,模块部署在 CDN,远程模块发布后,不需要重新构建发布,就能生效。
个人觉得它的实现原理非常的不错,因此分享给大家。
远程模块可以作为微模块(模块级别的微前端),是页面级别的微前端的一种补充,因为页面级别的微前端,如 qiankun、无界等,它们的粒度太粗了,有时候需要更细粒度的微前端,例如:组件、函数级别的。这种场景,就可以使用远程模块,来实现微模块的效果。
远程模块使用示例
import helMicro from 'hel-micro';export async function callRemoteMethod() {const lib = await helMicro.preFetchLib('hel-tpl-remote-lib');return lib.num.random(22);
}
1.引入 hel-micro 模块
2.通过 helMicro.preFetchLib 拉取远程模块
3.调用远程模块
整个使用过程非常的简单易懂,但这样无法使用 TS 类型检查。
于是又有了以下的写法:
需要先在项目入口调用:
await helMicro.preFetchLib('hel-tpl-remote-lib');
然后代码中就可以这样使用了:
import remoteLib from 'hel-tpl-remote-lib';function callRemoteMethod() {return remoteLib.num.random(19);
}
TS 类型则是由 hel-tpl-remote-lib 这个 npm 仓库提供。
hel 核心原理
概念约定
- 远程模块发布 CDN,在浏览器运行时,调用
helMicro.preFetchLib真正拉取代码* 代理模块用于开发时的类型提示,上传到 npm。开发时安装并使用该 npm 包,可以获得 TS 类型提示* 元数据 元数据是一份 json 配置清单,是在远程模块构建完成后,从构架产物中提取生成的。它记录了远程模块的名称、入口脚本路径等信息
hel 运行流程
1.当调用 helMicro.preFetchLib 时,先拉取元数据,从元数据中获取到入口脚本的 url,然后拉取远程模块入口并执行,最后 helMicro.preFetchLib 将模块返回,代码中就可以直接使用了。
2.import 代理模块,实际上是从远程模块的缓存中读取模块。因此,必须要等待 helMicro.preFetchLib 拉取完成后,import 的代理模块才能够获取到远程模块
hel 的默认拉取元数据的方式,是根据远程模块名称,到 unpkg CDN 对应的 npm 包下,获取元数据 meta_data.json 文件。这个拉取元数据的过程也可以开发者自定义。
整个流程非常简单,但难度在于,如何构建打包出代理模块和远程模块
模块构建
代理模块
代理模块负责以下内容:
- 在运行时读取远程模块的缓存
- 用于提供 TS 类型支持
运行时读取远程模块的缓存
hel 提供了 exposeLib 函数,用于读取远程模块的缓存
打包代理模块时,参考以下代码作为构建入口:
import type { LibProperties } from './你真正的模块代码';
import { exposeLib } from 'hel-lib-proxy';// 读取远程模块缓存,远程模块名为:hel-tpl-remote-lib
export const lib = exposeLib<LibProperties>('hel-tpl-remote-lib');// export 类型
export type Lib = LibProperties;// export 远程模块的缓存代码
export default lib;
该入口文件主要做了以下事情:
- export 导出 TS 类型
- 使用
exposeLib,将远程模块的缓存,暴露出来
以上述代码作为入口打包,实际上并没有将模块真实代码打包到产物中。因此代理模块,是一个非常小的模块,没有任何的模块逻辑。
在项目中使用远程模块 hel-tpl-remote-lib,最后打包只会打包代理模块这一小部分代码,不会将真正的代码打包到项目的产物中,因此还能提升项目的构建速度。
真正的代码,是运行时,在 preFetchLib 拉取远程模块时加载并运行的。
提供 TS 支持
只需要在 package.json 中声明 typing 字段:
{ "main": "hel_proxy/entry.js", "typings": "typings/index.d.ts",
}
typing的值为构建时生成的 TS 类型声明文件的路径。*main则用于声明代理模块的入口,指向的是打包后的产物。### 发布
代理模块直接发布到 npm 即可,按 npm 包的用法正常引入和使用即可
远程模块
远程模块的职责如下:
- 提供远程模块的真实运行代码
- 通知 hel 的
preFetchLib函数,远程模块加载完成 - 提供
index.html,用于提取元数据,例如提取出远程模块的入口(加载时,需要首先拉取哪些代码)
要做到以上的内容,远程的模块,也需要用一个入口文件再包一层,伪代码如下:
import { libReady } from '@tencent/hel-lib-proxy';async function main() {// 这里是 import 真正的模块代码了const lib = await import('./你真正的模块代码');// 注意此处传递的是 defaultlibReady('hel-tpl-remote-lib', lib.default);
}main().catch(console.error);
加载入口时立即调用 main 函数:
- import 真正的模块代码
- 调用
libReady并传入远程模块的值,该函数会通知preFetchLib,远程模块已经加载完成
如果一个远程模块,依赖另外一个远程模块,怎么办?
假如:hel-tpl-remote-lib 依赖 other-lib,other-lib 为另一个远程模块。即
// hel-tpl-remote-lib 的模块代码
import xxx from "other-lib"
那就 import other-lib 前,先执行 preFetchLib,拉取 other-lib。这样 other-lib 的代理模块,就能正确获取到内容。
import { LIB_NAME } from '../src/configs/subApp';
import { libReady } from '@tencent/hel-lib-proxy';async function main() {// 如有其他远程包依赖并且需要在内部使用静态导入的语法,可使用 preFetchLib 来加载这些包体const { preFetchLib } = await import('@tencent/hel-micro');await preFetchLib('other-lib');// 必须要用动态 import,因为如果当前包,还依赖其他的 hel 微前端依赖,需要 preFetchLib 之后,再进行引入。const lib = await import('./你真正的模块代码');// 注意此处传递的是 defaultlibReady('hel-tpl-remote-lib', lib.default);
}
如果存在嵌套的远程模块,就必须要用动态 import 引入真正的模块代码
await import('./你真正的模块代码')
元数据提取
hel 通过分析 index.html,来提取元数据,最重要的是要提取出模块的入口脚本,因为打包产物可能会有多个文件,要确定哪个才是入口。
假如有以下 HTML:
<!doctype html>
<html lang="en">
<script>这是一串内联 script
</script>
<script src="https://unpkg.com/hel-tpl-remote-lib@2.0.0/hel_dist/static/js/main.5ab2b93c.chunk.js"
></script>
</html>
那么会提取到两个入口脚本:
- 内联脚本:内联脚本会被提取出来,存放到单独的文件,该文件的路径会被记录到元数据
main.5ab2b93c.chunk.js
上述 index.html 会得到以下元数据(节选):
{bodyAssetList: [{"tag": "script","attrs": {"src": "https://unpkg.com/hel-tpl-remote-lib@2.0.0/hel_dist/hel_userChunk_1.js"}},{"tag": "script","attrs": {"src": "https://unpkg.com/hel-tpl-remote-lib@2.0.0/hel_dist/static/js/main.5ab2b93c.chunk.js"}}]
}
注意这里的资源路径是完整的 url 了。
preFetchLib 函数会读取元数据,然后拉取这些入口脚本。
发布
开源版本的 hel,远程模块和元数据,同样会发布到 npm。这样就可以从 unpkg 这个 CDN,直接拉取到元数据和远程模块
从元数据的入口脚本可以看出,入口脚本的路径,已经是指向了 unpkg
小结
以上内容,就是一个完整的 hel 的原理:
- 在页面初始化前,先
preFetchLib拉取远程模块,然后直接可以拿到远程模块的对象 - 然后代理模块也能够从缓存中,获取到远程模块的内容
难点则在于如何打包远程模块和代理模块,需要遵守特定的规范:
- 远程模块,则需要处理嵌套的远程模块,然后通知
preFetchLib函数,加载完成 - 代理模块,需要导出 TS 类型,并读取远程模块的缓存并导出
- 元数据,需要根据
index.html提取出入口脚本
但你觉得这就完了吗?其实没有。
元数据的妙用
hel 提供了自定义拉取元数据的能力,这意味着,我们有了控制的返回元数据的能力,元数据中有远程模块的入口,因此能控制拉取的远程模块。
下面是一个例子:
元数据通过版本管理平台的接口拉取。
通过在版本管理平台上配置,可以返回的元数据的对应的远程模块版本,从而做到控制远程模块的版本号,能做到回滚,灰度等能力。
上述版本管理平台,其实在腾讯内部已经实现,但目前仍未开源,但从 github 上已经看到是计划中了
有了自定义拉取元数据的能力,这个过程就会有非常大的自由度,由此可以衍生出一个非常大的微模块生态。理论上可以做到但不限于以下的效果:
- 控制全局的远程模块的版本
- 快速回滚能力
- 灰度能力、AB test 能力,根据地域分布、用户等条件分发不同的元数据
- 按项目维度,进行版本控制,不同的项目,返回不同的元数据,从而使用不同的远程模块版本
- ……
总结
不过截止目前(2022.12.13),开源 hel 目前提供的部署方式,只是部署到 unpkg CDN 上,对于公司项目来说,不太适合,需要提供更多的最佳实践;它的开源生态,也有待完善。
但不得不承认的是,hel 的整个思路,的确是较为优秀,值得学习和研究, 能够作为一种优秀的远程模块/微模块方案。
最后也希望 hel 能越做越好吧~
最后
整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
部分文档展示:




文章篇幅有限,后面的内容就不一一展示了
有需要的小伙伴,可以点下方卡片免费领取
相关文章:
腾讯开源的 hel 提供了加载远程模块的能力,谈谈它的实现原理
腾讯开源的 hel,提供了一种运行时引入远程模块的能力,模块部署在 CDN,远程模块发布后,不需要重新构建发布,就能生效。 个人觉得它的实现原理非常的不错,因此分享给大家。 远程模块可以作为微模块…...
【运动控制】CNC三轴小线段路径规划
CNC三轴小线段路径规划 文章目录CNC三轴小线段路径规划一、项目说明二、具体实现1、速度规划2、小线段插补3、运动学逆解刀轴插补点4、差分处理得到实际的速度和加速度5、加速度滑动平均6、实现的效果如图所示三、Reference写在前面,本文是作为一个练手小项目的总结…...
渗透测试之DNS域名信息探测实验
渗透测试之DNS域名信息探测实验实验目的一、实验原理1.1 域名1.2 .域名的构成1.3 域名的基本类型1.4 域名级别二、实验环境2.1 操作机器三、实验步骤1. 使用sp查询域名信息2. 进行探测实验实验目的 掌握使用nslookup进行DNS域名信息探测的原理和方式了解子域名查询网站 一、实…...
ASE140N04-ASEMI低压MOS管ASE140N04
编辑-Z ASE140N04在TO-220F封装里的静态漏极源导通电阻(RDS(ON))为4mΩ,是一款N沟道低压MOS管。ASE140N04的最大脉冲正向电流ISM为400A,零栅极电压漏极电流(IDSS)为1uA,其工作时耐温度范围为-55~175摄氏度。ASE140N04…...
Qt——QLineEdit
QLineEdit是一个单行文本编辑控件。 使用者可以通过很多函数,输入和编辑单行文本,比如撤销、恢复、剪切、粘贴以及拖放等。 通过改变QLineEdit的 echoMode() ,可以设置其属性,比如以密码的形式输入。 文本的长度可以由 maxLength(…...
前端-HTML-zxst
HTML HTML是超文本标记语言(HyperText Mark-up Language) CSS是层叠样式表(Cascading Style Sheets) JS,即JavaScript是一种具有函数优先的轻量级,解释型或即时编译型的编程语言 <!--doctype标签声明…...
终极方案,清理 docker 占用磁盘过大问题, 亲测有效!
背景 在笔者的工作测试环境中,使用过程中突然出现根磁盘快吃满了(docker也是使用的根池盘的/var/lib/docker), wtf ? 服务用不了? 当然网上找到了一些常规的清楚docker 日志文件 但是通过df -hT 查看到over…...
puzzle(1321)时间旅人
时间旅人 最强大脑同款项目。 每个指针会带动周围2圈指针一起带动,内圈8个旋转180度,外圈16个旋转90度,全部调整为朝上则胜利。 问题本质: 很明显,问题本质就是求每个格子的点击次数,最少为…...
活动预告 | 2023 Meet TVM 开年首聚,上海我们来啦!
内容一览:从去年 12 月延期至今的 TVM 线下聚会终于来了!首站地点我们选在了上海,并邀请到了 4 位讲师结合自己的工作实践,分享 TVM 相关的开发经验,期待与大家线下相聚~ 关键词:2023 Meet TVM 线下活动 自…...
CoreIDRAW 软件的强大功能及适用性
1.1 绘图功能CoreIDRAW 软件是一种特殊的设计软件和图形绘制软件,使用方便、功能强大,在网页效果、商业插画设计、海报广告设计、平面设计等各类行业中都得到广泛的应用,在服装设计行业中,也逐渐地投入使用。由于纺织服装行业在设…...
JavaScript Window History
在 Web 开发中,JavaScript Window History(浏览器窗口历史记录)是一个非常有用的对象,它提供了一个接口来与浏览器历史记录进行交互。JavaScript Window History 对象允许您访问当前会话的历史记录,以及在会话历史记录…...
2023年人力资源管理师报名和培训费用是多少
2023年考人力资源管理师各个地区的收费标准不同,报名费用在几百元左右,培训费上千,具体看各地区人力资源管理师考试报名要求。 12023人力资源管理师考试费用 人力资源管理师考试分为四个等级,各级别费用是不同的,一般来…...
2023-2-23 刷题情况
灌溉花园的最少水龙头数目 题目描述 在 x 轴上有一个一维的花园。花园长度为 n,从点 0 开始,到点 n 结束。 花园里总共有 n 1 个水龙头,分别位于 [0, 1, …, n] 。 给你一个整数 n 和一个长度为 n 1 的整数数组 ranges ,其中…...
数据归档,存储的完美储备军
数据爆炸性增长的同时,存储成为了大家首要担心的问题大家都希望自家数据保存20年、50年后仍完好无损但是,N年后的数据量已达到一个无法预测的峰值如此大量的数据在保存时极可能存在丢失、损坏等问题这时需要提前对数据进行“备份”、“归档”备份是对数据…...
ES6-11、基本全部语法
一,变量声明:let声明变量:1.变量不可重复声明,let star 罗志祥 let star 小猪结果报错2.块级作用域,{ let girl 周扬青 }在大括号内的都属于作用域内3.不存在变量提升4.不影响作用域链const声明常量:const SCHOOL …...
Spring Boot整合Thymeleaf和FreeMarker模板
虽然目前市场上多数的开发模式采用前后端分离的技术,视图层的技术在小一些的项目中还是非常有用的,所以一直也占有一席之地,如spring官方的spring.io等网站就是使用视图层技术实现的。 目前Spring Boot支持的较好的两个视图层模板引擎是Thyme…...
SQL的四种连接-左外连接、右外连接、内连接、全连接
SQL的四种连接-左外连接、右外连接、内连接、全连接 内连接inner join…on… / join…on… 展现出来的是共同的数据 select m.Province,S.Name from member m inner join ShippingArea s on m.Provinces.ShippingAreaID; 相当于:select m.Province,S.Name from m…...
“点工”的觉悟,5年时间从7K到24K的转变,我的测试道路历程~
2015年7月我从一个90%以上的人都不知道的二本院校毕业(新媒体专业),凭借自学的软件测试(点点点)在北京找到了一份月薪7000的工作,在当时其实还算不错,毕竟我的学校起点比较差,跟大部…...
【Web安全-MSF记录篇章一】
文章目录前言msfvenom生成远控木马基本系统命令webcam 摄像头命令常用的信息收集脚本注册表设置nc后门开启 rdp&添加用户获取哈希mimikatz抓取密码前言 最近打站,可以感觉到之前的学的渗透知识忘记很多。。。。。多用多看多练,简单回顾一下 msfven…...
配置Flutter开发环境
一、在Windows上搭建Flutter开发环境 1、去flutter官网下载其最新可用的安装包,下载地址:https://flutter.dev/docs/development/tools/sdk/releases 。 注意,Flutter的渠道版本一直在不断的更新,请以Flutter官网为准。 另外&…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...
break 语句和 continue 语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
