看过element-plus
的朋友都知道,它在开发阶段使用的是unbuild
进行的打包编译。相比较传统的rollup
、webpack
等老牌构建工具而言,unbuild
更快!!
但这个快并不是指的编译上更快,毕竟它说到底仍然是基于rollup
的,和借力了esbuild
的vite
相比它并不适合使用更
这个修饰词
这里的快,指的是次数,和其他构建工具监听文件变更后reCompile
不同,unbuild
只在启动时执行一次
而提供该能力的核心即jiti
包
jiti 是做什么的
jiti
是一个npm
包,它实现的核心能力即代码插桩
代码插桩
是指在运行时动态修改代码的技术
如何启用
在package.json
文件的scripts
配置中指定--stub
,示例如下
json
{
"scripts": {
"dev": "unbuild --stub"
}
}
编译结果如下
ts
import jiti from "jiti这个包对应的系统文件地址";
jiti(...)('目标工程的入口文件');
源码解析
注意,本文的重点是分析jiti
的核心原理,因此对于unbuild
不会进行深入探讨,同时,既是核心原理,因此对于jiti
的实现细节也不在探讨范围
我们关心的是:
1-jiti 是什么
2-实时编译是如何实现的
- 首先,jiti 是什么?
这要从其package.json
包开始看起
从框红的webpack
可以知道,它就是一个普通的不能再普通的常规npm
包,并没有使用啥高大上的技术,换言之,它和插桩技术本身毫无关联
因此,只能从入口找答案,它由main
字段标识,指向lib
文件夹
json
{
"main": "./lib/index.js"
}
- 实时编译是如何实现的
从它是由webpack
构建的就可以猜出来,像es
语法降级,ts to js
转换这些操作一定是基于wb
的某个loader
或者plugin
实现的,所以这一部分肯定也与插桩技术本身无关
故,去掉编译相关的逻辑之后,我们很容易就发现了如下代码。显然,jiti
对源代码创建模块并重写了require
方法
ts
const mod = new Module(...);
mod.require = createJITI(...);
而createJITI
函数,其实就是对模块的编译过程,这就做到了,当访问某个模块的时候,再进行编译,即运行时,也即插桩
总结
搞了半天,原来插桩就是个函数重写😂