You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
4、在生成的 bundle.js 中,每个模块的唯一标识是模块的 ID,所以在拼接bundle.js 的时候,需要将每个模块的名字替换成模块的 ID
// 转换前
var a = require('./a.js');
var b = require('./b.js');
var luna = require('@alipay/luna-core');
// 转换后
var a = require(/* ./a.js */1);
var b = require(/* ./b.js */2);
var luna = require(/* @alipay/luna-core */3);
webpack bundler 实现
前言
Q: 为什么我们要做这件事?
A: 太多小伙伴对 webpack 的认识都在
webpack.config.js
上,对 webpack 的使用也都是黑盒的,对其打包、loader、plugin等实现原理知之甚少Q: webpack 现在如此庞大,应该如何着手?
A: 我们可以从 webpack 的第一个提交版本着手研究,它主要实现了 bundler和 loader,代码量很小,并且可读性很高 webpack 的第一个 commit
bundler 主要功能
bundler 实现思路
分析 bundle.js,我们能够发现:
1、不管有多少个模块,头部那一块都是一样的,它实现了 commonJS 的 module、module.exports、require 等函数,所以可以写成一个模板,也就是 webpack 里面的 templateSingle.js。
2、需要分析出各个模块间的依赖关系。也就是说,bundler 需要知道 example 依赖于 a、b 和 模块 luna。
3、luna 模块位于 node_modules 文件夹当中,但是我们调用的时候却可以直接 require('@alipay/luna-core'),所以 bundler 肯定是存在某种自动查找的功能。
4、在生成的 bundle.js 中,每个模块的唯一标识是模块的 ID,所以在拼接bundle.js 的时候,需要将每个模块的名字替换成模块的 ID
下面我们逐一分析一下上面的 4 各部分
1、头部模板
Q: 为什么叫 templateSingle?
A: 因为 webpack 在打包其他比如代码切割等时,头部模板会不一样,这儿为了区分,就叫 templateSingle 了,算是将所有的模块都打包到一个 JS 文件里面
2、分析模块依赖
CommonJS 不同于 AMD,不会在模板定义时将所有依赖的声明。CommonJS 最显著的特征就是用到的时候再 require,所以我们得在整个文件的范围内查找依赖了哪些模块。
Q: 怎么在整个文件里面查找出依赖?
A: 正则匹配?
Q: 如果 require 是写在注释里面了怎么办?性能如何?
A: 正则行不通,我们可以采用 babel 等语言编译器的原理,将 JS 代码解析转换成 抽象语法树(AST),再对 AST 进行遍历,找到所有的 require 依赖。
Q: 如果模块 a 依赖 b,b 又依赖 c,然后 c 又依赖 d 这又怎么办?
A: 当解析 a 模块时,如果模块 a 中又 require 了其他模块,那么将继续解析依赖的模块。也就是说,总体上遵循深度优先遍历
3、深度优先遍历构建依赖树:(详见 buildDeep.js)
4、模块寻址:(详见 resolve.js)
简单的寻址方法
拼接 bundle:(详见 webpack.js)
生成的 deepTree 如下:
循环遍历 modules,拼接 module 模块的 source,拼接结构如下:
具体实现如下:
我们发现模块 source 里面的模块名还需要替换成模块 id。具体实现如下:
The text was updated successfully, but these errors were encountered: