既上篇脚手架学习
本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!
一、准备阶段
1.判断当前目录是否为空
接之前的代码,我们在commands/init/lib目录
项目的流程设计主要有准备阶段、下载模板、安装模板三个阶段,现在准备阶段。修改exec方法
exec() {
try {
// 准备阶段
this.prepare()
// 下载模板
// 安装模板
} catch (e) {
log.error(e.message)
}
}
复制代码
这里我们写了准备方法,首先要判断当前目录是否为空,这里写了一个isCwdEmpty判断目录是否为空
isCwdEmpty() {
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
}
复制代码
在prepare方法中,我们要对目录为空做是否继续创建操作,不为空,那么我们要做什么呢
prepare() {
// 判断当前目录是否为空
if(!this.isCwdEmpty()) {
// 1.1 询问是否继续创建
}
console.log('ret', ret)
// fs.readdirSync()
// 是否启动强制更新
// 选择创建项目或组件
// 获取项目的基本信息
}
复制代码
2.是否继续创建
当得到项目文件是否为空之后,我们通inquirer插件,做用户进行询问,这里我们要导入
lerna add inquirer commands/init/
lerna add fs-extra commands/init/
复制代码
导入fs-extra,可在确认清当前文件目录时,使用emptyDirSync,清空文件夹
async prepare() {
// 判断当前目录是否为空
const localPath = process.cwd()
if(!this.isDirEmpty(localPath)) {
let ifContinue = false
if (!this.force) {
// 1.1 询问是否继续创建
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.emptyDirSync(localPath)
}
}
}
}
复制代码
在这里,我们把isCwdEmpty修改为isDirEmpty,并将地址的获取放在了perpare中,
isDirEmpty(localPath) {
let fileList = fs.readdirSync(localPath)
// 文件过滤的逻辑
fileList = fileList.filter(file => (
!file.startsWith('.') && ['node_modules'].indexOf(file) < 0)
);
return !fileList || fileList.length <= 0
}
复制代码
之后我们可以获取用户信息,选择创建组件还是项目
async getProjectInfo() {
const projectInfo = {}
// 选择创建项目或组件
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) {
// 获取项目的基本信息
} else if (type === TYPE_COMPONENT){
}
return projectInfo
// return 项目的基本信息 (object)
}
复制代码
在prepare最后回调这个方法
return this.getProjectInfo()
复制代码
如果选择项目的话
if (type === TYPE_PROJECT) {
// 获取项目的基本信息
const o = await inquirer.prompt({
type: 'input',
name: 'projectName',
message: '请输入项目名称',
default: '',
validate: function(v) {
return typeof v === 'string'
},
filter: function(v) {
return v
}
}, {
type: 'input',
name: 'projectVersion',
message: '请输入项目版本号',
default: '',
validate: function(v) {
return typeof v === 'string'
},
filter: function(v) {
return v
}
})
console.log(o)
} else if (type === TYPE_COMPONENT){
}
复制代码
在这里可以加载semver依赖,使用valid对版本号和项目名称进行判断
项目名称
validate: function(v) {
let done = this.async();
setTimeout(function() {
// 1. 首字符必须为英文字符
// 2. 尾字符必须为英文或数字,不能为字符
// 3. 字符仅允许"-_"
if(!/^[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(v)) {
done('请输入合法的项目名称')
return
}
done(null, true)
}, 0)
},
复制代码
版本号
validate: function(v) {
let done = this.async();
setTimeout(function() {
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,
}
复制代码
二、下载模板
1.下载模板的数据获取
1.通过项目模板api获取项目模板信息
1.1 通过egg.js搭建一套后端系统
1.2 通过npm 存储项目模板(vue-cli/vue-element-admin)
1.3 将项目模板信息存储到mongodb数据库中
1.4 通过egg.js获取mongodb中的数据并通过api返回
在utils目录下创建request文件,加载axios依赖
lerna create @zl-cli-dev/request
lerna add axios .\utils\request\
复制代码
在request文件中配置请求
const axios = require('axios')
const BASE_URL = process.env.ZL_CLI_BASE_URL ? process.env.ZL_CLI_BASE_URL : 'xxxxxxxxxxx'
const request = axios.create({
baseURL: BASE_URL,
timeout: 5000,
})
request.interceptors.response.use(
response => {
return response.data;
},
error => {
return Promise.reject(error)
}
)
module.exports = request;
复制代码
在commands文件创建getProjectTemplate文件,调用服务
const request = require('@zl-cli-dev/request')
module.exports = function() {
return request({
url: '/project/template'
})
}
复制代码
在index中使用,判断当前是否有模板
const getProjectTemplate = require('./getProjectTemplate')
// 判断项目模板是否存在
const template = await getProjectTemplate()
if (!template || template.length === 0) {
throw new Error('项目模板不存在')
}
this.template = template
复制代码
2.下载模板的选择
在之前的交互方法中新加对项目模板选择的交互
{
type: 'list',
name: 'projectTemplate',
message: '请选择项目模板',
choices: this.createTemplateChoices()
}
复制代码
createTemplateChoices这个方法把数据都遍历出来,让用户选择
createTemplateChoices() {
return this.template.map(item => ({
value: item.npmName,
name: item.name
}))
}
复制代码
3.下载
加载package,userHome, path的依赖
lerna add user-home commands/init/
复制代码
1.获取项目信息
const { projectTemplate } = this.projectInfo
const templateInfo = this.template.find(item => item.npmName === projectTemplate)
复制代码
通过user-home获取本地目录,创建文件
const templateInfo = this.template.find(item => item.npmName === projectTemplate)
const targetPath = path.resolve(userHome, '.zl-cli-dev', 'template')
const storeDir = path.resolve(userHome, '.zl-cli-dev', 'template', 'node_modules')
复制代码
初始化package包,并下载包,如果已经下载了,就更新包
const templateNpm = new Package({
targetPath,
storeDir,
packageName: npmName,
packageVersion: version
})
if (!await templateNpm.exists()) {
await templateNpm.install()
} else {
await templateNpm.update()
}
复制代码
4.友好提示
使用cli-spinner,加载依赖到utils下的utils文件中
function spinnerStart (msg, spinnerString = '|/-\\') {
const Spinner = require('cli-spinner').Spinner
const spinner = new Spinner(msg + ' %s')
spinner.setSpinnerString(spinnerString);
spinner.start()
return spinner
}
function sleep (timeout = 1000) {
return new Promise((resolve, reject) => setTimeout(resolve, timeout))
}
复制代码
将方法导入到commands/init中,
const { spinnerStart, sleep } = require('@zl-cli-dev/utils')
if (!await templateNpm.exists()) {
const spinner = spinnerStart('正在下载模板...')
await sleep()
try {
await templateNpm.install()
log.success('下载模板成功')
} catch (e) {
throw e
} finally {
spinner.stop(true)
}
} else {
const spinner = spinnerStart('正在更新模板...')
await sleep()
try {
await templateNpm.update()
log.success('更新模板成功')
} catch (e) {
throw e
} finally {
spinner.stop(true)
}
}
复制代码
对模板下载和更新进行优化提示
上一篇:脚手架学习-基于node多进程
下一篇:未完待续。。。。