メインコンテンツに移動

ESMとは?JavaScript モジュールの基本から import・export・CommonJS との違いまで詳しく解説

JavaScript をある程度書くようになると、ほとんどの人が一度は「コードをどう分ければよいのか」という問題にぶつかります。小さなサンプルであれば、ひとつのファイルへ関数も定数も処理も全部まとめて書いてしまっても動きますし、最初の学習段階ではそのほうが分かりやすいこともあります。しかし、実際の開発では、機能が増えるにつれてコード量も増え、役割の違う処理が同じ場所に集まりやすくなります。そうなると、どこで何が定義されているのかが見えにくくなり、修正の影響範囲も追いにくくなります。たとえば、API 通信の処理、画面表示のロジック、utility 関数、設定値、共通コンポーネントなどがひとつのファイルや少数の巨大ファイルへ集中していると、少しの変更でも全体を読み直さなければならなくなります。こうした問題を整理するために重要なのが、モジュールという考え方です。

そして、そのモジュールを JavaScript 標準のやり方で扱うための仕組みが ESM です。ESM は ECMAScript Modules の略で、いまのフロントエンド開発でも Node.js 開発でも、非常に重要な基礎知識になっています。なぜなら、ESM を理解すると、単に importexport が書けるようになるだけではなく、ファイル分割の考え方、依存関係の見方、再利用しやすいコードの組み方、tree shaking のような build 最適化の前提まで理解しやすくなるからです。つまり、ESM は文法トピックに見えて、実際には設計、保守、配布、最適化といった多くの実務テーマにつながっています。本記事では、ESM とは何かを基礎から丁寧に整理しながら、実際のコード例も交えて、ブラウザと Node.js の両方の視点から分かりやすく解説していきます。

1. ESMとは

ESM とは、JavaScript における公式なモジュール仕様です。より正確に言うと、ECMAScript という JavaScript の標準仕様の中で定義されているモジュール機能を指します。昔の JavaScript では、コードを複数ファイルに分けたとしても、それを標準的な方法で整理して読み込む仕組みが十分には整っていませんでした。そのため、ブラウザでは <script> タグを順番に並べたり、Node.js では CommonJS のような仕組みを使ったり、あるいはツールやライブラリ独自のモジュール方式に頼ったりする必要がありました。しかし、アプリケーションが大きくなり、フロントエンドもバックエンドも複雑になるにつれて、「言語そのものが標準のモジュール方式を持つべきだ」という流れが強くなりました。その答えが ESM です。

ESM のいちばん基本的な役割は、ファイル間で「何を外へ公開するのか」と「何を外から受け取るのか」を明示できるようにすることです。これにより、コードの責務をファイル単位で分けやすくなり、依存関係も追いやすくなります。たとえば、計算ロジックだけをまとめたファイル、API 呼び出しだけをまとめたファイル、UI コンポーネントだけをまとめたファイルを作り、それぞれ必要なものだけを import して使うことができます。こうした設計がしやすくなることで、コード全体の見通しもよくなり、将来的な変更にも対応しやすくなります。つまり、ESM は単なる新しい書き方ではなく、JavaScript を大きなアプリケーションでも扱いやすくするための標準的な土台です。

1.1 モジュールとは何か

モジュールとは、ひとことで言えば「役割ごとに分けられたコードのまとまり」です。たとえば、文字列処理だけを集めたファイル、日付処理だけを集めたファイル、認証処理だけを集めたファイル、あるいは Button コンポーネントだけを定義したファイルなどは、どれもモジュールとして考えられます。モジュール化の目的は、コードを整理しやすくし、必要なものを必要な場所から使えるようにすることです。プログラムが小さいうちは、1 ファイルに全部書いてもそれほど問題にはならないかもしれません。しかし、機能が増えていくと、コードの責務を分けずにひとつの場所へ詰め込むことは、読みやすさや保守性の面でかなり不利になります。モジュールは、そうした「大きくなったコードをどう扱うか」という問題への基本的な答えです。

さらに、モジュールは単なるファイル分割ではなく、「何を外へ公開し、何を内部へ閉じるか」を決める境界でもあります。たとえば、ある utility ファイルの中に 10 個の関数があったとしても、そのうち本当に他の場所から使う必要があるのが 3 個だけなら、残りは内部実装として隠しておくほうが安全です。何でもかんでも外へ見せてしまうと、他のファイルがその内部実装へ依存しやすくなり、後から変更しにくくなります。つまり、モジュールはコードを分けるだけでなく、依存関係と公開範囲を整理するための重要な設計単位でもあります。

1.2 ESM が標準モジュール方式として重要な理由

ESM が重要なのは、「いまよく使われているから」というだけではありません。もっと大きいのは、JavaScript の標準仕様として定義されていることです。つまり、特定のライブラリやツールだけで通用する独自ルールではなく、言語としての JavaScript が正式に持っているモジュールの仕組みだということです。これによって、ブラウザでも Node.js でも、基本的には同じ考え方でモジュールを扱いやすくなります。もちろん環境ごとの違いはありますが、「標準の import / export をベースに設計する」という共通の前提があるだけでも、開発体験はかなり安定します。

もう一つ重要なのは、ESM が静的解析と相性がよいことです。importexport が明示的に書かれているため、bundler や build tool は「どのファイルがどこで使われているのか」を追いやすくなります。これにより、未使用コードを削除する tree shaking や、依存関係の最適化もしやすくなります。つまり、ESM の価値は単に標準であることだけでなく、現代的な開発ツールや最適化フローとも非常に相性がよいことにあります。そのため、ESM を理解することは、JavaScript 文法を覚える以上に、現代の開発基盤そのものを理解することにもつながります。

2. ESM の基本構文

ESM の基本構文は、JavaScript の他の構文に比べてもかなり分かりやすい部類です。外へ公開したいものには export を付け、別のファイルから使いたいものは import で読み込みます。このルールが非常に素直なので、最初に見たときからある程度意味を推測しやすいのが特徴です。以前の CommonJS では module.exportsrequire() という少し独特な書き方を覚える必要がありましたが、ESM では「出す」「受け取る」という関係がかなり直接的に表現されます。これによって、コードを後から読む人にとっても、どのファイルが何を依存しているのかを理解しやすくなります。

また、ESM の構文がよいのは、依存関係がコード上の早い段階で見えることです。一般的には import はファイルの先頭に書かれるため、「このファイルは何を使っているのか」が冒頭でかなり分かります。これは実務でかなり重要です。コードの途中まで読まないと依存関係が分からない構造より、最初にざっと全体像を把握できる構造のほうが、レビューもしやすく、修正時の影響範囲も読みやすいからです。つまり、ESM の基本構文は、単に新しい文法というだけでなく、依存関係を見える形で管理しやすくするための実務的な価値を持っています。

2.1 export の基本

export は、そのファイルの外側から使えるものを明示するために使います。関数、定数、クラス、オブジェクトなど、外へ見せたい値に対して export を付けることで、別のファイルから import できるようになります。逆に言えば、export されていないものはそのファイルの内部だけで閉じたものとして扱われます。この仕組みはとても重要です。なぜなら、「何を外へ公開するか」を自分で選べるからです。モジュールの中にいろいろな処理を書いていたとしても、本当に必要なものだけを公開すれば、他のファイルが内部実装へ過剰に依存することを防ぎやすくなります。

たとえば、次のようなファイルがあるとします。

// math.js export const PI = 3.14159; export function sum(a, b) {  return a + b; }

このファイルでは、PIsum が外へ公開されています。逆に、もしこの中に const internalValue = 10; のような変数を書いても export を付けなければ、他のファイルから直接使うことはできません。つまり、export は単に「外から使えるようにする」だけでなく、そのモジュールの公開 API を定義する役割も持っています。何でも export すればよいのではなく、「何を外へ見せるべきか」を考えて設計することが、モジュール設計では非常に大切です。

2.2 import の基本

import は、別のファイルで export された値を取り込むために使います。これにより、同じロジックを何度も書かずに再利用できるようになりますし、責務ごとに分かれたモジュールを組み合わせてプログラムを組み立てられるようになります。実務では、この import の設計がそのまま依存関係の設計になります。どのファイルがどのモジュールに依存しているのか、どのレイヤがどこまでを参照してよいのか、といったことも、最終的には import の形で表れます。つまり、import は単なる読み込み構文ではなく、コードのつながり方そのものを表すものです。

先ほどの math.js を使うなら、次のように書けます。

// app.js import { PI, sum } from "./math.js"; console.log(PI); console.log(sum(2, 3));

ここで重要なのは、math.js から必要なものだけを選んで取り込めることです。全部を無差別に読み込むのではなく、「このファイルでは PIsum が必要だ」ということが明示されています。この明示性があるからこそ、後からコードを読む人も「このファイルは何に依存しているのか」が把握しやすくなります。また、build tool 側もどの export が使われているか追いやすくなるため、tree shaking のような最適化にもつながります。つまり、import は使いたいものを受け取るだけの構文ではなく、依存関係を明文化するための重要な手段です。

3. named export と default export の違い

ESM には、公開方法として大きく分けて named exportdefault export の二つがあります。どちらもモジュールの値を外へ出すための方法ですが、意味や使われ方にはかなり違いがあります。この違いを理解していないと、ファイルごとの export 方針がばらばらになったり、import 側の書き方が不統一になったりしやすくなります。とくにチーム開発やライブラリ設計では、「なぜこのファイルは default なのか」「なぜこちらは named なのか」が曖昧だと、API 全体の一貫性が崩れやすくなります。つまり、named と default の違いは単なる文法差ではなく、モジュールの見せ方に関わる設計の話でもあります。

また、どちらが絶対によいというわけでもありません。ユースケースによって向き不向きがあります。ただ、実務では「とりあえず default export」に流れやすい一方で、named export のほうがモジュール全体の公開内容を明確にしやすいという利点もあります。だからこそ、両者の違いを理解したうえで、場面に応じて使い分けることが大切です。ESM を正しく使うというのは、import / export の文法を知ることだけではなく、「どういう公開方法が自分たちのコードベースに合うか」を判断できることでもあります。

3.1 named export の特徴

named export は、その名のとおり名前付きで値を公開する方式です。複数の関数や定数を同じファイルから外へ出したいときに自然で、どの値が公開されているのかがかなり明示的になります。利用側も同じ名前で import するため、モジュールの API が読みやすいです。とくに utility モジュールや、関連する小さな関数群をまとめたファイルでは、この形式がとても相性よく機能します。何が出ていて何を使っているのかが名前ベースで揃うため、大きくなったコードベースでも比較的見通しを保ちやすいです。

次のような書き方が named export の基本です。

// string-utils.js
export function upperCase(text) {
  return text.toUpperCase();
}

export function lowerCase(text) {
  return text.toLowerCase();
}

 

// app.js
import { upperCase, lowerCase } from "./string-utils.js";

console.log(upperCase("hello"));
console.log(lowerCase("WORLD"));

この形の利点は、「このモジュールは複数の機能を名前付きで提供している」ということがすぐ分かることです。また、IDE 補完やリファクタリングとも相性がよく、何が公開 API なのかをかなり明確にできます。つまり、named export は複数の値を整理して公開したいときに非常に扱いやすい形式です。

3.2 default export の特徴

default export は、そのモジュールの中心となる値を 1 つだけデフォルトで公開する方式です。たとえば、1 ファイル 1 コンポーネント、1 ファイル 1 クラス、1 ファイル 1 メイン関数のような構成では、default export が自然に感じられることがあります。利用側では好きな名前で import できるため、見た目がシンプルになるのも特徴です。小さなサンプルや単一責務のモジュールでは、かなり直感的に使えることがあります。

たとえば、次のように書けます。

// logger.js
export default function log(message) {
  console.log("[LOG]", message);
}

 

// app.js
import log from "./logger.js";

log("hello");

ただし、default export は import 側で自由に名前を付けられるため、コードベース全体で命名がぶれやすいという面もあります。同じモジュールをある場所では log、別の場所では logger、別の場所では printLog として読んでしまうこともできるため、一貫性が落ちやすいのです。また、barrel export や re-export が増えると、named export より見通しが悪くなることもあります。つまり、default export は便利な一方で、API 設計や命名の統一を意識しないと、規模が大きくなったときに扱いにくくなることがあります。

4. CommonJS との違い

ESM を理解するうえで、多くの人が気になるのが CommonJS との違いです。とくに Node.js を触ってきた人や、少し古めの JavaScript の記事やライブラリを見ている人なら、require()module.exports という書き方に馴染みがあるかもしれません。実際、JavaScript の実務では長い間 CommonJS が広く使われてきました。そのため、いまでも古いパッケージや既存プロジェクトのコードには CommonJS が多く残っています。つまり、ESM を理解するということは、同時に CommonJS との違いを理解することでもあります。

この違いは、単なる文法の差ではありません。ESM は言語標準として設計され、静的解析しやすい構造を前提にしています。一方、CommonJS は Node.js のサーバーサイド文脈で広く使われてきた仕組みで、実行時の柔軟性があります。そのため、build 最適化や tree shaking の観点では ESM のほうが有利なことが多い一方で、CommonJS は歴史的な資産が非常に多いです。つまり、両者は単純な優劣ではなく、成り立ちも強みも少し違います。その違いを知っておくと、なぜ modern frontend で ESM が重視されるのかもかなり理解しやすくなります。

4.1 CommonJS の書き方

CommonJS では、値を公開するときに module.exports を使い、他ファイルから読み込むときに require() を使います。Node.js ではこの方式が長い間標準的でした。そのため、バックエンド系のコードや古いツールチェーンを読むと、いまでも頻繁に出てきます。CommonJS のよいところは、Node.js の中で非常に自然に広まったこともあって、シンプルに使えた点です。ただし、実行時に読み込む形なので、ESM ほど静的解析しやすくはありません。

たとえば、次のような形です。

// math.cjs
const PI = 3.14159;

function sum(a, b) {
 return a + b;
}

module.exports = { PI, sum };

// app.cjs
const { PI, sum } = require("./math.cjs");

console.log(PI);
console.log(sum(1, 2));

この形でももちろんモジュール化はできますし、Node.js ではいまでも十分使えます。ただし、ESM と比べると「何を外へ公開しているか」「何を使っているか」が build tool から見て追いにくい部分があります。つまり、CommonJS は今でも重要ですが、現代的な最適化の文脈では ESM のほうが扱いやすい場面が多いです。

4.2 ESM と CommonJS の考え方の違い

ESM と CommonJS の違いを理解するときに大事なのは、見た目の書き方だけを比べないことです。ESM は最初から import / export を前提とし、どの依存があるのかを静的に追いやすいよう設計されています。一方で CommonJS は require() を実行時に呼ぶため、より柔軟ではありますが、そのぶん build tool にとっては解析しづらい部分もあります。この違いは、tree shaking や bundle size 最適化の場面で特に効いてきます。

また、Node.js の世界では長い間 CommonJS が中心だったため、ESM は「単に新しい書き方」ではなく、「既存文化との橋渡しをしながら移行している仕組み」という面もあります。そのため、実務では ESM と CommonJS が混在していることも珍しくありません。つまり、ESM を正しく理解するには、「なぜいま ESM が重視されているのか」と同時に、「なぜ CommonJS が今でも残っているのか」も見ておくと理解が深まりやすいです。

5. ブラウザでの ESM の使い方

ESM は build tool の中だけで使うものだと思われがちですが、実際にはブラウザでもそのまま使えます。これはかなり重要なポイントです。JavaScript の標準機能としての ESM は、ブラウザが直接理解できるため、<script type="module"> を使えば import / export ベースでコードを分けて読み込めます。これによって、以前のように複数の <script> タグを HTML へ並べて読み込み順を気にし続ける必要が減りますし、小さな学習用サンプルや簡単なアプリであれば、bundler なしでもモジュール的にコードを整理できます。つまり、ESM はツールありきの仕組みではなく、ブラウザ標準の一部として理解したほうがよいです。

ただし、ブラウザでの ESM には独自の注意点もあります。Node.js や bundler 環境のようにモジュール解決を柔軟にやってくれるわけではないため、パスはかなり明示的に書く必要があります。拡張子も含めて書かなければならない場面が多く、import の書き方には少し厳密さが求められます。つまり、ブラウザで ESM を使うこと自体は簡単ですが、「Node.js と同じ感覚」で書くと意外とつまずきやすいです。ブラウザ標準としての ESM を知るなら、その解決ルールも一緒に押さえておくべきです。

5.1 script type="module"

ブラウザで ESM を使うときの基本は、<script type="module"> を使うことです。これを付けると、そのスクリプトは通常の script ではなく、モジュールとして解釈されます。そのため、script 内で import を書いたり、別ファイルの export を取り込んだりできるようになります。学習段階では、これだけでも「ESM は bundler がなくてもブラウザで動くのだ」と理解しやすくなります。

たとえば次のように書けます。

<!doctype html>
<html>
 <body>
   <script type="module">
     import { sum } from "./math.js";
     console.log(sum(10, 20));
   </script>
 </body>
</html>

この形のよいところは、HTML から直接 ESM の仕組みを体験できることです。小さな検証やサンプルでは非常に分かりやすいですし、「モジュールをブラウザがどう扱うのか」をそのまま確認できます。つまり、type="module" は ESM をブラウザで使うための入口であり、標準機能としての ESM を実感するにはとてもよい方法です。

5.2 ブラウザで注意すべきパス解決

ブラウザで ESM を使うときに多くの人が引っかかるのが、パスの指定です。ブラウザは Node.js のように package 解決を柔軟にやってくれるわけではないため、基本的には ./math.js のように相対パスをかなり明示的に書く必要があります。つまり、拡張子まで含めてはっきり指定しないと、ブラウザはどのファイルを読めばよいのか判断できません。この点は bundler に慣れていると見落としやすいです。

この違いを知らないと、「Vite では動いたのに素のブラウザでは動かない」「Node.js の例をそのまま書いたのに import 解決できない」といったことが起こりやすくなります。つまり、ブラウザでの ESM はとても便利ですが、その便利さは「シンプルな解決ルールの上にある」ということを理解しておく必要があります。ブラウザと Node.js の両方で ESM を使うつもりなら、このパス解決の違いは早めに押さえておくとかなり役立ちます。

6. Node.js での ESM の使い方

Node.js でも、現在は ESM を正式に使うことができます。ただし、ブラウザのように「type="module" を付ければ終わり」というほど単純ではなく、Node.js ではそのファイルを ESM として扱うのか、CommonJS として扱うのかをある程度明示する必要があります。代表的なのは package.json"type": "module" を書く方法です。これによって .js ファイルが ESM として解釈されます。逆に、CommonJS を使いたい場合には .cjs を使うなど、拡張子や package 設定で区別することになります。つまり、Node.js で ESM を使うときは、コードの書き方だけでなく、「Node がどう解釈するか」という実行環境のルールも一緒に理解しておく必要があります。

また、Node.js の ESM はブラウザ標準の延長線上にありますが、CommonJS 文化が長かったため、完全に同じ感覚で扱えるわけではありません。既存ライブラリの多くが CommonJS ベースだったり、Node.js 独自のモジュール解決の癖があったりするため、実務では ESM と CommonJS の橋渡しを意識する場面もあります。つまり、Node.js における ESM は「JavaScript 標準の知識」だけでなく、「Node.js 環境としての扱い」を知って初めて実用的になるものです。

6.1 package.json の type 設定

Node.js で .js ファイルを ESM として扱うには、一般的に package.json"type": "module" を書きます。これがあることで、Node.js はその package の .js ファイルを ESM として解釈するようになります。逆に、この設定がなければ .js が CommonJS として扱われることもあるため、意図した import / export がそのまま動かないことがあります。つまり、Node.js では「ESM の文法を書いた」だけでは不十分で、「この package は ESM です」と環境へ伝える必要があるわけです。

例としては次のようになります。

{  "type": "module" }

この一行はとても小さく見えますが、Node.js のモジュール解釈を大きく変える重要な設定です。実務で ESM ベースのライブラリやアプリケーションを書くなら、ここを理解していないと「なぜ import が動かないのか」「なぜ require と混ざるのか」で混乱しやすくなります。つまり、Node.js の ESM はコードの中だけでなく、package 設定まで含めて成立しています。

6.2 Node.js での import 例

Node.js で ESM を使う場合、基本的な import / export の書き方はブラウザとよく似ています。たとえば、次のように書けます。

// math.js
export function multiply(a, b) {
 return a * b;
}

// app.js
import { multiply } from "./math.js";

console.log(multiply(4, 5));

このように、Node.js でも標準的な ESM 構文でモジュールを読み込めます。ただし、Node.js ではブラウザと同じく拡張子をきちんと書く必要があることが多く、そこを省略して動くことを期待すると混乱しやすいです。また、古い CommonJS ライブラリと混在するプロジェクトでは、ESM だけですべて完結しないこともあります。つまり、Node.js で ESM を使うときは、「ブラウザと似ているが、Node の実行ルールも持っている」と理解しておくと実務でかなり役立ちます。

7. ESM と tree shaking の関係

ESM が現代のフロントエンド開発で特に重視される理由の一つが、tree shaking と非常に相性がよいことです。tree shaking とは、ビルド時に未使用コードを解析して bundle から落とす最適化のことですが、その前提として「どの export がどこで使われているか」を bundler が理解しやすい必要があります。ESM は importexport が静的に書かれるため、こうした依存関係を追いやすく、未使用部分を落としやすいのです。つまり、ESM は単にモジュールを分けるための仕組みではなく、bundle size を小さく保つための前提にもなっています。

ただし、ここで誤解しやすいのは、「ESM で書けば自動的に tree shaking が完璧に効く」という考え方です。実際には、モジュールが副作用を持っていたり、巨大な barrel export が重い依存をまとめていたり、CommonJS が混ざっていたりすると、ESM でも思ったほど削れないことがあります。つまり、ESM は tree shaking の重要な土台ではありますが、それだけで十分条件ではありません。パッケージ設計、side effects、export の切り方まで含めて、初めて強い最適化が成立します。

7.1 なぜ ESM は静的解析しやすいのか

ESM の import / export は、基本的にコードを実行する前からどの依存があるかを把握しやすい形で書かれています。これは bundler にとって非常にありがたい性質です。どのファイルがどの export を使っているか、未使用なのはどれかを比較的安全に判断しやすくなるからです。つまり、ESM はモジュールの意味を人間に分かりやすくするだけでなく、ツールにも分かりやすい形にしているわけです。

この点は CommonJS と比べると理解しやすいです。CommonJS では require() が実行時に呼ばれるため、状況によってはどの依存が必要かを事前に完全には判断しづらいことがあります。一方で ESM は最初から構造が見えやすいため、未使用 export を落としやすくなります。つまり、ESM の重要性は人間向けの読みやすさだけでなく、ツール向けの解析しやすさにもあります。

7.2 ESM でも削れないケースがある

ESM で書いていても、必ずしもすべてがきれいに tree shaking されるわけではありません。たとえば、モジュールを import した時点でグローバルな初期化が走る、CSS import のような副作用がある、top-level barrel が重い依存をまとめて参照している、といった場合には、bundler は安全のためにコードを残すことがあります。つまり、ESM というだけで最適化が保証されるわけではなく、「削っても安全な構造」であることも必要です。

そのため、実務では ESM を採用したうえで、さらに exports 設計、sideEffects 設計、ファイル責務の分離まで気を配る必要があります。とくに component-based packages や design system を配布するときには、この差が bundle size にかなり効いてきます。つまり、ESM は very important ですが、それは出発点であって、最終的な最適化はモジュール設計全体で決まると考えるべきです。

8. 実務で ESM を理解しておくべき理由

実務で ESM を理解しておく価値は、単に importexport が書けるようになることにとどまりません。いまのフロントエンド開発では、コンポーネント分割、共通 utility の整理、ライブラリ import、dynamic import、code splitting、tree shaking、パッケージ配布といった多くの場面で ESM の理解が前提になっています。つまり、ESM を知っているかどうかで、「なぜこの書き方が好まれるのか」「なぜこのパッケージは軽いのか」「なぜこの構造は保守しやすいのか」といったことの理解度がかなり変わります。ESM は文法知識であると同時に、現代 JavaScript 開発の共通言語のようなものです。

さらに、チーム開発でも ESM を理解していることは大きな意味を持ちます。どこまでを export するべきか、shared module をどう切るか、default export と named export をどう使い分けるか、Node.js と browser 環境で何が違うのか、といった判断をするとき、ESM の基礎があると設計の会話がかなりしやすくなります。つまり、ESM の理解は「ひとりでコードを書くための知識」ではなく、「チームで読みやすく、再利用しやすく、将来も育てやすいコードを作るための知識」でもあります。JavaScript を実務で長く使うなら、ESM はかなり早い段階でしっかり押さえておくべきテーマです。

8.1 フロントエンド開発での重要性

React、Vue、Svelte、Vite、Rollup など、現代のフロントエンド開発でよく使われるツールやライブラリは、ESM と非常に相性がよい設計を前提にしています。つまり、フロントエンドの今の流れを理解するなら、ESM は避けて通れません。コンポーネントを分ける、shared function を import する、ライブラリを小さく bundle する、といった日常的な開発作業のかなり多くが、ESM の考え方の上に乗っています。

また、code splitting や tree shaking のような最適化も、ESM の理解があるとかなり読みやすくなります。なぜこの import が静的である必要があるのか、なぜこの re-export が bundle size に影響するのか、といったことも、ESM を知っていると自然につながります。つまり、フロントエンド開発における ESM は、基礎知識でありながら、そのまま高度な最適化や設計理解にもつながる重要なテーマです。

8.2 Node.js・ライブラリ開発での重要性

Node.js でも、ESM の重要性は年々高まっています。サーバーサイドのコードだけでなく、パッケージ配布や internal library の設計においても、ESM を前提にするケースはかなり増えています。とくに library author の立場では、ESM をどう配布するかが、利用側の build 最適化や tree shaking の効き方に直結するため、無視しづらいテーマです。

また、Node.js ではいまだに CommonJS と ESM が混在しているため、その違いを理解していることはかなり実務的です。古い依存パッケージを読むときにも役立ちますし、新しいライブラリを設計するときにも役立ちます。つまり、ESM はブラウザ側だけの知識ではなく、Node.js や package ecosystem 全体で見ても、かなり重要な基礎だと考えたほうがよいです。

おわりに

ESM とは、JavaScript の標準モジュール方式であり、コードを役割ごとに分け、必要なものだけを明示的に import / export できるようにする仕組みです。その価値は、単に文法が新しいことではありません。モジュールの責務を整理しやすくし、依存関係を見えやすくし、再利用しやすい構造を作りやすくし、さらに tree shaking や bundle 最適化とも非常に相性がよいという点にあります。つまり、ESM は JavaScript を大きなアプリケーションでも扱いやすくするための、非常に重要な基盤だと言えます。

実務で本当に大切なのは、ESM を importexport の書き方だけで終わらせないことです。named export と default export の違い、CommonJS との違い、ブラウザと Node.js での扱い、tree shaking との関係まで含めて理解しておくと、コードの見方も設計の考え方も大きく変わります。JavaScript を長く使っていくなら、ESM は早い段階でしっかり押さえておく価値のあるテーマです。ここが分かると、モジュール設計、ライブラリ設計、最適化設計の基礎がかなり見えやすくなります。

LINE Chat