クロスプラットフォーム(Win、Mac)で使えるECMAScript開発環境

以前投稿した[シンプルだけどシッカリ働く最新のECMAScript開発環境](https://qiita.com/zprodev/items/9d611a482715fa64512b)ではクロスプラットフォームなnodeモジュールをいくつか使わせてもらいながらも、Windows環境では動かない構成になっていました。

素晴らしいモジュールたちをしっかり活かすべくWindows対応を行い、その際必要だった対応をまとめます。

## 対応前のpackage.json

```json:package.json
{
  "private": true,
  "scripts": {
    "start": "npm run mkdist && npm run cpassets -- -w & npm run cphtml -- -w & webpack-dev-server",
    "build": "npm run mkdist && npm run cpassets && npm run cphtml && webpack --optimize-minimize",
    "mkdist": "rimraf dist/ && mkdirp dist/",
    "cpassets": "cpx 'assets/**/*' dist/",
    "cphtml": "cpx src/index.html dist/"
  },
  "dependencies": {
    "babel-polyfill": "^6.26.0"
  },
  "devDependencies": {
    "cpx": "^1.5.0",
    "mkdirp": "^0.5.1",
    "rimraf": "^2.6.2",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "webpack": "^3.5.6",
    "webpack-dev-server": "^2.7.1"
  }
}
```

## ダメだった箇所

### npmスクリプト内のシングルクオーテーション

cpxでのディレクトリ内再帰的コピーが動きませんでした

Macではコレでいけてましたが

```json:package.jsonより抜粋
"cpassets": "cpx 'assets/**/*' dist/",
```

Winではこうしないとダメでした

```json:package.jsonより抜粋
"cpassets": "cpx \"assets/**/*\" dist/",
```

npmスクリプトでは**シングルクオーテーションでなくエスケープ付きダブルクオーテーション**を使った方が良さそうです

### npmスクリプトの並列実行

`&`を使用したnpmスクリプトの並列実行ができませんでした

|コマンド|Mac|Windows|
|---|---|---|
|&|並列実行|エラー無視の**直列実行**|
|&&|直列実行|直列実行|

npmスクリプトを直列・並列実行させるためのクロスプラットフォームなモジュール[npm-run-all](https://www.npmjs.com/package/npm-run-all)を導入し


並列実行を使用している`start`をこのように書き換えました

Before

```json:package.jsonより抜粋
"start": "npm run mkdist && npm run cpassets -- -w & npm run cphtml -- -w & webpack-dev-server",
```

After

```json:package.jsonより抜粋
"start": "npm-run-all mkdist --parallel \"cpassets -- -w\" \"cphtml -- -w\" webpack-dev",
"webpack-dev": "webpack-dev-server"
```

`mkdist`を実行後、`cpassets -- -w` `cphtml -- -w` `webpack-dev`を並列実行させています

[npm-run-all](https://www.npmjs.com/package/npm-run-all)はオプション無しだと直列実行ですが、オプションを指定すると並列/直列を組み合わせることができます
並列 : `--parallel <tasks>`
直列 : `--serial <tasks>`

## 対応後のpackage.json

```json:package.json
{
  "private": true,
  "scripts": {
    "start": "npm-run-all mkdist --parallel \"cpassets -- -w\" \"cphtml -- -w\" webpack-dev",
    "build": "npm-run-all mkdist cpassets cphtml webpack",
    "mkdist": "rimraf dist/ && mkdirp dist/",
    "cpassets": "cpx \"assets/**/*\" dist/",
    "cphtml": "cpx src/index.html dist/",
    "webpack": "webpack --optimize-minimize",
    "webpack-dev": "webpack-dev-server"
  },
  "dependencies": {
    "babel-polyfill": "^6.26.0"
  },
  "devDependencies": {
    "cpx": "^1.5.0",
    "mkdirp": "^0.5.1",
    "npm-run-all": "^4.1.2",
    "rimraf": "^2.6.2",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "webpack": "^3.5.6",
    "webpack-dev-server": "^2.7.1"
  }
}
```

## まとめ

### クロスプラットフォーム対応の便利なモジュールを使う

コマンド差分が辛いので、クロスプラットフォームに対応しているモジュールを使いましょう

 - cpx : ファイルコピーをサポート&監視
 - mkdirp : ディレクトリ作成をサポート
 - rimraf : ディレクトリ削除をサポート
 - npm-run-all : npmスクリプトの並列実行をサポート

### npmスクリプト内ではシングルクオーテーションを使わない

エスケープ付きダブルクオーテーションを使いましょう

### パスの指定にはNodeAPIのpathを使う

今回は対応不要でしたが、ファイルパス系はMacとWindowsで以下のように異なります

Mac

```js
const indexPath = './src/index.js';
```

Windows

```js
const indexPath = '.\\src\\index.js';
```

これはNodeAPIのpathを使用することで、下記に統一することができます

```js
const path = require('path');

const indexPath = path.resolve('src', 'index.js');
```


## さいごに

対応後の環境は[こちら](https://github.com/zprodev/wds-template)にあるので、よかったら試してみてください。