本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
一、前言
本篇主要介绍如何搭建前端脚手架,一步一步地实现通过搭建的脚手架下载对应的项目模板。经过本人的一步一步的实践,终于做成了这第一步的目标。
本篇目标:通过自己搭建的脚手架,让用户选择下载对应的模板。
什么是脚手架?
简单来说,「前端脚手架」就是指通过选择几个选项快速搭建项目基础代码的工具。前端脚手架可以有效避免我们 ctrl + C 和 ctrl + V 相同的代码框架和基础配置。
前情提要
本篇文章node
环境版本为v16.15.1
!这个很重要!
二、实现步骤
初始化项目
首先我们创建一个文件夹first-engineering-1
(文件夹名字自定义哦),之后执行命令
npm init -y
这一步是初始化一个package.json,然后我们在文件夹下创建一个bin文件夹,在bin文件夹下面在创建一个index.js文件,如图所示
工程的创建
之后让我们进行相关的配置和测试,在index.js第一行加上这句话#! /usr/bin/env node
,如下所示
// first-engineering-1/bin/index.js
#! /usr/bin/env node
console.log('这是我的第一个脚手架项目')
然后在package.json文件中添加命令配置,这里咱们的命令叫做air
,这个是可以自定义的。
"bin": {
"air": "./bin/index.js"
}
如图所示
之后我们在项目内执行npm link
测试下命令,如图所示代表成功了。
npm link
,link将一个任意位置的npm包链接到全局执行环境,从而在任意位置使用命令行都可以直接运行该npm包。npm link
命令通过链接目录和可执行文件,实现npm包命令的全局可执行。点击查看官方文档
之后我们在命令行输入下我们的命令air
,执行结果如图
其实这里就相当于是执行了 node ./bin/index.js
。
这样我们就完成了第一步,接下来我们就要继续丰富我们的脚手架,来实现我们的目标。
实现读取用户命令行信息
这里我们要用到commander
,这个是用来解析读取用户命令行中输入内容的工具。commander中文文档
以下是部分commander的API
-
Command#command(): 定义一个命令名字
-
Command#action(): 注册一个callback函数
-
Command#parse(): 解析命令行参数argv
安装
npm install commander
注意:为了避免node版本带来的插件引入方式问题,我们将package.json中添加"type": "module"
,如图
之后我们开始编写读取用户输入命令的逻辑
// first-engineering-1/bin/index.js
import { program } from 'commander'
program.version(packageJsonData.version, '-v, --version')
.command('create <projectName>')
.action((projectName) => { // 当用户输入create命令时走这里
// 这里我们就可以对用户输入的命令进行进行操作
console.log(`用户想创建一个名为${projectName}的项目`)
})
program.parse(process.argv);
之后我们可以在命令行输入如下命令,就可以得到如图所示结果。我们的npm link
是一直在的,除非你把它unlink
这一步读取用户命令我们就实现了。
拉取模版代码
这里我们就用到了另一个插件download-git-repo
点击查看官方文档。
安装
npm install download-git-repo
这里咱们使用direct:url的方式
-
如果使用 direct,并且没有 clone配置项, 你必须传入完整的zip文件地址, 包括分支(如果需要的话)。
-
如果使用 direct 并带有 clone配置项, 你必须传入完整的 git repo url , 你可以通过 direct:url#my-branch指定分支。
加上拉取代码模版后,我们的代码就变成这样了
#! /usr/bin/env node
import { program } from 'commander'
import download from 'download-git-repo'
program.version('1.0.0', '-v, --version')
.command('create <projectName>')
.action((projectName) => { // 当用户输入create命令时走这里
// 这里我们就可以对用户输入的命令进行进行操作
console.log(`用户想创建一个名为${projectName}的项目`)
download(`direct:https://gitee.com/airdark/nuxt-website.git`, `./${projectName}`, {clone: true}, (err) =>{
if (err) {
console.log('获取模版失败')
} else {
console.log('Success!')
}
})
})
program.parse(process.argv);
之后我们在命令行执行并看下结果,如图所示
这个项目地址是我自己在码云上创建的,大家使用github或者gitlab的话,建议使用download-git-repo
插件的对应方式。
这一步我们就是实现了通过命令行拉取项目模板了。
实现增加选择项,与用户交互
假如我们有多个模板的话,我们可以让用户选择下载哪种模版。要实现这个,我们需要用到inquirer
这个插件。点击查看官方文档
用户与命令行交互的工具---inquirer
安装
npm install inquirer
接下来我以备注的形式为大家说明,增加用户选择后的总体代码如下
#! /usr/bin/env node
import { program } from 'commander'
import download from 'download-git-repo'
import inquirer from 'inquirer'
// 设置让用户选择模版的问题项
const question = [
{
name: "features", // 选项名称
message: "请选择要创建的项目模板", // 选项提示语
type: "list", // 选项类型 另外还有 confirm check 等
choices: [ // 具体的选项
{
name: "electron", // 选项展示的名称
value: "electron1", // 用户最终选择的值
description: "electron+vue2(桌面端项目)", // 自定义的说明
link: 'https://gitee.com/airdark/first-electron-1.git' // 自定义的模版项目地址
},
{
name: "web",
value: "web",
description: "vue2+webpack+iview(浏览器项目)",
link: 'https://gitee.com/airdark/vue2-demo.git'
},
{
name: "h5",
value: "h5",
description: "vue2+vant(移动端项目)",
link: 'https://gitee.com/airdark/nuxt-website'
}
]
}
]
program.version('1.0.0', '-v, --version')
.command('create <projectName>')
.action((projectName) => { // 当用户输入create命令时走这里
// 这里我们就可以对用户输入的命令进行进行操作
console.log(`用户想创建一个名为${projectName}的项目`)
// 交互输入的参数为上面的question,res是得到答案
inquirer.prompt(question).then(res => {
console.log('用户选择的答案', res)
// 获取到第一项中,用户选择的值,这里偷了个懒,大家可以根据答案和问题获取对应下载链接。
let info = question[0].choices.find(item => item.value === res.features)
download(`direct:${info.link}`, `./${projectName}`, {clone: true}, (err) =>{
if (err) {
console.log('获取模版失败')
} else {
console.log('Success!')
}
})
})
})
program.parse(process.argv);
之后我们执行代码得到如图所示结果
这样我们就完成了我们的初步目标!
美化一下(字体颜色、图标)
这里我们安装两个插件ora
和chalk
。其中ora是设置图标的,chalk是设置字体颜色的。
安装
npm i ora chalk
之后完整代码如下所示
#! /usr/bin/env node
import { program } from 'commander'
import download from 'download-git-repo'
import inquirer from 'inquirer'
import ora from 'ora'
import chalk from 'chalk'
/*** 初始化loading图标文字 start */
const spinner = ora('模版下载中 ...')
/*** 初始化loading图标文字 end */
// 设置让用户选择模版的问题项
const question = [
{
name: "features", // 选项名称
message: "请选择要创建的项目模板", // 选项提示语
type: "list", // 选项类型 另外还有 confirm check 等
choices: [ // 具体的选项
{
name: "electron", // 选项展示的名称
value: "electron1", // 用户最终选择的值
description: "electron+vue2(桌面端项目)", // 自定义的说明
link: 'https://gitee.com/airdark/first-electron-1.git' // 自定义的模版项目地址
},
{
name: "web",
value: "web",
description: "vue2+webpack+iview(浏览器项目)",
link: 'https://gitee.com/airdark/vue2-demo.git'
},
{
name: "h5",
value: "h5",
description: "vue2+vant(移动端项目)",
link: 'https://gitee.com/airdark/nuxt-website'
}
]
}
]
program.version('1.0.0', '-v, --version')
.command('create <projectName>')
.action((projectName) => { // 当用户输入create命令时走这里
// 这里我们就可以对用户输入的命令进行进行操作
console.log(`用户想创建一个名为${projectName}的项目`)
// 交互输入的参数为上面的question,res是得到答案
inquirer.prompt(question).then(res => {
console.log('用户选择的答案', res)
spinner.start()
// 获取到第一项中,用户选择的值,这里偷了个懒,大家可以根据答案和问题获取对应下载链接。
let info = question[0].choices.find(item => item.value === res.features)
download(`direct:${info.link}`, `./${projectName}`, {clone: true}, (err) =>{
if (err) {
spinner.fail()
console.log(chalk.red('获取模版失败'))
} else {
spinner.succeed()
console.log(chalk.green('Success!'))
}
spinner.stop()
})
})
})
program.parse(process.argv);
运行命令结果如图所示
三、后记
以上我们就完成了我们开头处立下的目标!细心的同学可能发现了,咱们的版本号是写死的。这里咱们再说下如何动态获取版本号,即package.json中的版本号。因为node版本的问题,我只能这么来取了
/*** 处理根路径获取,为了得到package.json中的数据 start */
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __filenameNew = fileURLToPath(import.meta.url)
const __dirnameNew = path.dirname(__filenameNew)
let rootPath = __dirnameNew.slice(0, __dirnameNew.length - 3)
const packageJsonData = JSON.parse(fs.readFileSync(rootPath + 'package.json', 'utf8'))
// console.log(packageJsonData.version)
// 替换到对应位置即可
/*** 处理根路径获取,为了得到package.json中的数据 end */
另外还有很多东西没做,比如说文件夹重名、根据用户指令给模版加配置等等,后续咱们继续说。
本篇完结!撒花!感谢观看! 希望能帮助到你!