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 相关文章推荐
用js查找法实现当前栏目的高亮显示的代码
Nov 24 Javascript
json的前台操作和后台操作实现代码
Jan 20 Javascript
json格式的时间显示为正常年月日的方法
Sep 08 Javascript
js捕获鼠标滚轮事件代码
Dec 16 Javascript
禁止页面刷新让F5快捷键及右键都无效
Jan 22 Javascript
JavaScript异步编程Promise模式的6个特性
Apr 03 Javascript
JavaScript实现打字效果的方法
Jul 10 Javascript
jQuery简单实现彩色云标签效果示例
Aug 01 Javascript
JavaScript中关键字 in 的使用方法详解
Oct 17 Javascript
bootstrap多层模态框滚动条消失的问题
Jul 21 Javascript
JS对象与json字符串相互转换实现方法示例
Jun 14 Javascript
更优雅的微信小程序骨架屏实现详解
Aug 07 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正则表达式中的非贪婪模式匹配的使用
2014/11/25 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
php自定义截取中文字符串-utf8版
2017/02/27 PHP
Laravel中前端js上传图片到七牛云的示例代码
2017/09/04 PHP
ExtJS 简介 让你知道extjs是什么
2008/12/29 Javascript
jquery中通过过滤器获取表单元素的实现代码
2011/07/05 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
js实现鼠标点击文本框自动选中内容的方法
2015/08/20 Javascript
利用HTML5的画布Canvas实现刮刮卡效果
2015/09/06 Javascript
jQuery Mobile 触摸事件实例
2016/06/04 Javascript
AngularJS改变元素显示状态
2017/04/20 Javascript
详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
2017/08/30 Javascript
Vue.js实现的表格增加删除demo示例
2018/05/22 Javascript
js 实现在2d平面上画8的方法
2018/10/10 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
python使用xslt提取网页数据的方法
2018/02/23 Python
python numpy 部分排序 寻找最大的前几个数的方法
2018/06/27 Python
python如何生成各种随机分布图
2018/08/27 Python
pyhanlp安装介绍和简单应用
2019/02/22 Python
python识别文字(基于tesseract)代码实例
2019/08/24 Python
python两个_多个字典合并相加的实例代码
2019/12/26 Python
Pandas对DataFrame单列/多列进行运算(map, apply, transform, agg)
2020/06/14 Python
基于Python的一个自动录入表格的小程序
2020/08/05 Python
HTML5实现表单自动验证功能实例代码
2017/01/11 HTML / CSS
凯特王妃父母建立的派对用品网站:Party Pieces
2017/05/28 全球购物
adidas泰国官网:adidas TH
2020/07/11 全球购物
远程调用的原理
2014/07/05 面试题
岗位职责风险防控
2014/02/18 职场文书
农业开发项目建议书
2014/05/16 职场文书
学雷锋日活动总结
2015/02/06 职场文书
致地震灾区的慰问信
2015/03/23 职场文书
售后前台接待岗位职责
2015/04/03 职场文书
2015年驾驶员工作总结
2015/04/29 职场文书
Python中npy和mat文件的保存与读取
2022/04/24 Python
css如何把元素固定在容器底部的四种方式
2022/06/16 HTML / CSS
java.util.NoSuchElementException原因及两种解决方法
2022/06/28 Java/Android