记录一次使用node开发脚手架工具

130 阅读3分钟

最近上班摸鱼的时候,看到公司项目的文件夹,由于项目是基于DDD进行开发的,所以目录结构基本是一致的,想到每次创建新模块的时候需要每个文件去创建,为什么不能写个脚本工具去帮助我快速生成新的目录结构和文件呢。

先创建个目录

mkdir xx-cli
cd xx-cli
npm init -y

本来想着用ts来开发的,想了想这个简易的工具其实代码不会特别多,直接js梭哈了,还省了编译这一步。

下面就得理清我们的需求,我们是想通过命令行工具帮我们快速创建文件目录,类似nest/cli那样,所以commander.js这个包肯定是需要的,至于模板引擎相关的工具,这个项目暂时用不到。

下面就是安装依赖,然后创建下项目目录

npm i commander
mkdir src
cd src
echo index.js
mkdir utils

好了之后,可以先改一下package.json的内容,把版本号(version),作者(author),模块(type),这里是在node环境下,type就用commonjs,然后是入口文件(main),由于我们是命令行工具,还需要配置bin,至于命令是什么,自己取个喜欢的名字就好了,后续就可以直接在终端输入xx ,就能看到命令行信息了。

"bin": {
       "xx": "src/index.js"
   },

基本工具基本做完了,下面就是开始写代码了,首先在index.js中引如commander,然后通过commander来帮助我们创建一个新的命令

// 引入commander
const program = require('commander');
// 加入版本号
program.version("0.0.1");
// 创建命令
program
 .command("create <name>")
 .description("create a new project")
 .action((name)=>{
     console.log('文件名:',name)
})

这样就已经创建好了命令了,在命令行输入node index.js xx create demo,就能看到打印文件名:demo了。

到这一步命令有了,文件名有了,下面就是我们创建文件的逻辑,创建文件肯定就需要nodejs的fs模块的帮助了。 在utils文件夹中新增两个文件

cd utils
// 创建文件的函数
echo createFile.js
// 存放目录文件信息
echo fileList.js

这里先把我们要的文件目录结构确定

// type dir表示目录,file表示文件,如果后续有需要可以加入template,来引用模板地址,暂时这里用不到
const generateFiles = (projectName) => {
  return [
    {
      name: projectName,
      type: 'dir',
      children: [{
        name: 'api',
        type: 'dir',
        children: [{
          name: 'command',
          type: 'dir',
        }, {
          name: `${projectName}API.ts`,
          type: 'file',
        },
          {
            name: `${projectName}Assembler.ts`,
            type: 'file',
          }
        ]
      }, {
        name: 'app',
        type: 'dir',
        children: [{
          name: `${projectName.replace(/^./, projectName[0].toUpperCase())}App.ts`,
          type: 'file',
        }
        ]
      }, {
        name: 'constant',
        type: 'dir',
      },
        {
          name: 'domain',
          type: 'dir',
        }, {
          name: 'exception',
          type: 'dir',
          children: [{
            name: `${projectName.replace(/^./, projectName[0].toUpperCase())}Exception.ts`,
            type: 'file',
          }]
        }, {
          name: 'plugins',
          type: 'dir',
        }, {
          name: 'view',
          type: 'dir',
        }]
    }
  ]

}


module.exports = {
  generateFiles
}

目录结构确定了,下面就是根据目录结构来编写创建文件的函数了

const fs = require("fs");
const path = require("path");

// 接受两个参数,basePath就是我们当前目录的路径,files就是我们的目录结构
const createFiles = (basePath, files) => {
  for (const file of files) {
   // 这里每次获取当前目录的完整路径
    const filePath = path.join(basePath, file.name);

    if (file.type === "dir") {
    // 如果是文件夹,使用mkdirSync直接创建文件夹
      fs.mkdirSync(filePath);
      if (file.children) {
        createFiles(filePath, file.children);
      }
    } else if (file.type === "file") {
    // 如果是file类型,在当前目录下,创建一个空文件
      fs.writeFileSync(filePath, "");
    }
  }
};

module.exports = {
  createFiles
}

这两个工具方法写好后,这个简易工具逻辑就基本实现了,下面完善下index.js就可以了

#!/usr/bin/env node

const program = require('commander');
const { generateFiles } = require("./utils/fileName");
const { createFiles } = require("./utils/createFiles");


program.version("0.0.1");

program
    .command("create <name>")
    .description("create a new project")
    .action((name) => {
          const files = generateFiles(name)
          const basePath = process.cwd()
          createFiles(basePath, files)
        }
    );


program.parse(process.argv);

这里如果想通过命令行来运行命令的话,文件开头需要加上 #!/usr/bin/env node,表示使用node解释器来执行脚本。 如果想要使用命令的话,还需要发布到npm上,然后下载到全局才可以使用这个命令,但是在本地测试可以不用这么复杂,直接运行npm link,这个可以在我们本地上创建一个软链接,可以让我们在本地直接引入这个包进行使用。 现在直接运行xx create demo,就可以创建一个完整目录了。

image.png 这个简易脚手架工具的编写到这里就结束,如果想要发布到npm上,需要有一个npm账号,我的密码现在不记得了,就不想发布私包了。