作者: ixlei
https://segmentfault.com/a/1190000013657042
webpack是现代前端开发中最火的模块打包工具,只需要通过简单的配置,便可以完成模块的加载和打包。那它是怎么做到通过对一些插件的配置,便可以轻松实现对代码的构建呢?
webpack的配置
从上面我们可以看到,webpack配置中需要理解几个核心的概念 、 、 、 、 :
Entry:指定webpack开始构建的入口模块,从该模块开始构建并计算出直接或间接依赖的模块或者库
Output:告诉webpack如何命名输出的文件以及输出的目录
Loaders:由于webpack只能处理javascript,所以我们需要对一些非js文件处理成webpack能够处理的模块,比如sass文件
Plugins: 将各类型的文件处理成webpack能够处理的模块, 有着很强的能力。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。但也是最复杂的一个。比如对js文件进行压缩优化的 插件
Chunk:coding split的产物,我们可以对一些代码打包成一个单独的chunk,比如某些公共模块,去重,更好的利用缓存。或者按需加载某些功能模块,优化加载时间。在webpack3及以前我们都利用 将一些公共代码分割成一个chunk,实现单独加载。在webpack4 中 被废弃,使用
webpack详解
读到这里,或许你对webpack有一个大概的了解,那webpack 是怎么运行的呢?我们都知道,webpack是高度复杂抽象的插件集合,理解webpack的运行机制,对于我们日常定位构建错误以及写一些插件处理构建任务有很大的帮助。
不得不说的tapable
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的 和负责创建bundles的 都是Tapable的实例。在Tapable1.0之前,也就是webpack3及其以前使用的Tapable,提供了包括:
注册插件到Tapable对象中
调用插件的定义,将事件监听器注册到Tapable实例注册表中
多种策略细致地控制事件的触发,包括 、 等方法实现对事件触发的控制,实现
(1)多个事件连续顺序执行
(2)并行执行
(3)异步执行
(4)一个接一个地执行插件,前面的输出是后一个插件的输入的瀑布流执行顺序
(5)在允许时停止执行插件,即某个插件返回了一个 的值,即退出执行
我们可以看到,Tapable就像nodejs中 ,提供对事件的注册 和触发 ,理解它很重要,看个栗子:比如我们来写一个插件
在webpack的生命周期中会适时的执行:
当然上面提到的Tapable都是1.0版本之前的,如果想深入学习,可以查看Tapable和事件流(https://segmentfault.com/a/1190000008060440)。
那1.0的Tapable又是什么样的呢?1.0版本发生了巨大的改变,不再是此前的通过 注册事件,通过 触发事件调用,那1.0的Tapable是什么呢?
暴露出很多的钩子,可以使用它们为插件创建钩子函数
我们来看看怎么使用。
对于所有的hook的构造函数均接受一个可选的string类型的数组。
对于一个 ,我们通过 来添加消费者,通过 来触发钩子的顺序执行。
对于一个非 类型的钩子,即 类型的钩子,我们还可以通过其它方式注册消费者和调用
通过上面的栗子,你可能已经大致了解了 的用法,它的用法:
插件注册数量
插件注册的类型(sync, async, promise)
调用的方式(sync, async, promise)
实例钩子的时候参数数量
是否使用了
Tapable详解
对于 类型的钩子来说:
注册在该钩子下面的插件的执行顺序都是顺序执行。
只能使用 注册,不能使用 和 注册
对于 类型钩子:支持 、 、 注册。
每次都是调用 、 、 注册不同类型的插件钩子,通过调用 、 、 方式调用。其实调用的时候为了按照一定的执行策略执行,调用 方法快速编译出一个方法来执行这些插件。
中调用 方法编译生成执行代码。
在 中调用到 方法,此方法将按照此钩子的执行策略,调用不同的方法来执行编译 生成最终的代码。
SyncHook中调用 编译生成最终执行插件的函数, 做的就是将插件列表中插件按照注册顺序遍历执行。
SyncBailHook中当一旦某个返回值结果不为 便结束执行列表中的插件。
SyncWaterfallHook中上一个插件执行结果当作下一个插件的入参。
AsyncParallelHook调用 并行执行插件
webpack流程篇
本文关于webpack 的流程讲解是基于webpack4的。
webpack 入口文件
从webpack项目的package.json文件中我们找到了入口执行函数,在函数中引入webpack,那么入口将会是 ,而如果在shell中执行,那么将会走到 ,我们就以 为入口开始吧!
webpack入口
webpack 的入口文件其实就实例了 并调用了 方法开启了编译,webpack的编译都按照下面的钩子调用顺序执行:
before-run 清除缓存
run 注册缓存数据钩子
before-compile
compile 开始编译
make 从入口分析依赖以及间接依赖模块,创建模块对象
build-module 模块构建
seal 构建结果封装, 不可再更改
after-compile 完成构建,缓存数据
emit 输出到dist目录
编译&构建流程
webpack中负责构建和编译都是 。
在webpack 钩子中, 注册了一个 , 就是将入口模块通过调用 方法将所有的入口模块添加到编译构建队列中,开启编译流程。
随后在 中调用 开始编译。在 首先会生成模块,最后构建。
在编译完成后,调用 方法封闭,生成资源,这些资源保存在 , , 在给webpack写插件的时候会用到。
最后输出
在 执行后,便会调用 钩子,根据webpack config文件的output配置的path属性,将文件输出到指定的path.
觉得本文对你有帮助?请分享给更多人
关注「前端大全」,提升前端技能
领取专属 10元无门槛券
私享最新 技术干货