npm和package.json那些不為常人所知的小祕密

weixin_33724059發表於2018-10-31

此文已由作者黃鍇授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。


強大的命令功能

如果你沒使用過script,那你可算是從來沒手動編輯過package.json。script作為package.json裡最強大的功能,它賦予你新增指令碼的能力。特別是從npm@2.0.0 之後,你可以用自定義引數執行指令碼。甚至有人宣言,有了npm你可以停止使用Grunt和Gulp了

查詢指令碼

你可以通過輸入npm run檢視所有的命令列表(雖然你也可以直接檢視package.json)

自定義指令碼

例如我們最常用的npm start,npm run dev ……,這些指令碼都是可以使用者自定義的,只用在scripts中寫相應的shell指令碼,可以快速的幫助我們編寫打包,啟動指令碼。

"scripts": {    "build": "webpack --config build.js",    "start": "node index.js",    "test": "tap test/*.js"}

然後你可以通過npm run ...執行 注意,start命令可以不用run,後面會講

同時,執行指令碼的時,npm會臨時自動將目錄的node_modules/.bin加入PATH變數。這意味著,可以使用node_modules中任何指令碼,而無需新增node_modules/.bin字首。比如,當前專案的依賴裡面有 Mocha,只要直接寫mocha test就可以了。

例如執行tap命令,你可以直接寫:

"scripts": {"test": "tap test/\*.js"}

而不是

"scripts": {"test": "node_modules/.bin/tap test/\*.js"}

傳遞引數

如果我們在執行npm run xxx 操作的時候想給裡面的指令碼傳引數可以使用—,如下所示:

 "scripts": {    "test": "mocha test/",    "test:xunit": "npm run test -- --reporter xunit"
  }

這種設定對於組合一些高階配置的命令是非常有用的。

“scripts”: {    "lint": "jshint **.js",    "lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"}

生命週期鉤子

這裡借用很多框架的生命週期鉤子的概念,其實npm也在不同的生命週期 提供了一些鉤子,可以方便你在專案執行的不同時間點進行一些指令碼的編寫。

它的鉤子分為兩類:pre- 和 post- ,前者是在指令碼執行前,後者是在指令碼執行後執行。所有的命令指令碼都可以使用鉤子(包括自定義的指令碼)。

例如:執行npm run build,會按以下順序執行:

npm run prebuild -->  npm run build -->  npm run postbuild

pre指令碼和post指令碼也是出口程式碼敏感(exit-code-sensitive) 的,這意味著如果您的pre指令碼以非零出口程式碼退出,那麼NPM將立即停止,並且不執行後續指令碼。

通常你可以在pre指令碼上執行一些準備工作,在post指令碼上執行一些後續操作。

"clean": "rimraf ./dist && mkdir dist","prebuild": "npm run clean","build": "cross-env NODE_ENV=production webpack"

另外,還有很多額外的生命週期鉤子,可以方便使用,例如husky  和 pre-commit 包提供了有關git的commit的生命週期鉤子。

使用環境變數

根據官網的介紹 ,在"scripts"中編寫的指令碼還可以方便使用一些內建變數,這些內建變數會在Node執行的時候放在process.env下,如果是shell指令碼,就直接使用環境變數$…,  這對你編寫一些指令碼工具特別有用。

package.json

package.json內的所有的配置項都可以通過npm_package_字首拿到,例如

"show": "echo $npm_package_name && echo $npm_package_version"

如果是使用node:

"show": "node ./show.js"
// show.jsconst { log } = console;
log(process.env.npm_package_name);
log(process.env.npm_package_version);

巢狀的屬性也可以通過_代替.進行巢狀顯示:**$npm_package_scripts_start**

configuration

配置引數放在**npm_config_**字首的環境中(你可以通過 npm config set 設定一些配置變數,下面介紹config的時候會介紹)

例如:

一些常用的指令碼配置

這裡引用阮老師的一些配置,可以看到配合一定的外掛,npm可是實現一些很實用的功能

// 刪除目錄"clean": "rimraf dist/*",// 本地搭建一個 HTTP 服務"serve": "http-server -p 9090 dist/",// 開啟瀏覽器"open:dev": "opener http://localhost:9090",// 實時重新整理
 "livereload": "live-reload --port 9091 dist/",// 構建 HTML 檔案"build:html": "jade index.jade > dist/index.html",// 只要 CSS 檔案有變動,就重新執行構建"watch:css": "watch 'npm run build:css' assets/styles/",// 只要 HTML 檔案有變動,就重新執行構建"watch:html": "watch 'npm run build:html' assets/html",// 部署到 Amazon S3"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/",// 構建 favicon"build:favicon": "node scripts/favicon.js",

npx

npm v5.2.0 之後還引入了npx,引入這個命令的目的是為了提升開發者使用包內提供的命令列工具的體驗。(在node_modules中,所有可執行檔案,也就是package中帶bin的,都會放在node_modules/.bin中)

舉例:使用create-react-app建立一個react專案。

老方法:

npm install -g create-react-app   // 實際就是把package.json中的bin命令連線到了/usr/local/bin中create-react-app my-app

npx方式:

npx create-react-app my-app // 執行本`node_modules/.bin`中的對應命令

這條命令會臨時安裝 create-react-app 包,命令完成後create-react-app 會刪掉,不會出現在 global 中。下次再執行,還是會重新臨時安裝。

npx 會幫你執行依賴包裡的二進位制檔案。

舉例來說,之前我們可能會寫這樣的命令:

npm i -D webpack
./node_modules/.bin/webpack -v

如果你對 bash 比較熟,可能會寫成這樣:

npm i -D webpack
**npm bin**/webpack -v

有了 npx,你只需要這樣:

npm i -D webpack
npx webpack -v

也就是說 npx 會自動查詢當前依賴包中的可執行檔案,如果找不到,就會去 PATH 裡找。如果依然找不到,就會幫你安裝!

npx 甚至支援執行遠端倉庫的可執行檔案:

npx github:piuccio/cowsay hello

再比如 npx http-server 可以一句話幫你開啟一個靜態伺服器!(第一次執行會稍微慢一些)

npx http-server

指定node版本來執行npm scripts:

npx -p node@8 npm run build

主要特點:

1、臨時安裝可執行依賴包,不用全域性安裝,不用擔心長期的汙染。 2、可以執行依賴包中的命令,安裝完成自動執行。 3、自動載入node_modules中依賴包,不用指定$PATH。 4、可以指定node版本、命令的版本,解決了不同專案使用不同版本的命令的問題。

內建命令(指令碼)

npm自帶了 數十個內建命令,這些命令都可以直接通過npm執行,除了install,還有很多實用的

與script相關

其中有幾條和我們剛才說過的script十分相關,我們可以通過在scripts中改寫命令執行。

  • start , npm run start的簡寫,如果不在script中配置start,那麼npm start預設執行node server.js

  • test ,npm run test的簡寫,執行自定義test指令碼,沒有預設行為。

  • stop,npm run stop的簡寫

  • restart,npm run stop && npm run restart && npm run start的簡寫

其他實用的命令

我們經常用的是install,但是其實還有很多命令很實用:

  • npm -l  列舉所有npm自帶的命令簡介,然後通過npm help可以詳細檢視某個命令

  • npm search 快速查詢npm中的相關包(和我們去npm官網查是一樣的)

  • npm root 檢視全域性的node_modules目錄

  • npm audit fix 這個命令很實用,自動掃描您的專案漏洞,並自動安裝任何相容更新到脆弱的依賴

  • npm restart 重新啟動模組

  • npm prune 移除當前不在package.json中但是存在node_modules中的依賴

  • npm repo 瀏覽器端開啟專案地址(GitHub), 省去開啟瀏覽器查詢的操作!

  • npm docs 檢視專案文件,同上

  • npm home 在瀏覽器端檢視專案(專案主頁),同上

  • npm search 查詢包含該字串的依賴包

  • npm view[field][--json]列出依賴資訊,包括歷史版本,可以指定field來檢視某個具體資訊,比如(versions) 可以新增–json引數輸出全部結果

亂七八糟的版本號

我相信只要開啟package.json,第一眼就會被裡面一堆亂七八糟的數字給晃得暈頭轉向,隨便給你晃一眼:

  { "foo" : "1.0.0 - 2.9999.9999"
  , "bar" : ">=1.0.2 <2.1.2"
  , "baz" : ">1.0.2 <=2.3.4"
  , "boo" : "^2.0.1"
  , "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
  , "lal" : "git://……"
  , "asd" : "http://asdf.com/asdf.tar.gz"
  , "til" : "~1.2"
  , "abc" : "haha/abc"
  , "elf" : "~1.2.3"
  , "two" : "2.x"
  , "thr" : "3.3.x"
  ……  }

光是看到數字就已經暈了,還有~,<>,^這麼多符號。npm官網推薦使用語義化的版本好,一般按如下規則:

首先版本按照大版本.次要版本.小版本,一般來說初始版本是1.0.0:

  • 小版本:修改bug或其他小的改動

  • 次要版本:增加了新的特性不改變已有特性

  • 大版本:大的變動,可能影響了向後的相容性

版本匹配

  • 指定版本:比如1.2.2,安裝時只安裝指定版本。

  • ~次要版本不變:比如~1.2.2,表示安裝1.2.x的最新版本(不低於1.2.2),但是不安裝1.3.x,也就是說安裝時不改變大版本號和次要版本號。

  • ^大版本不變:比如ˆ1.2.2,表示安裝1.x.x的最新版本(不低於1.2.2),但是不安裝2.x.x,也就是說安裝時不改變大版本號。需要注意的是,如果大版本號為0,則插入號的行為與波浪號相同,這是因為此時處於開發階段,即使是次要版本號變動,也可能帶來程式的不相容。

  • latest:安裝最新版本。

node-semver

如果你需要在程式中做版本匹配,手寫是不是很麻煩(我之前還真的自己用正則寫了一個,超麻煩)其實npm提供了一個現成的匹配版本號的工具: https://github.com/npm/node-semver#functions

指定專案執行環境

很多時候,我們的專案只能在特定的環境下執行,在其他環境下可能會報錯,因此我們需要在package.json中限制使用者執行專案的環境:

engines指明瞭該專案所需要的node.js版本

"engines": {"node" : ">= 4.0.0","npm": ">= 3.0.0"}

os指定了使用者執行的作業系統:

"os": [ "darwin", "linux", "!win32" ],

cpu可以指定包執行的cpu架構

  "cpu": [ "x64", "!arm" ]

config

之前我們說過npm有個配置檔案,裡面的變數可以通過$npmconfig拿到,而這個配置檔案通常在:

  • 專案config file (/path/to/my/project/.npmrc) : 通常要自己建立

  • 使用者config file (~/.npmrc)

  • 全域性config file ($PREFIX/etc/npmrc)

  • npm內建config file (/path/to/npm/npmrc)

通過以下命令可以檢視config資訊:

npm config ls/list

npm有很多預設配置,可以通過以下命令檢視,可以去官網檢視這些命令的詳細資訊

npm config ls -l

通過以下命令可以修改配置

npm config set key valuenpm set key valuenpm config get keynpm get key

當然,也可以通過$npm_config_key = 來修改,或者在node中通過**process.env.npm_config_key = 來修改,

陣列值是通過在鍵名後面新增“[]”來指定的。例如:

key[] = "first value"key[] = "second value"

安裝非NPM上釋出的包

通常,我們安裝的包都是在npm官網上,通過版本標明。但是,如果我想使用沒上傳到npm上的包怎麼辦?其實你可以直接加網址或git地址。官網明確了以下型別的包都是可以的:

a) 包含一個由package.json檔案描述的程式的資料夾。

b) 包含(a)的gzipped tarball 。

c)解析為(b)的URL。

d) \@\ : 在registry上釋出的(c)

e)\@\ : 能指向(d)。

f)\:  具有latest標籤,且滿足(e)。

g)git url,當clone時,得到(a)。

只要滿足以上條件,你的包不用釋出到npm上都能使用。其中,git url可以是以下形式:

git://github.com/user/project.git#commit-ishgit+ssh://user@hostname:project.git#commit-ishgit+http://user@hostname/project/blah.git#commit-ishgit+https://user@hostname/project/blah.git#commit-ish

其中,commit-ish 可以是任意的tag,branch,sha。

dependencies & devDependencies & peerDependencies

眾所周知,package.json裡有一堆dpendencies欄位,他們像親兄弟一樣,總是結伴同行。很多人容易弄混他們到底是什麼關係。

由於這裡面內容挺多的,會整理在另一篇文章中,後續這裡會放上鍊接

更新包

我們知道npm自帶的npm update可以根據pacaage.json的版本號更新包,但是你需要手動的更新版本號,因此出現了升級外掛npm-check-updates,可以自動搜尋當前包的更新情況,並且修改pacage.json

安裝npm-check-updates

$ npm install -g npm-check-updates

ncu命令

ncu是npm-check-updates的縮寫命令

$ ncu  -v  #查詢版本號
$ ncu    #直接輸入ncu可以檢視所有需要更新的包

$ ncu -u  # 更新所有的包,並修改package.json檔案

$ ncu -f regex # 只匹配特定的正則格式的包
$ ncu -g # 更新全域性包

參考文件:

https://docs.npmjs.com/misc/scripts

https://docs.npmjs.com/cli/run-script

https://docs.npmjs.com/files/package.json

https://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies

http://javascript.ruanyifeng.com/nodejs/packagejson.html#toc1

https://www.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/


免費體驗雲安全(易盾)內容安全、驗證碼等服務

更多網易技術、產品、運營經驗分享請點選




相關文章:
【推薦】 論使用者體驗測試:牛逼的功能千篇一律,好的使用者體驗萬里挑一
【推薦】 分散式儲存系統可靠性系列五:副本放置演算法&CopySetReplication

相關文章