Shimming(シミング):本質、アプローチ、動作の仕組み

著者: IT Sectr 公開日: 2026-05-19 読了時間: 8 分

Shimmingは、特定のグローバル変数やAPIを期待するモジュールの互換性を確保するテクニックです。Webpackエコシステムでは、shimmingはProvidePlugin、imports-loader、exports-loaderを通じて実装され、ソースコードを変更せずにレガシーライブラリを接続できます。Webpack Documentation (2026)によると、shimmingはモジュールシステムをサポートしないjQueryプラグインやその他の依存関係を統合するための主要なツールであり続けています。

要点

  • Shimmingは、ビルド内でモジュールの互換性を確保するためにグローバル変数やAPIを置き換えるテクニックです。
  • ProvidePluginは、コード内でグローバル変数への参照を検出すると、モジュールを自動的にインポートします。
  • imports-loaderexports-loaderは、モジュールのスコープを管理し、インターフェースを追加または変更します。
  • Shimは、欠落した機能を実装するのではなく、既存の呼び出しをリダイレクトする点でpolyfillとは異なります。
  • Webpackは、追加パッケージをインストールせずに組み込みのshimmingメカニズムを提供します。

Shimmingとは何か?

Shimmingは、モジュールのソースコードを変更せずに、コードと環境の間に互換性レイヤーを埋め込むソフトウェアテクニックです。JavaScriptビルドの文脈では、shimmingはモジュールがモジュール環境に存在しないグローバル変数(window.$global.process)にアクセスする問題を解決します。

Shimとpolyfill:主な違い

Polyfillは欠落した機能をゼロから実装し、環境に新しい能力を追加します。例えば、core-jsは古いブラウザ向けにArray.prototype.flatMapを追加します。Shimは既存の呼び出しを利用可能な実装にリダイレクトするか、期待されるグローバルオブジェクトを置き換えます。Webpackでは、ProvidePluginはコード内でグローバル変数$への参照が見つかるすべての場所にimport $ from 'jquery'を自動的に挿入し、コードの変更を必要としません。

主な違いは目的にあります。Polyfillは存在しないものを追加し、shimは既存のコードを実行環境に適合させます。どちらを選ぶかは、解決する問題(APIの欠如か、インターフェースの非互換性か)によります。

WebpackでのShimmingの仕組み

Webpackは各モジュールを独自のスコープを持つ分離されたユニットとして扱います。ライブラリがグローバル変数jQuerywindow.$として参照する場合、モジュールコンテキストにはこの変数が存在しないため、ビルドはエラーで終了します。ProvidePluginはコンパイル段階でこの問題を解決します:コード内で識別子$が検出されると、プラグインは自動的にファイルの先頭にimport $ from 'jquery'を挿入します。

js
// 元のコード(レガシーモジュールがグローバルなjQueryにアクセスする)
$('.element').hide();

// ProvidePluginの処理後(Webpackがimportを挿入する)
import $ from 'jquery';
$('.element').hide();

さらに、imports-loaderを使用すると、モジュールが受け取るべき依存関係を明示的に指定できます。これは、ライブラリがトップレベルでthisを使用し、thismodule.exportsではなくwindowを参照することを期待する場合に便利です。

ProvidePlugin:モジュール用のグローバル変数

ProvidePluginは、指定された識別子への参照を検出するとモジュールを自動的に読み込むWebpackの組み込みプラグインです。設定はオブジェクトで、キーは変数名、値はモジュールへのパスとエクスポートされるフィールドです。

プラグインの設定

js
// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      _: 'lodash',
      'window.$': 'jquery',
    }),
  ],
};

ProvidePluginは配列構文による部分インポートをサポートします。例えば、[lodash, debounce]はlodashからdebounce関数のみをインポートするため、最終バンドルのサイズが小さくなります。これは、1キロバイトごとに読み込み時間が影響するモバイルプロジェクトで特に重要です。

imports-loaderとexports-loader

imports-loaderはモジュールの先頭に必要なインポートを追加し、exports-loaderは明示的にmodule.exportsを使用しないモジュールのエクスポート値を定義します。これらのローダーはProvidePluginのようにグローバルではなく、個々のファイルのレベルで動作します。

imports-loaderによる依存関係の修正

js
// webpack.config.js — imports-loaderの設定
module.exports = {
  module: {
    rules: [
      {
        test: /legacy-module\.js$/,
        use: [
          {
            loader: 'imports-loader',
            options: {
              imports: [
                'jquery',
                '$',
              ],
            },
          },
        ],
      },
    ],
  },
};

exports-loaderは、ライブラリがグローバル変数に値を割り当てるが、モジュールシステムを通じてそれをエクスポートしない場合に使用されます。ローダーは値を抽出してモジュールエクスポートに変換するため、他のモジュールはimportでそれをインポートできます。

Webpack設定でのshimmingの構成

Shimmingwebpack.config.jsでプラグインとローダーの組み合わせによって構成されます。典型的なシナリオには、グローバル変数用のProvidePluginと、スコープの変更が必要な特定のモジュール用のimports-loaderが含まれます。

shimmingのためのWebpackの基本設定

js
const webpack = require('webpack');
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    globalObject: 'this',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules\/(?!legacy-lib)/,
        use: [
          {
            loader: 'imports-loader',
            options: {
              type: 'commonjs',
              imports: ['jquery', '$'],
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),
  ],
};

outputのglobalObjectフィールドは、トップレベルでのthisへの参照のコンテキストを定義します。ブラウザ環境では'this'という値はwindowを参照し、React NativeやNode.jsではglobalを参照します。正しい値を選択することで、対象環境での実行時エラーを防げます。

shimmingにおける典型的なエラー

Shimmingは強力ですが危険なツールです。設定を誤ると、バンドル内のコードの重複、名前の競合、予期しない実行時エラーにつながります。開発者は、ProvidePluginがコンパイル段階で動作し、変数への動的な参照を処理できないことを忘れがちです。

グローバル変数の競合

2つのプラグインがjQueryの異なるバージョンを使用している場合、ProvidePluginは設定で最初に指定された一方だけを置き換えます。2番目のライブラリは互換性のないバージョンを受け取り、デバッグが難しいエラーを引き起こします。解決策は、各ライブラリにバージョンを明示してexports-loaderを使用するか、webpack.IgnorePluginを適用して重複モジュールを除外することです。

もう一つのよくあるエラーは、動的なコンテキストでCommonJSの同期require呼び出しを使用するモジュールをshimしようとすることです。ProvidePluginは静的識別子のみを処理するため、動的な参照は手動またはNormalModuleReplacementPluginで置き換える必要があります。

不適切なshimmingによるパフォーマンスの問題

shimmingの設定を誤ると、バンドルサイズが大幅に増加する可能性があります。ProvidePluginが数十のグローバル変数用に構成されている場合、Webpackはそれらの変数が各ファイルで使用されているかどうかに関係なく、対応するインポートをプロジェクトのすべてのファイルに挿入します。これにより、特に数千のモジュールを持つ大規模プロジェクトでは、冗長なコードが生成されます。

shimmingの問題を診断するには、webpack-bundle-analyzer(バンドル構成を視覚化するツール)を使用してください。jQueryや他のライブラリがバンドルに複数回出現する場合、異なるバージョンが競合しているか、ProvidePluginがパッケージの異なるバージョンにつながる複数の識別子用に構成されている可能性があります。解決策は、resolve.aliasで依存関係のバージョンを統一し、shimされたすべての識別子が同じモジュールを指していることを確認することです。

shimmingの代替案:リファクタリングと依存関係の更新

shimmingを適用する前に、ライブラリをモジュールシステムをサポートするバージョンに更新できるかを評価してください。多くのレガシーパッケージには、shimmingを必要としない現代的な代替品があります。例えば、jQueryプラグインはネイティブのブラウザAPIで置き換えられます:$.ajaxfetch$.eachArray.forEach。リファクタリングは長期的な保守上の利益をもたらしますが、shimmingは構成を複雑にする一時的な解決策です。

更新が不可能な場合は、NormalModuleReplacementPluginを検討してください。これはソースコードを変更せずに、解決レベルでモジュールを別のモジュールに置き換えることができます。このプラグインはローダーが適用される前の依存関係グラフ構築段階で動作し、コンテキストに関係なくモジュールへのすべての参照を処理します。これは、個別のローダーよりもライブラリ全体を置き換えるためのクリーンな解決策です。

現代のJavaScriptでのshimming:ESMとimport maps

ブラウザでのネイティブESモジュールの発展とimport mapsの登場により、一部のshimmingシナリオはWebpackなしで解決できます。import mapsは、ビルド段階なしでブラウザレベルでモジュール名を動的に再割り当てできます。ただし、このアプローチはReact NativeやブラウザESMのない他の環境ではサポートされていないため、Webpackによるshimmingは、依存関係とそのバージョンを完全に制御する必要がある本番ビルドにとって依然として重要です。import mapsとWebpackのshimのどちらを選ぶかは、対象プラットフォームと古いブラウザとの互換性要件に依存します。

よくある質問

shimmingはtree shakingとどう違うのですか?

Shimmingは互換性を確保するためにコードを追加し、tree shakingは未使用のコードを削除します。これらのテクニックは目的が逆です:shimmingはバンドルサイズを増やし、tree shakingは減らします。本番ビルドでは両方が順に適用されます。

Webpackなしでshimmingを使用できますか?

はい、shimmingはWebpackとは独立したテクニックとして存在します — 例えば、HTMLのグローバルスクリプトや、再エクスポート付きのESモジュールを通じて。ただし、Webpackは最も便利な自動化ツールを提供します:ProvidePluginや、コードの手動変更を必要としないローダーです。

shimmingはビルドのパフォーマンスにどのように影響しますか?

ProvidePluginはASTコンパイル段階で動作するため、ビルド速度に影響しません。imports-loaderexports-loaderは各ファイルの処理にわずかな時間を追加します。数百のファイルで使用すると、その差はビルド全体の時間の5〜15%になる可能性があります。

shimmingをやめるべきなのはいつですか?

すべての依存関係がESモジュールとモジュールシステムをサポートしている場合、shimmingは冗長です。shimmingをやめると、構成が簡素化され、バンドルサイズが減り、名前の競合のリスクが下がります。caniuse.comで依存関係を確認することをお勧めします。

shimmingはTypeScriptでどのように動作しますか?

TypeScriptでは、shimされた変数に追加の型宣言が必要です。declare const $: anyを追加するか、@types/jqueryで型をインストールする必要があります。ProvidePluginはTypeScriptのコンパイル後にJavaScriptレベルでインポートを挿入するため、型は別途チェックされます。

まとめ

  • Shimmingは、グローバル変数やAPIを置き換えることでモジュールと環境の互換性を確保するテクニックです。
  • ProvidePluginは、コード内で指定された識別子への参照を検出するとモジュールを自動的にインポートします。
  • imports-loaderは特定のファイルの先頭にインポートを追加し、exports-loaderはエクスポート値を定義します。
  • Shimは、機能を実装するのではなく、呼び出しを既存の実装にリダイレクトする点でpolyfillとは異なります。
  • ProvidePluginはコンパイル段階で動作し、変数への動的な参照を処理しません。
  • outputのglobalObjectフィールドは、対象環境でトップレベルの正しいコンテキストを定義します。
  • shimmingは現代のモジュールシステムをサポートしないモジュールにのみ使用し、ESモジュールが完全にサポートされたらやめてください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください