使用webpack时,如果没有安装webpack-cli会自动提示你安装,并且给出选项yes/no,输入选择并敲enter键则开始安装,做的人性化的,特意拿来研究一下,分享给掘友。如果你想做Cli工具本文可能对你有帮助。
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
webpack执行路线分析
我们一般会运行npx webpack XXX,结合package.json的设置:
"bin": {
"webpack": "bin/webpack.js"
},
可以得知入口文件为/bin/webpack.js
打开代码,扫一眼大概的运行图:
我们关注的点来到了!cli.installed分支:
if(!cli.installed){
//提示需要安装 cli
console.error(
`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
" "
)} ${cli.package}".`
);
//征求用户的同意
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 => {
//用户输入只要以y(不分大小写)开头即是同意安装
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."
);
return;
}
//执行安装
runCommand(packageManager, installOptions.concat(cli.package))
.then(() => {
runCli(cli);
})
.catch(error => {
console.error(error);
process.exitCode = 1;
});
})
}
ok,看完上述简单的流程,我们总结一下:
- 检测是否安装了某个包:
existsSync,isDirectory - 没有则,文字提示并开启获取用户输入的程序:
readline.createInterface。 - 对用户的输入处理并判断是否开始安装: 子进程
child_process.spawn
来一个简单版的自动安装cli
这里,我们会省掉一些不必要的配置,如bin文件指向等,需要提示安装。
我们来实现一个简单版的检测并提示安装lodash的程序。
const path = require("path");
const fs = require('fs')
const readLine = require('readline')
const cp = require("child_process");
//判断是否安装
const isInstalled = packageName => {
let dir = __dirname;
const targetPath = path.join(dir, "node_modules", packageName)
if (
fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory()
) {
return true;
} else {
return false;
}
};
//开始主程序
if (!isInstalled('lodash')) {
const question = '您需要安装lodash,才能继续,您愿意这样做吗?(yes/no)'
const popupInterface = readLine.createInterface({
input: process.stdin,
output: process.stderr
});
popupInterface.question(question, answer => {
//关闭用户交互
popupInterface.close();
const yes = answer.toLowerCase().startsWith("y");
if (yes) {
const executedCommand = cp.spawn('npm', ['install', 'lodash', '--save'], {
stdio: "inherit",
shell: true
});
executedCommand.on("error", error => {
console.error('安装失败,请稍后重试')
});
executedCommand.on("exit", code => {
if (code === 0) {
console.log('恭喜你已经成功安装了lodash')
} else {
console.log('安装失败,请稍后重试')
}
});
} else {
console.log('您依然可以以后安装lodash,再见!')
}
})
} else {
console.log('恭喜你已经安装了lodash')
}
效果如下:
再次运行则提示: