关于Webpack详述系列文章 (第四篇)
1. webpack基本概念
Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。
2. 流程概括
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
3.详细流程
WebPack的构建流程可以分为以下三大阶段:
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
- 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
- 输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统。
3.1 初始化阶段
| 事件名 | 解释 | / |
|---|---|---|
| 初始化参数 | 从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。 | webpack-cli/bin/webpack.js:436 |
| 实例化 Compiler | 用上一步得到的参数初始化 Compiler 实例,Compiler 负责文件监听和启动编译。Compiler 实例中包含了完整的 Webpack 配置,全局只有一个 Compiler 实例。 | webpack/lib/webpack.js:32 |
| 加载插件 | 依次调用插件的 apply 方法,让插件可以监听后续的所有事件节点。同时给插件传入 compiler 实例的引用,以方便插件通过 compiler 调用 Webpack 提供的 API。 | webpack/lib/webpack.js:42 |
| environment | 开始应用 Node.js 风格的文件系统到 compiler 对象,以方便后续的文件寻找和读取。 | webpack/lib/webpack.js:40 |
| entry-option | 读取配置的 Entrys,为每个 Entry 实例化一个对应的 EntryPlugin,为后面该 Entry 的递归解析工作做准备。 | webpack/lib/webpack.js:275 |
| after-plugins | 调用完所有内置的和配置的插件的 apply 方法。 | webpack/lib/WebpackOptionsApply.js:359 |
| after-resolvers | 根据配置初始化完 resolver,resolver 负责在文件系统中寻找指定路径的文件。 | webpack/lib/WebpackOptionsApply.js:396 |
3.2 编译阶段
| 事件名 | 解释 | / |
|---|---|---|
| run | 启动一次新的编译。 | webpack/lib/webpack.js:194 |
| watch-run | 和 run 类似,区别在于它是在监听模式下启动的编译,在这个事件中可以获取到是哪些文件发生了变化导致重新启动一次新的编译。 | |
| compile | 该事件是为了告诉插件一次新的编译将要启动,同时会给插件带上 compiler 对象。 | webpack/lib/Compiler.js:455 |
| compilation | 当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。一个 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。Compilation 对象也提供了很多事件回调供插件做扩展。 | webpack/lib/Compiler.js:418 |
| make | 一个新的 Compilation 创建完毕,即将从 Entry 开始读取文件,根据文件类型和配置的 Loader 对文件进行编译,编译完后再找出该文件依赖的文件,递归的编译和解析。 | webpack/lib/Compiler.js:459 |
| after-compile | 一次 Compilation 执行完成。 | webpack/lib/Compiler.js:467 |
在编译阶段中,最重要的要数 compilation 事件了,因为在 compilation 阶段调用了 Loader 完成了每个模块的转换操作,在 compilation 阶段又包括很多小的事件,它们分别是:
| 事件名 | 解释 | / |
|---|---|---|
| should-emit | 所有需要输出的文件已经生成好,询问插件哪些文件需要输出,哪些不需要。 | webpack/lib/Compiler.js:146 |
| emit | 确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出内容。 | webpack/lib/Compiler.js:287 |
| after-emit | 文件输出完毕。 | webpack/lib/Compiler.js:278 |
| done | 成功完成一次完成的编译和输出流程。 | webpack/lib/Compiler.js:166 |
| failed | 如果在编译和输出流程中遇到异常导致 Webpack 退出时,就会直接跳转到本步骤,插件可以在本事件中获取到具体的错误原因。 |
在输出阶段已经得到了各个模块经过转换后的结果和其依赖关系,并且把相关模块组合在一起形成一个个 Chunk。 在输出阶段会根据 Chunk 的类型,使用对应的模版生成最终要要输出的文件内容。
4. 代码流程
4.1 node_modules/.bin/webpack-cli
- 通过yargs获得shell中的参数
- 把webpack.config.js中的参数和shell参数整合到options对象上
- 调用webpack-cli/bin/webpack.js开始编译和打包
- webpack-cli/bin/webpack.js中返回一个compiler对象,并调用了compiler.run()
- lib/Compiler.js中,run方法触发了before-run、run两个事件,然后通过readRecords读取文件,通过compile进行打包,该方法中实例化了一个Compilation类
- 打包时触发before-compile、compile、make等事件
- make事件会触发SingleEntryPlugin监听函数,调用compilation.addEntry方法
- 这个方法通过调用其私有方法_addModuleChain完成了两件事:根据模块的类型获取对应的模块工厂并创建模块;构建模块
- 调用loader处理模块之间的依赖
- 将loader处理后的文件通过acorn抽象成抽象语法树AST
- 遍历AST,构建该模块的所有依赖
- 调用Compilation的finish及seal方法
4.2 关键事件
- entry-option:初始化options
- after-plugins
- after-resolvers
- environment
- after-environment
- before-run
- run:开始编译
- watch-run
- normal-module-factory
- context-module-factory
- before-compile
- compile
- this-compilation
- compilation
- make:从entry开始递归分析依赖并对依赖进行build
- build-module:使用loader加载文件并build模块
- normal-module-loader:对loader加载的文件用acorn编译,生成抽象语法树AST
- program:开始对AST进行遍历,当遇到require时触发call require事件
- after-compile
- should-emit
- need-additional-pass
- seal:所有依赖build完成,开始对chunk进行优化(抽取公共模块、加hash等)
- optimize-chunk-assets:优化代码
- emit:把各个chunk输出到结果文件
- after-emit
- done
- failed
- invalid
- watch-close
参考
plugins:https://github.com/webpack/docs/wiki/plugins
how to write a plugins:https://github.com/webpack/docs/wiki/how-to-write-a-plugin
Webpack编写一个插件:https://www.webpackjs.com/contribute/writing-a-plugin/
Webpack编写一个loader:https://www.webpackjs.com/contribute/writing-a-loader/
关于Webpack详述系列文章 (第四篇)的更多相关文章
- 关于Webpack详述系列文章 (第二篇)
1.缩小文件搜索范围 1.1.1 include & exclude module:{ rules:[ { test:/\.js$/, use:['babel-loader?cacheDire ...
- 关于Webpack详述系列文章 (第一篇)
WebPack官网地址(https://webpack-china.org/) 1. 什么是WebPack WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript ...
- 关于Webpack详述系列文章 (第三篇)
1. 类图 1. 模块 Module是webpack中最核心的类,要加载定的一切和依赖都是Module. 它有很多子类 RawModule NormalModule MultiModule Conte ...
- spring cloud系列教程第四篇-Eureka基础知识
通过前三篇文章学习,我们搭建好了两个微服务工程.即:order80和payment8001这两个服务.有了这两个基础的框架之后,我们将要开始往里面添加东西了.还记得分布式架构的几个维度吗?我们要通过一 ...
- 一步步实现windows版ijkplayer系列文章之七——终结篇(附源码)
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- openstack系列文章(四)
学习 openstack 的系列文章 - Nova Nova 基本概念 Nova 架构 openstack Log Nova 组件介绍 Nova 操作介绍 1. Nova 基本概念 Nova 是 op ...
- 【NLP】揭秘马尔可夫模型神秘面纱系列文章(四)
维特比算法解决隐马尔可夫模型解码问题(中文句法标注) 作者:白宁超 2016年7月12日14:08:28 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无 ...
- 实例讲解webpack的基本使用第四篇
这一篇来讲解一下webpack的loader的使用,用webpack打包文件,css,img,icon等都需要下载安装对应的loader文件,并且写好配置项,才可以进行打包,废话不多说,直接开始实战. ...
- k8s系列文章第五篇(docker-compose)
更多精彩内容,猛搓这里 目录 一.Docker Compose 1.前言 2.官方介绍 1.Compose 中有两个重要的概念 2.三步骤 3.Compose是Docker官方的开源项目,需要安装! ...
随机推荐
- Java Exception和Error的差别
Java中异常的抽象类是Throwable,在此基础上.派生出两大类:Error和Exception. Error是程序中的严重错误,不应该用try-catch包括.Javadoc的说明例如以下: A ...
- JAVA 不同类载入器命名空间的理解
曾经一直有这样一个疑惑: 都说在JAVA中,由不同类载入器载入的类在虚拟机中位于不同的命名空间下,不同命名空间下的类相互不可见. 这让我产生了一个迷惑:假设有一个类A使用了ja ...
- uva 473(dp)
题意:按创作时间给出n首歌每首歌的时间ti,然后按创作时间装到m个光盘内,给出光盘最大分钟数t,问m个光盘最多总共放多少首歌. 题解:对于每首歌都能够选或者不选,假设选择了这首歌,是否把这首歌当做第j ...
- rman数据库恢复;关键/非重要文件、影像副本、控制文件、还原点、非归档、增量、新数据库、灾难性回复
运行全然恢复:在 ARCHIVELOG 模式下 丢失了系统重要数据文件: 假设某个数据文件丢失或损坏.且该文件属于 SYSTEM 或 UNDO 表空间,请运行下面步骤: 1. 实例可能会也可能不会自己 ...
- SpringMVC中JSP取不到ModelAndView的数据原因
自己搭的项目突然EL表达式取不到值了 不管是用 ${msg} 还是用JSTL的<c:out value="${msg}"/> 都不行 才发现犯了一个平时不会注意的错误 ...
- spring之DelegatingFilterProxy
DelegatingFilterProxy是一个标准servlet Filter的代理,代理实现了Filter接口的spring管理的Bean.支持一个在web.xml的init-param定义的&q ...
- Debian9 ifconfig命令找不到解决办法
Debian9 ifconfig命令找不到解决办法 ifconfig.route.arp和netstat等命令行工具(它们统称为net-tools),管理和排查各种网络配置.这类工具原先起源于BSD ...
- DEDE 修改后台图集上传单个图片的大小限制
默认情况下,DEDE图集中单个图片大小限制在2M以内,而有时我们需要上传一个2M以上的文件,这是只要修改几个文件就可以实现了. 一.需要修改php.ini这个文件,我们必须保证PHP的配置中允许上传一 ...
- Android布局之RelativeLayout
RelativeLayout用到的一些重要的属性: 第一类:属性值为true或falseandroid:layout_centerHrizontal 水平居中android:layout_center ...
- 利用js 获取ip和地址
1.引用第三方js<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> 2. I ...