node_modules下.bin目錄下有一個webpack.cmd腳本文件,組裝定位了要執行的webpack.js文件
"%~dp0\node.exe" "%~dp0\..\webpack\bin\webpack.js" %*
將啓動文件指向了webpack目錄下的bin\webpack.js。
在webpack.js文件中,有一個runCommond方法和isInstalled判斷包是否安裝函數,
const runCommand = (command, args) => {
const cp = require("child_process");
return new Promise((resolve, reject) => {
const executedCommand = cp.spawn(command, args, {
stdio: "inherit",
shell: true
});
executedCommand.on("error", error => {
reject(error);
});
executedCommand.on("exit", code => {
if (code === 0) {
resolve();
} else {
reject();
}
});
});
};
const isInstalled = packageName => {
try {
require.resolve(packageName);
return true;
} catch (err) {
return false;
}
};
installedClis獲取已經安裝的cli,這裏面重要的就是CLIs數組中第一行isInstalled("webpack-cli"),指向了webpack-cli。
const installedClis = CLIs.filter(cli => cli.installed);
接下來根據filter方法找到已經安裝包,處理了包路徑,通過最後的require導入了wbpack-cli/bin/cli.js
const path = require("path");
const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
// eslint-disable-next-line node/no-missing-require
const pkg = require(pkgPath);
// eslint-disable-next-line node/no-missing-require
require(path.resolve(
path.dirname(pkgPath),
pkg.bin[installedClis[0].binName]
));
在wbpack-cli/bin/cli.js中,是一個IIFE,一般的cli文件中一般有二個操作,處理參數,將參數交給不同的邏輯(分發業務),文件中導入webpack,創建一個webpack實例。根據參數options創建一個compile實例,掛載鈎子,
const webpack = require("webpack");
let lastHash = null;
let compiler;
try {
compiler = webpack(options);
} catch (err) {
if (err.name === "WebpackOptionsValidationError") {
if (argv.color) console.error(`\u001b[1m\u001b[31m${err.message}\u001b[39m\u001b[22m`);
else console.error(err.message);
// eslint-disable-next-line no-process-exit
process.exit(1);
}
throw err;
}
在文件結尾處,就找到了webpack打包入口run方法
compiler.run((err, stats) => {
if (compiler.close) {
compiler.close(err2 => {
compilerCallback(err || err2, stats);
});
} else {
compilerCallback(err, stats);
}
});