约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。Vue通用应用框架Nuxt.js就支持约定式路由。
如果我们不使用Nuxt.js也希望Vue项目能支持约定式路由。怎么办?现在我们就从0到1实现一个cli工具,使我们的项目也能支持约定式路由。
需要实现的功能
假设 pages 的目录结构如下:
pages/
--| user/
-----| index.vue
-----| one.vue
--| index.vue
那么,自动生成的路由配置如下:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'user',
path: '/user',
component: 'pages/user/index.vue'
},
{
name: 'user-one',
path: '/user/one',
component: 'pages/user/one.vue'
}
]
}
现在我们开始实现npm的功能
1. 创建工程
1.1 创建项目
mkdir vue-router-cli
cd vue-router-cli
npm init -y
1.2 新建执行文件bin/cli.js
bin/cli.js
#!/usr/bin/env node
console.log('cli...')
ps: 需要在脚本的第一行写上#!/usr/bin/env node ,用于指明该脚本文件要使用node来执行
1.3 package.json 增加 bin 脚本
package.json
"bin": {
"auto-router": "./bin/cli.js"
}
1.4 将 npm 模块连接到对应的运行项目中去
npm link
连接成功如下图:
连接成功后再命令行中输入
auto-router可以直接看到脚本输出的内容
2. 使用commander定制命令行界面
Commander.js 是一个完整的 node.js 命令行解决方案。是前端开发node cli 必备技能
npm install commander -s
bin/cli.js
#!/usr/bin/env node
const program = require("commander");
// 版本号
program.version(require("../package.json").version);
program
.command("init <name>")
.description("init project")
.action((name) => {
console.log("init " + name);
});
program.parse(process.argv);
定制完命令行之后测试效果:
3. 打印欢迎界面
3.1 安装依赖
npm install clear figlet chalk -s
3.2 打印欢迎界面代码
lib/init.js :
const { promisify } = require("util");
const figlet = promisify(require("figlet"));
const clear = require("clear");
const chalk = require("chalk");
// 可以在终端输出绿色的字体
const log = (msg) => console.log(chalk.green(msg));
module.exports = async (name) => {
// 清屏
clear();
// 在命令行里显示艺术字
const msg = await figlet("Auto-router welcome");
log(msg);
};
bin/cli.js
#!/usr/bin/env node
const program = require("commander");
// 版本号
program.version(require("../package.json").version);
program
.command("init <name>")
.description("init project")
.action(require('../lib/init'));
program.parse(process.argv);
执行命令
auto-router init test
输出
ps: 输出的样式可以通过figlet 修改字体样式;通过 chalk 修改字体和背景颜色.
4. 克隆脚手架
4.1 安装依赖
npm install download-git-repo ora@^5.0.0 -s
- ora Elegant terminal spinner
- download-git-repo 从 node 下载并提取 git 仓库(GitHub、 GitLab、 Bitbucket)
4.2 从github上克隆代码到本地
lib/download.js
const { promisify } = require("util");
module.exports.clone = async (repo, desc) => {
const download = promisify(require("download-git-repo"));
const ora = require("ora");
const process = ora(`下载...${repo}`);
process.start();
await download(repo, desc);
process.succeed();
};
lib/init.js
module.exports = async (name) => {
...
// 创建项目
log(`🚀创建项目:${name}`);
// 从github克隆项目到指定文件夹
await clone("github:banixing/vue-template", name);
};
终端输入:
auto-router init test
输出:
5. 安装依赖
lib/init.js
**
* 对接输出流
* @param {...any} args
* @returns
*/
const promisitySpawn = async (...args) => {
const { spawn } = require("child_process");
return new Promise((resolve) => {
const proc = spawn(...args);
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stderr);
proc.on("close", () => {
resolve();
});
});
};
module.exports = async (name) => {
// 清屏
clear();
// 在命令行里显示艺术字
const msg = await figlet("Auto-router welcome");
log(msg);
// 创建项目
log(`🚀创建项目:${name}`);
// 从github克隆项目到指定文件夹
await clone("github:banixing/vue-template", name);
log("安装依赖");
await promisitySpawn("npm", ["install"], { cwd: `./${name}` });
log(`
👌安装完成:
To get Start:
===========================
cd ${name}
npm run serve
===========================
`);
};
6. 启动项目
安装依赖
npm install open -s
lib/init.js
const open = require("open");
module.exports = async (name) => {
// ...
// 打开浏览器
open("http://localhost:8080");
await promisitySpawn("npm", ["run", "serve"], { cwd: `./${name}` });
};
7. 约定路由功能
实现思路
- 读取pages文件夹下面的文件,
- 使用模板引擎生成路由
- 使用模板引擎生成菜单 安装handlebars
npm install handlebars
handlebars 轻量的语义化模板, Handlebars 会将模板编译为 JavaScript 函数。这使得 Handlebars 的执行速度比其他大多数模板引擎都要快。
实现 lib/refresh.js
const fs = require("fs");
const handlebars = require("handlebars");
const chalk = require("chalk");
/**
* 编译模板文件
* @param {*} meta 数据定义
* @param {*} filePath 目标文件路径
* @param {*} templatePath 模板文件路径
*/
function compileFile(meta, filePath, templatePath) {
if (fs.existsSync(templatePath)) {
const content = fs.readFileSync(templatePath).toString();
const reslut = handlebars.compile(content)(meta);
fs.writeFileSync(filePath, reslut);
console.log(chalk.red(`🚀${filePath} 创建成功`));
}
}
module.exports = async () => {
// 1. 获取页面列表
const list = fs
.readdirSync("./src/pages")
.filter((f) => f !== "Home.vue")
.map((f) => ({
name: f.replace(".vue", "").toString(),
file: f,
}));
// 2. 生成路由
compileFile(
{
list,
},
"./src/router.js",
"./template/router.js.hbs"
);
// 3. 生成菜单
compileFile(
{
list,
},
"./src/App.vue",
"./template/App.vue.hbs"
);
};
增加 refresh 命令 bin/cli.js
program
.command("refresh")
.description("refresh routers...")
.action(require("../lib/refresh"));
实现以上功能之后,在pages文件夹下新增文件User.vue,在终端执行
auto-router refresh
可以在页面考到自动生成了User菜单,点击菜单可以跳转到User页面。
8. 实现对 src/pages 目录的监听
lib/serve.js
const spawn = (...args) => {
const { spawn } = require('child_process');
const proc = spawn(...args)
proc.stdout.pipe(process.stdout)
proc.stderr.pipe(process.stderr)
return proc
}
module.exports = async () => {
const watch = require('watch')
let process
let isRefresh = false
watch.watchTree('./src', async (f) => {
if (!isRefresh) {
isRefresh = true
process && process.kill()
await require('./refresh')()
setTimeout(() => { isRefresh = false }, 5000)
process = spawn('npm', ['run', 'serve'])
}
})
}
bin/cli.js
program
.command("refresh")
.description("refresh routers...")
.action(require("../lib/refresh"));
9. 发布npm
新建文件:publish.sh
#!/usr/bin/env bash
npm config get registry # 检查仓库镜像库
npm config set registry=http://registry.npmjs.org
echo '请进行登录相关操作:'
npm login # 登陆
echo "-------publishing-------"
npm publish # 发布
npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像
echo "发布完成"
exit
终端里运行
bash publish.sh
根据提示输入npm的账号和密码即可发布
如果发布不成功,如下
Beginning October 4, 2021, all connections to the npm registry - including for package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog for more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/
npm 发布公告称,从 2021 年 10 月 4 日开始,所有与 npm 网站和 npm registry 的连接(包括软件包的安装),都必须使用 TLS 1.2 或更高版本。
但如果看到的是 TLS 错误消息,建议开发者升级到当前支持的 Node.js 版本和最新版本的 npm v7。
mac升级npm到最新版本
# 升级npm到最新版本
sudo npm install -g npm
npm -v
# 7.24.0
重新发布npm一次。