原文链接 blog.csdn.net/weixin_4285...
npm init
安装前端脚手架制作所需要的一些插件
js
npm install chalk@4.0.0 commander@9.4.1 download-git-repo@3.0.2 fs-extra@11.1.0 inquirer@8.0.0 log-symbols@4.0.0 ora@5.0.0 path@0.12.7 update-notifier@4.0.0
js
"chalk": "^4.0.0", //用于修改终端(terminal)输出的字符串样式,包括字体色、背景色、字体样式
"commander": "^9.4.1", //是 node.js 命令行解决方案
"download-git-repo": "^3.0.2", //主要用来从一个代码仓库中下载文件的到目标文件夹
"fs-extra": "^11.1.0", //加强版的 fs(node 文件系统模块),主要用于操作文件
"inquirer": "^8.0.0", //inquirer.js 是一个用来实现命令行交互式界面的工具集合,它帮助我们实现与用户的交互式交流
"log-symbols": "^4.0.0", //为各种日志级别提供着色的符号
"ora": "^5.0.0", //主要用于创建和展示终端加载动画
"path": "^0.12.7", //主要用于格式化或拼接完整路径
"update-notifier": "^4.0.0" //检测 npm 包是否更新
配置 package.json文件
js
"name": "my-cli",
"main": "index.js",
"bin": {
"my-cli": "./bin/index.js"
},
编写 /bin/index.js,主要是编写交互的命令以及对应执行的操作
js
#!/usr/bin/env node
// 请求 commander 库
const program = require('commander')
// 从 package.json 文件中请求 version 字段的值,-v和--version是参数
program.version(require('../package.json').version, '-v, --version')
// 请求 lib/update.js
const updateChk = require('../lib/update')
// upgrade 检测更新
program
.command('upgrade')
.description("Check the my-cli version.")
.action(() => {
updateChk()
});
// 请求 lib/init.js
const initProject = require('../lib/create')
// init 初始化项目
program
.name('my-cli')
.usage('<commands> [options]')
.command('create <project_name>')
.description('create a new project')
.action(project => {
initProject(project)
})
// 解析命令行参数
program.parse(process.argv)
编写 /lib/create.js,主要的操作将会在这里完成
js
// 请求 fs-extra 库,用于文件操作
const fse = require('fs-extra');
// 请求 ora 库,用于初始化项目时等待动画
const ora = require('ora');
// 请求 chalk 库
const chalk = require('chalk');
// 请求 log-symbols 库
const symbols = require('log-symbols');
// 请求 inquirer 库,用于控制台交互
const inquirer = require('inquirer');
const path = require('path');
// 请求 download.js 文件,模板不在本地时执行该操作
const dlTemplate = require('./download');
// prompt文件
const promptProjectCover = require('./promptModules/projectCover');
const promptProjectSelect = require('./promptModules/projectSelect');
// 初始化项目
async function initProject(projectName) {
try {
const targetDir = path.join(process.cwd(), projectName);
if (fse.existsSync(targetDir)) {
// 项目重名时提醒用户
inquirer.prompt(promptProjectCover).then((answers) => {
if (answers.projectCover) {
createProject(targetDir, true);
} else {
console.log(symbols.error, chalk.red(`项目名称已存在,请重新设置!`));
process.exit();
}
}).catch((error) => {
console.log(symbols.error, chalk.red(`error:${error}`));
process.exit();
});
} else {
createProject(targetDir);
}
} catch (err) {
console.error(err);
process.exit();
}
}
// 开始创建项目
async function createProject(targetDir, removeDir) {
// 执行控制台交互
inquirer.prompt(promptProjectSelect).then(async (answers) => {
// 获取选择的模板
const projectSelect = answers.projectSelect;
// Spinner 初始设置
const initSpinner = ora(chalk.cyan('创建目录...'));
// 开始执行等待动画
initSpinner.start();
// 移除已有项目
if(removeDir){
try {
await fse.remove(targetDir)
} catch (err) {
// 如果出错,Spinner 就改变文字信息
initSpinner.text = chalk.red(`移除原有目录失败: ${err}`);
// 终止等待动画并显示 X 标志
initSpinner.fail();
// 退出进程
process.exit();
}
}
//判断目录是否存在,不存在则创建
fse.ensureDir(targetDir);
// 开始下载模板
try {
initSpinner.text = `下载模板...`;
await dlTemplate(targetDir, projectSelect);
}catch (e) {
// 如果成功,Spinner 就改变文字信息
initSpinner.text = chalk.red(e);
// 终止等待动画并显示 ✔ 标志
initSpinner.fail();
// 退出进程
process.exit();
}
// 如果成功,Spinner 就改变文字信息
initSpinner.text = '初始化项目完成.';
// 终止等待动画并显示 ✔ 标志
initSpinner.succeed();
}).catch((error) => {
console.log(symbols.error, chalk.red(error));
});
}
// 将上面的 initProject(projectName) 方法导出
module.exports = initProject;
编写 /lib/download.js,用于从指定仓库中下载文件模板
js
// 请求 download-git-repo 库,用于下载模板
const download = require('download-git-repo');
const path = require('path');
// 请求 mirror.js 文件
const dataMirror = require('./mirror');
async function dlTemplate(targetDir, projectSelect) {
return new Promise(((resolve, reject) => {
download(dataMirror[projectSelect], targetDir, {clone: true}, function (err) {
if (err) {
reject(`模板下载失败. ${err}`)
} else {
resolve(`模板下载完成`)
}
});
}))
}
// 将上面的 dlTemplate() 方法导出
module.exports = dlTemplate;
编写 /lib/update.js,检测npm仓库中我们的脚手架插件是否有新的版本
js
// 引用 update-notifier 库,用于检查更新
const updateNotifier = require('update-notifier')
// 引用 chalk 库,用于控制台字符样式
const chalk = require('chalk')
// 引入 package.json 文件,用于 update-notifier 库读取相关信息
const pkg = require('../package.json')
// updateNotifier 是 update-notifier 的方法,其他方法可到 npmjs 查看
const notifier = updateNotifier({
// 从 package.json 获取 name 和 version 进行查询
pkg,
// 设定检查更新周期,默认为 1000 * 60 * 60 * 24(1 天)
// 这里设定为 1000 毫秒(1秒)
updateCheckInterval: 1000,
})
function updateChk() {
// 当检测到版本时,notifier.update 会返回 Object
// 此时可以用 notifier.update.latest 获取最新版本号
if (notifier.update) {
console.log(`New version available: ${chalk.cyan(notifier.update.latest)}, it's recommended that you update before using.`)
notifier.notify()
} else {
console.log('No new version is available.')
}
}
// 将上面的 updateChk() 方法导出
module.exports = updateChk
编写 /lib/mirror.js,我的远程仓库地址,目前是固定写死的,这部分可以根据自身未来的项目需求,写成可以自动配置的方式
js
module.exports = {
'0': 'direct:https://gitee.com/meme-project/m-template-vue2-mb.git',
'1': 'direct:https://gitee.com/meme-project/m-template-vue2-pc.git',
'2': 'direct:https://gitee.com/meme-project/m-template-vue3-mb.git',
'3': 'direct:https://gitee.com/meme-project/m-template-vue3-pc.git',
'4': 'direct:https://gitee.com/meme-project/m-template-wx.git',
};
编写 /lib/promptModules/projectCover.js、/lib/promptModules/projectSelect.js,这个主要功能是编写inquirer终端命令行需要交互的命令
js
//projectCover.js
module.exports = [{
type: 'confirm',
message: '目录下存在相同名字的文件名称,是否覆盖?',
name: 'projectCover',
default: 'true'
}];
//projectSelect.js
module.exports = [{
type: 'list',
message: '请选择要创建的模板',
name: 'projectSelect',
default: 0,
choices: [
{value: 0, name: 'vue2 移动端模板'},
{value: 1, name: 'vue2 PC端后台模板'},
{value: 2, name: 'vue3 移动端模板'},
{value: 3, name: 'vue3 PC端后台模板'},
{value: 4, name: '微信小程序模板'}
]
}];
运行测试脚手架: 通过npm link软连接的方式,在项目本地测试脚手架的功能,可以看到已经成功完成了我想要的功能
js
// 根目录下执行
npm link
my-cli -v
my-cli create cli-demo
npm publish 命令,将当前脚手架发布到npm库
再次测试远程npm包,
js
npm i my-cli -g
my-cli upgrade
my-cli -v
my-cli create cli-demo