通过Node.js开发一个小型的脚手架工具以及脚手架工具的工作过程

987 阅读5分钟

什么是脚手架

  • 全局的命令行工具
  • 有交互能力
  • 项目模板代码的下载能力

如何实现一个脚手架?

  1. 创建一个本地的全局命令行
  2. 接收命令行传入的参数并处理
  3. 命令行交互:
    问问题,用户答,接收用户输入的答案,处理不同的答案
  4. 下载远程代码模板
  5. 项目初始化完成的提示消息

1. 创建一个本地的全局命令行

  • 创建 sample-scaffolding (自定义)目录, 创建 bin 目录,然后创建一个 cli.js 文件
  • 在 sample-scaffolding 项目路径,运行 npm init 初始化项目,得到 package.json
  • bin 目录:项目的命令行执行的脚本文件,根据文件创建了一个mycli命令行
  • 在当期项目路径,执行npm link 命令行,把脚手架连接到全局(link作用:把当前项目挂载到全局npm执行的系统变量里,创建一个全局的本地命令行)

image.png

脚手架基础应用搭建

Node CLI 应用入口文件必须要有这样的文件头,指示 node 运行cli.js

#!/usr/bin/env node

如果是 Linux 或 macOS 系统下还需要修改此文件的读写权限为 755 具体就是通过 chmod 755 cli.js 实现修改

通过 yarn link 命令行,把这个模块 link 到全局,这时我们就可以在命令行中,使用sample-scaffolding 命令行执行,看到终端 console.log 正常执行,就意味着这个 cli 的基础应用就已经可以了。

image.png

使用cli脚手架创建基本业务

脚手架的工作过程:

  1. 通过命令行交互询问用户问题
  2. 根据用户回答的结果动态生成文件

通过命令行交互询问用户问题

在node中,发起命令行交互询问,我们使用 inquirer 这个模块,执行命令行yarn add inquirer 安装。有了这个模块,我们就可以在代码中载入它

image.png

inquirer 具体使用如下图所示,配置完成后运行文件,可见,能正常打印我们输入的项目名称“Hello”。 image.png

根据用户回答的结果动态生成文件

在项目根目录下,新建一个 templates 的目录存放我们的文件模板,在templates 目录里新建一个index.html作为示例来介绍脚手架工作过程的一个模板文件 在模板中,可以通过<%= name %>的方式去输出我们cli.js 配置询问环节得到的答案,如name的值

image.png

我们还可以根据需要添加其他的模板文件...

有了模板文件之后,回到 cli.js 文件,可以根据用户回答的结果生成文件,生成之前,我们先把模板的目录和生成的文件目录确定下来:

  • 通过 path 拿到模板文件目录
const path = require('path')
// 模板目录
const tmplDir = path.join(__dirname, 'templates')
  • 而输出的目标目录,一般就是我们命令行在哪个目录下执行,就是哪个目录的路径,也就是我们的cwd目录,在node中,我们可以借助于process.cwd方法,得到这样一个目录的路径
// 目标目录
const destDir = process.cwd()

明确了模板目录和目标目录之后,我们就可以通过 fs 模块,去读取模板目录下,有哪些模板文件,将这些文件全部转换到目标目录,fs.readdir 会自动扫描 模板目录下所有文件 整体配置流程如下:

#!/usr/bin/env node

// console.log('Lily\'s cli working');

const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')  // 模板引擎

// prompt 发起询问,接收一个数组的参数
inquirer.prompt([
    {
        type: 'input',  // 指定问题的输入方式
        name: 'name',   // 指定问题返回值对应的键
        message: 'Project name?'   // 指定屏幕上给用户的提示
    }
]).then(answers => {  // then方法里可以拿到这个问题接收到的用户的答案
    // console.log(answers);
    // 模板目录
    const tmplDir = path.join(__dirname, 'templates')
    // 目标目录
    const destDir = process.cwd()
    // 将模板下的文件全部转换到目标目录,在readdir回调函数中,可以通过files拿到所有的文件列表
    fs.readdir(tmplDir, (err, files) => {
        // 读取过程中发生问题,可以把错误信息抛出
        if (err) throw err
        // 遍历每个文件
        files.forEach(file => {
            console.log(file); // 打印出来可以得知模板文件的路径是相对templates下的相对路径
            // 通过 ejs 模板引擎中 renderFile 方法渲染这个路径对应的文件  yarn add ejs 安装后需要引入
            // 参数一:文件的绝对路径,  参数二: 模板引擎工作中的数据上下文, 参数三:是一个渲染后的回调函数(成功或失败)
            ejs.renderFile(path.join(tmplDir, file), answers, (err, result) => {
                if (err) throw err
                console.log(result);
                // 通过文件写入的方式把结果写入到目标目录
                // 参数一:是目标目录的拼接, 参数二:输出的结果
                fs.writeFileSync(path.join(destDir, file), result)
            })

        })
    })
})

配置完成后,我们可以到一个新的目录,运行cmd ,执行命令行sample-scaffolding尝试使用这个脚手架是否搭建成功,如下图可见,已经把我们的模板文件和输入的信息,输出到对应的目标目录,脚手架生效了!

image.png

image.png

处理命令参数

(以下内容脚手架名称修改为mycli)

安装 commander:commander 专门用来接收并处理命令参数的工具 npm install commander

#!/usr/bin/env node

const { program } = require('commader')
program.parse(process.argv)

设置脚手架帮助信息 program.option() image.png

获取当前脚手架帮助信息 mycli --help

image.png

自定义脚手架指令 program.command('自定义指令名称')

<project>: 必填参数
[others...]: 选填
alias: 别名
description: 描述信息
action: 回调函数,要操作的事
image.png

然后就可以使用自定义的 create 指令 image.png

你们的点赞,是对我的鼓励!欢迎评论区给我留言