NPM 學習筆記整理
NPM 學習筆記整理
什麽是 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
不需要單獨安裝。在安裝 Node
的時候,會連帶一起安裝 npm
。但是,Node
附帶的 npm
可能不是最新版本,最後用下面的命令,更新到最新版本。
1 |
$ sudo npm install npm@latest -g |
如果是 Window 系統使用以下命令即可:
1 | npm install npm -g |
也就是使用 npm
安裝自己。之所以可以這樣,是因為 npm
本身與 Node
的其他模塊沒有區別。
然後,運行下面的命令,查看各種信息。
1 2 3 4 5 6 7 8 9 10 11 |
使用
npm init
npm init
用來初始化生成一個新的 package.json
文件。它會向用戶提問一系列問題,如果你覺得不用修改默認配置,一路回車就可以了。
如果使用了 -f
(代表force
)、-y
(代表yes
),則跳過提問階段,直接生成一個新的 package.json
文件。
1 | $ npm init -y |
npm set
npm set
用來設置環境變量
1 2 3 4 | $ npm set init-author-name ‘Your name‘ $ npm set init-author-email ‘Your email‘ $ npm set init-author-url ‘http://yourdomain.com‘ $ npm set init-license ‘MIT‘ |
上面命令等於為 npm init
設置了默認值,以後執行 npm init
的時候,package.json
的作者姓名、郵件、主頁、許可證字段就會自動寫入預設的值。這些信息會存放在用戶主目錄的 ~/.npmrc
文件,使得用戶不用每個項目都輸入。如果某個項目有不同的設置,可以針對該項目運行 npm config
。
npm info
npm info
命令可以查看每個模塊的具體信息。比如,查看 underscore
模塊的信息。
1 | $ npm |
上面命令返回一個 JavaScript
對象,包含了 underscore
模塊的詳細信息。這個對象的每個成員,都可以直接從 info
命令查詢。
1 2 3 4 5 | $ npm | $ npm $ npm
npm search
npm search
命令用於搜索 npm
倉庫,它後面可以跟字符串,也可以跟正則表達式。
1 | $ npm search <搜索詞> |
npm list
npm list
命令以樹形結構列出當前項目安裝的所有模塊,以及它們依賴的模塊。
1 2 3 4 5 6 7 | $ npm list # 加上 global 參數,會列出全局安裝的模塊 $ npm list -global # npm list 命令也可以列出單個模塊 $ npm list underscore |
npm install
使用 npm
安裝包的命令格式為:npm [install/i] [package_name]
本地模式和全局模式
npm
在默認情況下會從 NPM 搜索或下載包,將包安裝到當前目錄的 node_modules
子目錄下。
如果你熟悉 Ruby
的 gem
或者 Python
的 pip
,你會發現 npm
與它們的行為不同, gem
或 pip
總是以全局模式安裝,使包可以供所有的程序使用,而 npm
默認會把包安裝到當前目錄下。這反映了 npm
不同的設計哲學。如果把包安裝到全局,可以提供程序的重復利用程度,避免同樣的內容的多分副本,但壞處是難以處理不同的版本依賴。如果把包安裝到當前目錄,或者說本地,則不會有不同程序依賴不同版本的包的沖突問題,同時還減輕了包作者的 API
兼容性壓力,但缺陷則是同一個包可能會被安裝許多次。
我們在使用 supervisor
的時候使用了 npm install -g supervisor
命令,就是以全局模式安裝 supervisor
。
這裏註意一點的就是, supervisor
必須安裝到全局,如果你不安裝到全局,錯誤命令會提示你安裝到全局。如果不想安裝到默認的全局,也可以自己修改全局路徑到當前路徑 npm config set prefix "路徑"
安裝完以後就可以用 supervisor
來啟動服務了。supervisor
可以幫助你實現這個功能,它會監視你對代碼的驅動,並自動重啟 Node
。
一般來說,全局安裝只適用於工具模塊,比如 eslint
和 gulp
。關於使用全局模式,多數時候並不是因為許多程序都有可能用到了它,為了減少多重副本而使用全局模式,而是因為 本地模式不會註冊 PATH
環境變量。
“本地安裝”指的是將一個模塊下載到當前項目的 node_modules
子目錄,然後只有在項目目錄之中,才能調用這個模塊。
本地模式和全局模式的特點如下:
模式 | 可通過 require 使用 | 註冊 PATH |
---|---|---|
本地模式 | 是 | 否 |
全局模式 | 否 | 是 |
1 2 3 4 5 6 | # 本地安裝 $ npm install <package name> # 全局安裝 $ sudo npm install -global <package name> $ sudo npm install -g <package name> |
npm install
也支持直接輸入 Github
代碼庫地址。
1 2 | $ npm install git://github.com/package/path.git $ npm install git://github.com/package/path.git#0.1.0 |
安裝之前,npm install
會先檢查,node_modules
目錄之中是否已經存在指定模塊。如果存在,就不再重新安裝了,即使遠程倉庫已經有了一個新版本,也是如此。
如果你希望,一個模塊不管是否安裝過, npm
都要強制重新安裝,可以使用 -f
或 --force
參數。
1 | $ npm install <packageName> --force |
安裝不同版本
install
命令總是安裝模塊的最新版本,如果要安裝模塊的特定版本,可以在模塊名後面加上 @
和版本號。
1 2 3 | $ npm install sax@latest $ npm install sax@0.1.1 $ npm install sax@">=0.1.0 <0.2.0" |
install
命令可以使用不同參數,指定所安裝的模塊屬於哪一種性質的依賴關系,即出現在 packages.json
文件的哪一項中。
–save:模塊名將被添加到 dependencies,可以簡化為參數-S。
–save-dev:模塊名將被添加到 devDependencies,可以簡化為參數-D。
1 2 3 4 5 | $ npm install sax --save $ npm install node-tap --save-dev # 或者 $ npm install sax -S $ npm install node-tap -D |
dependencies 依賴
這個可以說是我們 npm
核心一項內容,依賴管理,這個對象裏面的內容就是我們這個項目所依賴的 js
模塊包。下面這段代碼表示我們依賴了 markdown-it
這個包,版本是 ^8.1.0
,代表最小依賴版本是 8.1.0
,如果這個包有更新,那麽當我們使用 npm install
命令的時候, npm
會幫我們下載最新的包。當別人引用我們這個包的時候,包內的依賴包也會被下載下來。
1 2 3 | "dependencies": { "markdown-it": "^8.1.0" } |
devDependencies 開發依賴
在我們開發的時候會用到的一些包,只是在開發環境中需要用到,但是在別人引用我們包的時候,不會用到這些內容,放在 devDependencies
的包,在別人引用的時候不會被 npm
下載。
1 2 3 4 5 6 7 8 9 10 11 | "devDependencies": { "autoprefixer": "^6.4.0", "babel-preset-es2015": "^6.0.0", "babel-preset-stage-2": "^6.0.0", "babel-register": "^6.0.0", "webpack": "^1.13.2", "webpack-dev-middleware": "^1.8.3", "webpack-hot-middleware": "^2.12.2", "webpack-merge": "^0.14.1", "highlightjs": "^9.8.0" } |
當你有了一個完整的 package.json
文件的時候,就可以讓人一眼看出來,這個模塊的基本信息,和這個模塊所需要依賴的包。我們可以通過 npm install
就可以很方便的下載好這個模塊所需要的包。
npm install
默認會安裝 dependencies
字段和 devDependencies
字段中的所有模塊,如果使用 --production
參數,可以只安裝 dependencies
字段的模塊。
1 2 3 | $ npm install --production # 或者 $ NODE_ENV=production npm install |
一旦安裝了某個模塊,就可以在代碼中用 require
命令加載這個模塊。
1 2 | var backbone = require(‘backbone‘) console.log(backbone.VERSION) |
npm run
npm
不僅可以用於模塊管理,還可以用於執行腳本。package.json
文件有一個 scripts
字段,可以用於指定腳本命令,供 npm
直接調用。package.json
文件內容:
1 2 3 4 5 6 7 8 9 10 11 12 | { "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
的縮寫,一般都使用前者,但是後者可以更好的反應這個命令的本質。
1 2 3 4 5 6 7 8 9 | // 腳本 "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
。
1 | "build": "npm run build-js && npm run build-css" |
上面的寫法是先運行 npm run build-js
,然後再運行 npm run build-css
,兩個命令中間用 &&
連接。如果希望兩個命令同時平行執行,它們中間可以用 &
連接。
寫在 scripts
屬性中的命令,也可以在 node_modules/.bin
目錄中直接寫成 bash
腳本。下面是一個 bash
腳本。
1 2 3 4 | cd site/main browserify browser/main.js | uglifyjs -mc > static/bundle.js |
假定上面的腳本文件名為 build.sh
,並且權限為可執行,就可以在 scripts
屬性中引用該文件。
1 | "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
。
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "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
腳本。
npm bin
npm bin
命令顯示相對於當前目錄的,Node
模塊的可執行腳本所在的目錄(即 .bin
目錄)。
1 2 3 |
創建全局鏈接
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: 包的依賴,一個關聯數組,由包名稱和版本號組成。
包的發布
通過使用 npm init
可以根據交互式回答產生一個符合標準的 package.json
。創建一個 index.js
作為包的接口,一個簡單的包就制作完成了。
在發布前,我們還需要獲得一個賬號用於今後維護自己的包,使用 npm adduser
根據提示完成賬號的創建
完成後可以使用 npm whoami
檢測是否已經取得了賬號。
接下來,在 package.json
所在目錄下運行 npm publish
,稍等片刻就可以完成發布了,打開瀏覽器,訪問 NPM搜索 就可以找到自己剛剛發布的包了。現在我們可以在世界的任意一臺計算機上使用 npm install neveryumodule
命令來安裝它。
如果你的包將來有更新,只需要在 package.json
文件中修改 version
字段,然後重新使用 npm publish
命令就行了。
如果你對已發布的包不滿意,可以使用 npm unpublish
命令來取消發布。
需要說明的是: json
文件不能有註釋
參考鏈接
http://javascript.ruanyifeng.com/nodejs/npm.html
? 著作權歸原作者所有NPM 學習筆記整理