npm scripts で rimraf を使わずディレクトリを再帰的に削除する
3 行で
- Node.js >= v14.14.0 であること
-
rimraf distはnode -e 'fs.rmSync(`dist`, {recursive:true, force:true})'で置き換えられる -
rimraf dist/*.bundle.jsみたいな glob を含むものは置き換えできない
長い説明
npm scripts で不要なキャッシュやビルドの出力ファイルを削除したい場合は rimraf というパッケージを POSIX の rm -rf の代わりに使うことが多いと思います。これは Windows で npm run の実行に使われる コマンドプロンプト (cmd.exe) に rm がないのを始めとした環境依存の問題を避けるためです。
とはいえパッケージなしではディレクトリの再帰的削除もできない、というのはちょっと困るので、v12.10.0 で fs.rmdir fs.promises.rmdir fs.rmdirSync に recursive オプションが追加され、fs.rmdirSync('foo/', { recursive: true }) とすることで rm -rf や rimraf に近いことができるようになりました。ちなみに、glob が使えないこと以外は rimraf がそのまま使われています。
しかし、実は POSIX の rmdir には再帰的削除の機能がないため、recursive を rmdir のオプションに追加するとややこしくなるという意見があったようです。代替案として rmtree という関数の追加とかが考えられたようです。また、POSIX との整合性で言うと rm に相当するのが fs.unlink になっていてややこしいといった問題もありました。
そこで、v14.14.0 で POSIX の rm に相当する fs.rm fs.promises.rm fs.rmSync が追加されました。Linux のシェルで rm -rf とするように、fs.rmSync('foo/', { recursive: true, force: true }) とすることでディレクトリを再帰的に削除できます。
ということで、fs.rmSync するコードを文字列として node --eval (node -e) に渡してディレクトリを削除できます。node -e や node -p では REPL と同じく fs のインポートは不要です。また、fs.rmSync にした理由は、fs.rm は ,()=>{} のぶん、fs.promises.rm は .promises のぶん若干長いためです。
fs.rm 系に再帰的削除オプションが追加されたため、fs.rmdir 系の recursive オプションは v16.0.0 で deprecated になりました。将来的にこのオプションは指定しても無視されることになります。
[nix-shell:~/fs]$ node -v
v16.1.0
[nix-shell:~/fs]$ node -e "fs.rmdirSync('bin', {recursive: true})"
(node:11973) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead
(Use `node --trace-deprecation ...` to show where the warning was created)
fs.rm が現行 LTS すべてで使えるようになるのは Node.js v12 が EOL になる 2022-04-30 以降です。それか v12 に fs.rm がバックポートされるかもしれません。
参考リンク
ここで fs.rmdir の recursive を知ってドキュメントを見に行ったら deprecated になっててびっくりしたのがこの記事を書いたきっかけです。
Discussion