随着前端工程化的不断发展,构建工具也在不断完善。作为大前端时代的新宠,webpack 渐渐成为新时代前端工程师不可或缺的构建工具,随着 webpack 4 的不断迭代,我们享受着构建效率不断提升带来的快感,配置不断减少的舒适,也一直为重写的构建事件钩子机制煞费苦心,为插件各种不兼容心灰意冷,虽然过程痛苦,但结果总是美好的。
在阅读本文之前,我就默认电脑前的你已经掌握了 webpack 的基本配置,能够独立搭建一款基于 webpack 的前端自动化构建体系,所以这篇文章不会教你如何配置或者使用 webpack,自然具体概念我就不做介绍了,直面主题,开始讲解 webpack 原理。
webpack的运行过程可以简单概述为如下流程:
初始化配置参数 -> 绑定事件钩子回调 -> 确定Entry逐一遍历 -> 使用loader编译文件 -> 输出文件
接下来,我们将对具体流程逐一介绍。
在分析 webpack 运行流程时,我们可以借助一个概念,便是 webpack 的事件流机制。
什么是 webpack 事件流?
Webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。 Webpack 通过
Tapable
来组织这条复杂的生产线。 Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。 Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。 --吴浩麟《深入浅出webpack》
我们将 webpack 事件流理解为 webpack 构建过程中的一系列事件,他们分别表示着不同的构建周期和状态,我们可以像在浏览器上监听 click 事件一样监听事件流上的事件,并且为它们挂载事件回调。我们也可以自定义事件并在合适时机进行广播,这一切都是使用了 webpack 自带的模块 Tapable
进行管理的。我们不需要自行安装 Tapable
,在webpack被安装的同时它也会一并被安装,如需使用,我们只需要在文件里直接 require
即可。
Tapable的原理其实就是我们在前端进阶过程中都会经历的 EventEmit,通过发布-订阅模式实现,它的部分核心代码可以概括成下面这样:
因为 webpack 4 重写了事件流机制,所以如果我们翻阅 webpack hook 的官方文档会发现信息特别繁杂,但是在实际使用中,我们只需要记住几个重要的事件就足够了。
在讲解 webpack 流程之前先附上一张我自己绘制的执行流程图:
首先,webpack 会读取你在命令行传入的配置以及项目里的 webpack.config.js 文件,初始化本次构建的配置参数,并且执行配置文件中的插件实例化语句,生成 Compiler 传入plugin 的 apply 方法,为 webpack 事件流挂上自定义钩子。
接下来到了 entryOption 阶段,webpack 开始读取配置的 Entries,递归遍历所有的入口文件
Webpack进入其中一个入口文件,开始 compilation 过程。先使用用户配置好的 loader 对文件内容进行编译(buildModule),我们可以从传入事件回调的 compilation 上拿到 module 的 resource(资源路径)、loaders(经过的 loaders)等信息;之后,再将编译好的文件内容使用 acorn 解析生成 AST 静态语法树(normalModuleLoader),分析文件的依赖关系逐个拉取依赖模块并重复上述过程,最后将所有模块中的 require
语法替换成 __webpack_require__
来模拟模块化操作。
emit 阶段,所有文件的编译及转化都已经完成,包含了最终输出的资源,我们可以在传入事件回调的 compilation.assets 上拿到所需数据,其中包括即将输出的资源、代码块 Chunk 等等信息。
在1.2.2中,我们看到了一个陌生的字眼——AST,上网一搜:
在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是 “抽象” 的,是因为这里的语法并不会表示出真实语法中出现的每个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;而类似于
if-condition-then
这样的条件跳转语句,可以使用带有两个分支的节点来表示。 --维基百科
其实,你只要记着,AST是一棵树,像这样:
转换成 AST 的目的就是将我们书写的字符串文件转换成计算机更容易识别的数据结构,这样更容易提取其中的关键信息,而这棵树在计算机上的表现形式,其实就是一个单纯的 Object。
示例是一个简单的声明赋值语句,经过AST转化后各部分内容的含义就更为清晰明了了。
接下来,我们来看看 webpack 的输出内容。如果我们没有设置 splitChunk,我们只会在dist 目录下看到一个 main.js 输出文件,过滤掉没用的注释还有一些目前不需要去考虑的Funciton,得到的代码大概是下面这样:
我们都知道其实 webpack 在浏览器实现模块化的本质就是将所有的代码都注入到同一个 JS 文件里,现在我们可以清晰明了地看出 webpack 最后生成的也不过只是一个 IIFE,我们引入的所有模块都被一个 function
给包起来组装成一个对象,这个对象作为 IIFE 的实参被传递进去。
但如果我们配置了 splitChunk,这时候输出的文件就和你的 Chunk 挂钩了
这时候,IIFE 的形参也变成了摆设,所有我们的模块都被放在了一个名为 webpackJsonp
的全局数组上,通过 IIFE 里的 webpackJsonpCallback
来处理数据。
纵观 webpack 构建流程,我们可以发现整个构建过程主要花费时间的部分也就是递归遍历各个 entry 然后寻找依赖逐个编译的过程,每次递归都需要经历 String->AST->String 的流程,经过 loader 还需要处理一些字符串或者执行一些 JS 脚本,介于 node.js 单线程的壁垒,webpack 构建慢一直成为它饱受诟病的原因。这也是 happypack 之所以能大火的原因,我们可以来看一段 happypack 的示例代码:
大家如果有用过 pm2 的话就能很容易明白了,其实原理是一致的,都是利用了 node.js 原生的 cluster 模块去开辟多进程执行构建,不过在 4 之后大家就可以不用去纠结这一问题了,多进程构建已经被集成在 webpack 本身上了,除了增量编译,这也是4之所以能大幅度提升构建效率的原因之一。
我经历过 Webpack 1、2、3、4 变迁,以上内容仅是我 webpack 专题课当中的冰山一角,我的 webpack 专题课上线以后已经有超过 510+ 人购买,并获得了 100% 好评。
我是志佳老师
曾就职于 百度 LBS 搜索研发部 腾讯 MIG 地图平台部
深度实践过 FIS1、2、3
经历过 Webpack 1、2、3、4 变迁
我的 webpack 教程是基于 4.x 版本,从配置到源码的 5 大关键点深研 webpack,让你可以游刃有余的配置自己的工程化环境,并深度理解 webpack 的整体运作流程。适合有一定前端开发经验的同学。
【webpack 专题课】是 5 次录播大课 +1次直播答疑服务,如果你不小心错过了直播,可以随时看回放。我将通过先点、后线、再面的方式帮你占领 wepack 每一个重要的阵地,并提前带你熟知使用 webpack 过程中会遇到的坑。
如果你报名了我的 webpack 专题课,我希望你能认真学完,因为它不仅仅能缓解你的知识焦虑,更重要的是让你学会实操技能,并运用到工作当中,相信你一定会成为下一个精通 webpack 的前端工程师。
通过以下内容,你可以判断我的 webpack 专题课究竟适不适合你。
基于 4.x 版本,从配置到源码深研 webpack。
01 使用 webpack 快速构建 SPA 应用
讲解SPA的技术始末 以及项目结构
讲解Webpack在工程化领域的作用
讲解SPA开发中常见loader的应用
讲解SPA开发中常见plugin的应用
02 使用 webpack 快速构建 MPA 应用
以 Nest.js 为基础介绍 MPA 与 SPA 的区别
讲解 MPA 应用中入口的自动化收集
讲解开发自定义的属于 MPA 的 plugin
介绍将 MPA 构建为 SPA 的一些技巧
03 webpack 在一线开发中的优化
介绍如 Happypack 优化 Webpack 手段
介绍 Webpack 打包结果分析的利器
介绍对生产环境加快 Webpack 编译常用库
前端性能优化 Webpack 有用的 plugin 如(workbox-webpack-plugin)
04 webpack 核心源码分析原理课
编写属于自己的 loader & plugin
了解 Webpack 整体运行流程
熟悉 AST 抽象语法分析树的运用
分析 Tapable 插件实现的原理
分析 Webpack Template 类的实现
05 手把手带你实现一个 webpack
从0开始实践一个 Webpack 的雏形,能够让大家更加深入了解 Webpack
【购课福利】
【webpack 专题课】原价 98 元,限时优惠:68元。
扫描下面海报中的二维码,领取30元优惠券,即可享受限时优惠价格:68元。
现在更有 phodal
粉丝专属福利:购买 webpack 专题课的第5、10、15、20、25、30位用户将获赠程序员减压神奇:超大 Enter 键 一个。
请购买专题课之后务必添加微信:yidengxuetang,海洋老师将邀请你加入学员群,获取直播答疑的地址,并公布获赠名单哦~
赶快扫描下方二维码报名吧!