首页 > 技术文章 > node命令行工具—cf-cli

auok 2017-05-19 16:26 原文

音乐分享: 

钢心 - 《龙王》

初喜《冠军》 后喜《龙王》

(PS:听一次钢心乐队的演出后采访才知道 “龙王”隐喻的是一起喝酒的老铁。。。。)

——————————————————————————————————————————————————————————————————————

 项目截图:

项目地址:https://github.com/uustoboy/create-cli

项目目录:

├── bin
│   └── cf.js
├── lib
│   ├── class.js
│   └── templates
├── node_modules
│   
└── package.json

 

第一步 主要靠Commander 命令行框架 和 inquirer 交互命令

cf.js代码:(主要命令的配置)

#!/usr/bin/env node 
'use strict';

const program = require('commander');
const appInfo = require('./../package.json');
const _class = require('../lib/class.js');
const log = console.log;

program
  .version(appInfo.version)
  .usage('创建简单前端项目! [options] <package>')
  .parse(process.argv);

program
    .command('delete')
    .alias('del')
    .description('删除操作')
    .action((cmd,option) => {
        _class(cmd,option);
    })

program
    .command('app [cmd]')
    .alias('a')
    .description('创建app项目文件夹')
    .option('-y, --fast', '快速创建默认目录')
    .action((cmd,option) => {
        _class(cmd,option);
    }).on('--help', function() {

        // 图片文字 http://ascii.mastervb.net/text_to_ascii.php
        
        log("                   ___                __    _   ");
        log("                 .' ..]              [  |  (_)  ");
        log("         .---.  _| |_  ______  .---.  | |  __   ");
        log("        / /'`\]'-| |-'|______|/ /'`\] | | [  |  ");
        log("        | \__.   | |          | \__.  | |  | |  ");
        log("        '.___.' [___]         '.___.'[___][___] ");

        log();
        log('     app 创建app项目文件夹');
        log();
        log('    -y, --fast 快速创建默认目录');
        log();
    });

program
    .command('pc [cmd]')
    .alias('p')
    .description('创建pc项目文件夹')
    .option('-y, --fast', '快速创建默认目录')
    .action((cmd,option) => {
        _class(cmd,option);
    }).on('--help', function() {

        // 图片文字 http://ascii.mastervb.net/text_to_ascii.php

        log("                   ___                __    _   ");
        log("                 .' ..]              [  |  (_)  ");
        log("         .---.  _| |_  ______  .---.  | |  __   ");
        log("        / /'`\]'-| |-'|______|/ /'`\] | | [  |  ");
        log("        | \__.   | |          | \__.  | |  | |  ");
        log("        '.___.' [___]         '.___.'[___][___] ");

        log();
        log('     pc 创建pc项目文件夹');
        log();
        log('    -y, --fast 快速创建默认目录');
        
        log();
    });


//默认不传参数输出help
if (!process.argv[2]) {
    program.help();
}

program.parse(process.argv); 

class.js代码:(主要是处理交互命令执行)

'use strict';

const log = console.log;
const program = require('commander');
const Gitdownload = require('download-git-repo');
const download = require('download');
const path = require('path');
const fs = require('fs');
const inquirer = require('inquirer');
const fse = require('fs-extra');
const del = require('del');
const archiver = require('archiver');
const chalk = require('chalk');
const join = path.join;

module.exports = function(cmd,option) {

  var promps = [];

    let _path = getPath( cmd );

    if( option._name == 'delete' ){

        if( !isFile( _path ) ){
            return log(chalk.yellow(`${cmd}不存在`));
        }

        promps.push({
          type: 'confirm',
          name: 'del',
          message: '是否删除'+cmd
      });

      inquirer.prompt(promps).then(function (answers) {

          if( answers.del ){
               del([ _path ])
           .then( (err)=>{
            //if(err) return log(chalk.red(err));
            log(chalk.green('删除完成!~'));
           }); 
          }
           
      });

    }else if( option._name == 'app' || option._name == 'pc' ){

        if( isFile( _path ) ){
            return log(chalk.yellow(`${cmd}已存在`));
        }

      if( option.fast ){
        var answers = {
           base : false,
           framework : false,
           sass:true
        }
        createInfo( answers,cmd,option);
      }else{
        createFile(cmd,option);
      }

    }

};

//判断文件/文件夹是否存在;
var isFile = ( _path ) => fse.pathExistsSync( _path )?true:false;
var getPath = ( _path ) => path.resolve( process.cwd(),_path );

function createInfo( answers,cmd,option ){
  fse.ensureDir(cmd)
      .then(() => {
        let jsStr = '';
        log(chalk.green(`${cmd}文件夹创建~`));

        fse.ensureDir( join(cmd,'c') ).then(() => {

          if( answers.base ){
            let baseAs = join(__dirname,'..','lib/templates/',option._name,'base.css');
            let baseBs = join(process.cwd(),cmd,'c','base.css');
            
            fse.readFile(baseAs,'utf8').then(data=>{
              
              var data = data;

              

              fs.writeFile(baseBs,data,function(){
                log(chalk.green('base文件创建~'));
              })

            });

            // fse.ensureLinkSync( join(__dirname,'..','lib/templates/',option._name,'base.css'), join(process.cwd(),cmd,'c','base.css') );  
            // log(chalk.green('base文件创建~'));
          }

        });
        
        fse.ensureDir( join(cmd,'j') ).then(() => {
          //加载jquery.js;
          if( answers.framework == 'jquery' ){
            download('http://apps.bdimg.com/libs/jquery/1.8.3/jquery.min.js', path.join(cmd,'j') ).then(() => {
                log(chalk.green('jquery文件创建~'));
            });
            jsStr = '<script src="j/jquery.min.js"></script>';
          }

          //加载zepto.js;
          if( answers.framework == 'zeop' ){
            download('http://apps.bdimg.com/libs/zepto/1.1.4/zepto.min.js', path.join(cmd,'j')).then(() => {
                log(chalk.green('zepto文件创建~'));
            });
            jsStr = '<script src="j/zepto.min.js"></script>';
          }

        });

      fse.ensureDir( join(cmd,'i') );

      if( answers.sass ){
        fse.ensureDir( join(cmd,'s') ).then(() => {
          Gitdownload('uustoboy/base_mixins',join(cmd,'/s/base_mixins'),function(){
            var txt = `@charset "UTF-8";\n@import "./base_mixins/_base_mixins.scss";`;
            fse.outputFileSync( join( process.cwd(),cmd,'/s/index.scss'), txt);
            log(chalk.green('sass文件创建~'));
          });
        });
      }

      let as = join(__dirname,'..','lib/templates/',option._name,'index.html');
      let bs = join(process.cwd(),cmd,'index.html');
      
      fse.readFile(as,'utf8').then(data=>{
        
        var data = data;

        if(answers.base){
          var c = data.replace(/<%getCSS%>/g,'<link rel="stylesheet" href="c/base.css">');
        }else{
          var c = data.replace(/<%getCSS%>/g,'');
        }

        if( answers.framework ){
          var j = c.replace(/<%getJS%>/g,jsStr);
        }else{
          var j = c.replace(/<%getJS%>/g,jsStr);
        }

        fs.writeFile(bs,j,function(){
          log(chalk.green('默认html文件创建~'));
        })

      });

  }); 
}

function createFile(cmd,option){
    var promps = [];

    promps.push({
      type: 'confirm',
      name: 'base',
      message: '创建base.css文件'
    });

    promps.push({
      type: 'list',
      name: 'framework',
      message: '使用框架库',
      choices:[
        {
          name: '不使用框架库',
          value: false
        },
        {
          name: 'jquery.js',
          value: 'jquery'
        },
        {
          name: 'zeop.js',
          value: 'zeop'
        }
      ]
    });

    promps.push({
      type: 'confirm',
      name: 'sass',
      message: '是否使用sass'
    });

    inquirer.prompt(promps).then(function (answers) {
        //log(answers)
        createInfo(answers,cmd,option);
    });

} 

第二步 package.json 配置

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

第三步 添加到全局(如果报错很有可能是你的命令名系统本来有了需要你删除在按)

$ sudo npm install . -g

 

发布模块:

先注册npm账号:(填 用户名、用户密码、邮件)

$ npm adduser

如果注册登录:

$ npm login

发布模块:(第一次发布的时候最好在npm搜搜你package.json里‘name’有木有已经发的要不然发布不了,每一次要发布npm上必须要更改‘version’的版本号)

$ npm publish 

(注意:如果npm源更改成淘宝镜像的要改回npm源,淘宝镜像源发布会报错发布不了,推荐使用 nrm 包查看、切换)

删除模板:

$ npm unpublish --force [name]

全局安装模块:

$ npm install [name] -g

 

参考资料:

极客学院 《使用 Node.js 开发命令行工具》 (视频教学)

阮一峰    :《Node.js 命令行程序开发教程》

小弟调调 :《Nodejs 制作命令行工具》 

自成   :《跟着老司机玩转Node命令行》

 

推荐阅读