nodejs 常用工具库 :)

在一些带有交互的库,如webpack、gulp、create-react-app 、vue-cli 这种带有交互显示的库,或者自己写一个脚手架也可以,通常都会用一些小工具,整理一下


validate-npm-package-name

判断一个包是否是npm的有效包, 注意,只是判断包名字是否合法,不判断是否存在

var validate = require("validate-npm-package-name")
// 如果有效,会返回 
// { validForNewPackages: true, validForOldPackages: true }
chalk

命令行字体带颜色

const chalk = require('chalk');
console.log(chalk.blue('Hello world!'));

ora

命令行加载 loading 转圈

const ora = require('ora');
const spinner = ora({
  text:  `Loading ${chalk.green('unicorns')}`,
  color: 'green'
})

spinner.start();

setTimeout(() => {
  spinner.color = 'yellow';
  spinner.text = 'Load finish';
  spinner.stop();
}, 3333);

cross-env

运行script 兼容各平台 设置环境变量

{
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  }
}

rimraf

rm -rf 的功能

// 同步删除文件夹 
const rm = require("rimraf").sync;
rm("dist")


user-home

获取用户主目录

var userHome = require('user-home');
console.log(userHome);  // D:\Users\david\

tildify

把正常路径转成 ~/

const tildify = require('tildify');
console.log(tildify(userHome+"/dev/huahua"));  // ~\dev\huahua

import-local

让一个全局安装包使用本地版本

const importLocal = require('import-local');
 
if (importLocal(__filename)) {
    console.log('Using local version of this package');
} else {
    // Code for both global and local version here…
}

my-local-ip

获取本机IP

console.log(require('my-local-ip')())
//==> 192.168.1.33

semver

版本控制,如,需要一个库或者工具最低版本,然后提示

const semver = require('semver')
// 比如需要nodejs版本11,本地版本是10,那就肯定不行,
// 很多工具cli都用这个
semver.satisfies('v10.12.0', ''v11.12.0“”) // false 

slash

转换windows斜杠成规范斜杠

const path = require('path');
const slash = require('slash');
 
const string = path.join('foo', 'bar');
// Unix    => foo/bar
// Windows => foo\\bar
 
slash(string);
// Unix    => foo/bar
// Windows => foo/bar

minimatch

简单的正则匹配库

var minimatch = require("minimatch")

minimatch("bar.foo", "*.foo") // true!
minimatch("bar.foo", "*.bar") // false!
minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy!

multimatch

minimatch 的多重版

const multimatch = require('multimatch');

multimatch(['unicorn', 'cake', 'rainbows'], ['*', '!cake']);
//=> ['unicorn', 'rainbows']

minimist

解析命令行参数

const minimist = require('minimist') 
const argv = minimist(process.argv.slice(2));
console.log(argv);
// node aa.js  -a beep -b boop
// 结果 { _: [], a: 'beep', b: 'boop' }


markdown

markdown 转html

var markdown = require( "markdown" ).markdown;
console.log( markdown.toHTML( "Hello *World*!" ) )

needle

简单易用的node http客户端

let needle = require('needle');

// 基本get请求 
needle.get('https://blog.csdn.net/qq_29334605/article/details/105411279', function(error, response) {
  console.log(response);
});
// 操作流
var out = fs.createWriteStream('logo.png');
needle.get('https://google.com/images/logo.png').pipe(out).on('done', function() {
  console.log('Pipe finished!');
});

download-git-repo

下载一个git的项目

const download = require('download-git-repo')
// 如果是github的项目,默认可以写地址,只写用户id和项目名 
download("single-spa/single-spa", "C:\\Users\\starbooks\\Desktop\\spa", function (err) {
if(err) console.log(err)
})


cli-prompt

一个简单的提示工具

let prompt = require('cli-prompt');

prompt('enter your first name: ', function (val) {
  let first = val;
  prompt('and your last name: ', function (val) {
    console.log('hi, ' + first + ' ' + val + '!');
    process.exit(0)
  }, function (err) {
    console.error('unable to read last name: ' + err);
  });
}, function (err) {
  console.error('unable to read first name: ' + err);
});


inquirer

terminal交互工具

const inquirer = require('inquirer');

const promptList = [
  {
    type: 'input',
    message: '设置一个用户名:',
    name: 'name',
    prefix: "vue-cli", // 前缀  默认是问号
    default: "test_user" // 默认值
  },
  {
    type: "password", // 密码为密文输入
    message: "请输入密码:",
    name: "pwd"
  },
  {
    type: 'input',
    message: '请输入手机号:',
    name: 'phone',
    validate: function (val) {
      if (val.match(/\d{11}/g)) { // 校验位数
        return true;
      }
      return "请输入11位数字";
    }
  },
  {
    type: "confirm",
    message: "是否使用监听?",
    name: "watch"
  },
  {
    // 多选 
    type: "checkbox",
    message: "选择颜色:",
    name: "color",
    choices: [
      "red",
      "blur",
      "green",
      "yellow"
    ],
    // pageSize: 2 // 设置行数
  },
  {
    type: 'list',
    message: '请选择一种语言:',
    name: 'lang',
    choices: [
      "C++",
      "Java",
      "Python"
    ],
    filter: function (val) { // 使用filter将回答变为小写
      return val.toLowerCase();
    }
  },
  {
    // rawlist 和 list 一样,但是选项是数字
    type: 'rawlist',
    message: '请选择一种水果:',
    name: 'fruit',
    choices: [
      "Apple",
      "Pear",
      "Banana"
    ]
  },
  {
    type: "editor",
    message: "请输入备注:",
    name: "editor"
  }
];


inquirer.prompt(promptList).then(answers => {
  console.log(answers); // 返回的结果
})
yargs

主要处理命令行参数

 // 1. 基本
 // let argv = require('yargs').argv;
 // hello --name=tom 返回 { name : 'tom'}

 // 2. alias 
 let argv = require('yargs').alias('n','name').argv
 // hello -n tom 返回 { name : 'tom', n: 'tom'}

 
 // 3. 返回不是 - 开头的参数
 console.log(argv._);

 // 4. 默认配置
 let argv = require('yargs')
.option('n',{
    alias:'name',
    default:'huahua',
    type:'string'
}).argv


fs-extra

fs extra添加本机fs模块中不包含的文件系统方法,并向fs方法添加promise支持,它可以是fs的替代品。主要分为两大类 Async 和 Sync方法

// 复制文件 
fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))
  .catch(err => console.error(err))
// 删除目录
fse.remove('/Users/davod/Desktop/kk', err => {
  if (err) return console.error(err)
  console.log('success!')
})

// 确保目录为空。如果目录不为空,则删除目录内容。如果该目录不存在,则创建该目录。目录本身不会被删除
fse.emptyDir('/Users/zhangyuhua583/Desktop/kk', err => {
  if (err) return console.error(err)
  console.log('success!')
})

// 移动文件 
const srcpath = '/tmp/file.txt'
const dstpath = '/tmp/this/path/does/not/exist/file.txt'
fse.move(srcpath, dstpath, err => {
  if (err) return console.error(err)
  console.log('success!')
})


Handlebars

前端模板引擎

 // 默认使用 {{ }} 绑定变量 
var template = Handlebars.compile("Handlebars <b>{{doesWhat}}</b>");
// 编译结果 
console.log(template({ doesWhat: "rocks!" }));
// helpers 可用于实现不属于Handlebar语言本身的功能
Handlebars.registerHelper('upp', function (aString) {
  return aString.toUpperCase()
})
// 这么使用 
var template = Handlebars.compile("Handlebars <b>{{upp doesWhat}}</b>");

// 内置 helper 和 v-if 差不多 
<div class="entry">
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>

// with 绑定一个对象 
{{#with person}}
{{firstname}} {{lastname}}
{{/with}}
consolidate

模板引擎的结合体。包括了常用的jade和ejs。通过配置我们就可以使用多种模板引擎

var cons = require('consolidate');
 
cons.swig('views/page.html', { user: 'tobi' })
  .then(function (html) {
    console.log(html);
  })
  .catch(function (err) {
    throw err;
  });


metalsmith

metalsmith, 一个非常简单,可以插入的static 站点生成器,运行机制,1 读取原目录所有文件 2 调用一系列插件处理文件 3 输出文件到目标路径

const MetalSmith = require('metalsmith');
// 处理md的插件 
const markdown   = require("metalsmith-markdown");
// 一个模板文件包裹你的 {{ contents }} 
// 默认 .njk 文件用 nunjucks引擎 .hbs 用 handlebars引擎
const layouts    = require('metalsmith-layouts');
const {render} = require('consolidate').handlebars;
let async = require('async');

// source("./lib")    修改源码目录 默认 ./src  内容文件可以在头部yaml语法执行layout文件
// destination        修改目标路径 默认 ./build
// MetalSmith 参数必填 工作目录
// clean              生成目标文件时候,是否清除原来的文件,默认true
// metadata(obj)      定义metadata对象 obj 
const app = MetalSmith(__dirname).source("./src").destination("./des").clean(true)

/**
 * @param files 所有文件的对象
 * @param metalsmith 当前metalsmith的实例
 * @param done 执行下个的方法
 */
const getUserData = function (files, app, done) {
  // 此处可使用一些交互工具获取用户输入的信息 此处就写死了
  const data = app.metadata();
  data.name = "starbooks";
  data.url = "https://blog.csdn.net/qq_29334605";
  data.description = "hello world !!";
  done()
}

// 替换占位符
const template = (files, app, done) => {
  let keys = Object.keys(files);
  let metadata = app.metadata();
  async.each(keys, run, done);
  function run(file, done) {
    let str = files[file].contents.toString();
    render(str, metadata, function (err, res) {
      if (err) return done(err);
      files[file].contents = Buffer.from(res);
      done();
    });
  }
}


// use 类似中间件
app.
use(getUserData).
// use(markdown())
// .use(layouts({
//    engine: 'handlebars',    // 指定渲染引擎
//    directory: 'layouts'     // layout 目录,默认就是layouts
//    pattern: "**/*.html"     // 匹配的文件才会被处理 
//  }))
use(template).
build(function (err, files) {
  if (err) throw err;
  console.log("success");
});

yaml-front-matter、gray-matter

一个把YAML(是一种递归缩写,是一个可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言) 转化成 json的包 内部使用gray-matter,更轻量一些

---
name: Derek Worthen
age: 127
contact:
  email: email@domain.com
  address: some location
pets:
  - cat
  - dog
  - bat
match: !!js/regexp /pattern/gim
run: !!js/function function() { }
---
Some Other content

// 上边 --- 和 --- 中间的内容 叫做 frontmatter
// 以上为文件内容

var fs = require('fs');
var yamlFront = require('yaml-front-matter');
 
fs.readFile('./some/file.txt', 'utf8', function(fileContents) {
    console.log(yamlFront.loadFront(fileContents));
});
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345