什么是脚手架
一个命令行工具
根据交互式终端动态生成项目结构和配置文件
通过命令行去完成那些重复性的工作,不需要在粘贴来粘贴去
开发一个通用的脚手架,去处理重复构建自己项目结构的这样一个事情
注意:vue-cli是一个整合了webpack+vue的脚手架,所以才会有一个面试题叫做:你有没有自己搭建一个vue项目? 这个知识点我回头会补充一下的。
实现自己的脚手架的思路
项目放在github上
用户通过命令行交互去下载不同的模板
经过模板引擎渲染去定制项目模板
模板变动,只需要更新模板,不需要用户更新脚手架
初始化-把脚本映射成命令
1、 初始化一个文件夹,文件夹中新建一个index.js,index.js的内容如下
#!/usr/bin/env node
console.log("这是使用自己创建的命令kvon-cli生成的代码");
文件头部的那一句话的含义:
使用node开发命令行工具去执行一个js脚本,必须在头部加上这一句声明
加上之后,在终端还是只能使用node index.js 执行这个文件,接下来就要编写自己的命令行了
执行npm init -y 生成package.json文件,在文件中进行配置
{
"name": "kvon-cli_01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"bin": {
"kvon-cli-log": "index.js"
}
}
bin这key是我配置的,首先bin是一个对象,我给了一个key:kvon-cli-log,是我的命令行;对应的值,就是这个命令行要执行的文件
此时在尝试使用命令行执行index.js文件,发现还是不能行,不过这一步就是把我们的js脚本映射成命令行,这一步做到了
还差的一步就是将这个命令行映射到全局,执行npm link,就可以通过命令行运行index.js文件了
思考💡:不过我发现我执行npm link之后,在我的文件夹下出现了package-lock.json文件,这个我也不知道我为什么,留作一个思考题把
使用commander解析命令行参数
以vue2为例,vue2提供的几个常用的命令行参数
所以我也打算做几个自己脚手架的参数
kvon -- help | -h
kvon -- version | -V
kvon list
kvon init <template-name> <project-name>
node原生提供了获取命令行参数的方法
// 原生获取命令行参数的方式
console.log(process.argv)
但是原生的老师就提了提,没教我,哈哈哈哈,那我们就直接用现成的吧
首先安装
npm i commander
访问网页github.com/tj/commande… ,利用现成的commander去编写自己的命令
// 代写在index.js下
#!/usr/bin/env node
const { program } = require('commander')
program.version('0.8.0')
program.parse(process.argv)
首先是实现了-v的命令,我们可以看一下
查看帮助文档
也就是说,-h| --help是默认提供我们的命令,因为我们没有写任何代码,他就可以运行这个命令,通过结果看出我们现在完成了
kvon -- help | -h
kvon -- version | -V
接下来就完成剩下的2条了,list和init命令
init是初始化我们项目的,所以init首先要定义一个模板、然后是项目名称
正如我们使用vue-cli初始化项目时,我们输入的一个命令
vue init webpack my-vue-demo
webpack 是一个模板的名称,my-vue-demo是自己定义的项目名称,可以随便写
list 是列出我们可用所有模板
经过以上分析,我们就编写出代码
const { program } = require('commander')
program.version('0.8.0')
program
.command('init <template> <project>')
.description('初始化项目模板')
.action(function (env, options) {
console.log(env, options)
})
program
.command('list')
.description('查看所有可用模板')
.action(() => {
console.log(
`xxxx ---> 模板1
xxxx ----> 模板2
xxxx ----> 模板3`
)
})
program.parse(process.argv)
准备模板
既然要基于模板去开发自己的项目,所以前提就是要设计自己的模板,现在github上搞一个几个简单的,测试着,回头在学习怎么设计自己的项目模板
既然模板已经存在了,就在list的命令中,获取所有模板了
const { program } = require('commander')
program.version('0.8.0')
const templates = {
'kvon-a': {
url: 'https://github.com/Kvon917/kvon-a',
description: '模板a',
},
'kvon-b': {
url: 'https://github.com/Kvon917/kvon-b',
description: '模板b',
},
'kvon-c': {
url: 'https://github.com/Kvon917/kvon-c',
description: '模板c',
},
}
program
.command('init <template> <project>')
.description('初始化项目模板')
.action(function (env, options) {
console.log(env, options)
})
program
.command('list')
.description('查看所有可用模板')
.action(() => {
for (key in templates) {
console.log(`${key} ---> ${templates[key].description}`)
}
})
program.parse(process.argv)
通过init将模板下载到本地
需要借助第三方工具,安装
npm install download-git-repo
安装完成之后,就完成我们init命令的代码
第一步:需要导入下载的download-git-repo
const download = require('download-git-repo')
第二步,在定义的对象中,丰富下载地址
const templates = {
'kvon-a': {
url: 'https://github.com/Kvon917/kvon-a',
downloadUrl: 'http://github.com:Kvon917/kvon-a#master',
description: '模板a',
},
'kvon-b': {
url: 'https://github.com/Kvon917/kvon-b',
downloadUrl: 'http://github.com:Kvon917/kvon-b#master',
description: '模板b',
},
'kvon-c': {
url: 'https://github.com/Kvon917/kvon-c',
downloadUrl: 'http://github.com:Kvon917/kvon-c#master',
description: '模板c',
},
}
第三步,使用download
program
.command('init <template> <project>')
.description('初始化项目模板')
.action(function (templateName, projectName) {
const { downloadUrl } = templates[templateName]
// download 第一个参数是 下载地址 第二个参数是项目名称
download(downloadUrl, projectName, (err) => {
if (err) {
console.log(err);
console.log('下载失败')
} else {
console.log('下载成功')
}
})
})
最后到了验证阶段,我们可以使用init命令,初始化项目
以向导的方式初始化项目
我们常用的vue初始化项目的时候,会出现一些命令行的交互,比如问你要不要安装XXX呀,要不要使用XXX标准呀,等一类的问题。
现在就来实现这个功能
首先我们在github上处理一下我们的package.json,新建一个package.json,内容写成模板引擎的模式
{
"name": "{{name}}",
"version": "1.0.0",
"description": "{{description}}",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "{{author}}",
"license": "ISC",
"bin": {
"kvon": "index.js"
},
"dependencies": {
"commander": "^9.4.1",
"download-git-repo": "^3.0.2"
}
}
接下就是处理了思路了
1、能够读取package.json文件
2、以向导的方式获取用户输入的值
3、使用模板引擎将获取的值解析到package.json
4、解析完成,把结果重新写入到package.json
安装模板引擎的插件
npm i handlebars
安装向导的插件
npm i inquirer
安装完成就可以编写index.js文件了
const { program } = require('commander')
const download = require('download-git-repo')
const handlebars = require('handlebars')
const inquirer = require('inquirer')
const fs = require('fs')
program.version('0.8.0')
const templates = {
'kvon-a': {
url: 'https://github.com/Kvon917/kvon-a',
downloadUrl: 'http://github.com:Kvon917/kvon-a#master',
description: '模板a',
},
'kvon-b': {
url: 'https://github.com/Kvon917/kvon-b',
downloadUrl: 'http://github.com:Kvon917/kvon-b#master',
description: '模板b',
},
'kvon-c': {
url: 'https://github.com/Kvon917/kvon-c',
downloadUrl: 'http://github.com:Kvon917/kvon-c#master',
description: '模板c',
},
}
program
.command('init <template> <project>')
.description('初始化项目模板')
.action(function (templateName, projectName) {
const { downloadUrl } = templates[templateName]
// download 第一个参数是 下载地址 第二个参数是项目名称
download(downloadUrl, projectName, (err) => {
if (err) {
return console.log('下载失败')
}
// 下载成功
inquirer
.prompt([
{
type: 'input',
name: 'name',
message: '请输入项目名称',
},
{
type: 'input',
name: 'description',
message: '请输入项目简介',
},
{
type: 'input',
name: 'author',
message: '请输入作者信息',
},
])
.then((answers) => {
// answers获取的是向导的输入值
const packagePath = `${projectName}/package.json`
const packageContent = fs.readFileSync(packagePath, 'utf-8')
//利用handlebars 将模板字段编译完成
const packageResult =
handlebars.compile(packageContent)(answers)
fs.writeFileSync(packagePath, packageResult)
console.log('初始化模板成功')
})
})
})
program
.command('list')
.description('查看所有可用模板')
.action(() => {
for (key in templates) {
console.log(`${key} ---> ${templates[key].description}`)
}
})
program.parse(process.argv)
其中遇到了报错,就是一段
我的解决方案是根据inquirer的官网,安装固定版本,不然跑不起来
npm install --save inquirer@^8.0.0
最后成功解决相关问题
视觉优化-增加下载效果
下载插件,我装的指定版本,最新版本报错
npm i ora@3.0.0
引入
const ora = require('ora')
使用
program
.command('init <template> <project>')
.description('初始化项目模板')
.action(function (templateName, projectName) {
// 下载之前的提示
const spinner = ora('正在下载模板...').start()
const { downloadUrl } = templates[templateName]
// download 第一个参数是 下载地址 第二个参数是项目名称
download(downloadUrl, projectName, (err) => {
if (err) {
// 下载失败
spinner.fail()
return
}
// 下载成功
spinner.succeed()
inquirer
.prompt([
........
视觉优化-增加文字颜色和对钩等
npm i chalk@2.4.1
npm i log-symbols@2.2.0
logSymbol处理图标、chalk处理颜色
........
const packageResult =
handlebars.compile(packageContent)(answers)
fs.writeFileSync(packagePath, packageResult)
console.log(
logSymbol.success,
chalk.yellow('初始化模板成功')
)
})
npm发包
- 打开npm官网
- 注册一个npm账号
- 在npm检查是否有重复包名
- 将package.json中的name修改为发布到npm上的包名
- 打开控制台,执行npm login,在控制台登录
- 登陆成功后,在项目下执行npm publish
- 发布成功
- 可自行测试