webpack_cli运行流程解析
准备工作
1、在github中下载webpack和webpack-cli的代码
2、通过webpack源码中的package.json分析webpack的入口在bin/webpack.js中。
流程分析
查看bin/webpack.js源码文件分析流程:
1、首先判断webpack-cli是否安装,没有安装就提示安装
2、安装之后执行runCli()
这里其实就是引入webpack-cli/bin/cli.js文件执行
cli.js
const runCli = cli => {
require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
};
在cli.js中主要是引入require("…/lib/bootstrap");
在bootstrap.js中就是引入require("./webpack-cli"),然后创建WebpackCLI,然后执行run方法。
bootstrap.js
const WebpackCLI = require("./webpack-cli");
const runCLI = async (args) => {
// Create a new instance of the CLI object
const cli = new WebpackCLI();
try {
await cli.run(args);
} catch (error) {
cli.logger.error(error);
process.exit(2);
}
};
- 构造函数分析
构造函数中主要是始化一些参数(colors、log、program)。
this.colors = this.createColors();
this.logger = this.getLogger();
// Initialize program
this.program = program;
this.program.name("webpack");
- run方法分析:
1、配置program参数和一些监听事件,配置default action
this.program.option("--color", "Enable colors on console.");
this.program.on("option:color", function () {
const { color } = this.opts();
cli.isColorSupportChanged = color;
cli.colors = cli.createColors(color);
});
...此处省略
this.program.usage("[options]");
this.program.allowUnknownOption(true);
this.program.action(async (options, program) => {
...省略
}
2、通过this.program.parseAsync(args, parseOptions)触发this.program.action(async (options, program) => {}
3、在this.program.action中首先解析program参数
4、加载命令loadCommandByName()
5、通过参数创建命令makeCommand(),传入两个回调函数(callback1, callback2)
await this.makeCommand(
isBuildCommandUsed ? buildCommandOptions : watchCommandOptions,
async () => {
// callback1
this.webpack = await this.loadWebpack();
},
async (entries, options) => {
// callback2
await this.runWebpack(options, isWatchCommandUsed);
},
);
6、在makeCommand(commandOptions, options, action)中
options = callback1, action = callback2
// 创建命令,添加命令相关的配置描述等
const command = this.program.command(commandOptions.name, {})
command.description(commandOptions.description, commandOptions.argsDescription);
...
// 检查依赖,并提示安装
this.checkPackageExists(dependency);
// 调用callback1,加载loadWebpack到this.webpack = webpack.js导出的函数
options = await options();
// 然后通过options 再次构建命令makeOption
options.forEach((optionForCommand) => {
this.makeOption(command, optionForCommand);
});
// 将callback2放入 command.action(action)中
command.action(action)
7、回到第一次的action中再次调用this.program.parseAsync()
await this.program.parseAsync([commandToRun, ...commandOperands, ...unknown], {
from: "user",
});
8、然后执行callback2,就是调用this.runWebpack()
await this.runWebpack(options, isWatchCommandUsed);
9、在this.runWebpack中开始构建
// 创建compiler
compiler = await this.createCompiler(options, callback);
// 那在this.createCompiler中做了什么呢
// 加载配置,构建配置
let config = await this.loadConfig(options);
config = await this.buildConfig(config, options);
// 开始执行调用webpack.js导出的函数,相当于开始执行webpack中的run方法开始编译
compiler = this.webpack(
config.options,
callback
? (error, stats) => {
if (error && this.isValidationError(error)) {
this.logger.error(error.message);
process.exit(2);
}
callback(error, stats);
}
: callback,
);
// 相当于执行这行代码开始编译代码
compiler.run((err, stats) => {}
- 补充说明
刚开始在webpack中利用node调试跟踪代码发现不行,后面更换了webpack-cli源码调试,找到同样的入口即可。
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/packages/webpack-cli/bin/cli.js"
}
]
}
webpack_cli源码流程分析图: