副作用インポートと polyfill を正しく理解する
はじめに
フロントエンド開発をしていると、次のようなコードを目にすることがあります。
import "./setup";
import "./polyfills";
「何も import していないのに、なぜ必要なのか?」
この記事では、副作用インポートと polyfill という概念をセットで整理し、
なぜ現代の JavaScript 開発で重要なのかを解説します。
副作用インポートとは?
副作用インポート(side-effect import) とは、
値(変数・関数・クラス)を使うためではなく、
モジュールが読み込まれたときに実行される処理そのものを目的としたimport
のことです。
基本形
import "./setup";
この書き方では、
-
setup.jsのトップレベルコードが実行される - export された値は一切使わない
という特徴があります。
「副作用」とは何か?
JavaScript における副作用とは、次のような処理です。
- グローバル変数や
window/globalThisの変更 - イベントリスナーの登録
- 初期化処理の実行
- CSS の適用
- polyfill の適用
つまり、
import しただけで、アプリの状態や実行環境が変わること
これが副作用です。
副作用インポートの具体例
初期化処理
// setup.js
console.log("アプリ初期化");
initAnalytics();
// main.js
import "./setup";
setup.js の実行自体が目的なので、副作用インポートになります。
CSS の読み込み
import "./global.css";
CSS ファイルは値を export しませんが、
import することでスタイルが適用されます。
これも典型的な副作用インポートです。
通常の import との違い
通常の import(値を使う)
import { add } from "./math";
add(1, 2);
- 目的:関数や変数などの値を使うこと
副作用インポート(実行が目的)
import "./math";
- 目的:モジュールが実行されること
- export は使わない
polyfill とは?
polyfill(ポリフィル) とは、
実行環境に存在しない JavaScript の機能を、後から追加して使えるようにするコード
のことです。
ブラウザや実行環境によっては、新しい API が存在しない場合があります。
[1, 2, 3].includes(2); // 古い環境ではエラーになる可能性
この差を埋めるために polyfill を使います。
polyfill の基本的な考え方
if (!Array.prototype.includes) {
Array.prototype.includes = function (value) {
return this.indexOf(value) !== -1;
};
}
- 機能がなければ追加する
- すでにあれば何もしない
既存コードを壊さず、環境だけを補強するのがポイントです。
polyfill はなぜ副作用インポートで読み込まれるのか?
polyfill は、
- グローバルオブジェクトを書き換える
- JavaScriptのprototypeプロパティを拡張する
といった強い副作用を持ちます。
そのため、多くの場合次のように読み込まれます。
import "./polyfills";
// polyfills.js
import "core-js/es/array/includes";
import "regenerator-runtime/runtime";
import した瞬間に、実行環境が拡張されます。
polyfill と transpile の違い
ここは非常に混同されやすいポイントです。
polyfill(機能を追加する)
対象例:
- Promise
- Array.prototype.includes
- fetch
実行時に API を追加します。
transpile(構文を変換する)
// before
const add = (a, b) => a + b;
// after
var add = function (a, b) {
return a + b;
};
コードの書き方(構文)を、古い JavaScript でも動く形に変換します。
polyfill が使えないケース
-
新しい構文(
?.,??など)- polyfill では対応できない
- transpile が必要
-
JavaScript で表現できない低レベルな機能
副作用インポートの注意点
1. 依存関係が分かりにくくなる
import "./setup";
この1行からは、何が起きるのか分かりません。
乱用すると可読性や保守性が下がります。
2. Tree Shaking されにくい
副作用があると、ビルドツールは
「消すと挙動が変わるかもしれない」
と判断し、不要コードの削除(最適化)ができなくなります。
現代フロントエンドでの考え方
- モダンブラウザ前提の Web アプリ
→ polyfill は最小限、もしくは不要 - 業務システムや古い端末対応
→ polyfill が重要
大切なのは、
なぜこの副作用インポートが必要なのかを説明できること
まとめ
- 副作用インポート
→ 実行させること自体が目的の import - polyfill
→ 存在しない機能を後付けで追加する仕組み - polyfill は副作用インポートで読み込まれることが多い
- transpile とは役割が異なる
- 便利だが、使いどころと理由を明確にすることが重要
「なんとなく import していたコード」を、
意味を理解して扱えるようになることが、設計力の向上につながります。
Discussion