美文网首页
npm脚手架开发学习

npm脚手架开发学习

作者: Felicity0512 | 来源:发表于2020-06-19 14:42 被阅读0次

    之前学习了怎么在npm上传自己的模块,现在可以开发自己的脚手架了。

    1、结构介绍

    模块目录基本结构如下:

    /bin  # ------ 命令执行文件
    /lib  # ------ 工具模块
    /template # ------ 模板
    package.json
    

    可以先不用在意这个结构。

    2、实现命令行的操作

    1)新建package.json

    $ md my-cli                 // 创建插件项目文件夹
    $ cd my-cli                 // 进入新建项目目录
    $ npm init -y               // 创建package.json文件
    

    根目录下得到package.json文件,修改如下:

    {
      "name": "my-cli",
      "version": "1.0.0",
      "description": "",
      // "main": "index.js",
      "bin": { // main入口修改为bin入口
        "my-cli": "./bin/cli.js"
      },
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    

    2)新建入口文件cli.js

    根目录新建./bin/cli.js文件,如下:

    #!/usr/bin/env node
    console.log("my-cli");
    

    此时根目录运行如下:

    $ node ./bin/cli.js
    my-cli
    

    得到my-cli的信息,表示运行成功。

    文件开头的 #!/usr/bin/env node 是必须的。详情见https://www.npmjs.cn/files/package.json/#bin

    3)使用commander开发命令行工具

    生产环境安装commander,如下:

    $ npm i commander -S
    

    注册命令行

    ./bin/cli.js文件修改如下:

    #!/usr/bin/env node
    const program = require('commander'); // npm i commander -S
    
    program.version('0.0.1')
        .usage('<command> [项目名称]')
        .command('init', 'init')
        .parse(process.argv)
    

    此时需要新增./bin/cli-init.js文件如下:

    #!/usr/bin/env node
    console.log('init');
    

    此时根目录运行如下:

    $ node ./bin/cli.js init
    init
    

    得到init的信息,表示命令行工具注册成功。

    获取命令行输入的内容

    ./bin/cli-init.js文件修改如下:

    #!/usr/bin/env node
    const program = require('commander')
    const path = require('path')
    
    program.usage('<project-name>').parse(process.argv)
    
    let projectName = program.args[0] // 根据输入,获取项目名称
    let rootName = path.basename(process.cwd()); // 获取当前进程的根目录名称
    console.log(projectName, rootName);
    

    验证:

    $ node ./bin/cli.js init my-project
    my-project my-cli
    

    官方中文文档:Commander开发命令行工具

    4)使用inquirer命令行交互工具

    生产环境安装inquirer,如下:

    $ npm i inquirer -S
    

    ./bin/cli-init.js文件修改如下:

    #!/usr/bin/env node
    const program = require('commander')
    const path = require('path')
    const inquirer = require('inquirer') // 新增引入inquirer
    
    program.usage('<project-name>').parse(process.argv)
    
    let projectName = program.args[0]
    let rootName = path.basename(process.cwd());
    console.log(projectName, rootName);
    
    // 新增命令行交互
    inquirer.prompt([
      {
        name: 'projectName', // 参数名称
        message: '项目的名称', // 信息提示
        default: projectName // 默认值
      }, {
        name: 'projectVersion',
        message: '项目的版本号',
        default: '0.0.1'
      }, {
        name: 'projectDescription',
        message: '项目的简介',
        default: `A project named ${projectName}`
      }
    ]).then(answers => {
      console.log(answers); // 打印输入参数
    })
    

    运行,输出如下:

    $ node ./bin/cli.js init my-project
    my-project my-cli
    ? 项目的名称 my-project
    ? 项目的版本号 0.0.1
    ? 项目的简介 A project named my-project
    {
      projectName: 'my-project',
      projectVersion: '0.0.1',
      projectDescription: 'A project named my-project'
    }
    

    以上,就得到了几个重要的参数:项目名称、项目更目录名称、用户录入参数。简单的实现了,node命令行的操作。

    推荐阅读:inquirer一个用户与命令行交互的工具

    3、脚手架本地运行和测试

    目前一直是$ node ./bin/cli.js init my-project的方式在运行脚本,体验并不好,没有脚手架的使用效果。我们现在可以进行本地包的运行和测试了。

    1)安装my-cli脚手架到全局

    my-cli根目录运行如下:

    $ npm link
    

    此时脚手架被安装到全局,可以使用了。

    推荐阅读:npm link的使用
    npm unlink // 卸载link安装

    2)新建一个项目

    在其它目录下新建一个项目如下:

    $ md my-project                // 创建项目文件夹
    $ cd my-project                // 进入项目文件夹
    $ my-cli init my-project       // 运行脚手架
    my-project my-project
    ? 项目的名称 my-project
    ? 项目的版本号 0.0.1
    ? 项目的简介 A project named my-project
    {
      projectName: 'my-project',
      projectVersion: '0.0.1',
      projectDescription: 'A project named my-project'
    }
    

    得到如上信息,代表脚手架运行成功!

    这篇文章的目的是为学习,为了最简单的理解脚手架是怎么工作,用什么实现的,所以这里是没有做校验逻辑。

    4、复制模板文件到项目

    只是单文件的复制,使用node的fs就能完成,但模板文件一般都是文件夹的多文件复制,所以我使用mvdir模块来复制文件夹,很好用。

    1)新建模板文件

    my-cli根目录下,新建template文件夹,新建模板文件package.json,也可以是任意你想复制的文件。
    my-cli/template/package.json文件如下:

    {
      "name": "{{projectName}}",
      "version": "{{projectVersion}}",
      "description": "{{projectDescription}}",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }
    

    {{}}内的是模板变量占位符。

    2)mvdir复制模板文件

    my-cli根目录安装mvdir,如下:

    $ npm i mvdir -S
    

    ./bin/cli-init.js文件修改如下:

      ……
    const mvdir = require('mvdir') // 引入模块
      ……
    ]).then(answers => {
      console.log(answers);
      // 使用mvdir复制template文件夹内容到my-project项目的.download-temp文件夹下。.download-temp为临时文件夹,编译模板后会删除。
      mvdir(path.join(__dirname, '../template'), '.download-temp', { copy: true }).then((err) => {
        if (err) {
          console.log(err);
        } else {
          console.log('复制成功');
        }
      });
    })
    

    my-project项目根目录下,运行:

    $ my-cli init my-project
    

    得到复制成功,就可在项目下看到复制的模板文件。

    目前模板文件很小,所以放在了npm包里。如果模板文件很大,不适合放在npm包里的时候,可以将模板文件放在git上,然后使用download-git-repo工具,下载git上的模板文件到.download-temp的临时文件夹下。

    5、使用Metalsmith编译模板文件

    metalsmith就是一个静态网站生成器,可以用在批量处理模板的场景。handlebars是metalsmith的超集。

    生产环境安装metalsmith和handlebars,如下:

    $ npm i metalsmith handlebars -S
    

    ./bin/cli-init.js文件修改如下:

      ……
    const Metalsmith = require('metalsmith') // 引入静态网站生成器
    const Handlebars = require('handlebars') // 引入模板引擎
    const rm = require('rimraf').sync
      ……
        } else {
          console.log('复制成功');
          const src = `${process.cwd()}/.download-temp`;
          Metalsmith(process.cwd())
          .metadata(answers) // 全局元数据
          .clean(false) // 是否删除
          .source(src) // 编译来源路径
          .destination('.') // 编译目标路径
          .use((files, metalsmith, done) => { // 自定义插件
            const meta = metalsmith.metadata()
            Object.keys(files).forEach(fileName => {
              const t = files[fileName].contents.toString()
              files[fileName].contents = Buffer.from(Handlebars.compile(t)(meta))
            })
            done()
          })
          .build(err => {
            rm(src)
            if(err) {
              console.log(err);
            } else {
              console.log('脚手架运行成功');
            }
          })
        }
      ……
    

    my-project下运行:

    $ my-cli init my-project
    

    得到“脚手架运行成功”的提示,至此npm脚手架的基本功能就完成了。

    目前还没有使用lib文件夹,后续的开发中,需要对用户输入的校验、模板编译文件的筛选、异步操作队列化等功能,都可封装到lib工具模块中使用,减小bin文件的体积,提高可复用性。

    扩展阅读:metalsmith-apihandlebars
    本人基于此文章《基于node.js的脚手架工具开发经历》学习,学习后重新整理思路,编写此文章留作笔记。

    相关文章

      网友评论

          本文标题:npm脚手架开发学习

          本文链接:https://www.haomeiwen.com/subject/fzjsxktx.html