【Node.js】package.jsonのscriptsをnpsとnps-utilsを利用して、綺麗に整理してマルチプラットフォーム対応

## はじめに
- npmやyarnを利用した開発の際に、以下の点が気になったため、良い方法があるか調査。
  - package.jsonへ定義するscriptsの量や内容が多くなってしまい、管理が大変
  - 柔軟性や拡張性が欲しいため、json以外のファイルで記述したい。
  - マルチプラットフォームで利用できる環境にしたい。
- 調査の結果、[nps](https://github.com/sezna/nps)と[nps-utils](https://github.com/kentcdodds/nps-utils)の2つのライブラリを発見。
- 今回は、上記2つのライブラリの概要や手順、設定テンプレートを記述する。

## 手順

### プロジェクト準備
- npmやyarnを利用している既存Node.jsプロジェクトを利用する。
  - **※新規の場合、package.jsonでscriptsを管理するものを各自作成**
- 今回は、下記の`package.json`の例を置き換える。

```json:置き換え対象のpackage.json
{
  "scripts": {
    "dev": "NODE_ENV=development nodemon index.js",
    "test": "NODE_ENV=test jest --coverage",
    "lint": "eslint . --cache"
    "build": "NODE_ENV=production run-s build:{clean,js}",
    "build:clean": "rm -rf ./dist",
    "build:js": "esbuild src/index.js --bundle --outfile=dist/out.js"
  },
  "devDependencies": {
　　................,
    "esbuild": "^0.6.12",
    "nodemon": "^2.0.4",
    "jest": "^26.4.0",
    "eslint": "^7.7.0",
    "npm-run-all": "^4.1.5"
  }
}
```

### 導入
- 上記プロジェクトへ以下2つのライブラリへインストール
  - [nps](https://github.com/sezna/nps) : npm scripts管理ツール
    - 利点
      - scriptsの詳細を別ファイルにすることで、管理や保守が容易になる。
      - jsonではなく、jsやyamlで記述できるため、柔軟性や拡張性が高い。
  - [nps-utils](https://github.com/kentcdodds/nps-utils) : npsを強化するためのパッケージツール
    - 利点
      - マルチプラットフォーム対応ライブラリ(rmコマンド対応、環境変数対応)が多数組み込まれているため、一つで完結する。
      - 並列実行サポートもされている。

```bash
# nps,nps-utilの導入
npm install --save-dev nps nps-utils
```

### 初期化
- 下記のコマンドで設定ファイルを作成する。
  - **※今回はjsで作成する**

```bash
# 設定ファイルの作成。デフォルトはpackage-scripts.js
./node_modules/.bin/nps init

# yamlで作成する場合。package-scripts.ymlが作成
./node_modules/.bin/nps init --type yml
```

- 作成後、下記の2つのファイルが入っている構造になっていることを確認する。

```
.
├── package.json
└── package-scripts.js
└── .......
```

### 設定テンプレート 
- まず、初期化で作成した`package-scripts.js`の中身を下記にする。

```js:package-scripts.js
// クロスプラットフォーム対応(Mac,Windows,Linux)
const {
  series,  // 連続実行の簡易化
  rimraf,  // rmコマンド
  crossEnv  // 環境変数設定
} = require('nps-utils');

module.exports = {
  scripts: {
    dev: {
      default: crossEnv('NODE_ENV=development nodemon index.js')
    },
    test: {
      default: crossEnv('NODE_ENV=test jest --coverage')
    },
    lint: {
      default: 'eslint . --cache'
    },
    build: {
      default: crossEnv(
        `NODE_ENV=production ${series.nps(
          'build.clean',
          'build.js',
        )}`,
      ),
      clean: rimraf('dist'),
      js: 'esbuild src/index.ts --bundle --outfile=dist/out.js',
    }
  }
};
```

- 最終的なpackage.jsonの中身を下記にする。
  - **※devDependenciesにはインストール済みのnps等が入っている。**

```json:最終package.json
{
  "scripts": {
    "dev": "nps dev",
    "test": "nps test",
    "lint": "nps lint",
    "build": "nps build"
  },
  "devDependencies": {
　　................,
    "esbuild": "^0.6.12",
    "nodemon": "^2.0.4",
    "jest": "^26.4.0",
    "eslint": "^7.7.0",
    "npm-run-all": "^4.1.5",
    "nps": "^5.10.0",
    "nps-utils": "^1.7.0",
    ..........
  }
}
```

### 実行
- 各種実行は、下記で行う。
  - **※基本的に、npm scriptsで行なっている方法と変わらない。**

```bash
# npm run スクリプト名

# dev
npm run dev
# test
npm run test
```

## 参考
- [nps Github](https://github.com/sezna/nps)
- [nps-utils Github](https://github.com/kentcdodds/nps-utils)