手摸手教你制作自己的模板下载工具

创建脚本项目

1.创建一个文件夹,比如叫test_cli
2.在该目录中创建一个index.js
3.在index.js文件中声明一下该文件是可以当脚本运行的node文件

#!/usr/bin/env node

console.log('hello')

4.在test_cli文件夹目录打开命令行,输入以下命令,初始化npm,生成一个名为package.json的配置文件

npm init -y

出现下面这样的提示,就是成功了


image.png

配置package.json

1.打开package文件,s添加一个bin字段,bin里面设置一个键值对,key是你想要设置的命令,value是你想要通过key执行的js文件

下面是添加命令配置后的package文件

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

2.在当前目录的命令行中输入npm link,把当前的配置链接到全局中

npm link

出现以下信息,说明链接到全局成功

image.png

接下来可以在命令行中输入你设置的命令,来测试一下你设置的有没有成功,,如果成功打印出来以下信息,说明命令设置成功
image.png

3.取消全局链接
如果想切换命令,可以使用

npm unlink

取消全局链接,然后重复上面的操作,切换命令

基本功能已经实现,接下来丰富一下命令行的操作,例如vue create,vue -help

获取命令行参数

可以使用node原生获取,在index.js里面输入

console.log(process.argv)

这个获取的是命令行的参数,接下来测试一下,在命令行输入test_cli init,然后来看一下打印的结果

image.png

发现打印出来一个数组,前两个不用管,第三个开始,后面的就是输入的参数,然后就可以根据获取的参数去做不同的操作.
不过这种方式比较麻烦,所以可以直接用插件来解决

安装commander插件

github地址:github:https://github.com/tj/commander.js

安装插件

npm install commander

安装完成以后,可以去github把他的examples拿下来,根据自己的需求改一下,
这边只介绍一下简单的用法,感兴趣的可以去移步github
version:版本号;command:要监听的命令;<>:必填参数;[]:选填参数;description:描述;action:处理命令行的函数
修改完的index.js

#!/usr/bin/env node
 // 声明一下是可以当脚本运行的node文件

// 引入命令插件
const {
    program
} = require('commander');

// 版本号
program.version('0.1.0');
// 创建项目模板
program
    .command('create <template> <project>')
    .description('创建项目')
    .action(() => {
        console.log('创建项目');

    });
// 模板列表
program
    .command('list')
    .description('模板列表')
    .action(() => {
        console.log('模版列表');
    });
// process.argv是原生获取的命令参数
program.parse(process.argv);

配置完以后,可以在命令行输入一下配置的参数测试一下,这里的help是插件自带的,会自动遍历你配置的命令,然后打印出来,当然,也可以自定义,具体操作可以参考github

test_cli --help

可以看到打印出来的帮助信息


image.png

说明我们的配置已经成功了

创建模版仓库

在github上创建你自己的模板仓库


image.png

下载模版

安装下载插件(没有找见该插件的github地址)

npm i download-git-repo

安装完成以后,在index.js中引入并配置下载地址

const download = require('download-git-repo');
//download的api
download("http://github.com:用户名/仓库名#分支","down下来以后的模版名字", {
            clone: true
        }, (err) => {
            if (err) {
              // 失败
              } else {
              //成功 
            }
        })

接下来开始实现逻辑
声明一个模板列表数组,
url:该模板的github地址;
desc:模板描述;
downLoadUrl:符合download插件规则的下载路径

// 模版的列表
const templateList = {
 "vue_tem_a": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版1",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    },
 "vue_tem_b": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版2",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    },
 "vue_tem_c": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版3",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    }
}

在命令的action里面配置一下,action接收的参数就是你的命令行后面的参数,参数名字可以自定义

// 创建项目模板
program
    .command('create <template> <project>')
    .description('创建项目')
    .action((templateName, projectName) => {
        const {
            downLoadUrl
        } = templateList[templateName];
        // 参数1 下载地址
        // 参数2 项目名称
        download(downLoadUrl, projectName, {
            clone: true
        }, (err) => {
            if (err) {
                // 失败
              console.log('下载失败')
            } else {
                // 成功
              console.log('下载成功')
            }
        })
    });
// 模板列表
program
    .command('list')
    .description('模板列表')
    .action(() => {
        for (const key in templateList) {
            if (templateList.hasOwnProperty(key)) {
                console.log(`${key} ${templateList[key].desc}`)
            }
        }
    });

配置完以后可以测试一下
在你的工作目录下打开命令行,输入

test_cli list

打印出来了所有模版,说明list配置成功


image.png

再试一下主要的下载功能

test_cli create vue_tem_a vue_tem

发现等待了一段时间以后,出现了下载成功


image.png

接下来你就可以在的项目目录里看见你down下载的模板了

美化命令行

功能实现以后就要追求一下美观,所以就来美化一下命令汗,添加一下loading,成功,失败图标之类的

ora 设置loading 成功 失败的图标
github地址:https://github.com/sindresorhus/ora
chalk 设置打印信息的字体颜色
github地址:https://github.com/chalk/chalk

安装插件

npm i ora chalk

安装完成以后添加并修改一下index.js

//添加对插件的引用
// loading美化效果
const ora = require('ora');
// 视觉优化  修改输出的文字颜色
const chalk = require('chalk');
// loading插件的实例对象
const spinner = ora('正在下载模板...');
// 创建项目模板
program
    .command('create <template> <project>')
    .description('创建项目')
    .action((templateName, projectName) => {
        spinner.start();
        const {
            downLoadUrl
        } = templateList[templateName];
        // 参数1 下载地址
        // 参数2 项目名称
        download(downLoadUrl, projectName, {
            clone: true
        }, (err) => {
            if (err) {
                // 失败
                //失败状态 红色的字
                spinner.fail(chalk.red(err));
            } else {
                // 成功
                // 成功状态 绿色的字
                spinner.succeed(chalk.green('初始化模板成功'));
            }
        })
    });

然后来测试一下美化效果

test_cli create vue_tem_a vue_test

如果出现loading和成功图标,说明设置成功


image.png

命令行交互

实现像vue-cli那种一问一答的交互模式
交互插件
github地址:https://github.com/SBoudrias/Inquirer.js
解析插件
github地址:https://github.com/handlebars-lang/handlebars.js

安装插件

npm i inquirer handlebars

安装完成以后添加修改index.js

// 解析插件
const handleBars = require('handlebars');
// 命令行交互
const inquirer = require('inquirer');
program
    .command('create <template> <project>')
    .description('创建项目')
    .action((templateName, projectName) => {
        spinner.start();
        const {
            downLoadUrl
        } = templateList[templateName];
        // 参数1 下载地址
        // 参数2 项目名称
        download(downLoadUrl, projectName, {
            clone: true
        }, (err) => {
            if (err) {
                // 失败
                spinner.fail(chalk.red(err));
            } else {
                // 成功
                spinner.succeed(chalk.green('初始化模板成功'));
              //  添加命令行交互
                inquirer.prompt([{
                    type: 'input',
                    name: 'author',
                    message: '请输入作者名称'
                }, {
                    type: 'input',
                    name: 'version',
                    message: '请输入版本'
                }]).then((answer) => {
                    console.log(answer);
                })
            }
        })
    });

测试一下


image.png

配置成功,并且拿到了交互后的数据,拿到这个数据以后需要修改模版里面的package.json

修改package

在github仓库模版项目里新建一个package.json文件,并修改成选填参数模式

{
  "name": "vue_com_tem",
  "version": "{{ version }}",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "{{ author }}",
  "license": "ISC",
}

在index.js文件添加修改,用交互的数据替换掉模版里面预留的字段

// 引用原生的fs模块
const fs = require('fs');

// 创建项目模板
program
    .command('create <template> <project>')
    .description('创建项目')
    .action((templateName, projectName) => {
        spinner.start();
        const {
            downLoadUrl
        } = templateList[templateName];
        // 参数1 下载地址
        // 参数2 项目名称
        download(downLoadUrl, projectName, {
            clone: true
        }, (err) => {
            if (err) {
                // 失败
                spinner.fail(chalk.red(err));
            } else {
                // 成功
                spinner.succeed(chalk.green('初始化模板成功'));
                inquirer.prompt([{
                    type: 'input',
                    name: 'author',
                    message: '请输入作者名称'
                }, {
                    type: 'input',
                    name: 'version',
                    message: '请输入版本'
                }]).then((answer) => {
                    // 文件的路径
                    const packagePath = `${projectName}/package.json`;
                    // 读取package文件
                    const packageStr = fs.readFileSync(packagePath, 'utf8');
                    // 解析替换package文件预留的字段
                    const packageResult = handleBars.compile(packageStr)(answer);
                    // 重写package文件
                    fs.writeFileSync(packagePath, packageResult);
                })
            }
        })
    });

测试一下


image.png

设置成功,然后打开下载以后的模板项目的package.json文件

image.png

大功告成
这样就是一个基础的模板下载工具了,如果你想发布到npm上让大家使用的话,你可以自行查找一下相关的步骤获取去看一下最下面的链接里面的视频,我这里就不往上传了

最后附上一份完整的index.js文件和详细的视频教程

#!/usr/bin/env node
 // 声明一下是可以当脚本运行的node文件

// 引入命令插件
const {
    program
} = require('commander');

// 从github下载模板的插件
const download = require('download-git-repo');
// loading美化效果
const ora = require('ora');
// 视觉优化  修改输出的文字颜色
const chalk = require('chalk');
// loading插件的实力对象
const spinner = ora('正在下载模板...');
// 模版引擎
const handleBars = require('handlebars');
// 命令行交互
const inquirer = require('inquirer');
// 引用原生的fs模块
const fs = require('fs');
// 仓库列表
const templateList = {
    "vue_tem_a": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版1",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    },
    "vue_tem_b": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版2",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    },
    "vue_tem_c": {
        url: "git@github.com:doubino/vue_com_tem.git",
        desc: "模版3",
        downLoadUrl: 'http://github.com:doubino/vue_com_tem#master'
    }
}
// 版本号
program.version('0.1.0');
// 创建项目模板
program
    .command('create <template> <project>')
    .description('创建项目')
    .action((templateName, projectName) => {
        spinner.start();
        const {
            downLoadUrl
        } = templateList[templateName];
        // 参数1 下载地址
        // 参数2 项目名称
        download(downLoadUrl, projectName, {
            clone: true
        }, (err) => {
            if (err) {
                // 失败
                spinner.fail(chalk.red(err));
            } else {
                // 成功
                spinner.succeed(chalk.green('初始化模板成功'));
                inquirer.prompt([{
                    type: 'input',
                    name: 'author',
                    message: '请输入作者名称'
                }, {
                    type: 'input',
                    name: 'version',
                    message: '请输入版本'
                }]).then((answer) => {
                    // 文件的路径
                    const packagePath = `${projectName}/package.json`;
                    // 读取package文件
                    const packageStr = fs.readFileSync(packagePath, 'utf8');
                    // 解析替换package文件预留的字段
                    const packageResult = handleBars.compile(packageStr)(answer);
                    // 充血package文件
                    fs.writeFileSync(packagePath, packageResult);
                })
            }
        })
    });
// 模板列表
program
    .command('list')
    .description('模板列表')
    .action(() => {
        for (const key in templateList) {
            if (templateList.hasOwnProperty(key)) {
                console.log(`${key} ${templateList[key].desc}`)
            }
        }
    });
// process.argv是原生获取的命令参数
program.parse(process.argv);

b站教学视频链接:https://www.bilibili.com/video/BV1sx411Z7tN?p=1

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容