入口文件
通过 package.json 文件,找到了入口文件 ./lib/index.js 和 命令注册文件 ./bin/cli.js
"bin": {
"webpack-cli": "./bin/cli.js"
},
"main": "./lib/index.js",
在 index.js 中,module.exports 抛出了两个方法 utils 和 CLI;
在 cli.js 中,核心代码就是 require("../lib/bootstrap"),然后执行 runCLI 方法;
在cli.js 中引入了第三方依赖库 import-local
当全局node_modules和本地node_modules中存在相同的库时,优先使用本地node_modules中的版本
runCLI 方法
-
通过require("./webpack-cli"),引入WebpackCLI;
-
new WebpackCLI(),实例化CLI对象;
-
将utils方法挂载到this.utils上;
-
初始化 commander 的 program,并挂载到 this.program 上;
this.logger = utils.logger; this.utils = utils; // Initialize program this.program = program; this.program.name("webpack"); this.program.configureOutput({ writeErr: this.logger.error, outputError: (str, write) => write(`Error: ${this.utils.capitalizeFirstLetter(str.replace(/^error:/, "").trim())}`), }); -
-
执行cli的run方法;
run 方法
- 配置 program 的 option 选项,同时添加监听命令和选项的自定义函数
this.program.option("--color", "Enable colors on console.");
this.program.on("option:color", function () {
...
});
this.program.option("--no-color", "Disable colors on console.");
this.program.on("option:no-color", function () {
...
});
this.program.option(
"-v, --version",
"Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.",
);
this.program.option("-h, --help [verbose]", "Display help for commands and options.");
- 重写退出和输出
this.program.exitOverride(async (error) => {
if (error.exitCode === 0) {
process.exit(0);
}
if (error.code === "executeSubCommandAsync") {
process.exit(2);
}
if (error.code === "commander.help") {
process.exit(0);
}
...
this.logger.error("Run 'webpack --help' to see available commands and options");
process.exit(2);
});
- 异步解析命令行的字符串数组,然后执行 action 事件
this.program.parseAsync(args, parseOptions)
this.program.action(async (options, program) => {})
- 通过命令行的命令名称,来动态加载commander命令,然后在 program.action 的回调中执行makeCommand方法
loadCommandByName(commandToRun, true);
...
this.makeCommand(
isBuildCommandUsed ? buildCommandOptions : watchCommandOptions,
async () => {
this.webpack = await this.loadWebpack();
return isWatchCommandUsed
? this.getBuiltInOptions().filter((option) => option.name !== "watch")
: this.getBuiltInOptions();
},
async (entries, options) => {
...
await this.runWebpack(options, isWatchCommandUsed);
},
)
- 判断命令是否已经加载,如果已经加载则返回,如果没有加载则动态创建命令
const command = this.program.command(commandOptions.name, {
noHelp: commandOptions.noHelp,
hidden: commandOptions.hidden,
isDefault: commandOptions.isDefault,
});
...
command.action(action);
- 在command回调中先通过 loadWebpack 方法加载了 webpack,然后执行了 runWebpack 方法
this.runWebpack(options, isWatchCommandUsed);
- 在runWebpack中,创建webpack的complier
compiler = this.webpack(
config.options,
callback
? (error, stats) => {
...
callback(error, stats);
}
: callback,
);
this.createCompiler(options, callback);
- 进行webpack打包
webpack(config).run((err, stats) => {})