初始化阶段:

  1. 初始化参数: 从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。这个过程中还会执行配置文件中的插件实例化语句 new Plugin()。
  2. 初始化默认参数配置: new WebpackOptionsDefaulter().process(options)
  3. 实例化Compiler对象:用上一步得到的参数初始化Compiler实例,Compiler负责文件监听和启动编译。Compiler实例中包含了完整的Webpack配置,全局只有一个Compiler实例。
  4. 加载插件: 依次调用插件的apply方法,让插件可以监听后续的所有事件节点。同时给插件传入compiler实例的引用,以方便插件通过compiler调用Webpack提供的API。
  5. 处理入口: 读取配置的Entrys,为每个Entry实例化一个对应的EntryPlugin,为后面该Entry的递归解析工作做准备。

编译阶段:

  1. run阶段:启动一次新的编译。this.hooks.run.callAsync。
  2. compile: 该事件是为了告诉插件一次新的编译将要启动,同时会给插件带上compiler对象。
  3. compilation: 当Webpack以开发模式运行时,每当检测到文件变化,一次新的Compilation将被创建
    1. 一个Compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。
    2. Compilation对象也提供了很多事件回调供插件做扩展。
  4. make:一个新的 Compilation 创建完毕主开始编译 完毕主开始编译this.hooks.make.callAsync。
  5. addEntry: 即将从 Entry 开始读取文件。
  6. _addModuleChain: 根据依赖查找对应的工厂函数,并调用工厂函数的create来生成一个空的MultModule对象,并且把MultModule对象存入compilation的modules中后执行MultModule.build。
  7. buildModules: 使用对应的Loader去转换一个模块。开始编译模块,this.buildModule(module) buildModule(module, optional, origin,dependencies, thisCallback)。
  8. build: 开始真正编译模块。
  9. doBuild: 开始真正编译入口模块。
  10. normal-module-loader: 在用Loader对一个模块转换完后,使用acorn解析转换后的内容,输出对应的抽象语法树(AST),以方便Webpack后面对代码的分析。
  11. program: 从配置的入口模块开始,分析其AST,当遇到require等导入其它模块语句时,便将其加入到依赖的模块列表,同时对新找出的依赖模块递归分析,最终搞清所有模块的依赖关系。

文件输出阶段:

  1. seal: 封装 compilation.seal seal(callback)。
  2. addChunk: 生成资源 addChunk(name)。
  3. createChunkAssets: 创建资源 this.createChunkAssets()。
  4. getRenderManifest: 获得要渲染的描述文件 getRenderManifest(options)。
  5. render: 渲染源码 source = fileManifest.render()。
  6. afterCompile: 编译结束 this.hooks.afterCompile。
  7. shouldEmit: 所有需要输出的文件已经生成好,询问插件哪些文件需要输出,哪些不需要。this.hooks.shouldEmit。
  8. emit: 确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出内容。
  9. done: 全部完成 this.hooks.done.callAsync。