前言
在写下一篇关于webpack2打包流程的文章之前,需要把webpack2中的一些概念来理一理。这样能提供更好的理解。
tapable
webpack的整个流程是通过事件进行控制的。webpack在整个流程中对事件的执行顺序和错误的处理问题是需要考虑的,tapable刚好提供了这么一个解决方案。(tapable详细使用,自行查阅资料)
- tapable事件流程控制事例123456789101112131415161718192021222324252627282930const tapable = require('tapable');const Tapable = new tapable();Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(null,500);}, value)})Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(null,200);}, value)})Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(null,'end');}, value)})Tapable.applyPluginsAsyncWaterfall('name', 1000, function (err,result) {console.log("end",err,result)});/*执行结果1000500200end null end*/
执行结果遵循先入先出原则,当前事件的处理函数执行cb()
后才会执行下一个处理函数。注:applyPluginsAsyncWaterfall
中,前一个处理函数执行cb(null,value)
传入的第二个参数value
作为下一个执行函数的传入参数值。
- tapable错误处理事例123456789101112131415161718192021222324252627282930313233const tapable = require('tapable');const Tapable = new tapable();Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(null,500);}, value)})Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(new Error('test error'));}, value)})Tapable.plugin('name', function (value, cb) {setTimeout(function () {console.log(value);cb(null,'end');}, value)})Tapable.applyPluginsAsyncWaterfall('name', 1000, function (err,result) {console.log("end",err,result)});/*执行结果1000500end Error: test errorat Timeout._onTimeout (/Users/xxx/xxx/src/test.js:24:27)at ontimeout (timers.js:469:11)at tryOnTimeout (timers.js:304:5)at Timer.listOnTimeout (timers.js:264:5) undefined*/
第二个事件处理函数中抛出了错误cb(new Error('test error'))
时,后面的处理函数将不会被执行,直接结束。执行applyPluginsAsyncWaterfall
中的函数。
webpack概念
webpack中有许多的实体,而其中部分核心实体和我们打包过程密不可分。
compiler 和 compilation
compiler源码解析:
我们可以在源码中看出,在options配置信息生成后,compiler对象被webpack创建。compiler继承于Tapable,包含了所有配置信息。compiler控制着打包的整个流程,包括创建compilation对象,然后执行编译,文件输出等流程。
compilation源码解析:
compilation也继承于Tapable,被compiler创建。不仅包含了webpack环境配置,模块和compiler等信息,还包含了模块和模块依赖的创建和构建,封装方法。chunk的创建和最终生成assets信息的方法等。每当一个文件发生改变时就会产生一个新的compilation。
(关于compilation中的各种方法,在下一篇的打包流程的文章中将被详细讲到。)
module
- 所有的入口文件,文件中的依赖都会被创建为module,module是整个过程最核心,最基础的实体。chunk的封装和asset生成都是基于module。
- module包含了
NormalModule
,MultiModule
,ContextModule
,DelegatedModule
,ExternalModule
等子类。 - NormalModule为单一入口时创建的模块,MultiModule为多入口时创建模块,ContextModule为模块化规范(amd,common,es6等)使用而创建的模块。
- module由
NormalModuleFactory
,ContextModuleFactory
,DllModuleFactory
,MultiModuleFactory
等工厂模块所创建。
dependency
依赖在模块执行loader之后,通过acorn解析生成AST(抽象语法树)之时,被依赖解析插件遍历,最终将依赖加入dependencies数组,其实依赖也是模块。
chunk
chunk是由多个module的具体的拆分处理后生成,包含了一个或多个module。比如:异步加载的模块就会被创建生成一个新的chunk,使用CommonsChunkPlugin也会生成新chunk。
Template
将不同的chunk通过对应的依赖模板,封装成source,赋值给asset。