2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
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.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05