再エクスポートとは何か(まずイメージから)
再エクスポート(re-export)は、
「他のモジュールから import したものを、そのまま(または名前を変えて)もう一度 export し直すこと」 です。
簡単に言うと:
- A ファイルで何かを定義する
- B ファイルで A から import して、それをそのまま export(再エクスポート)する
- C ファイルは、A ではなく B からまとめて import できる
という流れです。
// math/add.js
export function add(a, b) {
return a + b;
}
JavaScript// math/index.js
export { add } from "./add.js"; // 再エクスポート
JavaScript// main.js
import { add } from "./math/index.js"; // add.js を意識せず使える
JavaScriptここが重要です。
再エクスポートは、「内部構造は細かくファイル分けしつつ、外に見せる入口はシンプルにする」ための仕組みです。
大きくなってきたプロジェクトほど、これが効いてきます。
基本形:export { 名前 } from “モジュール”
特定のものだけを再エクスポートする
一番シンプルな再エクスポートは、この形です。
export { 名前 } from "./path.js";
JavaScript具体例を見ます。
// math/add.js
export function add(a, b) {
return a + b;
}
JavaScript// math/sub.js
export function sub(a, b) {
return a - b;
}
JavaScript// math/index.js
export { add } from "./add.js"; // add を再エクスポート
export { sub } from "./sub.js"; // sub を再エクスポート
JavaScript// main.js
import { add, sub } from "./math/index.js";
console.log(add(2, 3)); // 5
console.log(sub(5, 1)); // 4
JavaScriptmain.js から見ると、add.js と sub.js の存在を知らなくても、math/index.js だけ見ておけば必要なものが揃う、という状態になっています。
ここが重要です。
「内部の細かいファイル名は隠し、math/index.js を窓口にする」
これが再エクスポートの基本的な使い方です。
別名をつけて再エクスポートする(as)
再エクスポート時に名前を変えることもできます。
// math/add.js
export function add(a, b) {
return a + b;
}
JavaScript// math/index.js
export { add as plus } from "./add.js";
JavaScript// main.js
import { plus } from "./math/index.js";
console.log(plus(2, 3)); // 5
JavaScript元のモジュールでは add という名前でも、
外に見せる名前を plus に変えられます。
まとめて再エクスポート:export * from “モジュール”
「そのモジュールの名前付き export を全部まとめて外に流す」
export * from "./x.js" は、
「そのモジュールの名前付き export を全部、このモジュールからも export する」 という意味です。
// math/basic.js
export function add(a, b) { return a + b; }
export function sub(a, b) { return a - b; }
JavaScript// math/advanced.js
export function mul(a, b) { return a * b; }
export function div(a, b) { return a / b; }
JavaScript// math/index.js
export * from "./basic.js";
export * from "./advanced.js";
JavaScript// main.js
import { add, sub, mul, div } from "./math/index.js";
console.log(add(1, 2), mul(3, 4));
JavaScriptindex.js が「basic と advanced から export されたものを全部まとめて再エクスポートする」役目です。
ここが重要です。export * は「名前付き export だけが対象」です。
default export は含まれません(後で触れます)。
名前がかぶるときの注意
もし複数のモジュールから export * していて、
同じ名前の export が存在すると、どれが正しいか分からずエラーになります。
// a.js
export function hello() {}
JavaScript// b.js
export function hello() {}
JavaScript// index.js
export * from "./a.js";
export * from "./b.js"; // hello が重複 → エラー
JavaScriptこういうときは、export * ではなく、
「どの名前を再エクスポートするか」を厳選したほうが安全です。
default export を再エクスポートする
default をそのまま流し直す
default export も再エクスポートできます。
形が少し違います。
export { default } from "./Module.js";
JavaScript例を見てみます。
// User.js
export default class User {
constructor(name) {
this.name = name;
}
}
JavaScript// index.js
export { default as User } from "./User.js";
JavaScript// main.js
import { User } from "./index.js";
const u = new User("Alice");
JavaScriptポイントは次の通りです。
default自体を名前付きで再エクスポートするときはdefault as 名前と書く- こうすると、「index.js の名前付き export として User が使える」ようになる
default をそのまま default として流したいときはこうも書けます。
// index.js
export { default } from "./User.js";
JavaScriptこの場合、index.js の default export になります。
// main.js
import User from "./index.js";
JavaScript再エクスポートを使う場面と設計の考え方
「バレル(barrel)モジュール」で入口を一本化する
現場では、index.js などの「まとめ役」モジュールを作って、
そこから再エクスポートするパターンがよく使われます。
これを「バレル(barrel)モジュール」と呼ぶことがあります。
例えば、models ディレクトリがあったとします。
models/
User.js
Post.js
Comment.js
index.js
// models/User.js
export default class User { /* ... */ }
// models/Post.js
export default class Post { /* ... */ }
// models/Comment.js
export default class Comment { /* ... */ }
JavaScript// models/index.js
export { default as User } from "./User.js";
export { default as Post } from "./Post.js";
export { default as Comment } from "./Comment.js";
JavaScriptこうしておくと、外からはこう書けます。
// main.js
import { User, Post, Comment } from "./models/index.js";
// あるいは "./models" だけでいける設定も多い
JavaScriptここが重要です。
再エクスポートを使って「まとめ役」を作ると、
他のファイルは「細かいファイル構成」を知らなくてもよくなります。
この「依存先をシンプルにする」のが、再エクスポートの最大のメリットです。
内部構造を変えても外の import を壊さない
例えば、最初はこんな構成だったとします。
// math.js
export function add(a, b) { /* ... */ }
export function sub(a, b) { /* ... */ }
JavaScript他のファイルではこう import していました。
import { add, sub } from "./math.js";
JavaScript後から、「中身をファイル分割したい」と思ったとします。
math/
add.js
sub.js
index.js
// math/add.js
export function add(a, b) { /* ... */ }
// math/sub.js
export function sub(a, b) { /* ... */ }
// math/index.js
export { add } from "./add.js";
export { sub } from "./sub.js";
JavaScriptこれでも、外の import はそのままにできます。
// main.js
import { add, sub } from "./math/index.js";
// 設定によっては "./math" だけで済む
JavaScript外側のコードから見れば「math モジュール」が提供している add / sub に変わりはないので、
内部をどう分割しようが関係ありません。
再エクスポートは、
「内側の構造を自由に変えられる余地を残す」
という設計上の自由度をくれます。
実践的な再エクスポートの書き方パターン
複数モジュールの名前付き export を集約する
// utils/string.js
export function capitalize(str) { /* ... */ }
export function trimAll(str) { /* ... */ }
// utils/number.js
export function clamp(value, min, max) { /* ... */ }
export function randomInt(min, max) { /* ... */ }
JavaScript// utils/index.js
export * from "./string.js";
export * from "./number.js";
JavaScript// main.js
import { capitalize, randomInt } from "./utils/index.js";
JavaScriptこの形だと、utils/index.js を開くだけで、
「どのユーティリティが外に公開されているか」が一発で分かります。
default + 名前付きを混ぜて再エクスポートする
// api/request.js
export default function request(url, options) { /* ... */ }
// api/helpers.js
export function buildUrl(path) { /* ... */ }
export function parseResponse(res) { /* ... */ }
JavaScript// api/index.js
export { default as request } from "./request.js";
export * from "./helpers.js";
JavaScript// main.js
import { request, buildUrl } from "./api/index.js";
JavaScriptrequest は default を名前付きとして再エクスポート、buildUrl などは export * でまとめて流している例です。
つまずきやすいポイントと注意
「再エクスポート = import してから export」ではない書き方
もちろん、こう書いても再エクスポートに近いことはできます。
// index.js
import { add } from "./add.js";
export { add };
JavaScriptただ、ES モジュールではこれを一気に書いた形が export { add } from "./add.js"; です。
手順としては同じですが、後者の方が「これは再エクスポートだ」と一目で伝わります。
できるだけ、「from を伴う export は再エクスポート」と体で覚えておくと読みやすいです。
default は export * には含まれない
さきほど少し触れましたが、もう一度強調します。
// someModule.js
export default function main() {}
export function helper() {}
JavaScript// index.js
export * from "./someModule.js";
JavaScriptこのとき、再エクスポートされるのは helper だけです。main(default)は流れてきません。
default も出したいなら、明示的に書きます。
export { default as main } from "./someModule.js";
JavaScriptまとめ
再エクスポートの核心は、
「モジュールの中身(他モジュールの export)を、そのまま(または名前を変えて)外に流すことで、“入口”を整理する」 ことです。
押さえておきたいポイントをまとめると:
export { 名前 } from "./x.js";で特定の export を再エクスポートできるexport * from "./x.js";で、そのモジュールの名前付き export を全部再エクスポートできるexport { default as 名 } from "./x.js";で default を名前付きとして外に出せる- index.js や “barrel” モジュールを作って、再エクスポートで入口を一本化すると、import 側がスッキリする
- 内部のファイル構成を変えても、再エクスポートの窓口さえ保てば外のコードを壊さずに済む
最初は小さなディレクトリ(例えば models/ や utils/)を作って、
その中にいくつかファイルを分け、index.js で再エクスポートしてみてください。
「中は細かく、外からはシンプルに」というモジュール設計の気持ちよさが、感覚で分かってくるはずです。
