解密 Vue CLI,打造属于自己的项目脚手架工具
使用脚手架可以减少重复性的工作,不需要从零开始创建一个项目。他会提供一个项目的公共模板供使用者拉取使用。
对于Vue提供的vue-cli脚手架,是通过npm install – global vue -cli进行安装。
1.初始化项目
新建项目Vue-cli并创建index.js,并在终端npm init -y 初始化一个package.json包管理工具文件:
为package.json增加bin字段属性:
“bin”: {
“abc”: “index.js”
}
其是指为命令行增加可执行命令abc,当在命令行输入"abc"后将会执行index.js脚本文件。
然后再在命令行执行npm link命令,将新增的命令映射到全局。执行完后就可以在终端输入abc就可执行index.js脚本了。
2. 命令行工具参数设计
myVue -h | --help //查看使用帮助
myVue -V | --version // 查看myVue工具的版本号
myVue --list //列出所有可用模板
myVue init <template-name> <project-name> //基于指定得模板进行项目初始化
3. 获取终端命令行中的命令方式
获取终端命令行中的命令方式主要有两种,其一是采用原生的nodeJs提供的进程对象;其二是采用commander模块来获取命令。
方式一:原生获取命令行中的命令
使用node.js提供的进程对象process.argv
#!/usr/bin/env node // 使用Node开发命令行工具所执行的js脚本必须在顶部加入 #!/usr/bin/env node该声明,是为了告诉执行器使用node来执行当前脚本代码
// 使用Node开发命令行工具所执行的js脚本必须在顶部加入 #!/usr/bin/env node该声明,是为了告诉执行器使用node来执行当前脚本代码
console.log("vue脚手架工具");
// 1. 获取用户输入的命令
// 实现这个功能可使用原生node.js提供的进程对象process.argv,但是这种方法比较麻烦,所以可以使用commander模块实现读取命令行中的命令
console.log(process.argv); //process.argv是一个数组,里面数组的第三个元素开始是终端上的命令
/**比如输入 myVue init则process.arg为:
* [
'D:\\development_tools\\node\\node.exe',
'C:\\Users\\wang_He\\AppData\\Roaming\\npm\\node_modules\\vue-cli\\index.js',
'init'
]
*/
方式二:使用Commander模块获取命令行中的命令
require引入commander模块
const program = require("commander")
// commander的一些规则
program
.version('0.1.0') // myVue -V | --version时终端输出0.8.0
// 自己配置myVue init命令功能
program
// <>尖括号为必须参数,[]为可选参数
.command('init <template> <project>')
.description('初始化项目模板')
// action函数为匹配到init后执行的回调函数
.action((templateName, projectName) => {
// 根据模板名下载1对应的模板到本地并起名为projectName
console.log(templateName);
});
program
.command("list")
.description("查看所有可用模板")
.action(() => {
console.log("a模板 b模板");
})
// program
// .command('*')
// .action(function (env) {
// console.log('deploying "%s"', env);
// });
program.parse(process.argv);
program.parse();
4. 预配置模板
在github仓库中设置几个模板仓库。
然后在项目中引用这几个模板的网络地址。
// myVue init时所用到的模板
const templates = {
// 模板tpl-a: 模板a的地址
"tpl-a": {
url: "https://github.com/Wanghe0428/template-a",
description: "a模板"
},
"tpl-b": {
url: "https://github.com/Wanghe0428/template-b",
description: "b模板"
},
"tpl-c": {
url: "https://github.com/Wanghe0428/template-c",
description: "c模板"
},
}
5. 使用download-git-repo模块在本地项目代码中下载github上的模板
cnpm i download-git-repo //安装依赖
然后使用该模块提供的download()函数下载模板。(别忘了在项目中引入const download = require(“download-git-repo”))
const program = require("commander")
const download = require("download-git-repo")
// myVue init时所用到的模板
const templates = {
// 模板tpl-a: 模板a的地址
"tpl-a": {
url: "https://github.com/Wanghe0428/template-a",
// download-git-repo模块提供的download函数的第一个参数下载地址,仔细看清楚它由url转变的书写规则
downloadUrl: "https://github.com:Wanghe0428/template-a#main",
description: "a模板"
},
"tpl-b": {
url: "https://github.com/Wanghe0428/template-b",
downloadUrl: "https://github.com:Wanghe0428/template-b#main",
description: "b模板"
},
"tpl-c": {
url: "https://github.com:Wanghe0428/template-c",
downloadUrl: "https://github.com/Wanghe0428/template-c#main",
description: "c模板"
},
}
// 自己配置myVue init命令功能
// myVue init a a-name 基于a模板进行初始化项目,并为此项目起名为a-name
program
// <>尖括号为必须参数,[]为可选参数
.command('init <template> <project>')
.description('初始化项目模板')
// action函数为匹配到init后执行的回调函数
.action((templateName, projectName) => {
// 根据模板名下载对应的模板到本地
// console.log(templates[templateName].url);
/**
* download()函数:
* 第一个参数是:仓库地址
* 第二个参数是:创建的项目名字
*/
let myDownloadUrl = templates[templateName].downloadUrl
download(myDownloadUrl, projectName, { clone: true }, (err) => {
if (err) {
console.log("下载失败");
} else {
console.log("下载成功");
}
})
});
此时在命令行中输入myVue init tpl-a wh 就可以将模板a的内容下载到当前路径下的wh项目中了。
如图:wh项目(模板只是配置了readme文件)
6. 利用handlebars模板引擎来修改package.json文件
即通过命令行的一问一答的方式来修改package.json文件。
步骤:
首先在github中的package.json文件中设定要动态改变的地方:
使用inquirer模块来实现命令行中一些字段的一问一答(比如:name、description、author)
cnpm install inquirer
// 引入向导模块,实现命令行交互式一问一答
const inquirer = require('inquirer');
program
// <>尖括号为必须参数,[]为可选参数
.command('init <template> <project>')
.description('初始化项目模板')
// action函数为匹配到init后执行的回调函数
.action((templateName, projectName) => {
// 根据模板名下载对应的模板到本地
// console.log(templates[templateName].url);
/**
* download()函数:
* 第一个参数是:仓库地址
* 第二个参数是:创建的项目名字
*/
let myDownloadUrl = templates[templateName].downloadUrl
download(myDownloadUrl, projectName, { clone: true }, (err) => {
if (err) {
return console.log("下载失败");
} else {
console.log("下载成功");
}
// 把项目下的package.json文件读取出来
// 使用向导的方式即一问一答的方式(这里采用inquire库来实现)采集用户输入的数据,然后将数据解析到package.json文件中
inquirer
.prompt([
/* 这里放置想要询问的字段 */
{
type: "input",
name: "name",
message: "请输入项目名称"
}, {
type: "input",
name: "author",
message: "请输入作者名称"
}, {
type: "input",
name: "description",
message: "请输入项目简介"
}
])
.then((answers) => {
// answers就是一个对象,对象里面存储了name、author、description三个属性字段
// 把采集到的数据用户输入的数据(也就是answers对象中的字段)解析替换到package.json文件中
console.log(answers);
// 读取package.json文件,这里是使用的fs模块的readfilesync函数,第一个参数是指文件路径,第二个参数是读取文件方式,这里是utf8表示读取的是字符串,若没有utf8则表示读取的是二进制数据
const packageContent = fs.readFileSync(`${projectName}/package.json`, "utf-8")
})
.catch((error) => {
if (error.isTtyError) {
// Prompt couldn't be rendered in the current environment
} else {
// Something else went wrong
}
});
// 解析完毕,把解析之后的结果重新写入到package.json文件中
})
});
使用handlebars模板引擎来解析fs.readFileSync文件读取的package.json文件字符串
cnpm i handlebars
// 引入handlebars模块,用于解析项目中的package.json文件
const handlebars = require("handlebars");
// myVue init a a-name 基于a模板进行初始化项目,并为此项目起名为a-name
program
// <>尖括号为必须参数,[]为可选参数
.command('init <template> <project>')
.description('初始化项目模板')
// action函数为匹配到init后执行的回调函数
.action((templateName, projectName) => {
// 根据模板名下载对应的模板到本地
// console.log(templates[templateName].url);
/**
* download()函数:
* 第一个参数是:仓库地址
* 第二个参数是:创建的项目名字
*/
let myDownloadUrl = templates[templateName].downloadUrl
download(myDownloadUrl, projectName, { clone: true }, (err) => {
if (err) {
return console.log("下载失败");
}
// 把项目下的package.json文件读取出来
// 使用向导的方式即一问一答的方式(这里采用inquire库来实现)采集用户输入的数据,然后将数据解析到package.json文件中
inquirer
.prompt([
/* 这里放置想要询问的字段 */
{
type: "input",
name: "name",
message: "请输入项目名称"
}, {
type: "input",
name: "author",
message: "请输入作者名称"
}, {
type: "input",
name: "description",
message: "请输入项目简介"
}
])
.then((answers) => {
// answers就是一个对象,对象里面存储了name、author、description三个属性字段
// 把采集到的数据用户输入的数据(也就是answers对象中的字段)解析替换到package.json文件中
// console.log(answers);
// 读取package.json文件,这里是使用的fs模块的readfilesync函数,第一个参数是指文件路径,第二个参数是读取文件方式,这里是utf8表示读取的是字符串,若没有utf8则表示读取的是二进制数据
const packagePath = `${projectName}/package.json` //package.json文件路径
// packageContent就是读取到的package.json字符串文件
const packageContent = fs.readFileSync(packagePath, "utf-8")
// 使用handlebars来将文件编译为渲染函数,然后将从命令行中获取到的数据解析到packageContent中,就得到了已完成字段插入解析完成后的package.json
const packageResult = handlebars.compile(packageContent)(answers)
// console.log(packageResult);
// 最后将结果packageResult重新写入到package.json文件中
fs.writeFileSync(packagePath, packageResult)
console.log("初始化模板成功");
})
.catch((error) => {
if (error.isTtyError) {
// Prompt couldn't be rendered in the current environment
} else {
// Something else went wrong
}
});
// 解析完毕,把解析之后的结果重新写入到package.json文件中
})
});
packageResult:
package.json文件最终解析成功:
7. 视觉美化
7.1 使用ora模块处理美化效果
ora模块的作用是当模板开始下载、下载中以及下载完毕之后会提示用户并携带一些美化效果。
安装:
cnpm i ora
因其 ora 最新版只能使用 import 来导入,所以要设置当前项目的默认包管理为 ESModule
// 在 package.json 文件中,添加这行。
"type": "module"
- 修改包引入
将 require 引入方式全部改为 import 方式
#!/usr/bin/env node
// 进入commander模块,来获取命令myVue之后的字段
import { program } from "commander";
// 引入下载github内容模块,用于下载github仓库中的template模板
import download from "download-git-repo"
// 引入向导模块,实现命令行交互式一问一答
import inquirer from "inquirer";
// 引入用于读取文件的node原生模块fs
import fs from "fs";
// 引入handlebars模块,用于解析项目中的package.json文件
import handlebars from "handlebars"
// 引入样式美化模块ora
import ora from "ora";
分别在模板下载开始前,下载中,下载完后调用 ora 的 start()、fail()、succeed() 方法。
// 添加下载中样式,开始
loading.start();
// 调用 ora 下载失败方法,进行提示
loading.fail("下载失败:");
// 调用 ora 下载成功方法,进行提示
loading.succeed("下载成功!");
ora美化成功:
7.2 使用chalk模块处理美化效果
chalk模块的作用是给字体增加颜色
安装:
cnpm i chalk
// 引入chalk模块,用来增加字体颜色美化效果
import chalk from 'chalk';
console.log(chalk.blue("初始化模板成功"));
7.3 使用log-symbols增加符号美化效果
增加√ ×等符号效果。
安装:
cnpm i log-symbols
使用:
// 引入log-symbols模块,来增加一些符号美化效果
import logSymbols from "log-symbols"
// 表示输出 √ +“绿色的初始化模板成功”
console.log(logSymbols.success, chalk.blue("初始化模板成功"));
console.log(logSymbols.error, "下载失败啦您"); //logSymbols.error为错误"×"符号
npm发包
npm发包是指自己做的这个脚手架工具公布到外网上以供其他人下载使用安装此脚手架。
通过执行以下命令来安装此myVue脚手架:
npm install --globol myVue
- 代开npmjs.npm官网
- 注册一个npm账号
- 在npm检索是否有重复的包名
- 将package.json中的name修改为发布到npm上的包名,这里我取名为vue-wh
- 打开控制台,执行npm login,在控制台登录npm
logged in表示登录成功
-
登录成功以后,在项目下执行npm publish进行发布。
npm上vue-wh包发布成功:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-caNr2d3q-1644831160568)(C:/Users/wang_He/AppData/Roaming/Typora/typora-user-images/image-20220214173032885.png)]
-
发布成功就可以在本地进行安装测试了
npm install --global vue-wh