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後,本身特別想用幾個小黃臉表情:-)! 可是不支持啊啊啊啊!憾最後,初次寫做,有不當或錯誤的地方但願各位見諒,更歡迎你們指出,讓我能改正。另外你們以爲不錯的話,但願能點個贊,謝謝!

相關文章
相關標籤/搜索