持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
前言
脚手架本质上就是提供模板的工具,在vue
中,我们通过npm install -g @vue/cli
命令全局安装脚手架,然后执行vue create hello-world
就能创建一个项目了,实质上就是通过全局指令,下载了一套webpack
模板,让我们可以进行快速开发。我们也可以实现自己的脚手架,在本地上先定义一套webpack
模板,然后ctrl+c
、ctrl+v
就创建了一个新项目。所以,实现脚手架前提,是需要有一套自定义webpack
模板,然后就是如何才能像vue
一样,可以通过npm
全局安装脚手架,然后通过全局指令,在文件夹中下载webpack
模板呢?这篇文章主要介绍如何实现,从npm
下载自定义脚手架,本地通过全局指令下载webpack
模板。
演示:
-
全局引入
npm i -g lxj-cli
-
查看已有模板
go list
-
创建
vue2
项目,并配置package.json
-
查看项目
一、定义本地全局指令
新建index.js
随便创建一个文件夹都行
console.log('666')
然后在当前文件夹的终端输入 node 执行命令
node index.js
但是这样输出又有些不方便,这时就可以尝试在本地定义一个全局的自定义命令。
- 初始化
package.json
输入命令后文件夹下会多出一个
package.json
配置文件。
npm init -y
- 配置自定义命令
现在在在这个配置文件的最下面添加 bin 选项并自定义一个名叫
go
的指令执行index.js
。
-
指令连接全局
输入
link
连接全局后,我们就可以在全局任何地方通过输入go
命令来运行index.js
。npm link
解绑指令:
npm unlink
且
index.js
最上面必须加上这行代码,或者绑定指令之后运行会报错。#!/usr/bin/env node
配置
#!/usr/bin/env node
, 就是解决了不同的用户node
路径不同的问题,可以让系统动态的去查找node
来执行你的脚本文件。#!
这个符号在Linux
或者Unix
中叫做:shebang,#!
这两个符号就叫shebang
带有#!就是代表此文件可以当做脚本运行
/usr/bin/env node
这行的意思就是用node
来执行此文件,去用户(usr
)的安装根目录(bin
)下的env
环境变量中去找如果之前已经设置过
link
了,必须解绑才能link
二、使用 Commander 解析命令行参数
1. 原生获取命令行参数的方式
使用:process.argv
关键字。
会将路径已数组的形式打印,如果需要加参数,以空格符隔开即可
2. 使用包 Commander.js 模块来获取处理命令行参数
Commander.js
中文文档:
Commander
文档写的很详细,不会的看文档就行,Commander是一个Nodejs
模块,需要在Node
环境中运行,在使用前确认一下Node
环境是否已安装。
- 安装
npm install commander
-
安装好后我们可以直接将官网中的示例复制到我们的代码中,然后在控制台输入
go -V
就可以看到控制台已经输出了我们的默认版本号。同理,直接输入
go
会弹出选项提示:
#!/usr/bin/env node
const {
Command
} = require('commander');
const program = new Command();
program
.name('deploy')
.version('0.0.1')
.option('-c, --config <path>', 'set config path', './deploy.conf');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option('-s, --setup_mode <mode>', 'Which setup mode to use', 'normal')
.action((env, options) => {
env = env || 'all';
console.log('read config from %s', program.opts().config);
console.log('setup for %s env(s) with %s mode', env, options.setup_mode);
});
program
.command('exec <script>')
.alias('ex')
.description('execute the given remote cmd')
.option('-e, --exec_mode <mode>', 'Which exec mode to use', 'fast')
.action((script, options) => {
console.log('read config from %s', program.opts().config);
console.log('exec "%s" using %s mode and config %s', script, options.exec_mode, program.opts().config);
}).addHelpText('after', `
Examples:
$ deploy exec sequential
$ deploy exec async`);
program.parse(process.argv);
输入指令:
打印内容:
3. 设计自己的命令行参数
1. init 初始化模板命令
// init 命令
program
// 定义命令:.command(命令名,[参数])
// []:表示可选参数
// <>:表示必填参数
.command("init <templateName> <projectName>")
// 命令别名
.alias("i")
// 命令作用介绍
.description("初始化项目模板")
// 可接在此命令之后连用的指令
.option("-i, --init <name>", "命令后使用选项接参数示例", "normal")
// 命令执行回调
.action((templateName, projectName, options) => {
// templateName:传给本项命令的参数
// projectName:传给本项命令的第二个参数
// options.***:传给命令之后使用的指令的参数(option.init)
console.log(
`使用模板名:${templateName}, 项目名称为:${projectName}, ${
options.init === "normal" ? "" : `选项参数为:${options.init}`
}`
);
});
2. list 查看模板命令
// list 命令
program
.command("list")
.description("查看所有可用模板")
.action(() => {
console.log(`Webpack Webpack-vue2模板`);
});
三、进行模板下载
1. 准备模板
-
进入
GitHub
新建仓库准备好需要使用的模板。 -
初始化模板信息
这里我是在
GitHub
上新建一个仓库,并将自己之前写的一个开发环境上传当做这里的模板进行测试的。// 存储模板地址 const templates = { "vue2-cli": { // 仓库地址 url: "https://github.com/liuxueji/vue2-cli.git", // 仓库下载地址,格式为:仓库地址:用户名/仓库名#分支名 downloadUrl: "github:liuxueji/vue2-cli#master", description: "Webpack5 + Vue2模板", }, };
-
修改
go list
命令// list 命令 program .command("list") .description("查看所有可用模板") .action(() => { // 遍历模板数组 for (let i in templates) { console.log(`模板名称:${i}`); console.log(`模板URL:${templates[i].url}`); console.log(`模板介绍:${templates[i].description}`); } });
2. 下载模板(download-git-repo)
自定义模板的好处就是,可以灵活设置项目配置,有时候可能需要一个干净的
vue
项目,有时候可能需要一个比较完整的vue
项目模板,方便进行快速开发。
使用 download-git-repo
下载
NPM
地址:
- 安装
npm i download-git-repo
- 使用
在
init
命令中的action
回调中设置,接收两个参数:仓库地址和下载路径
GitHub
GitLab
Bitbucket
// 使用 download-git-repo 下载模板
// download 第一个参数:仓库地址;第二个参数:下载路径
const {downloadUrl} = templates[templateName];
download(downloadUrl, projectName, {
clone: true
}, err => {
if (!err) {
return console.log("模板创建成功");
}
});
- 测试
-
使用前我们需要看看仓库中有哪些模板可以选择(当前只有一个,后续会添加)
-
根据打印的模板,选择适合的进行下载
-
此时,就通过全局命令,下载到
github
仓库中预设置好的模板了,到这里基本功能已经完成。但是模板中的package.json
文件是写死的,下面就通过与用户交互,动态创建package.json
文件
四、使用 inquirer 和 handlebars 采集处理用户信息
1. 命令行交互 inquirer
能够与用户在命令行进行参数选择交互。
-
安装
npm i inquirer
-
使用
将其放在
download
的下载回调中。
const inquirer = require('inquirer')
inquirer.prompt([
{
// 输入类型
type: "input",
// 字段名称
name: "name",
// 提示信息
message: "请输入项目名称",
},
{
// 输入类型
type: "input",
name: "description",
message: "请输入项目简介",
},
{
type: "input",
name: "author",
message: "请输入作者名称",
},
])
// 获取输入结果
.then((answers) => {
console.log(answers.author);
});
- 测试
-
初始化项目并完成与用户交互
-
成功初始化模板并获取到用户输入信息
-
接下来,只需要将用户输入的信息写入到
package.json
中,使用handlebars
完成
2. 模板引擎 handlebars
能够读取当前项目下的文件,并重新写入
- 安装
npm i handlebars
- 修改模板的
package.json
- 写入配置文件中
依然使用 fs
模块中的 .writeFileSync()
进行文件写入。
// 导入 handlebars、fs
const handlebars = require('handlebars')
const fs = require("fs");
// 把采集到的用户数据解析替换到 package.json 文件中
// 保存下载下来的模板 package.json 配置文件路径
const packagePath = `${projectName}/package.json`;
// 使用 fs 获取下载到的模板中额 package.json 配置文件
const packageContent = fs.readFileSync(packagePath, "utf8");
// 使用 handlebars 编译这个文件为渲染函数
const packageResult = handlebars.compile(packageContent)(answers);
// 将修改后配置写入下载下来的模板中
fs.writeFileSync(packagePath, packageResult);
console.log("初始化模板成功!");
- 测试
-
初始化模板,并设置项目名、项目简介、作者名称
-
项目
package.json
中信息成功修改
五、npm 发包
-
上
npm
官网注册一个账号 -
上
NPM
搜索看有无重名包。 -
把
package.json
中的name
修改为发布到npm
上的包名。 -
打开控制台,执行登录命令:
npm login
-
登陆成功以后,在项目下执行发布命令:
npm publish
-
解绑全局命令:
npm unlink
-
发布成功,在本地进行安装
npm i lxj-cli
-
安装完毕,使用go命令进行测试
go list go init vue2-cli project1
总结:
脚手架的意义是快速构建项目,提高我们的开发效率。对我来说,每次做一个项目,都要重新配置一次webpack,特别难受。所以,我自定义脚手架的目的,就是希望能制作一个开箱即用的模板,能不配置就不配置,而且还有利于统一每个项目结构,百利无一害🤗。所以,最重要的就是如何配置一个开箱即用的webpack模板了。