2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
node_modules のブラックホールとの向き合い方について(全1記事)
リンクをコピー
記事をブックマーク
Naturalclar氏:よろしくお願いします。「node_modulesのブラックホールとの向き合い方」という資料で発表します。Naturalclarです。
はじめにちょっと自己紹介すると、本名はJesseと申します。現在、株式会社stand.fmというところで、音声配信アプリを作っています。React NativeでAndroid・iOS向けのアプリを作っています。また、OSS活動をいろいろとやっていて、「React Native Community」というGithub Organizationの中で、React Nativeの周辺モジュールの開発やReact Native自身のリリースに携わったりしています。
本日は、node_modules black holeにどう対処していくかというトピックです。この画像を見てもわかるとおり、node_modulesはブラックホールよりも重く、この宇宙の中で一番重いものとして知られています。
今回話すことは、けっこう軽めなトピックだと思っているんですが、ふだんnpmやyarnを使っていても解決しないことや、node_modulesを意識的に削減することで何がうれしいのか、そしてそれをどうやって行うのかについて話していこうと思います。
ご存じの方も多いとは思いますが、npm・yarnについて一言で説明すると、dependency managerです。「npm install」や「yarn install」というコマンドを叩くことで、Node.jsを開発するうえで使う外部モジュールをインストールできます。
ふだん開発するうえで「yarn install」「npm run-script」「yarn script」など、なにかしらpackage.jsonの中で作ったコマンドだけを意識すればNode.jsの開発はできると思います。
それらは、指定moduleをsemverに沿ってinstallしてれます。なので、Reactのversion 17をインストールしたい場合「yarn install react」とするとそのReactが降ってきてくれます。いろいろな人が「yarn install」を行った時に、それぞれバージョンが同じになるように、lockファイルを作ってくれます。それが「npm install」なり「yarn install」なりをした時にやってくれることです。
逆に「yarn install」だけだと、何をしてくれないのかというと、使用していないパッケージの削除だったり、例えばReactのversion 16とReactのversion 17が一緒に入っているなど、同じパッケージで重複バージョンがあったりする時に、それを勝手に削除してはくれません。また、publishされているパッケージの不要物の削除はしてくれません。
なので、JSを開発していくうえでプロジェクトを進めていくと、node_modulesは必然的に重くなっていきます。
重くなる原因は、さっきとほぼ重複しているのですが、使用していないパッケージが含まれていたり、複数バージョンが含まれていたり、パッケージの不必要なファイルを含めてpublishしてしまっていたりです。
あと、monorepoという1つのリポジトリの中に複数の子 パッケージを使用する構成にしている時に、共通で使えるパッケージを意図的にhoistするようにしないとhoistされなくて、node_modulesが重くなってしまいます。これについて一つひとつ詳しく説明していきます。
例えばpackage Aにlodashの4.17.20が依存しているとします。package Bがlodashの4.17.21に依存している状態で、package Aとpackage Bをインストールした時に、node_modulesの中は簡単に言うとこんなふうになります。これはバージョンが固定されている場合ですね。
node_modulesの中に、package Bが使っている4.17.21のlodashが入ってきて、package Aもnode_modulesに入ってきます。ただ、lodashのバージョンが違うので、package Aの中のnode_modulesの中に4.17.20のlodashが入ります。こんなふうに複数のlodashが入ってしまうケースがあります。lodash1つにつき4.7MBあるので、こういうケースがたくさんのパッケージで起こっていると、それだけ容量が増えてしまいます。
また、npmにpublishされているパッケージはあくまで人が作ったものなので、その中に不要なファイルが含まれているケースがけっこうあります。例えば、自分が作ったパッケージの使用例で、exampleフォルダみたいなものを作って、そこに使用例を記載して、そのままpublishしてしまった。または、docsがそのパッケージに含まれていて、それをpublishしてしまうと、そのパッケージをインストールした時に、node_modulesの中にexampleやdocsが含まれてしまいます。パッケージを作る人が、きちんと設定をすれば問題ないのですが、すべてのパッケージがそうではありません。こういうのもnode_modulesが重くなる原因です。
さっき言っていたmonorepoのケースですが、例えばTypeScriptは1つで57MBぐらいあります。例えば8個の子パッケージすべてでTypeScriptをインストールしていると、それだけで400MB以上の容量が使われてしまいます。これはmonorepoを使っている時限定になりますが、TypeScriptみたいな共通して使えるパッケージはrootに置いて、そこのTypeScriptをすべての子パッケージで使うようにしないと、node_modulesの容量がかなり膨れ上がってしまいます。
逆に、削減されていると何がうれしいのかについて説明します。簡単に言うと、インストール時間の削減、CI時間の短縮、monorepoのバージョンのずれによるエラー防止です。あと、コードの負債の防止などが挙げられます。
例えばインストール時間の削減。これは当たり前ですが、モジュールが増えれば、それだけインストール時間も増えます。一時期、僕がやっていたプロジェクトで、全体的にnode_modulesが6~7GBぐらいあって「yarn install」するだけで10分ぐらいかかっていました。それは後述するいろいろな削減を行ったうえで、2分ぐらいに削減できました。
また、CI時間の短縮もメリットの1つとして挙げられます。GitHub Actionsなどの従量課金制のCIサービスを使っている場合は、CI時間が延びれば延びるほど払うお金も増えてくるので、CIの時間はできるだけ抑えたいというのがあります。node_modulesの中を小さくすれば小さくするほどCIの時間も短くなって、より払うお金を減らせます。
あと、特定のパッケージに限った話なんですが、複数のバージョンが存在していると、それだけでエラーが起きてしまうパッケージがあります。僕がよく使っているReactのversion 16、React Native、webpackとかは、複数のバージョンがnode_modulesに含まれてしまうと、それだけでエラーが起きてしまうケースがあり、そういうバージョンも統一することでエラーを削減できます。
node_modulesをアップデートすることを常に意識することによって、コードの負債の防止になります。世の中、アップデートするだけでも大変なパッケージがいろいろとあります。React Nativeの場合、マイナーバージョンなどがアップデートした時に、それだけでは動かないケースが多々あるんですが、意識的にアップデートしていくことによって、あとでアップデートするのが大変ということがなくなります。
削減する方法は大きく分けて4つのステップがあります。まず、どの依存モジュールが容量を食っているかを把握する必要があります。そのうえで使用されていない依存modulesを削除したり、複数バージョンが入っているパッケージのバージョンを統一します。最後に、package上で必要ないファイルが含まれていたら、それを削除します。そのためのいろいろなツールや手法を紹介します。
どのmodulesが容量を食っているかを把握するツールはいろいろあるんですが、僕の場合は「ncdu」を使っています。画像で表示しているのは、僕がやっているとあるプロジェクトのmonorepoですが、これは確か12個ぐらいの子パッケージが入っている巨大なプロジェクトで、「yarn install」した時に最終的にnode_modulesを1.4GBに抑えられています。
また、複数バージョンのパッケージを把握するには、yarn.lockやpackage-lock.jsonを見ます。これはlodashの例ですが、lodashのsemverがいろいろと入っていて、ここにlodash 4.17.20が入っています。その次の行に、lodashの4.17.21や4.3.0が入っていて、こっちは4.17.21がインストールされているみたいなケースがあります。
ただ、これはsemverを見てみるとすべて同じバージョンを指しているので、削減できるはずです。なので、ここはyarn.lockやpackage-lock.jsonのこの部分を削除して、もう一度インストールすれば、この部分が削減されます。これだと、この部分のlodashが削減されるので、それだけで30MB削減できます。
まとめると、JavaScriptを開発するうえでnpm/yarn installすることは避けられないので、そこを最適化する必要があります。インストールの時間がかかりすぎるとそれだけでDXが悪くなるし、CIでの経費削減もできないので、ここらへんはぜひやってもらいたいと思います。
package-lock.jsonやyarn.lockは、一見人間には読めないような羅列になっているかもしれませんが、これはレビュー可能であると伝えたかったです。ちょっと駆け足になってしまいましたが、ご清聴ありがとうございました。
関連タグ:
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには