项目创建准备阶段——判断当前目录是否为空功能开发
// commands/init/lib/index.js 文件部分内容
class InitCommand extends Command {
......
async exec() {
try {
// 1. 准备阶段
this.prepare();
// 2. 下载模板
// 3. 安装模板
} catch (e) {
log.error(e.message);
}
}
......
async prepare() {
// 1. 判断当前目录是否为空
if (!this.isCwdEmpty()) {
// 1.1 询问是否继续创建
}
// 2. 是否启动强制更新
// 3. 选择创建项目或组件
// 4. 获取项目的基本信息
}
isCwdEmpty() {
// 获取当前文件目录
// console.log(path.resolve('.'))
const localPath = process.cwd();
let fileList = fs.readdirSync(localPath);
// 文件过滤的逻辑
fileList = fileList.filter(file => (
!file.startsWith('.') && ['node_modules'].indexOf(file) < 0
));
return !fileList || fileList.length <= 0;
}
}
inquirer 基本用法和常用属性入门
作用:命令行交互库
npm install --save inquirer@^8.0.0
const inquirer = require('inquirer');
inquirer
.prompt([
/* Pass your questions in here */
/* 参考文档 Objects Question A question object is a hash containing question related values: */
{
type: 'input',
name: 'yourName',
message: 'your name:',
default: 'noname',
validate: function(v) {
return v === 'sam'
},
transformer: function(v) { //作补充信息的,备注说明,不会影响最终结果。
return 'name:' + v
},
filter: function(v) { // 会改变最终结果。
console.log(v);
}
},
{ ...... }
])
.then((answers) => {
// Use user feedback for... whatever!!
console.log(answers.yourName)
})
.catch((error) => {
if (error.isTtyError) {
// Prompt couldn't be rendered in the current environment
} else {
// Something else went wrong
}
});
inquirer 其他交互形式演示
type: 'confirm' 二选一 Y/N
type: 'list' 需要提供 choices: [{value: xx, name: xx}]
type: 'rawlist' 和上面类似
type: 'expand' 需要提供 choices: [{value: xx, key: xx}],会显示key的首字母拼接如Rgbh
type: 'checkbox' 需要提供 choices: [{value: xx, name: xx}],会有多选功能
type: 'number' 非数字会返回 NaN
type: 'password'
type: 'editor' 和vim效果类似
强制清空当前目录功能开发
lerna add inquirer commands/init/
lerna add fs-extra commands/init/
# core/cli 引用了 commands/init/,commands/init/加入新包时,core/cli 要 npm link
// commands/init/lib/index.js 文件内容
//命令行中 --force,有两层含义。一:强制清空目录后安装,二:有文件时,直接安装模版
async exec() {
try {
// 1. 准备阶段
const ret = await this.prepare();
if (ret) {
// 2. 下载模板
// 3. 安装模板
}
} catch (e) {
log.error(e.message);
}
}
async prepare() {
// 1. 判断当前目录是否为空
const localPath = process.cwd();
if (!this.isDirEmpty(localPath)) {
let ifContinue = false;
if (!this.force) {
// 询问是否继续创建
ifContinue = (await inquirer.prompt({
type: 'confirm',
name: 'ifContinue',
default: false,
message: '当前文件夹不为空,是否继续创建项目?',
})).ifContinue;
if (!ifContinue) {
return;
}
}
// 是否启动强制更新
if (ifContinue || this.force) {
// 给用户做二次确认
const { confirmDelete } = await inquirer.prompt({
type: 'confirm',
name: 'confirmDelete',
default: false,
message: '是否确认清空当前目录下的文件?',
});
if (confirmDelete) {
// 清空当前目录
// fse.removeSync()
// 不会把当前目录删除
fse.emptyDirSync(localPath)
}
}
}
}
获取项目基本信息功能开发
项目名称和版本号合法性校验
lerna add semver commands/init/
async getProjectInfo() {
function isValidName(v) {
return /^[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(v);
}
const TYPE_PROJECT = 'project'
const TYPE_COMPONENT = 'component'
let projectInfo = {};
// 1. 选择创建项目或组件
const { type } = await inquirer.prompt({
type: 'list',
name: 'type',
message: '请选择初始化类型',
default: TYPE_PROJECT,
choices: [{
name: '项目',
value: TYPE_PROJECT,
}, {
name: '组件',
value: TYPE_COMPONENT,
}],
});
log.verbose('type', type);
if (type === TYPE_PROJECT) {
const project = await inquirer.prompt([{
type: 'input',
name: 'projectName',
message: `请输入项目名称`,
default: '',
validate: function(v) {
// 根据文档,可对用户输入做提示
const done = this.async();
setTimeout(function() {
// 1.首字符必须为英文字符
// 2.尾字符必须为英文或数字,不能为字符
// 3.字符仅允许"-_"
if (!isValidName(v)) {
done(`请输入合法的项目名称`);
return;
}
done(null, true);
}, 0);
},
filter: function(v) {
return v;
},
},{
type: 'input',
name: 'projectVersion',
message: `请输入项目版本号`,
default: '1.0.0',
validate: function(v) {
// 根据文档,可对用户输入做提示
const done = this.async();
setTimeout(function() {
// semver.valid() 可以format版本号,不规范的返回null
if (!(!!semver.valid(v))) {
done('请输入合法的版本号');
return;
}
done(null, true);
}, 0);
},
filter: function(v) {
if (!!semver.valid(v)) {
return semver.valid(v);
} else {
return v;
}
},
}]);
projectInfo = {
type,
...project
}
} else if (type === TYPE_COMPONENT) {
}
// 返回项目基本信息
return projectInfo
}