千字简述webpack打包原理

千字简述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阶段做一些操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值