背景
咱们用 vue,react,或是 vite,树立项目时,大都是履行一个指令行,然后终端出现模板,让你挑选,你输入项目名称,挑选模板,挑选一些装备项,是否需求装置等等,最终得到一个初始化的模板,然后在上面进行事务的开发。
完成一个这样的指令行脚手架,其实不难,借助一些第三方库,咱们就能做到
为啥要自己自定义封装这么一个指令行脚手架
。削减重复性的作业,不再需求复制其他项目再删除无关代码,或许从零创立一个项目和文件。
。依据交互动态生成项目结构和装备文件等。
。多人协作更为方便,不需求把文件传来传去,ctrl + C/V。
快速讲解下完成的进程
- 在github库房先树立好模板
- 用户通过指令交互的办法下载不同的模板
- 通过用户自定义的挑选,将模板引擎渲染定制项目模板
- 模板变化,只需更新模板即可,不需求用户更新脚手架
用到的第三方库
js库 | 说明 |
---|---|
commander.js | 能够主动的解析指令和参数,用于处理用户输入的指令 |
download-git-repo | 下载并提取 git 库房,用于下载项目模板 |
inquirer.js | 通用的指令行用户界面集合,用于和用户进行交互 |
handlebars.js | 模板引擎,将用户提交的信息动态填充到文件中 |
ora | 下载进程久的话,能够用于显现下载中的动画效果 |
chalk | 能够给终端的字体加上色彩 |
log-symbols | 能够在终端上显现出√或x等的图标 |
再放下各个插件的版别,避免因为插件的凹凸版别不同,导致同样的代码运转起来频频报错
"dependencies": {
"chalk": "^2.4.1",
"commander": "^12.0.0",
"download-git-repo": "^3.0.2",
"handlebars": "^4.0.11",
"inquirer": "^6.1.0",
"log-symbols": "^2.2.0",
"ora": "^3.0.0"
}
这儿或许咱们会有个好奇,package.json
中有 dependencies
,还有 devDependencies
,我为什么要把这些插件装置在 dependencies
中,而不是装置在 devDependencies
,我为什么 npm i xx -S
而不是 npm i xx -D
这儿我不展开详细讲 dependencies
和 devDependencies
的差异,我就快速简略说一下:
-
devDependencies
里边平常放的都是东西类的插件,在出产环境中不会再用到
- 举个栗子:比方
Babel
这种,我不期望它在出产环境中还在,因为出产环境的代码是已经打包过之后,已经从 es6 处理成 es5 了,不需求再用Babel了
- 举个栗子:比方
-
dependencies
里边平常放的也是东西类的插件,可是这类插件在出产环境中也依然会用到
- 举个栗子:比方
echarts
, 我最终代码打包之后,在出产环境中要可视化展现一些数据,需求用到图表,那echarts, 便是在出产环境中也要用到的
- 举个栗子:比方
那问题来了:我开发自定义的脚手架,为什么扯到了dependencies
和 devDependencies
?它两的差异我也不是不知道。
发布答案:主要原因是因为开发脚手架,我在本地用这两个没啥差异,最终发现问题是出在发包之后
的下载装置
上
我本地调的没问题,我当时的依靠都是放在devDependencies
里的,发包之后
# 发包之后进行装置
npm install --global my-hahaha-cli
通过排查,才发现,问题便是出在 devDependencies
上,当我把我的包卸载掉之后,把一切的依靠都转移到dependencies
上。
# 卸载自己装置的包
npm uninstall --global my-hahaha-cli
# 从头发布之后,再次装置
npm install --global my-hahaha-cli
这个时分,依靠才主动装置上了。
本地环境
nodejs 14.18.0
因为我是本地用 nvm办理多版别的node, 一起也装置了 yarn, 今天复盘收拾笔记的时分,之前是用 npm install来装置的,后来习惯性的用了 yarn 成果报错了,这儿需求注意一下
简略介绍下各个插件
commander
效果:能够主动的解析指令和参数,用于处理用户输入的指令
node原生有 process.argv
这个特点,也能用户输入的指令。 可是这个特点是从第三个开始
才是用户输入的,比较麻烦, 所以咱们仍是运用 commander
库
npm install commander@12.0.0 -S
download-git-repo
效果:这个包能够协助咱们下载 github库房中的包到本地
npm install download-git-repo@3.0.2 -S
运用这个库时,有个注意点
运用 download-git-repo
这个第三方包 进行模板的下载,先在自己的github上创立几个公开的git库房,用 down-git-repo的时分,要注意一个问题,他的download办法
的第一个参数 要写 git库房的地址,可是这个地址一般来讲,是 https://github.com/github用户名/库房名
,可是在用这个第三方库download
的时分,https://github.com
后边跟紧的是 :(冒号
)然后才是github用户名/库房名
再跟着 #分支名
否则,会报一个128 没有权限的问题
inquirer
效果:主要是 完成向导效果,完成一问一答的交互办法
handlebars
效果:主要是 当作模板引擎来处理字符串,再合作 node自带的 fs模块
将处理好的字符串 替换掉本来的模板package.json
inquirrer
和 handlebars
合作运用
视觉美化的第三方库
ora
效果:控制台下的loading效果,加载中…
npm install ora@3.0.0 -S
chalk
效果:为打印信息加上款式,比方成功信息为绿色,失利信息为赤色,这样子会让用户更加简单分辩一起也让终端的显现更加的好看
npm install chalk@2.4.1 -S
log-symbols
npm install log-symbols@2.2.0 -S
效果:各种日志等级的五颜六色符号,给终端的提示信息前面加上 ✔, 的符号
进程及代码
- 先在github上树立3个项目模板
如法炮制,再新建2个
然后,以第一个my-template1
为例,新建一个package.json,给里边的字段设置成动态的
github这边的已经设置好了,然后便是编码环节
- 这儿我直接放代码了,讲解都写在了注释里了
index.js
#!/usr/bin/env node
//运用Node开发指令行东西所履行的 Javascript 脚本必须在顶部加入 #!/usr/bin/env node 声明
// console.log("hello demo")
// 1. 获取用户输入指令 (原生获取指令行参数的办法)
// console.log(process.argv)
const { Command } = require('commander');
const download = require('download-git-repo')
const chalk = require('chalk')
const logSymbols = require('log-symbols')
const inquirer = require('inquirer')
const fs = require('fs')
const handlebars = require('handlebars')
const ora = require('ora')
const program = new Command();
program
.version('0.1.0');
const templates = {
'tpl-obj1': {
url: 'https://github.com/OhBadWorld/my-template1',
downloadUrl: 'https://github.com:OhBadWorld/my-template1#main',
description: '根据vue2树立的obj1模板'
},
'tpl-obj2': {
url: 'https://github.com/OhBadWorld/my-template2',
downloadUrl: 'https://github.com:OhBadWorld/my-template2#main',
description: '根据vue2树立的obj2模板'
},
'tpl-obj3': {
url: 'https://github.com/OhBadWorld/my-template3',
downloadUrl: 'http://github.com:OhBadWorld/my-template3#main',
description: '根据vue2树立的obj3模板'
}
}
// mycli init a a-name 根据 a模板进行初始化
// mycli init b b-name 根据 b模板进行初始化
// mycli init c c-name 根据 c模板进行初始化
program
.command('init <template-name> <project-name>')
.description('初始化项目模板')
.option('-s, --setup_mode [mode]', 'Which setup mode to use')
.action((templateName, projectName) => {
// 下载之前做 loading 提示
const spinner = ora('正在下载模板...').start();
// 依据模板名下载对应的模板到本地并取名为 projcetName
// console.log(templates[templateName], projectName);
// download
// 第一个参数: 库房地址
// 第二个参数: 下载路径
const { downloadUrl } = templates[templateName]
download(downloadUrl, projectName, { clone: true }, (err)=>{
if (err) {
spinner.fail() // 下载失利提示
console.log(logSymbols.error, chalk.red(`${templateName} download fail`))
return
}
spinner.succeed() // 下载成功提示
// 把项目下的 package.json 文件读取出来
// 运用向导的办法收集用户输入的值
// 运用模板引擎把用户输入的数据解析到 package.json 文件中
// 解析完毕,把解析之后的结架从头写入package.json 文件中
inquirer.prompt([
{
type: 'input',
name: 'name',
message:'请输入项目名称'
},
{
type: 'input',
name: 'description',
message:'请输入项目简介'
},
{
type: 'input',
name: 'author',
message:'请输入作者名称'
},
]).then((answers)=>{
const packagePath = `${projectName}/package.json`
// 把收集到的用户输入的数据解析替换到 package.json 文件中
const packageContent = fs.readFileSync(packagePath, 'utf8')
// 通过 handlebars进行模板解析,效果 编译并替换
const packageResult = handlebars.compile(packageContent)(answers)
fs.writeFileSync(packagePath, packageResult)
console.log(logSymbols.success, chalk.green(`模板 ${templateName} init success`))
})
})
});
program
.command('list')
.description('检查一切可用模板')
.action(() => {
for (let key in templates) {
console.log(`
${key} ${templates[key].description}
`)
}
})
program.parse();
package.json
{
"name": "my-cli",
"version": "1.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"type": "commonjs",
"keywords": [],
"author": "",
"license": "ISC",
"bin": {
"my": "index.js"
},
"dependencies": {
"chalk": "^2.4.1",
"commander": "^12.0.0",
"download-git-repo": "^3.0.2",
"handlebars": "^4.0.11",
"inquirer": "^6.1.0",
"log-symbols": "^2.2.0",
"ora": "^3.0.0"
}
}
- 本地开发,npm link 指令
你本地开发,你要用自定义的脚手架指令,需求在项目的当前目录下,在终端履行npm link
指令,这样,你在任何方位目录的终端里,输入 my
,都能够履行到你自定义的指令。
假如你想换个指令名,不叫my
,叫my123
,也能够,你仍是去在项目的当前目录下,在终端,先履行npm unlink
, 再履行 npm link
即可。
你本地开发好了,那就在项目的当前目录下,在终端履行npm unlink
即可。
发包
前置条件:将你本地的 npm源 设置成 npm官网的镜像源
在这儿,需求把你的npm的镜像源设置成 npm官方网站的镜像源
因为 平常咱们开发,下载依靠包,因为npm官网在国外,受到网络的传输速度的影响,平常咱们都是在淘宝镜像
上下载依靠的。可是你要发包,是发布在npm官网
上,所以就要切换成 npm官网的依靠
检查npm的装备
npm config list
设置官方源
npm config set registry https://registry.npmjs.org/
设置国内镜像源
npm config set registry http://registry.npmmirror.com/
这儿推荐运用 nrm 来办理 镜像源,能够参考我这篇文章:npm 与 nrm
- 首要需求先登录 翻开你的终端,任何方位的终端都行,输入 npm login,然后输入你的账号暗码 (账号邮箱能够看见,暗码是看不见的,你照旧输入就行)
- 进入你的脚手架目录,翻开终端,输入 npm publish 指令
- 在输入指令之前,你先查下,你要发布的包名,在npm官网上有没有重名的,或许会存在冲突
- 莽一波,果然失利了
便是包名重复了
这下发布成功了
# 下载依靠
npm install --global my-hahaha-cli
# 卸载依靠
npm uninstall --global my-hahaha-cli