千字简述webpack打包原理
(本文不讲解webpack的具体使用,以及如何配置,适合有webpack经验的人群阅读,并且本文对一些原理做了些简化,并非真正webpack处理方式。学代码重在思路而不是深究某一点,思路有了那么什么都有了)

对于webpack,这是现代前端用来构建与打包的工具,只需要做一点配置,就可以使得我们一大堆的开发文件变成可上线的代码,比如说把react,Vue文件都编译成能够在浏览器运行的代码。这到底是如何做到的?
其实原理并不是很复杂。究其根本,代码仅仅只是一堆字符串罢了,只要我们用个什么方法去操纵这堆字符串,那不就可以控制代码的任意行为了嘛
举个简单的例子,我现在需要实现一个转译器,我需要把js语言转换成c语言,要怎么做?其实最笨的方法就是通过读取文件中的字符串,把js语法的字符串,通过一堆规则转换成c语言即可,如下:
// 文件A中:
let a = 20
// 如果我需要把上面这个文件中的内容转换成c语言代码,
// 那么现在通过文件操作,读取文件A中的内容,拿到代码字符串‘let a = 20’后
// 制定一个转换规则, 遇到let ,并且等号后面的内容是个数字,那么把let 换成int,如果结尾没有分号,那么加上分号
// 最后就转换为了这样
int a = 20;
以上就是webpack能够转换代码的原理。下面是webpack代码的正式分析
1.模块化分析
在前端工程化中,模块化占据了相当重要的位置,正式有了模块化,才得以我们把代码大化小,那么webpack,也必须做到能够识别模块化所依赖的内容
有以下代码:
//A.js
let a = 20
export function test(){
console.log(a)
}
//B.js
import { test } from './A.js'
let k = 20
test()
如果我们使用了webpack,执行了打包命令,通常会被打包为以下内容
let a = 20 function test(){ console.log(a) } test()
我们发现代码被打包成了一个文件,并且,没有用到的变量进行了剔除,另外就是换行写的代码,被改成了不太便于观看的一行显示。这块的内容就是打包工具中比较重要的功能,一个是treeShaking,另一个则是代码压缩。
可以看到名词虽然高级,但实际上看上去并不难,treeShaking就是去掉了没用到的代码,而代码压缩则是把长文件缩短了,所谓的压缩,就是压缩代码中字符串的数量,一堆换行符和空格肯定会加大文件内容。
虽然代码发生了变化,但是执行结果是不变的,那么代码压缩和treeShaking以及webpack 是如何知道import 和export的?
代码压缩就不用说了,操作文件减去空格换行符即可。那么是如何分析import 和 export 的?问题看似难,实际上也可以使用文件操作来做到,我们遍历每一个文件,通过正则匹配import 和export,有对应的,就放到一个文件中。但是这种方法有一个问题,如果我们代码中定义了一串字符串变量,如下:
let a = 'import a from'
这个时候正则一定会匹配到这个字符串,这个时候就会有冲突了。那么现在我们就需要一个新东西帮我们处理代码了。
即大名鼎鼎的代码抽象语法树(ast Tree)
此处不详细介绍抽象语法树,我们只要知道,抽象语法树,是通过当前文件字符串,然后通过分析之后,我们可以拿到一个树形结构,这颗树上的节点字段,代表了文件中,代码的含义,比如说
ast语法树:{
A文件: {
变量: a:{ 值:20 }
}
B文件: {
函数:fn: { 内容:打印123 }
}
}
以上是举个例子,实际上可没这么简单。ast语法树是一个非常庞大的东西,通常不需要我们自己实现,我们只需要借助第三方库即可。比如说webpack就是使用的babel库的parser函数和traverse函数来分析ast树的(注意,treeShaking 也是通过ast语法树实现的)
有了库我们可以方便的处理文件了,我们从ast树上从入口文件开始,通过广度优先搜索遍历树,分析export 和import,接着把依赖的文件放进一个队列之中,这时,我们就拿到了这个项目中依赖了哪些js文件
依赖队列
queue:[index.js, A.js, B.js]
2.文件整合,生成bundle.js
此处任然是通过文件操作,用上面的依赖队列,以及ast语法树来操作文件,生成bundle.js 有以下步骤
1.建立闭包,文件变函数
2.建立映射,路径变id
3.建立require,导入执行require
4.建立moudle.export,导出执行moudle.export
任然是这个案例
//A.js
let a = 20
export function test(){
console.log(a)
}
//B.js
import { test } from './A.js'
let k = 20
test()
打包成这样
//bundle.js
function()(
moudle.export = { }
//文件映射
map = {
'A.js' : a函数,
'B.js': b函数
}
function a () {
let k = 20
function test(){
console.log(k)
}
moudle.export.test = test
}
function b() {
const ff = require('A.js')
ff()
const fn = moudle.export.test
fn()
}
b()
)()
如此,就把多个文件合成了一个文件去执行代码
3.几句话讲讲loader和plugin的原理
loader本质就是一个函数,在解析代码字符串时,对不同的文件放到loader 函数中做操作,没什么巧的
plugin也类似,他在loader后执行,他在webpack解析的过程中执行,在某个webpack阶段做一些操作

4373

被折叠的 条评论
为什么被折叠?



