90行代码实现模块打包器
大家好,我卡颂。
今天来聊聊如何用90行代码实现一个现代JS
模块打包器。
【90行代码实现模块打包器】我们的打包器虽然迷你,但是实现了webpack
的核心功能。
而且,我知道你看到大段代码头疼,所以这篇文章都是图。看完感兴趣的话,这里是完整代码的仓库地址,只有90行代码哦。
让我们愉快的开始吧。
文章图片
生成依赖图
如果应用是个毛线团的话,那么入口文件就是线头。打包器要做的第一件事是:
顺着线头开始滤清整条线的走向
文章图片
假设入口文件是
entry.js
:// entry.jsimport a from './a.js';
import b from './b.js';
console.log(a, b);
他依赖了
a.js
与b.js
。文章图片
em... 有点太简陋了,让我们再扩展下
a.js
与b.js
:// a.js
import c from './c.js';
// ...
// b.js
import d from './d.js';
import e from './e.js';
// ...
所以整个依赖关系是这样:
文章图片
打包器会从入口文件开始,尝试建立模块(即
js
文件)间的依赖关系,也就是刚才我们讲的顺着线头开始滤清整条线的走向。模块间的依赖关系可以通过分析模块代码中的
import 声明语句
得知。为了能分析
import 声明语句
,可以使用babel
等编译工具将模块代码分解为AST
(抽象语法树)。文章图片
遍历
AST
,类型为ImportDeclaration
的节点就是import声明语句
。最后,我们将
AST
重新转换为可执行的目标代码
,可能还需要根据代码要执行的宿主环境(一般为浏览器)对代码做一些转换。比如,浏览器不支持
import './a.js'
这样的ESM
语法,那么我们需要将所有ESM
语法转为CJS
语法。// 源代码
import './a.js';
// 转换后
require('./a.js');
所以,对于任一模块(
js
文件),会经历:文章图片
右边包含
目标代码
和模块间依赖关系
的数据结构被称为asset
。每个
asset
可以通过模块间依赖关系
找到依赖的模块,重复这一过程,生成新的asset
,最终形成整个应用所有asset
间的依赖关系:文章图片
应用完整的依赖关系被称为依赖图(dependency graph)。
打包代码 接下来,只需要遍历依赖图,将所有
asset
的目标代码
打包在一起就行。所有代码会被打包在一个立即执行函数中:
(function(modules) {
// 打包好的代码
})(modules)
modules
中保存了所有asset
及他们之间的依赖关系。
如果你对
modules
的细节感兴趣,可以去文末仓库里翻代码
刚才说过,asset
的目标代码
是CJS
规范的,类似:// entry.jsrequire('./a.js');
require('./b.js');
这意味着我们需要实现:
require
方法(用于引入依赖的其他asset
的目标代码
)module
对象(用于保存当前asset
的目标代码
执行后导出的数据)
asset
的目标代码
中的变量互相污染,每个目标代码
需要独立的作用域。我们将
目标代码
包裹在函数
中:// 我们操作的是字符串模版
`function (require, module, exports) {
${asset.code}
}`
所以,最终打包的结果为:
(function(modules) {
function require() {// ...}require(入口asset的ID)
})(modules)
这段字符串被包裹在浏览器
标签内,会依次执行:require(入口asset的ID)
,执行入口asset
的目标代码
目标代码
内部会调用require
执行其他asset
的目标代码
- 一步步执行下去...
- 从入口文件开始遍历,生成依赖图
- 根据依赖图,将代码打包进一个立即执行函数
- 解决循环依赖
- 缓存
欢迎加入 人类高质量前端框架研究群,带飞
推荐阅读
- CVE-2020-16898|CVE-2020-16898 TCP/IP远程代码执行漏洞
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 孩子不是实现父母欲望的工具——林哈夫
- opencv|opencv C++模板匹配的简单实现
- Node.js中readline模块实现终端输入
- java中如何实现重建二叉树
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 人脸识别|【人脸识别系列】| 实现自动化妆