Compiler 模块是 Webpack 最核心的模块。每次执行 Webpack 构建的时候,在 Webpack 内部,会首先实例化一个 Compiler 对象,然后调用它的 run 方法来开始一次完整的编译过程。直接使用 Webpack API webpack(options) 的方式得到的就是一个 Compiler 实例化的对象,这时候 Webpack 并不会立即开始构建,需要手动执行 comipler.run() 才可以。

  1. const webpack = require('webpack')
  2. const webpackConfig = require('./webpack.config.js')
  3. // 只传入 config
  4. const compiler = webpack(webpackConfig)
  5. // 开始执行
  6. compiler.run(callback)
  7. // 上面两句等价于
  8. webpack(webpackConfig, callback)

Tips:使用 webpack-dev-server API 方式时,只需要传入 compiler 对象给 dev server 即可,不需要手动执行 compiler.run()

如果要手动实例化一个 Compiler 对象,可以通过const Compiler = webpack.Compiler来获取它的类,一般只有一个父 Compiler,而子 Compiler 可以用来处理一些特殊的事件。

在 Webpack Plugin 中,每个插件都有个 apply 方法。这个方法接收到的参数就是 Compiler 对象,可以通过在对应的钩子时机绑定处理函数来编写插件。

Compiler 钩子

image.png

上面的方式只是输出了 compiler.run() 之后的一部分钩子,Compiler 还有很多钩子。比如在 watch 模式下,还会有 watchRunwatchCloseinvalid

如果要绑定某个钩子,则可以使用下面的方法来绑定:

  1. compiler.hooks.someHook.tap('MyPlugin', (params) => {
  2. /* ... */
  3. })

列举一下对应的关系

image.png

Tips:整个 Compiler 完整地展现了 Webpack 的构建流程:

  • 准备阶段:make 之前做的事情都属于准备阶段,这阶段的 calback 入参以 compiler 为主
  • 编译阶段:这阶段以 compilation 的钩子为主,calback 入参以 compilation 为主
  • 产出阶段:这阶段从 compilation 开始,最后回到 Compiler 钩子上,calback 传入参数是跟结果相关的数据,包括 stats、error

Resolver

Compiler 的 Resolver 是指来自于 enhanced-resolve 模块,它主要功能是一个提供异步 require.resolve(),即从哪里去查找文件的路径,可以通过 Webpack 的 resolveresolveLoader 来配置。Compiler 类有三种类型的内置 Resolver:

  • Normal:通过绝对路径或相对路径,解析一个模块
  • Context:通过给定的上下文(context)解析一个模块
  • Loader:解析一个 webpack loader

thisCompilation 和 compilation

thisCompilationcompilation 两个钩子其实是跟子编译(child compiler)有关, Compiler 实例通过 createChildCompiler 方法可以创建子编译实例 childCompiler。创建 childCompiler 时,childCompiler 会复制 compiler 实例的任务点监听器。compilation 的钩子会被复制,而 thisCompilation 钩子则不会被复制。