webpack 打包构建流程分析整理

如何调试 webpack

require(加载) node_modules/webpack-cli/bin 目录下的cli.js,预先设置debugger(断点),然后开启调试模式。

debugger.js

1
2
var webpackPath=require('path').resolve(__dirname,'node_modules', 'webpack-cli', 'bin', 'cli.js');
require(webpackPath);

webpack.config.js

1
2
3
4
5
6
7
8
9
const path=require('path');
module.exports={
mode:"development",
entry: './src/index.js',
output: {
path: path.resolve(__dirname,'dist'),
filename:'bundle.js'
}
}

webpack 主要工作流程

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

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的run方法开始执行编译; 确定入口:根据配置中的 entry 找出所有的入口文件
  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

webpack打包流程图

流程详解

初始化阶段

事件名解释代码位置
读取命令行参数 从命令行中读取用户输入的参数require(“./convert-argv”)(argv)
实例化 Compiler1.用上一步得到的参数初始Compiler 实例
2.Compiler 负责文件监听和启动编译
3.Compiler 实例中包含了完整的
Webpack 配置,全局只有一个 Compiler 实例。
compiler = webpack(options);
加载插件1.依次调用插件的 apply 方法,
让插件可以监听后续的所有事件节点。
同时给插件传入 compiler 实例的引用,
以方便插件通过 compiler 调用
Webpack 提供的 API。
plugin.apply(compiler)
处理入口读取配置的 Entrys,为每个 Entry 实例化
一个对应的 EntryPlugin,为后面该
Entry 的递归解析工作做准备
new EntryOptionPlugin().apply(compiler)
new SingleEntryPlugin(context, item, name)
compiler.hooks.make.tapAsync

编译阶段

事件名解释代码位置
run启动一次新的编译this.hooks.run.callAsync
compile该事件是为了告诉插件一次新的编译将要启动,同时会给插件传入compiler 对象。compile(callback)
compilation当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。一个 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。Compilation 对象也提供了很多事件回调供插件做扩展。newCompilation(params)
make一个新的 Compilation 创建完毕主开始编译this.hooks.make.callAsync
addEntry即将从 Entry 开始读取文件compilation.addEntry
this._addModuleChain
moduleFactory创建模块工厂const moduleFactory = this.dependencyFactories.get(Dep)
create创建模块moduleFactory.create
factory开始创建模块factory(result, (err, module)
resolver(result) this.hooks.resolver.tap(“NormalModuleFactory”)
resolveRequestArray解析loader路径resolveRequestArray
resolve解析资源文件路径resolve
userRequest得到包括loader在内的资源文件的绝对路径用!拼起来的字符串userRequest
ruleSet.exec它可以根据模块路径名,匹配出模块所需的loaderthis.ruleSet.exec
_run它可以根据模块路径名,匹配出模块所需的loader_run
loaders得到所有的loader数组results[0].concat(loaders, results[1], results[2])
getParser获取AST解析器this.getParser(type, settings.parser)
buildModule开始编译模块this.buildModule(module)
buildModule(module, optional, origin,dependencies, thisCallback)
build开始真正编译入口模块build(options)
doBuild开始真正编译入口模块doBuild
执行loader使用loader进行转换runLoaders
runLoaders
iteratePitchingLoaders开始递归执行pitch loaderiteratePitchingLoaders
loadLoader加载loaderloadLoader
runSyncOrAsync执行pitchLoaderrunSyncOrAsync
processResource开始处理资源processResource
options.readResource
iterateNormalLoaders
iterateNormalLoaders
createSource创建源代码对象this.createSource
parse使用parser转换抽象语法树this.parser.parse
parse解析抽象语法树parse(source, initialState)
acorn.parse解析语法树acorn.parse(code, parserOptions)
ImportDependency遍历并添加添加依赖parser.state.module.addDependency(clearDep)
succeedModule生成语法树后就表示一个模块编译完成this.hooks.succeedModule.call(module)
processModuleDependencies递归编译依赖的模块this.processModuleDependencies(module)
processModuleDependencies(module, callback)
this.addModuleDependencies
buildModule
make后结束makethis.hooks.make.callAsync(compilation, err => {}
finish编译完成compilation.finish();

结束阶段

事件名解释代码
seal封装compilation.seal
seal(callback)
addChunk生成资源addChunk(name)
createChunkAssets创建资源this.createChunkAssets()
getRenderManifest获得要渲染的描述文件getRenderManifest(options)
render渲染源码source = fileManifest.render();
afterCompile编译结束this.hooks.afterCompile
shouldEmit所有需要输出的文件已经生成好,询问插件哪些文件需要输出,哪些不需要。this.hooks.shouldEmit
emit确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出内容。this.emitAssets(compilation)
this.hooks.emit.callAsync
const emitFiles = err
this.outputFileSystem.writeFile
this.emitRecords写入记录this.emitRecords
done全部完成this.hooks.done.callAsync
© 2020 GOYTH All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero