毎日、Node.js(あるいはBun?)をシバいているエンジニアさんこんにちは。
今回の話は普段我々があまり意識をしていないNode.js系におけるビルドの話になります。
JavaScriptってブラウザネイティブで動くはずなのになぜビルドする必要があるのでしょうか?
他言語のビルドの話も通づるところはありますが、入門編として以下の話を目に通しておくとJavaScriptアプリをわざわざビルドすることに対しての理解がより深まると思います。
アプリケーションのチャンク戦略
Minify
Node.jsにより、ライブラリーを簡単に導入できるようになり勢いを増したJavaScript。
しかし、ここで大きな問題に直面します。
JavaScriptのファイル容量が多すぎ問題
ライブラリーをどんどん入れられるようになるとその分だけJavaScriptの容量が肥大化して、パフォーマンスに影響を及ぼすことになります。
ここで取った一つの戦略はJavaScriptを圧縮することです。
仕組みは難しいですが概念としては簡単です。
例えば”hogehoge”という変数を”h”と縮めたり、不要な改行やインデントを削除するだけです。
バンドル
もう一つ困ったことが発生します。
それはJavaScriptのファイルが多すぎる問題です。
これはhttp1.1の仕様ですが、1つのURL(オリジン)に対して2つのファイルを送受信できるものです。(Chromeは行儀悪く6つ)
つまり、JavaScriptを何個も受ける取ると通信的なオーバーヘッドが生まれるわけです。
このオーバーヘッドを無くすために出来るだけ無駄なく一つのファイルにまとめてしまうのがバンドルです。

参考

チャンク分割
しかし、前述のバンドルで満足してしまうと特にSPAでは足枷となることになります。
HTTP1.1ではJavaScriptのファイルを出来るだけまとめてしまうことで高速化を行ってましたがHTTP2で送受信の多重化ができるようになりました。
このことで今度はJavaScriptのオーバーヘッドのほうが深刻な問題となりました。
- JavaScriptのファイルが読み込まれるまでページを表示できない
- ページに不要なJavaScriptもバンドルされている分、読み込みに時間がかかる
このため、次に効率良くまとまったJavaScriptを分割してしまいます。せっかくまとめたのに
const SomeComponent = lazy(load)
const Foo = () => import('./Foo.vue')
({
manualChunks: {
lodash: ['lodash']
}
});
他にもありますが、上記を駆使して効率よくJavaScriptを分割します。
チャンク戦略まとめ
実はたったの3ステップでJavaScriptアプリのパフォーマンスは最適化できます。
- バンドル(ライブラリの依存関係を解決・整理してまとめる)
- チャンク分割(効率よくファイルを分ける)
- Minify(JavaScriptのファイルサイズを削減する)
たとえば、私の簡単なポートフォリオサイトでもチャンクを画像化すると以下になります。
https://github.com/patatan168/portfolio_front

Node.jsの互換性
ECMAScript

ECMAScriptとはEcma Internationalという国際的な標準化団体が制定したJavaScriptの標準規格(ECMA-262)のことを示します。
ブラウザ乱立時代、JavaScriptの仕様がブラウザごとに大きく異なりました。
そのため、ブラウザによっては誤作動が多発し、JavaScriptの信頼は地に落ちていました。
これを解決するために中立なEcma Internationalという団体により、各ブラウザのJavaScriptの仕様を統一することにしました。
現在でも以下のようにJavaScriptのエンジンは異なりますが、ECMAScriptのおかげで、昨今のJavaScriptはどのブラウザでも安定して動作するようになっています。
| Web Browser | Rendering Engine | JavaScript Engine |
|---|---|---|
| Chrome | Blink | V8 |
| Firefox | Gecko | SpiderMonkey |
| Safari | Webkit | JavaScriptCore |
毎年更新されるECMAScript
| Standard | Date |
|---|---|
| EcmaScript 1st | June 1997 |
| EcmaScript 2nd | August 1998 |
| EcmaScript 3rd | December 1999 |
| EcmaScript 5th | December 2009 |
| EcmaScript 5.1th | June 2011 |
| EcmaScript 2015 | June 2015 |
| EcmaScript 2016 | June 2016 |
| EcmaScript 2017 | June 2017 |
| EcmaScript 2018 | June 2018 |
| EcmaScript 2019 | June 2019 |
| EcmaScript 2020 | June 2020 |
| EcmaScript 2021 | June 2021 |
| EcmaScript 2022 | June 2022 |
| EcmaScript 2023 | June 2023 |
| EcmaScript 2024 | June 2024 |
| EcmaScript 2025 | June 2025 |
上記の細長い表のように
ECMAScriptは2015年以降、毎年6月にアップデートされています。
何がどう変わったのか毎年仕様を追うのがすごく大変ですね…。
Babel

毎年更新されるECMASCript。
仕事熱心なのは良いのですが、これもなかなかの弊害を生んでいます。
- JavaScriptのエンジンが最新の規格に対応していない場合がある
- 古いバージョンのブラウザでは最新の記法が動作しない
これを解消するJavaScriptのコンパイラーBabelが登場しました。
Babelの役割は以下になります。
- 新しい規格の記法を古い記法に変換する
- TypeScriptやフレームワーク特有の記法をJavaScriptに変換する
Babelは機械語に変換をするコンパイラーと異なり、
JavaScript=>JavaScriptの変換です。
人によっては同じ言語同士で変換しているのでコンパイラーと区別するために、
トランスパイラーと呼んでいる人もいるようです。
特に組み込み系のシステムでは、お客様のブラウザーが古いこともあるので、Babelを導入して、環境によるトラブルを避ける用途が期待されます。
互換のまとめ
- ECMAScriptのお陰でどのブラウザでも均一にJavaScriptが動作するようになった
- ECMAScriptは毎年更新される
- 仕様が毎年更新されるので、古い規格に変換するコンパイラーが登場した
ECMAScriptのお陰でJavaScriptは広く使われるようになりました。
しかし、毎年規格が更新されるので一部のシステムでは互換性に配慮する必要がありました。
その問題を解決するためにBabelという素晴らしい技術が発明されることになりました。
全体のまとめ
いかがでしたでしょうか?
JavaScriptをわざわざコンパイルする意味は、ライブラリのチャンク戦略や互換性を上手いことやっているんだなと掴んでいただければOKです。
他にも例えばライブラリ独自のファイル形式 (JSX 、Vueなど)をコンパイルするというのもありますが、記事を書いている途中にどうやってこの2つはJavaScriptに変換しているんだ・・・というのに興味を持ったので、そこにもスポットライトを当てていきたいと思います。

