Shimmingは、特定のグローバル変数やAPIを期待するモジュールの互換性を確保するテクニックです。Webpackエコシステムでは、shimmingはProvidePlugin、imports-loader、exports-loaderを通じて実装され、ソースコードを変更せずにレガシーライブラリを接続できます。Webpack Documentation (2026)によると、shimmingはモジュールシステムをサポートしないjQueryプラグインやその他の依存関係を統合するための主要なツールであり続けています。
要点
Shimmingは、モジュールのソースコードを変更せずに、コードと環境の間に互換性レイヤーを埋め込むソフトウェアテクニックです。JavaScriptビルドの文脈では、shimmingはモジュールがモジュール環境に存在しないグローバル変数(window.$、global.process)にアクセスする問題を解決します。
Polyfillは欠落した機能をゼロから実装し、環境に新しい能力を追加します。例えば、core-jsは古いブラウザ向けにArray.prototype.flatMapを追加します。Shimは既存の呼び出しを利用可能な実装にリダイレクトするか、期待されるグローバルオブジェクトを置き換えます。Webpackでは、ProvidePluginはコード内でグローバル変数$への参照が見つかるすべての場所にimport $ from 'jquery'を自動的に挿入し、コードの変更を必要としません。
主な違いは目的にあります。Polyfillは存在しないものを追加し、shimは既存のコードを実行環境に適合させます。どちらを選ぶかは、解決する問題(APIの欠如か、インターフェースの非互換性か)によります。
Webpackは各モジュールを独自のスコープを持つ分離されたユニットとして扱います。ライブラリがグローバル変数jQueryをwindow.$として参照する場合、モジュールコンテキストにはこの変数が存在しないため、ビルドはエラーで終了します。ProvidePluginはコンパイル段階でこの問題を解決します:コード内で識別子$が検出されると、プラグインは自動的にファイルの先頭にimport $ from 'jquery'を挿入します。
// 元のコード(レガシーモジュールがグローバルなjQueryにアクセスする)
$('.element').hide();
// ProvidePluginの処理後(Webpackがimportを挿入する)
import $ from 'jquery';
$('.element').hide();
さらに、imports-loaderを使用すると、モジュールが受け取るべき依存関係を明示的に指定できます。これは、ライブラリがトップレベルでthisを使用し、thisがmodule.exportsではなくwindowを参照することを期待する場合に便利です。
ProvidePluginは、指定された識別子への参照を検出するとモジュールを自動的に読み込むWebpackの組み込みプラグインです。設定はオブジェクトで、キーは変数名、値はモジュールへのパスとエクスポートされるフィールドです。
// 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は明示的にmodule.exportsを使用しないモジュールのエクスポート値を定義します。これらのローダーはProvidePluginのようにグローバルではなく、個々のファイルのレベルで動作します。
// webpack.config.js — imports-loaderの設定
module.exports = {
module: {
rules: [
{
test: /legacy-module\.js$/,
use: [
{
loader: 'imports-loader',
options: {
imports: [
'jquery',
'$',
],
},
},
],
},
],
},
};
exports-loaderは、ライブラリがグローバル変数に値を割り当てるが、モジュールシステムを通じてそれをエクスポートしない場合に使用されます。ローダーは値を抽出してモジュールエクスポートに変換するため、他のモジュールはimportでそれをインポートできます。
Shimmingはwebpack.config.jsでプラグインとローダーの組み合わせによって構成されます。典型的なシナリオには、グローバル変数用のProvidePluginと、スコープの変更が必要な特定のモジュール用のimports-loaderが含まれます。
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は強力ですが危険なツールです。設定を誤ると、バンドル内のコードの重複、名前の競合、予期しない実行時エラーにつながります。開発者は、ProvidePluginがコンパイル段階で動作し、変数への動的な参照を処理できないことを忘れがちです。
2つのプラグインがjQueryの異なるバージョンを使用している場合、ProvidePluginは設定で最初に指定された一方だけを置き換えます。2番目のライブラリは互換性のないバージョンを受け取り、デバッグが難しいエラーを引き起こします。解決策は、各ライブラリにバージョンを明示してexports-loaderを使用するか、webpack.IgnorePluginを適用して重複モジュールを除外することです。
もう一つのよくあるエラーは、動的なコンテキストでCommonJSの同期require呼び出しを使用するモジュールをshimしようとすることです。ProvidePluginは静的識別子のみを処理するため、動的な参照は手動またはNormalModuleReplacementPluginで置き換える必要があります。
shimmingの設定を誤ると、バンドルサイズが大幅に増加する可能性があります。ProvidePluginが数十のグローバル変数用に構成されている場合、Webpackはそれらの変数が各ファイルで使用されているかどうかに関係なく、対応するインポートをプロジェクトのすべてのファイルに挿入します。これにより、特に数千のモジュールを持つ大規模プロジェクトでは、冗長なコードが生成されます。
shimmingの問題を診断するには、webpack-bundle-analyzer(バンドル構成を視覚化するツール)を使用してください。jQueryや他のライブラリがバンドルに複数回出現する場合、異なるバージョンが競合しているか、ProvidePluginがパッケージの異なるバージョンにつながる複数の識別子用に構成されている可能性があります。解決策は、resolve.aliasで依存関係のバージョンを統一し、shimされたすべての識別子が同じモジュールを指していることを確認することです。
shimmingを適用する前に、ライブラリをモジュールシステムをサポートするバージョンに更新できるかを評価してください。多くのレガシーパッケージには、shimmingを必要としない現代的な代替品があります。例えば、jQueryプラグインはネイティブのブラウザAPIで置き換えられます:$.ajax → fetch、$.each → Array.forEach。リファクタリングは長期的な保守上の利益をもたらしますが、shimmingは構成を複雑にする一時的な解決策です。
更新が不可能な場合は、NormalModuleReplacementPluginを検討してください。これはソースコードを変更せずに、解決レベルでモジュールを別のモジュールに置き換えることができます。このプラグインはローダーが適用される前の依存関係グラフ構築段階で動作し、コンテキストに関係なくモジュールへのすべての参照を処理します。これは、個別のローダーよりもライブラリ全体を置き換えるためのクリーンな解決策です。
ブラウザでのネイティブESモジュールの発展とimport mapsの登場により、一部のshimmingシナリオはWebpackなしで解決できます。import mapsは、ビルド段階なしでブラウザレベルでモジュール名を動的に再割り当てできます。ただし、このアプローチはReact NativeやブラウザESMのない他の環境ではサポートされていないため、Webpackによるshimmingは、依存関係とそのバージョンを完全に制御する必要がある本番ビルドにとって依然として重要です。import mapsとWebpackのshimのどちらを選ぶかは、対象プラットフォームと古いブラウザとの互換性要件に依存します。
よくある質問
Shimmingは互換性を確保するためにコードを追加し、tree shakingは未使用のコードを削除します。これらのテクニックは目的が逆です:shimmingはバンドルサイズを増やし、tree shakingは減らします。本番ビルドでは両方が順に適用されます。
はい、shimmingはWebpackとは独立したテクニックとして存在します — 例えば、HTMLのグローバルスクリプトや、再エクスポート付きのESモジュールを通じて。ただし、Webpackは最も便利な自動化ツールを提供します:ProvidePluginや、コードの手動変更を必要としないローダーです。
ProvidePluginはASTコンパイル段階で動作するため、ビルド速度に影響しません。imports-loaderとexports-loaderは各ファイルの処理にわずかな時間を追加します。数百のファイルで使用すると、その差はビルド全体の時間の5〜15%になる可能性があります。
すべての依存関係がESモジュールとモジュールシステムをサポートしている場合、shimmingは冗長です。shimmingをやめると、構成が簡素化され、バンドルサイズが減り、名前の競合のリスクが下がります。caniuse.comで依存関係を確認することをお勧めします。
TypeScriptでは、shimされた変数に追加の型宣言が必要です。declare const $: anyを追加するか、@types/jqueryで型をインストールする必要があります。ProvidePluginはTypeScriptのコンパイル後にJavaScriptレベルでインポートを挿入するため、型は別途チェックされます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。