脚手架的基础

首先需要新建一个package.json文件,并在配置里添加"bin"属性,"bin"的值为文件路径。

手把手带你使用node实现搭建小型脚手架_node

PS:如果你想自定义CLI启动的名字,可以给bin一个对象,键值就是你启动输入的名字,不过你开发项目的时候要注意不要跟其他的CLI名称重复了。不自定义名称的话,就是输入项目的名称即可。本次演示我就不取自定义名称了,想自定义名称的小伙伴记得启动项目时,需要用自定义的名称(如下图)。

手把手带你使用node实现搭建小型脚手架_node_02

CLI应用的入口文件必须要有 #!/usr/bin/env node 作为文件头,如果使用的是Linux和macOS系统的话,还需要将此文件的读写权限改为755。

手把手带你使用node实现搭建小型脚手架_node_03

接着我们通过yarn link的方式将此模块link到全局 ,来看看这个项目的能不能跑起来。手把手带你使用node实现搭建小型脚手架_node_04

可以看到打出了log的信息,就代表项目正常执行了,脚手架的基础已经建好了。

PS:这里如果执行不了,可能是环境变量配置有问题,你可以用'yarn global bin'去查看你的yarn全局Bin的地址,并加到环境变量中就可以了。

脚手架的工作过程

接下来,我们来编写脚手架的工作过程,其过程分为两点:1.通过命令行交互询问用户问题;2.根据用户回答的结果生成文件。

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

在node里想使用命令行对用户发起询问,需要使用‘inquirer’这个模块,所以需要先安装这个模块,可以用yarn add来加载。

yarn add inquirer

安装好后,将quirer引入cli,inquirer有个prompt方法,可以通过传递相关配置,用这个方法来对用户进行询问,询问完后,通过‘.then’来获得用户的输入值。

#!/usr/bin/env node

// console.log('cli working')

const inquirer = require('inquirer');

inquirer.prompt([
    {
        type: 'input',  //指定问题的输入方式
        name: 'name',   //指定问题返回值的键名
        message: 'Project name?'  //给用户的提示
    }
]).then( answer => {
    console.log(answer);
});

我们回到控制台看看能否进行询问并返回。

手把手带你使用node实现搭建小型脚手架_node_05

我们可以看到询问和返回都是没有问题的,我们的询问这一步就完成了

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

现在我们需要根据回答生成文件,生成的文件需要模板,所以我们要先建立模板文件,模板文件可以使用<%= name %>来填入刚才回答的问题,如果你刚刚在prompt中name的value值用的是别的,这里就把name换成你自己写的value值即可。

手把手带你使用node实现搭建小型脚手架_node_06

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= name %></title>
</head>
<body>

</body>
</html>

在生成模板文件之前,我们一般先要把模板的根目录和目标路径给确定下来

#!/usr/bin/env node

// console.log('cli working')

const inquirer = require('inquirer');
const path = require('path');

inquirer.prompt([
    {
        type: 'input',  //指定问题的输入方式
        name: 'name',   //指定问题返回值的键名
        message: 'Project name?'  //给用户的提示
    }
]).then( answer => {
    // console.log(answer);
    // 模板目录
    const tmplDir = path.join(__dirname, '../temp')
    // 目标目录
    const destDir = process.cwd()
});

在确定了路径之后,我们再通过fs去读取模板目录下的目标文件,再将读取到的文件通过模板引擎渲染文件并转化到目标路径,这里需要通过'yarn add ejs'下载模板引擎。

#!/usr/bin/env node

// console.log('cli working')

const inquirer = require('inquirer');
const path = require('path');
const fs = require('fs');
const ejs = require('ejs')

inquirer.prompt([
    {
        type: 'input',  //指定问题的输入方式
        name: 'name',   //指定问题返回值的键名
        message: 'Project name?'  //给用户的提示
    }
]).then( answer => {
    // console.log(answer);
    // 模板目录
    const tmplDir = path.join(__dirname, '../temp')
    // 目标目录
    const destDir = process.cwd()
    // 将模板下的文件全部转换到目标目录
    fs.readdir(tmplDir, (err, files) => {
        if (err) throw err
        files.forEach(file => {
            // 通过模板引擎渲染文件
            ejs.renderFile(path.join(tmplDir, file), answer, (err, result) => {
                if (err) throw err
                // 将结果写入目标文件路径
                fs.writeFileSync(path.join(destDir, file), result)
            })
        })
    })
});

完成之后,这个脚手架就完成搭建了!

尝试使用新搭建的脚手架

我们建立一个新的目录,并在下面去执行我们的脚手架命令

手把手带你使用node实现搭建小型脚手架_node_07手把手带你使用node实现搭建小型脚手架_node_08

可以看到新建的文件夹里生成了一个html文件,我们打开看看这个文件是不是按照我们的模板渲染生成的

手把手带你使用node实现搭建小型脚手架_node_09

可以看到<title></title>标签里的name就是我们输入的demo,到此我们的脚手架就成功完成了!