webpack-cli 如何调用 webpack

  • 在 demo 目录运行 webpack-cli,会自动把 src/index.js 打包为 dist/main.js
  • 显然会调用 webpack 来打包,是如何做到的

打开webpack-cli源码
packages/webpack-cli/bin/cli.js
image.png
packages/webpack-cli/lib/bootstrap.js
image.png
packages/webpack-cli/lib/webpack-cli.js 构造函数中没东西
image.png
packages/webpack-cli/lib/webpack-cli.js run
image.png
packages/webpack-cli/lib/webpack-cli.js createCompiler
image.png
image.png

结论

webpack-cli通过调用webpack()这个函数创建了一个编译器

webpack = require(‘webpack’)
compiler = webpack(options, callback)

webpack-cli就这样调用了webpack

webpack 如何分析 index.js

打开webpack项目

package.json
image.png

lib/index.js
image.png

lib/webpack.js webpack
image.png

lib/webpack.js createCompiler
image.png

/lib/Compiler 构造函数,都是初始化 go back
image.png

回到lib/webpack.js
image.png

hooks.xxx.call()

Tapable
这是 webpack 团队为了写 webpack 而写的一个事件/钩子库

  • 用法
    • 定义一个事件/钩子
    • this.hooks.eventName = new SyncHook(["arg1", "arg2"]);
    • 监听一个事件/钩子
    • this.hooks.eventName.tap('监听理由', fn)
    • 触发一个事件/钩子
    • this.hooks.eventName.call('arg1', 'arg2')

webpack的流程

lib/webpack.js createCompiler
image.png

lib/webpack.js
image.png

lib/Compiler.js run
image.png

lib/Compiler.js run run
image.png

lib/Compiler.js onCompiled
image.png
image.png
目前看来大概有这些执行过程

  • environment
  • afterEnvironment
  • initialize
  • beforeRun
  • run
  • ——this.readRecords——
  • ——this.compile(x)——
  • —-onCompiled——
  • shouldEmit
  • ——nextTick——
  • ——this.emitAssets——
  • ——this.emitRecords——
  • done

看——this.compile()——

/lib/compile
image.png
image.png
这一部分的过程

——this.compile——
beforeCompile
compile
——this.newCompilation(x)——
make
finishMake
——nextTick——
——compilation.finish(x)——
——compilation.seal(x)——
afterCompile

看this.newCompilation()

/lib/Compiler
image.png

/lib/Compilation 都是初始化 go back
image.png

看compilation.finish(x)

/lib/Compilation.js finish
image.png
过程
——compilation.finish(x)——
finishModules

看compilation.seal(x)

/lib/Compilation.js seal
image.png
image.png
image.png
image.png
这一部分的过程
——compilation.seal(x)——
seal
afterOptimizeDependencies
beforeChunks
——this.addChunk——
——buildChunkGraph——
afterChunks
optimize
optimizeModules
optimizeChunks
optimizeTree
optimizeChunkModules

总结webpack的打包流程

  • environment
  • afterEnvironment
  • initialize
  • beforeRun
  • run
  • ——this.readRecords——
  • ——this.compile(x)——
    • beforeCompile
      • compile
      • ——this.newCompilation(x)——
      • make
        • finishMake
          • ——nextTick——
            • ——compilation.finish(x)——
              • finishModules
              • ——compilation.seal(x)——
                • seal
                • afterOptimizeDependencies
                • beforeChunks
                • ——this.addChunk——
                • ——buildChunkGraph——
                • afterChunks
                • optimize
                • optimizeModules
                • optimizeChunks
                • optimizeTree
                  • optimizeChunkModules
                • afterCompile
  • —-onCompiled——
  • shouldEmit
  • ——nextTick——
  • ——this.emitAssets——
  • ——this.emitRecords——
  • done

Webpack 是如何处理 Entry

读取 index.js 并分析和收集依赖是在哪个阶段?

  • 用排除法可以知道,肯定不是 env 和 emit,肯定在 beforeCompile 和 afterCompile 之间
  • 最有可能是在 make - finishMake 阶段
  • C 语言中make 是编译时必然会用到的工具

/lib/Compiler.js
image.png

全局搜索 make.tap
image.png

/lib/EntryPlugin.js
05ed009bb38478d5e0b793c31422a88.png

/lib/Compilation.js
image.png
image.png
image.png
image.png
image.png
image.png
image.png

/lib/NormalModuleFactory.js
image.png

搜索factorize.tap
image.png

image.png
搜索createModule.tap
image.png

/lib/sharing/ConsumeSharedPlugin.js
image.png

代码到factorizeQueue就没有后续代码了
image.png

factory.create是什么

  • factory从factorizeModule(options)的options.factory来的
  • options.factory从moduleFactory来的
  • moduleFactory是用this.dependencyFactories.get(Dep)得到的
  • this.dependencyFactories.get(Dep)是normalModuleFactory简称
  • 结论 factory就是nmf,所以factory.create 就是 nmf.create

nmf.create做了什么

  • NormalModuleFactory.js中
  • beforeResolve.call 和 factorize.call
  • 搜索对应tap ,factorize.tap中
    • 触发resolve,而resolve主要手机loaders
    • 然后触发createModule,得到createdModule
  • 也就是nmf.create得到了一个module对象
  • 等价于factory.create得到了一个module对象
  • 综上,从factorizeModule来到factory.create的
  • 回到factorizeMOdule,发现后续操作是addModule和buildModule

addModule做了什么

  • 把module添加到compilation.modules里
  • 而且还通过检查id防止重复添加

buildModule做了什么

  • 调用module.build()
  • NormaModule.js中发现runLoaders
  • 然后来到processResult(),发现了_source = … 和 _ast = null
  • 这一步就是把_source 变成 _ast
  • doBuild回调,发现this.parser.parse()
  • parse就是把code变成ast
  • 后面就是parser来自acorn库