文章目录

  • 思路
  • 一、步骤
  • 1.新建项目
  • 2.项目初始化
  • 3.脚本映射为命令
  • 3.1.配置在package.json
  • 3.2.命令链接到全局
  • 4.命令行工具参数设计
  • 5. 使用commander 模块处理 命令行
  • 5. 准备模板
  • 6. 设置命令行交互
  • 7. 本项目发布到npm
  • 遇到的问题
  • 1. 报以下信息:



思路



  • 项目模板放在GitHub上面
  • 用户通过命令交互的方式下载不同的模板(类似 npm install)
  • 经过模板引擎渲染定制项目模板
  • 模板变动,只需要更新模板即可,不需要用户更新脚手架

一、步骤

1.新建项目

一般脚手架命名格式:xxx-cli

mkdir 项目名称

其实就是新建一个文件夹,再新建一个文件,命名为index.js.并写入以下内容:

//index.js
#!/usr/bin/env node
console.log("脚手架工具")

注意😕 使用node开发命令行工具所执行的 JavaScript脚本必须在顶部加入#!/usr/bin/env node声明,为了告诉执行器使用node执行当前脚本代码

2.项目初始化

cd 项目名
npm init -y

此时 项目会新增一个package.json文件

脚手架 开发框架 MES 脚手架建模_脚手架 开发框架 MES

3.脚本映射为命令

这一步可以让我们的项目使用命令行就可以执行

3.1.配置在package.json

在package.json 中新增 bin 对象:

"bin": {
    "abc": "index.js"
  }

新增的 bin 对象,键 “abc” 是终端命令交互的时候输入的值(命令),值 index.js 是终端输入 abc 命令的时候要执行的文件

3.2.命令链接到全局

npm link

提示的warn没有关系,这时候可以执行 bin里面配置的命令测试,即再输入 abc ,则会出现提示 ”脚手架工具“,说明已经执行了 index.js文件了

脚手架 开发框架 MES 脚手架建模_bc_02


而且不用在项目目录下输入 abc 也是可以执行的

如果要修改package.json 里面bin字段的值,需要先 npm unlink 再修改bin里面的名称,保存之后再次链接:npm link

4.命令行工具参数设计

目标是设置以下命令

abc -h|--help  查看帮助
abc -v|--version 查看工具的版本号
abc list 列出所有可用的模板
abc init <template-name> <project-name> 基于指定的模板进行项目初始化
其中<>代表必填

5. 使用commander 模块处理 命令行

安装commander,官网

npm install commander

代码:

const { program } = require('commander');//加载commander
//以下每一个program 设置一个命令行参数返回
program
  .version('0.1.0')//终端输入 abc -v|--version 返回 0.1.0

program
  .command('init <template> <project>') //根据模板名下载对应的模板到本地并起名为projectName
  .description('初始化项目模板')
  .action(function(templateName, projectName){
  //终端输入 “abc init webpack abc” 得到的templateName, projectName分别为 webpack abc 
  })
//abc init a a-name
//基于 a 模板进行初始化并重命名为 a-name
//itcast init b b-name
//基于 b 模板进行初始化重命名为 b-name
  
program
  .command('list')//终端输入 abc list 返回以下设置的所有可用模板
  .description("查看所有可用模板")
  .action(() => {
模板选项
    }

program.parse(process.argv);

5. 准备模板

在gitee上新建了两个仓库,地址为:
https://gitee.com/zuozuomufeishi/tpl-a.git https://gitee.com/zuozuomufeishi/tpl-b.git 使 abc init 可遍历输出模板

const templates = {
  'tpl-a': {
    url: 'https://gitee.com/zuozuomufeishi/tpl-a',
    downloadUrl: 'https://gitee.com/zuozuomufeishi/tpl-a#master',
    description: 'a模板'
  },
  'tpl-b': {
    url: 'https://github.com/soandend/tpl-b',
    downloadUrl: 'https://github.com.cnpmjs.org/soandend/tpl-b.git#master',
    description: 'b模板'
  }
}

program
  .command('list')
  .description("查看所有可用模板")
  .action(() => {
    for(let key in templates){//遍历输出模板
      console.log(`
      ${key} ${templates[key].description}
      `);
    }
  })

自行下载需要用到的插件:download-git-repo

npm install download-git-repo

代码引入

const download = require('download-git-repo');//引用下载模板需要的包

使模板使用命令abc init tpl-a aaa可以下载

program
  .command('init <template> <project>')
  .description('初始化项目模板')
  .action(function(templateName, projectName){
    //根据模板名下载对应的模板到本地并起名为projectName
    //下载模板需要安装 npm install download-git-repo
    // 第一个参数:仓库地址
    // 第二个参数: 下载路径\
    const {downloadUrl} = templates[templateName]
    download(downloadUrl, projectName, {clone: true},(err) => {
      if(err){
        return console.log("下载失败")
      }
    })
  })

6. 设置命令行交互

命令行交互,就是和用户一问一答的方式,对下载的项目进行自定义一些信息

给 tpl-a 添加一个package.json文件:

{
  "name": "{{ name }}",
  "version": "1.0.0",
  "description": "{{ description }}",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "{{ author }}",
  "license": "ISC",
  "bin": {
    "itcast": "index.js"
  },
  "dependencies": {
    "commander": "^7.1.0"
  }
}

其中三个字段用于交互:name,description,author 下载模板引擎和向导需要的包:

npm i handlebars
npm install inquirer

index.js引进模板引擎并设置交互模式:

const handlebars = require('handlebars');//引用下载引擎
const inquirer = require('inquirer');//引用向导
const fs = require("fs");//node的文件系统

program
  .command('init <template> <project>')
  .description('初始化项目模板')
  .action(function(templateName, projectName){
    //根据模板名下载对应的模板到本地并起名为projectName
    //console.log(templateName);
    //console.log(projectName);
    //
    //下载模板需要安装 npm install download-git-repo
    // 第一个参数:仓库地址
    // 第二个参数: 下载路径\
    const {downloadUrl} = templates[templateName]
    download(downloadUrl, projectName, {clone: true},(err) => {
      console.log(err)
      if(err){
        return console.log("下载失败")
      }
      //把项目下的package.json 文件读取出来
      //使用向导的方式采集用户输入的值
      //使用模板引擎把用户输入的数据解析到package.json文件中
      //解析完毕,把解析之后的结果重新写入 package.json 文件中
      //使用一个插件:npm install inquirer
      inquirer.prompt([
        {
        type: "input",
        name: "name",
        message: "请输入项目名称"
        },{
          type: "input",
          name: "description",
          message: "请输入项目简介"
        },{
            type: "input",
            name: "author",
            message: "请输入作者名称"
        },
      ]).then((answers) => {
          //得到用户输入的数据
          //解析到package.json 文件中,readFileSync(路径,字符集)
          const packageContent = fs.readFileSync(`${projectName}/package.json`, 'utf-8')
          const packageResult =  handlebars.compile(packageContent)(answers)
          //新写入 package.json 文件中
          fs.writeFileSync();
      })  
    })
  })

7. 本项目发布到npm

目标:使用npm install --g abc-cli可以下载这个包

1、到 npm官网 注册一个账号
2、检索是否有重名的包名
3、将 package.json 中的name名修改为要发的npm包名
4、控制台登录 npm

npm login

5、登录成功以后,在项目下执行发布:

npm publish

注:npm官网更新比较慢,但是不影响下载

遇到的问题

1. 报以下信息:

internal/modules/cjs/loader.js:883 throw err; 
^ Error: Cannot find module 'd

解决:删除node_modules文件夹,重新 执行 npm install