[指令] npm cli & package.json
keywords: npm
, cli
, package.json
TL;DR
- runtime 和 production 會用到這個套件 --> dependencies
- 只有開發時會用到 --> devDependencies
- 希望使用者自行安裝 --> peerDependencies
npm init -y # --yes, 接受所有預設值產生 package.json
npm init --scope=@pjchender -y # --scope, 專案屬於某個 scope 底下
npm ls # 列出該專案安裝的套件
npm ls | grep react # 只列出和 react 有關的套件
npm ls <package> # 可以檢視專案中有沒有使用到這個套件,以及版本號
npm install <package>@latest # latest stable release
npm install <package>@beta # latest beta release
npm install --verbose # 顯示安裝時的詳細資訊
npm install --production # 只安裝 dependencies,不會安裝 devDependencies
npm install --dev # 只會安裝 devDependencies,不會安裝 dependencies
npm view <package> # 檢視該套件有哪些版本
npm home <package> # 進到該套件的官網
npm repo <package> # 進到該套件的 github
npm docs <package> # 進到該套件的文件
npm run # 列出所有該 package 定義的指令
npm prune # 移除多餘沒 用到的套件
npm doctor # 檢查 node, npm 版本,並檢驗有無足夠的權限安裝 dependencies
npm dedupe # npm ddp,移除重複的套件(duplicate packages)
npm outdated # 檢查版本過期的套件
npm outdated -l # --long
npm info "<pkg>@latest" peerDependencies # 列出該套件的所有 peerDependencies
npx <package> # 執行某個 package 內的指令
npx sort-package-json # 重新排序 package.json 的檔案(第三方)
npx install-peerdeps --dev <pkg> # 安裝某套件所需的所有 peerDependencies
預設的情況下 scope 的專案是 restricted,但這需要額外付費,因此可以透過設定把它改成 public,設定的方式可以參考這裡。
npm init # 專案初始化(建立 package.json)
npm install # 根據 package.json 安裝所需要的檔案
npm install --save <packageName> # 套件會安裝在 dependencies 中(簡寫 -S)
npm install --save-dev <packageName> # 套件會安裝在 devDependencies 中(簡寫 -D)
npm install --global <packageName> # 套件會以全域的方式安裝(簡寫 -g)
npm install <packageName>@~1.14 # 安裝特定版本的模組
npm install <packageName>@latest # 安裝最新的穩定版
npm install <packageName>@next # 安裝最新的版本
npm uninstall <packageName> # 解除安裝〈簡寫 un〉
npm list # 列出所有已安裝的套件
npm update # 更新套件, -dd 顯示詳細資訊
npm prune # 根據 package.json 移除和專案無關的套件
npm outdated # 告訴你有哪些安裝的套件已經不是最 新版了
sudo npm i -g npm # 更新 npm
npm -v # 查看 npm 版本
npm init # 初始化 package.json
使用
npm update
時,仍會依據package.json
所定的版號作為依據,不會直接更新到最新版。
npm documentation @ npm
安裝模組參數說明
-g, --global 全局安裝(global)
-S, --save 安裝包信息將加入到dependencies(生產階段的依賴)
-D, --save-dev 安裝包信息將加入到devDependencies(開發階段的依賴),所以開發階段一般使用它
-O, --save-optional 安裝包信息將加入到optionalDependencies(可選階段的依賴)
-E, --save-exact 精確安裝指定模塊版本
開發套件相關
npm init # 建立 npm module (package)
npm ci # 在 CI 環境執行 npm install(確保相依套件是乾淨的)
npm adduser # 建立使用者
npm login # 登入使用者
npm config ls # 檢視本地端記錄了哪些註冊的使用者
npm publish # 上傳 package 到 npm(版本變動時上傳就是更新)
npm version <major | minor | patch> # 透過 cli 更新版本編號
npm deprecate <package-name> "<message>" # 不再維護某一專案
npm deprecate <package-name>@<version> "<message>" # 不再維護專案的某一版本
npm unpublish # 移除 npm 上的 package(需聯絡 npm)
# 將不繼續維護的的套件轉移給 npm 組織
npm owner add npm <package-name>
npm owner rm <user> <package-name>
# 將本地套件建立捷徑以方便測試
npm link # 進到要測試的套件中(例如 foo),執行後會在 global 產生一個捷徑
npm link foo # 進到要使用測試套件的專案中,執行 npm link <local_package>
npm ls -g depth 0 # 列出所有在 global 有被 link 的套件
npm rm <package-name> -g # 移除在 global 中被 link 的套件
npm ci
的作用和 npm install
類似,但它會
- 依據
package-lock.json
中所定義的版號安裝套件 - 移除
node_modules
以乾淨的環境重新安裝 - 如果有錯誤的話,它不會改變
package.json
或package-lock.json
而是直接拋出錯誤
- npm-ci @ npmjs docs
- Creating Node.js modules @ npmjs docs
- Creating a package.json file @ npmjs docs
- UnPublishing packages from the registry @ npmjs docs
- Deprecating and undeprecating packages or package versions @ npmjs docs
workspaces
- workspaces @ npmjs
- ts-monorepo-template @ pjchender github
npm 7 支援 workspaces 的功能,讓開發者可以從單一個上層的 root package 管理底下多個 packages。
定義 workspaces
只需要在 package.json
中使用 workspaces
這個欄位,裡面指的是 root packages 裡面的其他 packages:
// package.json
{
"name": "my-workspaces-powered-project",
"workspaces": ["workspace-a", "packages/*"]
}
workspaces 中套件安裝的位置
當我們的資料夾結構是:
.
├── packages
│ ├── bar
│ └── foo
└── workspace-a
在 .
執行 npm install
時,會在根目錄的 node_modules
內會多一個名為 workspace-a
、foo
、bar
的捷徑,它會指向 ./workspace-a
、packages/foo
和 packages/bar
的專案位置。像是這樣:
.
├── node_modules
│ ├── bar -> ../packages/bar
│ ├── foo -> ../packages/foo
│ └── workspace-a -> ../workspace-a
├── packages
│ ├── bar
│ └── foo
└── workspace-a
對於會重複在多個 packages 中使用到的套件,實際套件會安裝在根目錄的 ./node_modules
中。
直接把 workspaces 內的套件當成 package 匯入
由於會在根目錄的 node_modules
中建立捷徑,因此我們也可以直接把 workspaces
中定義好的套件 workspace-a
、packages/foo
和 packages/bar
直接匯入。例如:
// ./workspace-a/index.js
module.exports = 'workspace-a';
// ./packages/foo/index.js
module.exports = 'foo';
// ./packages/bar/index.js
module.exports = 'bar';
匯入這些 workspaces 中的套件:
// ./index.js
const a = require('workspace-a'); // 'workspace-a'
const b = require('foo'); // 'foo'
const c = require('bar'); // 'bar'
// ./packages/foo/index.js
const bar = require('bar'); // 也可以直接匯入 'bar'
module.exports = 'foo';
在 root package 執行 npm 指令
在執行 npm 指令時,可以透過 --workspace="package-name"
這個 option 來執行 workspaces 內某 package 的指令;如果是想要一次執行 workspaces 內的所有 npm script,則可以使用 --workspaces
(多 s
)。例如,當執行:
# 只執行 workspace-a 裡的 npm script
$ npm run start --workspace=workspace-a
> [workspace-a] I am workspace-a
# 執行 workspace-a 和 bar 裡的 npm script
$ npm run start --workspace=workspace-a --workspace=bar
> [workspace-a] I am workspace-a
> [bar] I am bar
# 執行所有 workspaces,記得要加 s
$ npm start --workspaces
套件更新
How to Publish an Updated Version of an npm Package @ cloud 4
NPM Scripts and Package.json
# 使用 && 會依序執行各個指令
$ npm run build && npm run start
# 使用 & 會平行(parallel)執行多個指令
$ npm run build & npm run start
# 使用 -- 可以帶入參數
$ npm run foo -- "hello"
preinstall
會在所有套件安裝前執行npm run env
列出 package 中所有環境變數,和在程式中使用process.env.npm_package_name
類似- 在 package.json 中可以新增
config
欄位,來裡面定義的變數將可以透過npm_package_config_foo
取得
// npm_package_config_foo=Hello World
"config": {
"foo": "Hello World"
},
npm init
keywords: npm create
, npm innit
npm-init @ npmjs
npm init 一般可以用來初始化 npm 專案,最常見的應該是使用 npm init -y
,也就是建立專案時,全部按 yes:
但除此之外,還有一種方式是 npm init <initializer>
,這麼做的話意思不太一樣,npm 會透過 npx
(npm-exec) 來找到並執行名稱為 create-<initializer>
的專案,例如:
npm init foo
等同於npx create-foo
npm init @usr/foo
->npx @usr/create-foo
npm init @usr
->npx @usr/create
透過這樣的邏輯,我們可以知道:
- 除了使用
npx create-react-app my-app
外,也可以使用npm init react-app my-app
npm exec
npm-exec @ npmjs
keywords: npx
npm exec 和 npx 的差別
當使用 npx
或 npm exec
來執行 binary 時,帶入參數的方式有些不同
- 當使用
npx
時,可以直接在 binary 後帶入要給 binary 的參數 - 當是用
npx exec
時,需要使用--
來分開那些是要給 npm 的參數,那些是要給 binary 的參數
具體來說:
# 如果我們希望執行的是
$ vite react-ts-vite --template react-ts
# 用 npx 要這樣寫
$ npx create-vite@latest react-ts-vite --template react-ts
# 用 npm exec 要這樣寫
$ npm exec create-vite@latest -- react-ts-vite --template react-ts
問題解決與錯誤處理
解決 package-lock.json 檔案內容異動的問題
$ rm -rf node_modules/
$ npm cache clean --force
(Revert the changes in your package-lock.json file) # 還原到原本的 package-lock.json
$ npm install
npm install downgrading resolved packages from https to http registry in package-lock.json
npm cache 位置
有些時候更新了 package.json
中的設定後(例如,browserslist
),卻沒有立即產生對應的改變,這有可能是 babel-loader
沒有偵測到 package.json
中的變化,這時候可以刪除 node_modules/.cache
的檔案:
$ ls node_modules/.cache
package.json 範例
-
The package.json guide @ flaviocopes
-
npm-package.json @ npm docs
-
Package entry points @ Node.js
-
在
package.json
中使用了exports
:- 一旦使用
exports
當想要明確定義 ESM 和 CJS 的載入點時,另一方面也表示的是這個 package 只有暴露這些 API 給其他人使用,所以沒被定義到的 entry-point,就會沒辦法被 import exports
也可以被當作類似 package 的 export alias 被使 用,可以參考這裡的用法:「RFC: Use package.json exports to "hide" the dist folder for packages and control our exported surface-area」
- 一旦使用
{
"name": "pkg-name",
"version": "0.0.1",
"scripts": {
"build": "webpack --optimize-minimize",
"start": "webpack-dev-server"
},
// https://nodejs.org/api/packages.html
// 除了用 main 也可以用 "exports" 來更精確描述不同 module system 要載入的檔案
// 但是一旦用了 exports 後,其他人就只能從有被定義 exports 的路徑載入檔案
"exports": {
".": {
// Entry-point for `import "my-package"` in ESM
"import": "./esm/index.js",
// Entry-point for `require("my-package") in CJS
"require": "./commonjs/index.cjs"
}
// 可以當作 export alias 使用,用的人只需 import "pkg-name/tailwind.config" 即可,不用進到 dist
"./tailwind.config": {
"import": "./dist/tailwind.config.js",
"require": "./dist/tailwind.config.cjs"
},
"./lib/ArrowTooltip": {
"import": "./dist/lib/ArrowTooltip/index.js",
"require": "./dist/lib/ArrowTooltip/index.cjs"
},
},
// 引用此 package 的進入點(CJS fall-back for older versions of Node.js)
"main": "./commonjs/index.cjs",
// 選擇 Node.js 要用 ES Module 或 CommonJS(預設)的 module system
"type": "module", // "module" 或 "commonjs"(預設)
// app 運作時會用到的 package
"dependencies": {
"jquery": "^3.1.0"
},
// 開發環境會用到的 package
"devDependencies": {
"webpack": "^1.13.1"
}
}
參考
- npm documentation @ npm