分别是核心、cli、本地开发服务器
package.json
"main": "lib/webpack.js", "web": "lib/webpack.web.js", "bin": "./bin/webpack.js",
命令行调用,执行bin对应js文件;nodejs代码调用执行main对应文件。
process.exitCode,设置退出状态,0成功,1错误。
runCommand,使用child_process开启子进程,执行命令,返回promise。inherit:继承父进程相关的stdio。
/** * @param {string} packageName name of the package * @returns {boolean} is the package installed? */ const isInstalled = packageName => { try { require.resolve(packageName); return true; } catch (err) { return false; } };
require.resolve执行成功,说明包存在,出现错误,则捕获说明不存在。
/** * @typedef {Object} CliOption * @property {string} name display name * @property {string} package npm package name * @property {string} binName name of the executable file * @property {string} alias shortcut for choice * @property {boolean} installed currently installed? * @property {boolean} recommended is recommended * @property {string} url homepage * @property {string} description description */ /** @type {CliOption[]} */ const CLIs = [ { name: "webpack-cli", package: "webpack-cli", binName: "webpack-cli", alias: "cli", installed: isInstalled("webpack-cli"), recommended: true, url: "https://github.com/webpack/webpack-cli", description: "The original webpack full-featured CLI." }, { name: "webpack-command", package: "webpack-command", binName: "webpack-command", alias: "command", installed: isInstalled("webpack-command"), recommended: false, url: "https://github.com/webpack-contrib/webpack-command", description: "A lightweight, opinionated webpack CLI." } ];
两个包的信息,webpack-cli和webpack-command,下面会用到。
const installedClis = CLIs.filter(cli => cli.installed);过滤这两包,获取安装过的包组成的数组。
if (installedClis.length === 0) { const path = require("path"); const fs = require("fs"); const readLine = require("readline"); let notify = "One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:"; for (const item of CLIs) { if (item.recommended) { notify += `\n - ${item.name} (${item.url})\n ${item.description}`; } } console.error(notify); const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock")); const packageManager = isYarn ? "yarn" : "npm"; const installOptions = [isYarn ? "add" : "install", "-D"]; console.error( `We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join( " " )}".` ); const question = `Do you want to install 'webpack-cli' (yes/no): `; const questionInterface = readLine.createInterface({ input: process.stdin, output: process.stderr }); questionInterface.question(question, answer => { questionInterface.close(); const normalizedAnswer = answer.toLowerCase().startsWith("y"); if (!normalizedAnswer) { console.error( "You need to install 'webpack-cli' to use webpack via CLI.\n" + "You can also install the CLI manually." ); process.exitCode = 1; return; } const packageName = "webpack-cli"; console.log( `Installing '${packageName}' (running '${packageManager} ${installOptions.join( " " )} ${packageName}')...` ); runCommand(packageManager, installOptions.concat(packageName)) .then(() => { require(packageName); //eslint-disable-line }) .catch(error => { console.error(error); process.exitCode = 1; }); }); }如果两个包,一个也没安装,就提示必须安装,这是推荐的包。
使用 fs.existsSync,在当前工作目录,判断是否存在yarn.lock文件。
存在,设置yarn add;否则npm install -D 。
提示询问是否同意安装webpack-cli? yes/no
使用readLine.createInterface,监控用户输入。
questionInterface.question监控到输入,就关闭监控输入,转小写判断输入是否y开头,不是,就提示你得安装,你可以人工手动安装。
并设置错误process.exitCode = 1;返回。
如果输入的开头是y,就提示安装webpack-cli,并且执行安装命令,注意runCommand参数,第二个参数是数组,表示命令行命令的参数,child_process子进程的.spawn函数,也支持这个数组形式参数。
前面runCommand返回promise,子进程执行退出时,如果code为0,表示成功执行命令,也就是成功安装,执行resolve。
然后就到了then,为了确保成功安装了webpack-cli,就require(packageName)下试下。 如果异常,也是catch,提示错误,设置process.exitCode = 1。 子进程如果失败,非0,会走reject();这时也会到catch逻辑。 promise的错误传递体现了。
else if (installedClis.length === 1) { 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] )); }俩个如果有一个安装了,我们这时并不知道安装了哪儿个,不过无所谓,我们就取这个安装过的包的package.json文件路径,然后引用它。
path.dirname(pkgPath),找到文件路径的目录路径。
找到package.json内bin对象,进而根据安装过的cli的binName,找到对应bin对应的js路径。
然后引用它。
这里引用它,其实就是执行它,相当于执行命令行命令。
else { console.warn( `You have installed ${installedClis .map(item => item.name) .join( " and " )} together. To work with the "webpack" command you need only one CLI package, please remove one of them or use them directly via their binary.` ); // @ts-ignore process.exitCode = 1; }
如果两个都安装了,提示只需要一个,卸载一个吧,设置退出码=1。