前言
在上一篇文章中,咱们实现了一个 web 工程通用脚手架工具,目标是疾速搭建我的项目。在理论开发中,特地是后盾管理系统,有很多类似的代码实现。于是乎,咱们能够持续实现一个疾速生成 web 代码模板的工具,辞别复制 / 粘贴。
根本流程
基本思路其实很简略,就是通过命令调取定义好的模板,而后生成代码文件:
我的项目构造
xman-tcli
├─ bin
│ └─ xmant.js
├─ command
│ ├─ createFile.js
│ └─ createManyFiles.js
├─ config
│ └─ fileList.js
├─ templates
│ ├─ index.js
│ ├─ js
│ │ ├─ reactClassJSX.js
│ │ └─ reactFuncJSX.js
│ └─ ts
│ ├─ reactClassTSX.js
│ ├─ reactFuncTS.js
│ └─ reactFuncTSX.js
├─ utils
│ └─ index.js
├─ .gitignore
├─ LICENSE
├─ package.json
└─ README.md
具体实现
很多依赖的用途上一篇文章曾经提及,所以这篇文章就不会过多的介绍。
初始化我的项目
能够用 npm init 进行创立,也能够依据上面列出的 package.json 进行批改。
{
"name": "xman-tcli",
"version": "1.0.0",
"description": "web-cli 工具,能够疾速创立 template",
"bin": {"xmant": "bin/xmant.js"},
"scripts": {"test": "echo \"Error: no test specified\"&& exit 1"},
"repository": {
"type": "git",
"url": "https://github.com/XmanLin/xman-tcli.git"
},
"keywords": ["cli"],
"author": "xmanlin",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"clui": "^0.3.6",
"commander": "^8.2.0",
"figlet": "^1.5.2",
"handlebars": "^4.7.7",
"inquirer": "^8.1.5",
"update-notifier": "^5.1.0"
}
}
编写 bin/xman.js
#!/usr/bin/env node
const {program} = require('commander');
program
.version(require('../package').version, '-v, --version');
program.parse(process.argv); // 这里是必要的
if (!program.args.length) {program.help();
}
在以后 xmant-cli 目录下,执行 npm link
后,就能够在本地对脚手架工具进行调试了。
而后在当前目录下执行:
xmant -v
阐明工程初步搭建胜利。
通过命令疾速创立单个代码模板
编写模板
代码模板能够依据理论我的项目进行抽离,这里利用几个简略的模板作为例子。
templates/js/reactClassJSX.js
return `
import * as React from 'react';
export class ${className} extends React.Component{constructor(props){super(props);
this.state = {}}
componentDidMount(){}
render() {
return (<div></div>)
}
}
`
}
templates/js/reactFuncJSX.js
module.exports = function (funcName) {
return `
import React, {useEffect, useState} from 'react';
const ${funcName} = (props) => {
return (<div></div>)
}
export default ${funcName};
`
}
templates/ts/reactClassTSX.js
module.exports = function (className) {
return `
import * as React from 'react';
interface Props {}
interface State {}
export class ${className} extends React.Component<Props, State>{constructor(props: Props){super(props);
this.state = {}}
componentDidMount(){}
render() {
return (<div></div>)
}
}
`
}
templates/ts/reactFuncTS.js
module.exports = function (funcName) {
return `
export const ${funcName} = () => {}
`
}
templates/ts/reactFuncTSX.js
module.exports = function (funcName) {
return `
import React, {useEffect, useState} from 'react';
const ${funcName} = (props: any) => {useEffect(() => {},[])
return (<div></div>)
}
export default ${funcName};
`
}
模板定义好之后,通过 index.js
对立导出。
templates/index.js
const reactClassJSX = require('./js/reactClassJSX');
const reactFuncJSX = require('./js/reactFuncJSX');
const reactClassTSX = require('./ts/reactClassTSX');
const reactFuncTSX = require('./ts/reactFuncTSX');
const reactFuncTS = require('./ts/reactFuncTS');
// 命名标准:name 由“-”链接,后面为模板名,前面为创立后文件的后缀
module.exports = [
{name: 'reactClass-jsx', src: reactClassJSX},
{name: 'reactFunc-jsx', src: reactFuncJSX},
{name: 'reactClass-tsx', src: reactClassTSX},
{name: 'reactFunc-tsx', src: reactFuncTSX},
{name: 'reactFunc-ts', src: reactFuncTS}
]
这里的“命名标准”,目标是为了前面创立文件时失去相应的后缀。
创立工具函数 utils/index.js:
module.exports = {getFileSuffix: (name) => {if(typeof name === 'string') {return name.split('-')[1]
}
}
}
编写创立文件逻辑
筹备工作就绪,接下来就是文件创建的逻辑 command/createFile.js:
// 创立单个文件
const templates = require('../templates/index');
const chalk = require('chalk');
const inquirer = require('inquirer');
const fs = require("fs");
const utils = require('../utils/index');
module.exports = () => {
inquirer.prompt([
{
name: 'templateName',
type:'list',
message: '请抉择你想要生成的代码模板:',
choices: templates
},
{
name: 'filename',
type:'input',
message: '请输出代码文件中类名或办法名:',
validate: function (value) {if (value.length) {return true;} else {return '请输出代码文件中类名或办法名';}
},
}
])
.then(answers => {
const templateName = answers.templateName;
const filename = answers.filename;
templates.forEach((item) => {if(item.name === templateName) {const suffix = utils.getFileSuffix(item.name)
const file = `./index.${suffix}`
// 测验以后文件夹下是否有同名文件
fs.access(file, function(err) {if(!err) {console.log('创立失败:', chalk.yellow('文件已存在'))
} else {fs.writeFile(file, item.src(filename), function(err) {if(err) {console.log('创立失败:', chalk.red(err))
} else {console.log(chalk.green(` 创立文件胜利!${file}`));
}
})
}
})
}
})
})
}
这里须要留神的是:如果不在文件创建之前查看以后文件夹下是否有同名文件的话,原有的同名文件将被笼罩。
编写命令
最初就是命令的编写 bin/xman.js:
#!/usr/bin/env node
const {program} = require('commander');
...
program
.command('create')
.description("Create a file")
.alias('c')
.action(() => {require('../command/createFile')()});
...
调试
在以后我的项目文件夹下执行 npm link --force
, 而后轻易找个文件下执行 xmant c
:
关上咱们新创建的文件看看:
也能够抉择其余模板创立试试。
通过命令疾速批量创立代码模板
如果咱们想一次性创立大量的代码模板呢?当然还是通过命令批量的创立文件。
这里的思路:通过读取配置文件,而后进行批量创立。
编写配置文件
// 阐明:// folder: 文件夹名,能够嵌套,用“/”分隔
// fileName: 文件名
// funcName: 类名或函数名
// template:用到的文件模板
module.exports = [
{
folder: './home',
fileName: 'index',
funcName: 'Home',
template: 'reactFunc-tsx'
},
{
folder: './home/compnent',
fileName: 'index',
funcName: 'Compnent',
template: 'reactFunc-tsx'
},
{
folder: './home/service',
fileName: 'index',
funcName: 'service',
template: 'reactFunc-ts'
},
{
folder: './news',
fileName: 'index',
funcName: 'News',
template: 'reactFunc-tsx'
},
{
folder: './news/service',
fileName: 'index',
funcName: 'service',
template: 'reactFunc-ts'
}
]
这里用到的文件模板就是咱们之前编写好的模板。
编写批量创立文件逻辑
依据配置文件进行文件夹和文件的批量创立 command/createManyFiles.js:
// 批量创立文件
const chalk = require('chalk');
const inquirer = require('inquirer');
const fs = require('fs');
const path = require('path');
const utils = require('../utils/index');
const fileList = require('../config/fileList');
const templates = require('../templates/index');
const clui = require('clui');
const Spinner = clui.Spinner;
const status = new Spinner('正在创立...');
// 递归创立目录 同步办法
function mkdirsSync(dirname) {if (fs.existsSync(dirname)) {return true;} else {if (mkdirsSync(path.dirname(dirname))) {fs.mkdirSync(dirname);
console.log(chalk.green(` 创立目录胜利 -${dirname}`));
}
}
}
module.exports = () => {
inquirer.prompt([
{
name: 'choices',
type:'list',
message: '请确认配置好模板批量生成列表',
choices: ['yes', 'no']
}
])
.then(answers => {
const choices = answers.choices
if(choices === 'yes') {
// 批量创立目录
fileList.forEach(item => {if(item.folder) {mkdirsSync(`${item.folder}`)
}
})
// 批量创立文件
fileList.forEach(item => {
templates.forEach(tpl => {if(item.template === tpl.name) {const suffix = utils.getFileSuffix(item.template)
const fileName = `${item.fileName}.${suffix}`
fs.writeFile(`${item.folder}/${fileName}`, tpl.src(item.funcName), function(err) {if(err) {console.log('创立失败:', chalk.red(err))
} else{console.log(chalk.green(` 创立文件胜利!${fileName}`));
}
})
}
})
})
}
})
}
编写命令
最初编写 bin/xman.js:
#!/usr/bin/env node
const {program} = require('commander');
...
program
.command('create-many')
.description("Create many folders and files")
.alias('cm')
.action(() => {require('../command/createManyFiles')()});
...
调试
在以后我的项目文件夹下执行 npm link --force
, 而后轻易找个文件下执行 xmant cm
:
看一下咱们批量创立的文件和文件夹:
总结
对于疾速创立代码模板的办法有很多,有 VSCode 插件,也有 CLI 工具,更有做成 lowcode/nocode 平台的形式等等。本文这种形式的益处在于足够灵便,咱们能够依据具体的需要进行灵便的革新,使得更实用。