node通过npm写一个cli命令行工具


Posted in Javascript onOctober 12, 2017

前言

如果你想写一个npm插件,如果你想通过命令行来简化自己的操作,如果你也是个懒惰的人,那么这篇文章值得一看。

po主的上一篇文章介绍了定制自己的模版,但这样po主还是不满足啊,项目中我们频繁的需要新建一些页面,逻辑样式等文件,每次都手动new一个,然后复制一些基本代码进去非常的麻烦,所以就有了这篇文章。接下来就让po主为大家一步一步演示怎么做一个npm命令行插件。

node通过npm写一个cli命令行工具

注册npm账户

发布npm插件,首先肯定要有个npm帐号了,过程就不??铝耍?吣恪?/p>

npm官网

有了账号后,我们通过npm init 生成一个package配置文件,填写一些你的信息,然后就可以开始写逻辑代码了。

编写命令入口

首先看一下项目结构

.
├── bin      //命令配置
├── README.md   //说明文档
├── index.js   //主入口
├── src      //功能文件
├── package.json //包信息
└── test     //测试用例

实例命令代码都是写在bin目录下,我们现在配置文件package文件中启用命令,添加一个配置项bin

"bin": {
    "xu": "./bin/xu.js"
  },

然后安装一个依赖,TJ大神写的commander插件,

npm i commander --save

有了这个工具我们可以很方便的编写命令代码

xu.js

#!/usr/bin/env node

process.title = 'xu';

require('commander')
.version(require('../package').version)
.usage('<command> [options]')
.command('generate', 'generate file from a template (short-cut alias: "g")')
.parse(process.argv)


require('./xu-generate');  >>引入

这个文件可以看作是入口文件,第一行代码是必须添加的,脚本用env启动的原因,是因为脚本解释器在linux中可能被安装于不同的目录,env可以在系统的PATH目录中查找。同时,env还规定一些系统环境变量。 这种写法主要是为了让你的程序在不同的系统上都能适用。

在这一步,你可以简单测试你自己的npm插件

$ node ./bin/xu.js

>>> 输出一些插件usage。help信息

关于commander,大家可以去作者的Github先学习了解,这里不对参数讲解。

xu-generate.js

#!/usr/bin/env node

const program = require('commander');
const chalk = require('chalk')
const xu = require('../src/generate');


/**
 * Usage.
 */

program
.command('generate')
.description('quick generate your file')
.alias('g')
.action(function(type, name){
  xu.run(type, name);
});
program.parse(process.argv);

这就是功能命令,定义了一个generate命令,.alias('g')是该命令的缩写,然后.action(function(type, name){xu.run(type, name); });返回一个函数,这个函数就是我们定义这个命令需要做什么事。

编写功能函数

./src/generate.js

这个文件就定义了当我们输入

$ xu g

所做的操作了。

/**
 * Created by xushaoping on 17/10/11.
 */

const fs = require('fs-extra')
const chalk = require('chalk')
exports.run = function(type, name) {
  switch (type) {
    case 'page':
      const pageFile = './src/page/' + name + '/' + name + '.vue'
      const styleFile = './src/page/' + name + '/' + name + '.less'
      fs.pathExists(pageFile, (err, exists) => {
        if (exists) {
          console.log('this file has created')
        } else {
          fs.copy('/usr/local/lib/node_modules/vue-xu-generate/src/template/page.vue', pageFile, err => {
            if (err) return console.error(err)
        
            console.log(pageFile + ' has created')
          })
          fs.copy('/usr/local/lib/node_modules/vue-xu-generate/src/template/page.less', styleFile, err => {
            if (err) return console.error(err)
        
            console.log(styleFile + ' has created')
          })
        }
      })
      break;
    case 'component':
      const componentFile = './src/components/' + name + '.vue'
      fs.pathExists(componentFile, (err, exists) => {
        if (exists) {
          console.log('this file has created')
        } else {
          fs.copy('/usr/local/lib/node_modules/vue-xu-generate/src/template/component.vue', componentFile, err => {
            if (err) return console.error(err)
          
            console.log(componentFile + ' has created')
          })
        }
      })
      break;
    case 'store':
      const storeFile = './src/store/modules' + name + '.js'
      fs.pathExists(storeFile, (err, exists) => {
        if (exists) {
          console.log('this file has created')
        } else {
          fs.copy('/usr/local/lib/node_modules/vue-xu-generate/src/template/store.js', storeFile, err => {
            if (err) return console.error(err)
          
            console.log(storeFile + ' has created')
          })
        }
      })
      break;
    default:
      console.log(chalk.red(`ERROR: uncaught type , you should input like $ xu g page demo` ))
      console.log()
      console.log(' Examples:')
      console.log()
      console.log(chalk.gray('  # create a new page'))
      console.log('  $ xu g page product')
      console.log()
      console.log(chalk.gray('  # create a new component'))
      console.log('  $ xu g component product')
      console.log()
      console.log(chalk.gray('  # create a new store'))
      console.log('  $ xu g store product')
      console.log()
      break;
  }
};

这里有2个新的依赖,分别是命令输出颜色和一个文件操作的插件,通过npm安装。

$ npm i fs-extra --save

$ npm i chalk --save

这个js文件导出了一个run函数给 xu-generate.js调用,我们通过参数拿到了用户输入的type,name,然后就可以根据type通过node fs模块(这里用了一个依赖,不过原理还是fs)操作把template文件复制了一份到你的项目中。

到这,我们就已经完成了一个命令的开发,这个命令可以快速生成项目的模版文件。

本地测试

npm包开发不像web开发,可以直接在浏览器看,实例目录下建立一个test文件,再 node test 就可以测试我们的逻辑。如果有一些功能需要在发布后才能测,npm 有个 link命令 可以连接你本地的模块,当然你也可以发布后 自己安装插件测试,就跟平时引入一个插件一样。

发布npm包

首先在项目根目录执行npm登陆

$ npm login 

$ npm publish

如果这里有个报错,可能是你使用了cnpm地址,需要把npm仓库设置回来

$ npm config set registry https://registry.npmjs.org/

然后,更新更新npm包,版本号需要大于上一次

后记

至此,一个入门级的npm包就制作完成了。万分感慨,记得刚入门前端的时候看到别人的插件做的真牛,自己只要简单安装一下就能搞得那么漂亮,想搞~但是看到一堆陌生的东西,立刻怂了(node环境,东西非常非常多,直接拷个vue-cli看到一对代码,一头雾水。。。大牛请无视)

学习是一个循序渐进的过程,大牛写出来的东西,没有一定的基础,和长时间的积累经验,源码是很难学习。非要啃,也行,只是效率感觉不如循序渐进来的好。

插件已经发布,Github也有完整源码,想学习的同学可以fork一个自己玩玩,干这一行~随心所动 ,跟着兴趣走,准没错

传送门: npm地址

传送门:github源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery困惑—包装集 DOM节点
Oct 16 Javascript
某页码显示的helper 少量调整,另附js版
Sep 12 Javascript
用显卡加速,轻松把笔记本打造成取暖器的办法!
Apr 17 Javascript
用js实现table单元格高宽调整,兼容合并单元格(兼容IE6、7、8、FF)实例
Jun 25 Javascript
javascript实现依次输入input自动定焦
Dec 23 Javascript
浅谈JS函数定义方式的区别
Oct 30 Javascript
微信小程序 slider 详解及实例代码
Jan 10 Javascript
vuejs手把手教你写一个完整的购物车实例代码
Jul 06 Javascript
node实现简单的反向代理服务器
Jul 26 Javascript
JS实现的抛物线运动效果示例
Jan 30 Javascript
vue+iview 实现可编辑表格的示例代码
Oct 31 Javascript
ES6 class类链式继承,实例化及react super(props)原理详解
Feb 15 Javascript
JS实现自定义状态栏动画文字效果示例
Oct 12 #Javascript
AngularJS实现表单验证功能详解
Oct 12 #Javascript
vue mintui-Loadmore结合实现下拉刷新和上拉加载示例
Oct 12 #Javascript
AngularJS 中的数据源的循环输出
Oct 12 #Javascript
详解微信小程序中的页面代码中的模板的封装
Oct 12 #Javascript
BootStrap Validator 根据条件在JS中添加或移除校验操作
Oct 12 #Javascript
Angular实现预加载延迟模块的示例
Oct 12 #Javascript
You might like
PHP目录函数实现创建、读取目录教程实例
2011/01/13 PHP
php 日期和时间的处理-郑阿奇(续)
2011/07/04 PHP
一个典型的PHP分页实例代码分享
2011/07/28 PHP
PHP远程采集图片详细教程
2014/07/01 PHP
jQuery 学习入门篇附实例代码
2010/03/16 Javascript
js的逻辑运算符 ||
2010/05/31 Javascript
javascript避免数字计算精度误差的方法详解
2014/03/05 Javascript
javascript获取函数名称、函数参数、对象属性名称的代码实例
2014/04/12 Javascript
js匿名函数的调用示例(形式多种多样)
2014/08/20 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
firefox浏览器用jquery.uploadify插件上传时报HTTP 302错误
2015/03/01 Javascript
jQuery+CSS实现的网页二级下滑菜单效果
2015/08/25 Javascript
jQuery ui实现动感的圆角渐变网站导航菜单效果代码
2015/08/26 Javascript
JavaScript中三种常见的排序方法
2017/02/24 Javascript
jQuery Ajax自定义分页组件(jquery.loehpagerv1.0)实例详解
2017/05/01 jQuery
Node.JS文件系统解析实例详解
2017/05/15 Javascript
详解AngularJS用Interceptors来统一处理HTTP请求和响应
2017/06/08 Javascript
Vue和Bootstrap的整合思路详解
2017/06/30 Javascript
Nodejs中使用phantom将html转为pdf或图片格式的方法
2017/09/18 NodeJs
Angular5集成eventbus的示例代码
2018/07/19 Javascript
详解微信小程序与内嵌网页交互实现支付功能
2018/10/22 Javascript
使用vue完成微信公众号网页小记(推荐)
2019/04/28 Javascript
微信小程序webview与h5通过postMessage实现实时通讯的实现
2019/08/20 Javascript
js 递归json树实现根据子id查父id的方法分析
2019/11/08 Javascript
[01:32]DOTA2 2015国际邀请赛中国区预选赛第四日战报
2015/05/29 DOTA
Python处理字符串之isspace()方法的使用
2015/05/19 Python
python对数组进行反转的方法
2015/05/20 Python
Python如何在循环内使用list.remove()
2020/06/01 Python
英国的知名精品百货公司:House of Fraser(福来德)
2016/08/14 全球购物
西班牙多品牌鞋店连锁店:Krack
2018/11/30 全球购物
Farfetch台湾官网:奢侈品牌时尚购物平台
2019/06/17 全球购物
.net软件工程师应聘上机试题
2015/03/10 面试题
《北京的春节》教学反思
2014/04/07 职场文书
青春寄语大全
2014/04/09 职场文书
校长师德师风自我剖析材料
2014/09/29 职场文书
Mysql忘记密码解决方法
2022/02/12 MySQL