Node.js
npm
npm-scripts

OSに依存しない形でnpm scriptsにglobを書く

背景

Windowsで開発してたプロジェクトをMacのマシンで動かしたらnpm scriptsが思ったように動かなくて困った。
rm -rfなんかは気をつけていたけど、glob (src/**/*.jsみたいなやつ) がMacでちゃんと認識されなくて困った。

結論

npm scriptsに出てくるglobはすべて「'」(シングルクォーテーション)で囲む。

参考文献

ここを参考にしました。

https://medium.com/@jakubsynowiec/you-should-always-quote-your-globs-in-npm-scripts-621887a2a784

解決までの道のり

ぶち当たった問題

今回解決したかったのは、以下のようなglobの含まれるnpm scriptsでした。

  "scripts": {
    "test": "mocha src/**/*.spec.ts"
  },

このプロジェクトでは、当初Windowsマシンを使って開発を進めていました。
そのときのテスト結果がこちら。

  190 passing (277ms)
  2 pending

開発の途中でMacのマシンを購入することができたため、Macのマシンで開発を続けようと思い、環境セットアップしてテストを回すと…。

  72 passing (88ms)

少ない??

原因

普段意識せずに使っている、"**"と書けばネストしたディレクトリを含む、というようなglobはglobstarというシェル拡張を使っているそうです。

記事執筆時点のMacだとデフォルトでbashのバージョンが3系なので、そもそもglobstarが使えません。(globstarが追加されたのはバージョン4から)

その状態で"**"を含むglobを書くと、2段以上ネストされたディレクトリに対応できなくなったわけです。

ではBashのバージョンを4系に上げ、globstarを有効にすればそれだけで使えるようになるかというと、そういうわけでもありませんでした。

どうも、npm scriptsに書いたスクリプトはsh -cに続く形で渡されるようです。
このとき、元のシェルセッションでglobstarを有効にしていたとしても、新しく作られたシェルのセッションではglobstarが無効になってしまっていました。

この時点で上記の参考ブログに出会うわけですが、mochaなどのnpm moduleでは引数にglobが含まれる場合、node-globというモジュールで解決するそうです。

このnode-globというモジュールはglobstarにも対応しているため、npm scriptsに書くglobをglobとしてシェルに認識させないようにすると良いということが分かりました。

つまり、こうです。

  "scripts": {
    "test": "mocha 'src/**/*.spec.ts'"
  },

globをシングルクォーテーションで囲むことで、bashにとってはただの文字列として扱われるため、上記の場合だとmochaが使うnode-globで解決されるようになります。

まとめ

まさかOSが変わるとこんなところに影響があるとは思ってもいませんでした。
普段Windowsしか触らないといろいろ怖い。システムのデフォルトでIgnore Caseだったり、ついbashのスクリプト書いたら動かなかったり。UNIX系OSはやれ。