最近发现写后台管理页面时有许多重复的工作,浪费很多时间。就想着用node来自动化处理了,同时也可以避免人工操作可能出现的一些失误。本文只针对我自己的项目做出的一些优化,但是提供的一些思路大家可以参考下,灵活运用到自己的项目里去。
每当我想新建一个页面的时候,会有一些列连带的操作:
新建一个vue文件
>添加路由
>在el-menu中添加一个子菜单
>添加页面权限相关信息
,现在要做的就是把这一系列操作交给node,我们要写一个cli来实现。
认识cli
cli即command-line interface,命令行工具。首先使用npm init
创建package.json
,然后在其中加入关键代码
"bin":{
"test": "./index.js"
}
test即为指令名,使用如:test xxx
。使用npm link将bin里面的指令链接的全局,方便调试。
接下来来看index.js,它必须是可执行文件,所以我们在头部加上#!/usr/bin/env node
//index.js
#!/usr/bin/env node
console.log('执行了test');
此时在命令行执行test将打印出"执行了test"
commander配合inquirer的命令行交互
program
.version('1.0.0')
.command(`add`)
.action(() => {
inquirer.prompt([
{
type: 'list',
name: 'page',
message: '请选择页面等级',
default: '二级',
choices: ['一级', '二级']
},
{
type: 'input',
name: 'parent',
message: '请输入一级模块的英文名',
when: answers => answers.page === '二级',
validate: val=>{
if (!val) {
return '输入不能为空'
}
return true
}
},
{
type: 'input',
name: 'en',
message: '请输入模块英文名',
validate: val=>{
if (!val) {
return '输入不能为空'
}
return true
}
},
{
type: 'input',
name: 'cn',
message: '请输入模块中文名',
validate: val=>{
if (!val) {
return '输入不能为空'
}
return true
}
},
{
type: 'input',
name: 'code',
message: '请输入模块编码(权限用)',
validate: val => {
if (!val) {
return '输入不能为空'
}
return true
}
},
{
type: 'input',
name: 'route',
message: '请输入页面路径(对应的页面名和路由名)',
when: answers => answers.page === '二级',
validate: val => {
if (!val) {
return '输入不能为空'
}
return true
}
}
]).then(async answers => {
// 执行相应的操作
// 问题的答案都会以每个问题的name字段体现在answers的属性里
console.log(chalk.green('操作成功'))
})
})
收集完我需要用到的一些参数后,就是如何生成对应的内容了。
使用node的fsPromise模块对文件进行读写
const fs = require('fs').promises
const path = require('path')
const fileHandle = await fs.open(path.resolve(yourpath), 'r')
let content = await readHandle.readFile('utf-8')
...
一系列对content的操作
...
await fileHandle.close() // 关闭文件
const writeHandle = await fs.open(path.resolve(yourpath), 'w')
await writeHandle.writeFile(content) // 用新的content覆盖文件
await writeHandle.close()
打开文件并读取文件内容,然后修改文件内容后重新覆盖,这里要注意一点,文档上写的文件标识符"r+
"是"打开文件用于读取和写入",但是我还是只能读取,最后只能通过分别打开两次r
和w
来进行读写。
对content的操作
修改文件内容主要用到的是正则,我们通过正则匹配到想要添加内容的位置,一般都会有一个\s
可以匹配,然后用String.replace(reg, yourString)
替换即可,yourString是上面接收完参数后拼接的字符串。例如我的路由:
const reg = new RegExp('}\\s*]')
const route = `},
{ path: '/${routeName}', component: () => import('@/page/${routePath}') }
]`
routerContent = routerContent.replace(reg, `${route}`)
这里我选择用上面的代码来替换router.js里的}]
,要替换的地方很多,但都是这个套路。还有正则的前瞻和后顾都是很好的定位手段。
新建页面
就是将一段字符串写入文件,没什么好说的,当文件不存在的时候调用writeFile会自动创建文件。
const content = `<template>
<div></div>
</template>
<script>
export default {
data () {
return {}
},
created () {},
methods: {}
}
</script>
<style lang="scss" scoped>
</style>
`
await fs.writeFile(path.resolve(`./src/page/${routePath}.vue`), content)
格式化代码
这样生成的代码都贴在一起格式会很乱,最后我们用eslint自动修复一下。node的child_process
模块可以执行shell命令:
child_process.exec(command, [options], callback)
衍生一个 shell 然后在该 shell 中执行 command,需要注意的是,必须将eslint的执行目录添加到这个shell的环境变量中去:
const SEPARATOR = process.platform === 'win32' ? ';' : ':'
const env = Object.assign({}, process.env)
env.Path = path.resolve('./node_modules/.bin') + SEPARATOR + process.env.PATH
const option = {
env: env
}
child_process.exec('eslint --fix --ext .js,.vue src', option, callback)
最后将完成的代码上传的npm。至此,大功告成!运行test add
查看效果就行了!
总结
我们将所有手动修改的地方都挪到命令行执行啦,简直太方便啦,觉得有帮助的话就点个赞吧( •̀ ω •́ )✧