前言

在上一篇文章中,咱们实现了一个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 nodeconst { 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 nodeconst { 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 nodeconst { 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 平台的形式等等。本文这种形式的益处在于足够灵便,咱们能够依据具体的需要进行灵便的革新,使得更实用。