webpack

2.1 打包,webpack和gulp的区别

参考答案

Gulp:

Gulp是一个自动化构建工具,强调的是前端开发的流程,通过配置一系列的task,定义task处理的事物,然后定义执行顺序,来让Gulp执行task,从而构建前端项目的流程,说白了就是用来打包项目。

不管做什么功能,都有一个统一的接口进行管理,必须去注册一个任务,然后去执行,这也是它的特点之一,即“任务化”。

WebPack:

WebPack是一个前端模块化方案,侧重模块打包,把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源,Gulp也可以配置seajs、requirejs甚至webpack的插件。

它会分析你的项目结构,找到JS模块以及那些浏览器不能够直接运行的扩展语言(如:TypeScript等),然后将其转换和打包为合适的格式供浏览器使用。它最大的优点就是“模块化”(万物皆模块)。
相同点:

  • 都可以对文件进行合并与压缩(JS、CSS)。

不同点:

  • Gulp是构建工具,可以配合各种插件做css.压缩等,解放了双手,实现了自动化。
  • Gulp严格上讲,它旨在规范前端开发流程,不包括模块化功能。
  • WebPack是文件打包工具,可把各个项目的css.压缩文件等打包合并成一个或多个文件,主要就是应用于模块化操作。
  • WebPack更是明显强调模块化开发,而那些文件压缩合并、预处理等功能,只是他附带的功能。
  • WebPack整合了Gulp的优点,当我们想要一步一步来配置自己的环境时,那么gulp就可以满足我们的需要,但是如果我们想一下就配备大部分我们所需要的环境,那么此时可以选用WebPack,前提是写好package.json。
  • gulp与webpack上是互补的,还是可替换的,取决于你项目的需求,它们可不存在冲突的关系哈。
  • Gulp与WebPack可以组合起来使用,以便快速编译(依靠Gulp丰富的组件可以让JS与HTML实现联动,从而控制WebPack应用程序,达到高自动化)

2.2 webpack的打包流程

参考答案

Webpack的运行流程是一个串行的过程,从启动到结束依次执行以下流程:

  1. 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
  2. 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
  3. 输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统。

如果只执行一次构建,以上阶段将会按照顺序各执行一次。但在开启监听模式下,流程将变为如下:

img

下面具体介绍一下webpack的三个大阶段具体的小步。

初始化阶段

初始化阶段大致分为:

  • 合并shell和配置文件文件的参数并且实例化Complier对象
  • 加载插件
  • 处理入口
事件名 解释
初始化参数 从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。 这个过程中还会执行配置文件中的插件实例化语句 new Plugin()。
实例化 Compiler 用上一步得到的参数初始化Compiler实例,Compiler负责文件监听和启动编译。Compiler实例中包含了完整的Webpack配置,全局只有一个Compiler实例。
加载插件 依次调用插件的apply方法,让插件可以监听后续的所有事件节点。同时给插件传入compiler实例的引用,以方便插件通过compiler调用Webpack提供的API。
environment 开始应用Node.js风格的文件系统到compiler对象,以方便后续的文件寻找和读取。
entry-option 读取配置的Entrys,为每个Entry实例化一个对应的EntryPlugin,为后面该Entry的递归解析工作做准备。
after-plugins 调用完所有内置的和配置的插件的apply方法。
after-resolvers 根据配置初始化完resolver,resolver负责在文件系统中寻找指定路径的文件。

编译阶段

事件名 解释
before-run 清除缓存
run 启动一次新的编译。
watch-run 和run类似,区别在于它是在监听模式下启动的编译,在这个事件中可以获取到是哪些文件发生了变化导致重新启动一次新的编译。
compile 该事件是为了告诉插件一次新的编译将要启动,同时会给插件带上compiler对象。
compilation 当Webpack以开发模式运行时,每当检测到文件变化,一次新的Compilation将被创建。一个Compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。Compilation对象也提供了很多事件回调供插件做扩展。
make 一个新的Compilation创建完毕,即将从Entry开始读取文件,根据文件类型和配置的Loader对文件进行编译,编译完后再找出该文件依赖的文件,递归的编译和解析。
after-compile 一次Compilation执行完成。这里会根据编译结果 合并出我们最终生成的文件名和文件内容。
invalid 当遇到文件不存在、文件编译错误等异常时会触发该事件,该事件不会导致Webpack退出。

这里主要最重要的就是compilation过程,compilation实际上就是调用相应的loader处理文件生成chunks并对这些chunks做优化的过程。几个关键的事件(Compilation对象this.hooks中):

事件名 解释
build-module 使用对应的Loader去转换一个模块。
normal-module-loader 在用Loader对一个模块转换完后,使用acorn解析转换后的内容,输出对应的抽象语法树(AST),以方便Webpack后面对代码的分析。
program 从配置的入口模块开始,分析其AST,当遇到require等导入其它模块语句时,便将其加入到依赖的模块列表,同时对新找出的依赖模块递归分析,最终搞清所有模块的依赖关系
seal 所有模块及其依赖的模块都通过Loader转换完成后,根据依赖关系开始生成Chunk。

输出阶段

事件名 解释
should-emit 所有需要输出的文件已经生成好,询问插件哪些文件需要输出,哪些不需要。
emit 确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出内容。
after-emit 文件输出完毕。
done 成功完成一次完成的编译和输出流程。
failed 如果在编译和输出流程中遇到异常导致Webpack退出时,就会直接跳转到本步骤,插件可以在本事件中获取到具体的错误原因。

2.3 webpack 有哪些阶段

参考答案

  1. webpack的准备阶段
  2. modules和chunks的生成阶段
  3. 文件生成阶段