首先介紹創建 package.json 文件的科學方法,目標是掌握 npm init 命令。然后,通過在終端中運行自動生成的 test 命令,詳細講解 npm 腳本基本執行流程。 然后,動手給項目增加 eslint 命令,熟悉創建自定義命令的基本流程。
## 用 npm init 快速創建項目
開始探索 npm script 之前,我們先聊聊這些 scripts 所依賴的文件 package.json,以它為基礎的 npm 則是 node.js 社區蓬勃發展的頂梁柱。
npm 為我們提供了快速創建 package.json 文件的命令 npm init,執行該命令會問幾個基本問題,如包名稱、版本號、作者信息、入口文件、倉庫地址、許可協議等,多數問題已經提供了默認值,你可以在問題后敲回車接受默認值:
```
package name: (hello-npm-script)
version: (0.1.0)
description: hello npm script
entry point: (index.js)
test command:
git repository:
keywords: npm, script
license: (MIT)
```
上面的例子指定了描述(description)和關鍵字(keywords)兩個字段,基本問題問完之后 npm 會把 package.json 文件內容打出來供你確認:
```
{
"name": "hello-npm-script",
"version": "0.1.0",
"description": "hello npm script",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"npm",
"script"
],
"author": "wangshijun <wangshijun2010@gmail.com> (https://github.com/wangshijun)",
"license": "MIT"
}
```
按回車確認就能把package.json 的內容寫到文件系統,如果要修改 package.json,可以直接用編輯器編輯,或者再次運行 npm init,npm 默認不會覆蓋修改里面已經存在的信息。
> **TIP#1**: 嫌上面的初始化方式太啰嗦?你可以使用 npm init -f(意指 --force,或者使用 --yes)告訴 npm 直接跳過參數問答環節,快速生成 package.json。
初始化 package.json 時的字段默認值是可以自己配置的,細心的同學可能已經發現,我上面的默認版本號是 0.1.0,而 npm 默認的版本號是 0.0.1,可以用下面的命令去修改默認配置:
```
npm config set init.author.email "wangshijun2010@gmail.com"
npm config set init.author.name "wangshijun"
npm config set init.author.url "http://github.com/wangshijun"
npm config set init.license "MIT"
npm config set init.version "0.1.0"
```
> **TIP#2**: 將默認配置和 -f 參數結合使用,能讓你用最短的時間創建 package.json,快去自己試試吧。
嚴肅的工程師都會使用 Git 對源代碼進行版本管理,在 npm init 的基礎上,你可以使用 git init 來初始化 git 倉庫,不再展開。
紙上得來終覺淺,想掌握 npm script,請打開終端,執行下列命令:
```
cd ~
mkdir hello-npm-script && cd $_
npm init
npm init -f
```
**執行上面第 3、4 行命令時結果是否符合預期?如果不符合預期,請在下面留言,或者在讀者群里反饋。**
## 用 npm run 執行任意命令
使用 npm init 創建的 package.json 文件中包含了 scripts 字段:
```
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
```
在終端中運行 npm run test,能看到 Error: no test specified 的輸出。npm run test 可以簡寫為 npm test,或更簡單的 npm t,得到的結果是幾乎相同的。npm test 顧名思義,就是運行項目測試,實際用法在實戰環節會有介紹。
和 test 類似,start 也是 npm 內置支持的命令,但是需要先在 scripts 字段中聲明該腳本的實際內容,如果沒聲明就執行 npm start,會直接報錯。如下圖所示:

那么,npm 是如何管理和執行各種 scripts 的呢?作為 npm 內置的核心功能之一,npm run 實際上是 npm run-script 命令的簡寫。當我們運行 npm run xxx 時,基本步驟如下:
1. 從 package.json 文件中讀取 scripts 對象里面的全部配置;
2. 以傳給 npm run 的第一個參數作為鍵,本例中為 xxx,在 scripts 對象里面獲取對應的值作為接下來要執行的命令,如果沒找到直接報錯;
3. 在系統默認的 shell 中執行上述命令,系統默認 shell 通常是 bash,windows 環境下可能略有不同,稍后再講。
注意,上面這是簡化的流程,更復雜的鉤子機制后面章節單獨介紹。
舉例來說,如果 package.json 文件內容如下:
```
{
"name": "hello-npm-script",
"devDependencies": {
"eslint": "latest"
},
"scripts": {
"eslint": "eslint **.js"
}
}
```
如果不帶任何參數執行 npm run,它會列出可執行的所有命令,比如下面這樣:
```
Available scripts in the myproject package:
eslint
eslint **.js
```
如果運行 npm run eslint,npm 會在 shell 中運行 eslint \*\*.js。
有沒有好奇過上面的 eslint 命令是從哪里來的?其實,npm 在執行指定 script 之前會把 node\_modules/.bin 加到環境變量 $PATH 的前面,這意味著任何內含可執行文件的 npm 依賴都可以在 npm script 中直接調用,換句話說,你不需要在 npm script 中加上可執行文件的完整路徑,比如 `./node_modules/.bin/eslint **.js`。
## 創建自定義 npm script
知道如何運行 npm script 之后,接下來我們在 hello-npm-script 項目中添加有實際用途的 eslint 腳本,[eslint](https://eslint.org) 是社區中接受度比較高的 javascript 風格檢查工具,有大把現成的規則集可供你選擇,比如 [google](https://github.com/google/eslint-config-google)、 [airbnb](https://www.npmjs.com/package/eslint-config-airbnb)。
在新項目或者任何現有項目中添加 eslint 自定義腳本的步驟如下:
### 1\. 準備被檢查的代碼
要做代碼檢查,我們必須有代碼,創建 index.js 文件,輸入如下內容:
```
const str = 'some value';
function fn(){
console.log('some log');
}
```
### 2\. 添加 eslint 依賴
執行如下命令將 eslint 添加為 devDependencies:
```
npm install eslint -D
```
### 3\. 初始化 eslint 配置
用 eslint 做檢查需要配置規則集,存放規則集的文件就是配置文件,使用如下文件生成配置文件:
```
./node_modules/.bin/eslint --init
```
> **TIP#3**: 把 eslint 安裝為項目依賴而非全局命令,項目可移植性更高。
在命令行提示中選擇 Answer questions about your style,如下圖回答幾個問題,答案可以根據自己的偏好:

回車后根目錄下就有了 .eslintrc.js 配置文件:
```
module.exports = {
env: {
es6: true,
node: true,
},
extends: 'eslint:recommended',
rules: {
indent: ['error', 4],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
},
};
```
### 4\. 添加 eslint 命令
在 package.json 的 scripts 字段中新增命令 eslint:
```
{
"scripts": {
"eslint": "eslint *.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
}
```
**手動修改 package.json 時一定要注意語法正確。**
### 5\. 運行 eslint 命令
執行 npm run eslint,可以看到,按照官方推薦規則代碼里有 3 處不符合規范的地方:

* * *
如果讀到這里,相信你已經完成 npm script 上手,接下來我們去探索更高級的話題。
* * *
## 20171205 增補:eslint 完成 react、vue.js 代碼的檢查
如果需要結合 eslint 檢查主流前端框架 react、vue.js,下面提供兩條線索,因為官方倉庫的 README 就可以作為入門文檔,仔細讀讀相信絕大多數同學都能配置好。
使用 [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) 檢查 react 代碼,使用 [react-plugin-react-native](https://github.com/Intellicode/eslint-plugin-react-native) 檢查 react-native 代碼,如果你比較懶,可以直接使用 [eslint-config-airbnb](https://www.npmjs.com/package/eslint-config-airbnb),里面內置了 eslint-plugin-react,新人常遇到 peerDependencies 安裝失敗問題可參照 npmjs 主頁上的如下方法解決:
```
(
export PKG=eslint-config-airbnb;
npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest"
)
```
推薦使用 vue.js 官方的 eslint 插件:[eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) 來檢查 vue.js 代碼,具體的配置方法官方 README 寫的清晰明了,這里就不贅述了。
上面的幾種 eslint 規則集的官方倉庫都列出了各自支持的規則,如果你需要關閉某些規則,可以直接在自己的 .eslintrc\* 里面的 rules 中配置,比如我們倉庫里面的:
```
module.exports = {
env: {
es6: true,
node: true,
},
extends: 'eslint:recommended',
rules: {
indent: ['error', 2],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
},
};
```
如果你配置過程中遇到什么問題,歡迎留言或者在讀者群里面交流。
- 為什么選擇 npm script
- 入門篇 01:創建并運行 npm script 命令
- 入門篇 02:運行多個 npm script 的各種姿勢
- 入門篇 03:給 npm script 傳遞參數和添加注釋
- 進階篇 01:使用 npm script 的鉤子
- 進階篇 02:在 npm script 中使用環境變量
- 進階篇 03:實現 npm script 命令自動補全
- 高階篇 01:實現 npm script 跨平臺兼容
- 高階篇 02:把龐大的 npm script 拆到單獨文件中
- 高階篇 03:用 node.js 腳本替代復雜的 npm script
- 實戰篇 01:監聽文件變化并自動運行 npm script
- 實戰篇 02:結合 live-reload 實現自動刷新
- 實戰篇 03:在 git hooks 中運行 npm script
- 實戰篇 04:用 npm script 實現構建流水線
- 實戰篇 05:用 npm script 實現服務自動化運維