什么是 NPM
npm
之於 Node
,就像 pip
之於 Python
, gem
之於 Ruby
, pear
之於 PHP
。
npm
是 Node
官方提供的包管理工具,他已經成了 Node
包的標准發布平台,用於 Node
包的發布、傳播、依賴控制。npm
提供了命令行工具,使你可以方便地下載、安裝、升級、刪除包,也可以讓你作為開發者發布並維護包。
為什么要使用 NPM
npm
是隨同 Node
一起安裝的包管理工具,能解決 Node
代碼部署上的很多問題,常見的場景有以下幾種:
- 允許用戶從
npm
服務器下載別人編寫的第三方包到本地使用。 - 允許用戶從
npm
服務器下載並安裝別人編寫的命令行程序到本地使用。 - 允許用戶將自己編寫的包或命令行程序上傳到
npm
服務器供別人使用。
npm
的背后,是基於 CouchDB
的一個數據庫,詳細記錄了每個包的信息,包括作者、版本、依賴、授權信息等。它的一個很重要的作用就是:將開發者從繁瑣的包管理工作(版本、依賴等)中解放出來,更加專注於功能的開發。
如何使用 NPM
# 查看 npm 命令列表 $ npm help # 查看各個命令的簡單用法 $ npm -l # 查看 npm 的版本 $ npm -v # 查看 npm 的配置 $ npm config list -l
npm install
安裝本地包
npm install <package_name>:這個命令將在當前目錄中創建node_modules目錄(如果尚不存在),並將該軟件包下載到該目錄。該命令默認本地安裝。
安裝了哪個版本的軟件包?
如果本地目錄中沒有package.json文件,則會安裝最新版本的軟件包。
如果有package.json文件,則安裝滿足該package(如果有的話)在package.json中聲明的semver規則的最新版本。
安裝全局包
npm install -g <package>:全局安裝包。
npm init
npm init:這個命令用於創建一個package.json。
npm init --yes或npm init -y:從當前目錄中提取的信息生成默認的package.json。創建過程中不會提問。
如果您的目錄中已經有一個package.json文件,並且運行了npm install,那么npm將查看該文件中的dependencies,並下載滿足所有這些的最新版本。
package.json文件中的description幫助人們在npm搜索中找到您的包,所以在package.json中進行自定義描述非常有用。
也可以完全自定義package.json文件的內容和在init期間提出的問題。這通過創建自定義.npm-init.js來完成。默認情況下,npm將查找您的主目錄。 〜/ .npm-init.js
dependencies與devDependencies
dependencies和devDependencies指定了項目依賴的包。
dependencies:這些包在生產中需要。
devDependencies:這些包用於開發和測試。
npm install <package_name> --save命令會添加條目到package.json的dependencies中。
npm install <package_name> --save-dev命令會添加條目到package.json的devDependencies中。
npm update
更新本地軟件包npm update:用於更新依賴的軟件包。需要在package.json文件所在的目錄中運行該命令。
更新全局軟件包
npm update -g <package>:更新全局軟件包。
npm update -g:更新所有的全局軟件包。
npm outdated -g --depth=0:找出需要更新的包。
npm uninstall
卸載本地軟件包
npm uninstall <package>:從node_modules目錄中移除一個包。
npm uninstall --save <package>:從package.json的dependencies中移除一個包。
npm uninstall --save-dev <package>:從package.json的devDependencies中移除一個包。
實際操作時,發現使用npm uninstall <package>不僅會在node_modules目錄下刪除該包,還會將該包在package.json中dependencies或devDependencies里面的信息刪除。
卸載全局軟件包
npm uninstall -g <package>:卸載全局軟件包。
npm run
npm
不僅可以用於模塊管理,還可以用於執行腳本。package.json
文件有一個 scripts
字段,可以用於指定腳本命令,供 npm
直接調用。package.json
文件內容:
{ "name": "myproject", "devDependencies": { "jshint": "latest", "browserify": "latest", "mocha": "latest" }, "scripts": { "lint": "jshint **.js", "test": "mocha test/" } }
scripts:
顧名思義,就是一些腳本代碼,可以通過 npm run script-key
來調用,例如在這個 package.json
的文件夾下使用 npm run dev
就相當於運行了 node build/dev-server.js
這一段代碼。
使用 scripts
的目的就是為了把一些要執行的代碼合並到一起,使用 npm run 來快速的運行,方便省事。
npm run
是 npm run-script
的縮寫,一般都使用前者,但是后者可以更好的反應這個命令的本質。
// 腳本 "scripts": { "dev": "node build/dev-server.js", "build": "node build/build.js", "docs": "node build/docs.js", "build-docs": "npm run docs & git checkout gh-pages & xcopy /sy dist\\* . & git add . & git commit -m 'auto-pages' & git push & git checkout master", "build-publish": "rmdir /S /Q lib & npm run build &git add . & git commit -m auto-build & npm version patch & npm publish & git push", "lint": "eslint --ext .js,.vue src" }
npm run
如果不加任何參數,直接運行,會列出 package.json
里面所有可以執行的腳本命令。npm
內置了兩個命令簡寫, npm test
等同於執行 npm run test
,npm start
等同於執行 npm run start
。
"build": "npm run build-js && npm run build-css"
上面的寫法是先運行 npm run build-js
,然后再運行 npm run build-css
,兩個命令中間用 &&
連接。如果希望兩個命令同時平行執行,它們中間可以用 &
連接。
寫在 scripts
屬性中的命令,也可以在 node_modules/.bin
目錄中直接寫成 bash
腳本。下面是一個 bash
腳本。
#!/bin/bash cd site/main browserify browser/main.js | uglifyjs -mc > static/bundle.js
假定上面的腳本文件名為 build.sh
,並且權限為可執行,就可以在 scripts
屬性中引用該文件。
"build-js": "bin/build.sh"
pre- 和 post- 腳本
npm run 為每條命令提供了 pre- 和 post- 兩個鈎子( hook )。
以 npm run lint 為例,執行這條命令之前, npm 會先查看有沒有定義 prelint 和 postlint 兩個鈎子,
如果有的話,就會先執行 npm run prelint ,然后執行 npm run lint ,最后執行 npm run postlint 。
{ "name": "myproject", "devDependencies": { "eslint": "latest" "karma": "latest" }, "scripts": { "lint": "eslint --cache --ext .js --ext .jsx src", "test": "karma start --log-leve=error karma.config.js --single-run=true", "pretest": "npm run lint", "posttest": "echo 'Finished running tests'" } }
上面代碼是一個 package.json 文件的例子。如果執行 npm test,會按下面的順序執行相應的命令。
pretest
test
posttest
如果執行過程出錯,就不會執行排在后面的腳本,即如果 prelint 腳本執行出錯,就不會接着執行 lint 和 postlint 腳本。
總結:本地命令加上-g就是全局命令。
創建全局鏈接
npm 提供了一個有趣的命令 npm link,它的功能是在本地包和全局包之間創建符號鏈接。我們說過使用全局模式安裝的包不能直接通過 require 使用。但通過 npm link 命令可以打破這一限制。
舉個例子,我們已經通過 npm install -g express 安裝了 express ,這時在工程的目錄下運行命令:npm link express ./node_modules/express -> /user/local/lib/node_modules/express 我們可以在 node_modules 子目錄中發現一個指向安裝到全局的包的符號鏈接。通過這種方法,我們就可以把全局包當做本地包來使用了。 除了將全局的包鏈接到本地以外,使用 npm link 命令還可以將本地的包鏈接到全局。
使用方法是在包目錄(package.json 所在目錄)中運行 npm link 命令。
如果我們要開發一個包,利用這種方法可以非常方便地在不同的工程間進行測試。
創建包
包是在模塊基礎上更深一步的抽象,Node 的包類似於 C/C++ 的函數庫或者 Java 、.Net 的類庫。它將某個獨立的功能封裝起來,用於發布、更新、依賴管理和版本控制。Node 根據 CommonJS 規范實現了包機制,開發了 npm 來解決包的發布和獲取需求。
Node 的包是一個目錄,其中包含了一個 JSON 格式的包說明文件 package.json。嚴格符合 CommonJS 規范的包應該具備以下特征:
package.json 必須在包的頂層目錄下;
二進制文件應該在 bin 目錄下;
JavaScript 代碼應該在 lib 目錄下;
文檔應該在 doc 目錄下;
單元測試應該在 test 目錄下。
Node 對包的要求並沒有這么嚴格,只要頂層目錄下有 package.json,並符合一些規范即可。當然為了提高兼容性,我們還是建議你在制作包的時候,嚴格遵守 CommonJS 規范。
我們也可以把文件夾封裝為一個模塊,即所謂的包。包通常是一些模塊的集合,在模塊的基礎上提供了更高層的抽象,相當於提供了一些固定接口的函數庫。通過定制 package.json,我們可以創建更復雜,更完善,更符合規范的包用於發布。
Node 在調用某個包時,會首先檢查包中 packgage.json 文件的 main 字段,將其作為包的接口模塊,如果 package.json 或 main 字段不存在,會嘗試尋找 index.js 或 index.node 作為包的接口。
package.json 是 CommonJS 規定的用來描述包的文件,完全符合規范的 package.json 文件應該含有以下字段:
name: 包的名字,必須是唯一的,由小寫英文字母、數字和下划線組成,不能包含空格。
description: 包的簡要說明。
version: 符合語義化版本識別規范的版本字符串。
keywords: 關鍵字數組,通常用於搜索。
maintainers: 維護者數組,每個元素要包含 name 、 email(可選)、 web(可選)字段。
contributors: 貢獻者數組,格式與 maintainers 相同。包的作者應該是貢獻者數組的第一個元素。
bugs: 提交 bug 的地址,可以是網址或者電子郵件地址。
licenses: 許可證數組,每個元素要包含 type (許可證的名稱)和 url(鏈接到許可證文本的地址)字段。
repositories: 倉庫托管地址數組,每個元素要包含 type (倉庫的類型,如 git)、URL(倉庫的地址)和 path(相對於倉庫的路徑,可選)字段。
dependencies: 包的依賴,一個關聯數組,由包名稱和版本號組成。
https://segmentfault.com/p/1210000009653830/read