npm模块管理进阶 — npm-check + cnpm 构建包更新环境

前言

近期在项目中准备更新一下npm依赖包,可一尝试,惊了!批量更新还真麻烦。各类包要挨个更新,就算直接更改package.json也挺费事。
因而度娘到了npm-check,而后琢磨了一下,结合cnpm构建了一个本人很满意的包更新环境。遂决定写一篇博文,分享给你们。
阅读本文须要必定node,npm,webpack基础(不高,挺低 <( ̄ˇ ̄)/)
本文为我我的理解,一家之言,若有不当或错误的地方欢迎你们指正,谢谢!
博文地址:npm模块管理进阶 — npm-check + cnpm 构建包更新环境node

1. npm-check

npm 是node下的包管理工具,给咱们提供了强大的包管理功能,简化了项目的代码部署过程。可是,npm也不是尽善尽美,批量更新时便很捉急。
npm-check便应运而生。
npm-check是一个npm包更新工具。它还能够检查项目的npm依赖包是否有更新,缺失,错误以及未使用等状况。其 几大主要优点以下:webpack

1.提供图形化界面,还有emoji,点个赞(不用对着黑白界面简直良心啊!我也想用emoji写啊!:-))
2.批量更新依赖包,还兼职检测包使用状况
3.项目下更新支持自动检测包的 "dependencies" 和"devDependencies"并更新"package.json"信息   !

npm-check

1.1 npm-check安装

> npm install -g npm-check //全局安装。项目下安装可自行选择
> npm install npm-check    //项目下安装,项目根目录执行

1.2 npm-check项目依赖包更新

(1)查看包更新信息,会有小黄脸提示你包的相关状况(需更新,缺失,错误以及未使用等)(表情包大牛。。。)git

> npm-check

npm-check-2

(2)更新包。分类别展现,使用空格选择包,而后enter开始更新。自动更新package.json内的相关包信息es6

> npm-check -u //-update

npm-check-3

基础就是这样,下面是npm-check指令列表:github

-u, --update       显示一个交互式UI,用于选择要更新的模块,并自动更新"package.json"内包版本号信息
-g, --global       检查全局下的包
-s, --skip-unused  忽略对未使用包的更新检查
-p, --production   忽略对"devDependencies"下的包的检查
-d, --dev-only     忽略对"dependencies"下的包的检查
-i, --ignore       忽略对指定包的检查.
-E, --save-exact   将确切的包版本存至"package.json"(注意,此命令将存储'x.y.z'而不是'^x.y.z')

1.3 npm-check的问题

npm-check更新包时是根据版本号动态生成更新语句并执行。其本质是仍然npm install指令:web

npm-check-4

因此,问题不是npm install,而是国内的问题。介于网络等因素,国内用户更倾向于使用cnpm,cnpm也比较稳定和快速。
下面就介绍如何使用让npm-check使用cnpm执行更新。shell

3.npm-check + cnpm

cnpm 是阿里提供的一个完整 npmjs.org 镜像,便于国内用户使用npm。这里就不过多赘述了。
准备:安装好cnpm,npm-check
本文将介绍两种方法将cnpm加入npm-check,以及其原理,具体以下。npm


3.1 两种方法简述

1. 源码修改法json

(1) 找到npm-check包下的"npm-check\lib\""npm-check\lib-es5\"下的cli.js文件。
(2) 对文件内代码"options"的属性"installer"进行修改:babel

installer: process.env.NPM_CHECK_INSTALLER || 'npm'  //改前
installer: process.env.NPM_CHECK_INSTALLER || 'cnpm' //改后

2.修改环境变量值
NPM_CHECK_INSTALLER设为cnpm。后文将介绍三种修改方法,效果有些差异。

3.2 两种方法原理

1. 源码修改法

npm-check目录结构以下。一眼就看见"./lib""./lib-es5"目录结构彻底相同,是有什么缘由吗?没错,后面看了各位就明白了。
npm-check-5

首先最基础的,咱们先来看npm-check"package.json"。(里面"dependencies"等有些属性与本文无关,我删除了其内容,以避免代码过长)

{
  "name": "npm-check",
  "version": "5.4.5",
  "description": "Check for outdated, incorrect, and unused dependencies.",
  "main": "lib",
  "bin": {
    "npm-check": "bin/cli.js"
  },
  "engines": {
    "node": ">=0.11.0"
  },
  "types": "./index.d.ts",
  "typings": "./index.d.ts",
  "scripts": {
    "lint": "xo ./lib/*.js",
    "test": "npm run lint && ./bin/cli.js || echo Exit Status: $?.",
    "transpile": "babel lib --out-dir lib-es5",
    "watch": "babel lib --out-dir lib-es5 --watch",
    "prepublish": "npm run transpile"
  },
  "xo": {
    "space": 4,
    "rules": {
      "no-warning-comments": [
        0
      ],
      "global-require": [
        0
      ]
    }
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/dylang/npm-check.git"
  },
  "keywords": [],
  "author": {
    "name": "Dylan Greene",
    "email": "dylang@gmail.com"
  },
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/dylang/npm-check/issues"
  },
  "homepage": "https://github.com/dylang/npm-check",
  "files": [
    "bin",
    "lib",
    "lib-es5"
  ],
  "dependencies": {},
  "devDependencies": {},
  "_from": "npm-check@5.4.5",
  "_resolved": "http://registry.npm.taobao.org/npm-check/download/npm-check-5.4.5.tgz"
}

能够看到"bin"属性值为{"npm-check": "bin/cli.js"},其做用是将"bin/cli.js"连接到"npm-check"
当在命令行执行"npm-check",便会执行"bin/cli.js"。接着咱们看看"bin/cli.js"到底有什么玄机。
在查看以前,你可能会以为里面是一大串代码,看着就头晕,然而事实是,里面只有9行:

#!/usr/bin/env node

var isEs2015;
try {
    isEs2015 = new Function('() => {}');
} catch (e) {
    isEs2015 = false;
}
isEs2015 ? require('../lib/cli') : require('../lib-es5/cli');

代码的意思很明显,判断js环境是否支持es6(Es2015)。

isEs2015 = new Function('() => {}');

经过es6的箭头函数判断js环境,支持则isEs2015true,导入'../lib/cli',不然导入'../lib-es5/cli'
因此上文提到的"./lib""./lib-es5"目录结构彻底相同也就明白了,由于他们分别是es6es5npm-check的实现。
接下来咱们就分析"./lib/cli,js"的源码,毕竟es6是趋势嘛,"./lib-es5/cli.js"殊途同归。
"./lib/cli,js":

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

const meow = require('meow');
const updateNotifier = require('update-notifier');
const isCI = require('is-ci');
const createCallsiteRecord = require('callsite-record');
const pkg = require('../package.json');
const npmCheck = require('./index');
const staticOutput = require('./out/static-output');
const interactiveUpdate = require('./out/interactive-update');
const debug = require('./state/debug');
const pkgDir = require('pkg-dir');

updateNotifier({pkg}).notify();

const cli = meow({...});           //"npm-check -u,-g等指令的相关设计"

const options = {
    cwd: cli.input[0] || cli.flags.dir,
    update: cli.flags.update,
    global: cli.flags.global,
    skipUnused: cli.flags.skipUnused,
    ignoreDev: cli.flags.production,
    devOnly: cli.flags.devOnly,
    saveExact: cli.flags.saveExact,
    specials: cli.flags.specials,
    emoji: cli.flags.emoji,
    installer: process.env.NPM_CHECK_INSTALLER || 'npm',
    debug: cli.flags.debug,
    spinner: cli.flags.spinner,
    ignore: cli.flags.ignore
};

if (options.debug) {...}         //"是否显示调试输出"

npmCheck(options)                //"根据options的数据运行npm-check"
    .then(currentState => {...})
    .catch(err => {...});

具体代码过长,我以...代替了,我将对里面里面函数的理解注释在了后面,以做参考。
下面就是最重要的"options"对象:

const options = {
    cwd: cli.input[0] || cli.flags.dir,
    update: cli.flags.update,
    global: cli.flags.global,
    skipUnused: cli.flags.skipUnused,
    ignoreDev: cli.flags.production,
    devOnly: cli.flags.devOnly,
    saveExact: cli.flags.saveExact,
    specials: cli.flags.specials,
    emoji: cli.flags.emoji,
    installer: process.env.NPM_CHECK_INSTALLER || 'npm',
    debug: cli.flags.debug,
    spinner: cli.flags.spinner,
    ignore: cli.flags.ignore
};

里面定义的是 npm-check 运行时的一些默认配置。再看 "installer" 属性:

installer: process.env.NPM_CHECK_INSTALLER || 'npm'

这个值定义了 npm-check 在更新包时所使用的包管理工具:process.env.NPM_CHECK_INSTALLER 或者npm
process.env.NPM_CHECK_INSTALLER 是环境变量,与第二种方法有关,这里先不作介绍。
由于因此process.env.NPM_CHECK_INSTALLER通常未定义,因此将取第二个值npm。将其改成cnpm便可使用cnpm install("./lib-es5"同上)

npm-check-6

再说一些:我在实际源码分析时还挺麻烦的,上面是为你们作介绍,比较简单。在这里简述一下我我的阅读源码以后的理解,供你们参考:

  1. 首先"./lib/out/install-packages.js"中定义了install()函数,负责npm-check进行包更新信息分析并输出更新语句的功能,而后导出install()函数。
  2. "./lib/out/interactive-updates.js"引入install()并加上对图形化界面的实现后导出。
  3. 最后"./lib/cli.js"引入并结合options实现完整包更新的功能。

2. 修改环境变量

修改源码的方法毕竟不太好,修改环境变量则相对更优。
回到前面,"./lib/cli,js"里:

installer: process.env.NPM_CHECK_INSTALLER || 'npm'

要操做的就是 process.env.NPM_CHECK_INSTALLER

> 'process' : Node 的一个全局对象,提供当前 Node 进程的信息。
> 'process.env' : 存储着"当前Shell"的环境变量。
一般的作法是,新建一个环境变量"NODE_ENV",用它肯定当前所处的开发阶段;
生产阶段设为production,开发阶段设为develop或staging;
而后在脚本中读取process.env.NODE_ENV判断开发状况。

process.env.NPM_CHECK_INSTALLER就是NPM_CHECK_INSTALLER变量。
由于这是一个自定义变量,因此缺省环境是不存在这个值的,修改源码法才能成功。当定义了这个变量,installer的第二个参数便失效了。(固然,||规则,若NPM_CHECK_INSTALLEfalse结果的值,第二个参数仍会生效)

2.1 node变量设置法

> set NPM_CHECK_INSTALLER=cnpm //win端,cnpm不要加引号,否则是string值,是错误的

npm-check-7

进入node查看,设置成功。以后执行npm-check更新时使用的即是cnpm

npm-check-8

注意:此设置方法下环境变量的生命周期为当前shell。关闭终端或者用另外一个shell等都读取不到此设置,环境不一样!

2.2 项目"package.json"配置

此方法针对具体项目进行配置,在一个项目里进行一次配置便可。另外你们也能够自行进行优化。
"package.json"中的"scripts"对象能够自定义脚本命令。其键是运行的事件名,值是要运行的命令,经过 npm run ***运行。将"scripts"增长新属性"nc-u"以下:

"scripts": {
    "start": "webpack-dev-server",
    "nc-u":"set NPM_CHECK_INSTALLER=cnpm&& npm-check -u"
  }

使用npm run nc-u便可一步执行。有几点须要注意:
1."nc-u"天然是本身命名,合乎规范的均可以;
2."set NPM_CHECK_INSTALLER=cnpm&& npm-check -u"也很明了。先执行set NPM_CHECK_INSTALLER=cnpm,再执行npm-check -u
3.注意NPM_CHECK_INSTALLER=cnpm&&&&需紧跟cnpm,如&&前有空格,则空格也会赋值给NPM_CHECK_INSTALLER,执行到更新包时会出错。
4.脚本命令中环境变量值的生命周期在命令执行期间。此命令执行完,NPM_CHECK_INSTALLER便会被回收,还原为undefined,不污染全局。

2.3 项目"package.json"配置进阶 — 使用cross-env

上面2.2配置中使用&&,set等是由于window环境须要,若是转为Mac那便会出错了,不一样平台还有诸多细节不一样。怎样才能跨平台使用呢?这时候咱们就可使用cross-env
cross-env是一个解决跨平台设置"scripts"的工具,使用以后便不用考虑平台问题了。基本大部分项目都默认添加了cross-env

> npm install --save-dev cross-env //本地安装,写入依赖
//package.json

"scripts": {
    "start": "webpack-dev-server",
    "nc-u":"cross-env NPM_CHECK_INSTALLER=cnpm npm-check -u"
  },
  "devDependencies": {
    "cross-env": "^5.0.5"
  }

在句首加上cross-env便可,执行时cross-env会对指令进行处理。
注意:
使用cross-env时使用&&会改变先后语句环境,即每一语句段都有本身的环境,即环境变量设置会失效。慎用&&

4.总结

本文首先简单介绍了npm-check及其用法,而后介绍了如何结合cnpm进行cnpm install以及方法的原理。
至此,结合了npm-check模块更新工具和cnpm国内镜像,在模块更新的操做和速度上都已得到提高,模块更新环境搭建完毕!

5.后记

断断续续写了也快一天了,写完以后校对,一会儿都快1点钟了,感受还在早上刚开始写的时候同样。总算是写完了这篇博文。
其实这是我第一篇正式意义上的博文,莫名地感受有种莫名的感受,写完以后还有点不舍..W( ̄_ ̄)W,但总归是完成了本身的写做,仍是很开心的!
初次写做,还有许多遗憾的地方未能作好,甚是惋惜。特别是看了npm-check后,本身特别想用几个小黄脸表情:-)! 可是不支持啊啊啊啊!憾最后,初次写做,有不当或错误的地方但愿各位见谅,更欢迎你们指出,让我能改正。另外你们以为不错的话,但愿能点个赞,谢谢!

相关文章
相关标签/搜索