Shimming: istota, podejścia i zasada działania

Autor: IT Sectr Opublikowano: 2026-05-19 Czas czytania: 8 min

Shimming — technika zapewniania zgodności modułów, które oczekują określonych zmiennych globalnych lub API. W ekosystemie Webpack shimming jest implementowany przez ProvidePlugin, imports-loader i exports-loader, umożliwiając podłączanie bibliotek legacy bez zmiany ich kodu źródłowego. Według Webpack Documentation (2026) shimming pozostaje kluczowym narzędziem do integracji wtyczek jQuery i innych zależności, które nie obsługują systemu modułów.

Najważniejsze

  • Shimming — technika podmiany zmiennych globalnych i API w celu zapewnienia zgodności modułów w budowaniu.
  • ProvidePlugin automatycznie importuje moduł po wykryciu odwołania do zmiennej globalnej w kodzie.
  • imports-loader i exports-loader zarządzają zakresem widoczności modułów, dodając lub zmieniając ich interfejsy.
  • Shim różni się od polyfill tym, że nie implementuje brakującej funkcjonalności, lecz przekierowuje istniejące wywołania.
  • Webpack udostępnia wbudowane mechanizmy shimmingu bez konieczności instalowania dodatkowych pakietów.

Czym jest Shimming?

Shimming to technika programowa, która wbudowuje warstwę zgodności między kodem a środowiskiem, nie zmieniając kodu źródłowego modułu. W kontekście budowania JavaScript shimming rozwiązuje problem, gdy moduł odwołuje się do zmiennych globalnych (window.$, global.process), których nie ma w środowisku modułowym.

Shim i polyfill: podstawowe różnice

Polyfill implementuje brakującą funkcjonalność od zera, dodając nowe możliwości do środowiska. Na przykład core-js dodaje Array.prototype.flatMap dla starych przeglądarek. Shim natomiast przekierowuje istniejące wywołania na dostępne implementacje lub podmienia oczekiwane obiekty globalne. W Webpack ProvidePlugin automatycznie wstawia import $ from 'jquery' wszędzie tam, gdzie występuje odwołanie do zmiennej globalnej $, nie wymagając zmian w kodzie.

Podstawowa różnica polega na celu. Polyfill dodaje to, czego nie ma, a shim sprawia, że istniejący kod staje się zgodny ze środowiskiem, w którym jest wykonywany. Wybór między nimi zależy od tego, jaki problem jest rozwiązywany: brak API czy niezgodność interfejsów.

Jak działa Shimming w Webpack

Webpack traktuje każdy moduł jako izolowaną jednostkę z własnym zakresem widoczności. Jeśli biblioteka odwołuje się do zmiennej globalnej jQuery jako do window.$, budowanie zakończy się błędem, ponieważ w kontekście modułowym tej zmiennej nie ma. ProvidePlugin rozwiązuje problem na etapie kompilacji: po wykryciu identyfikatora $ w kodzie wtyczka automatycznie wstawia import $ from 'jquery' na początku pliku.

js
// Kod źródłowy (moduł legacy odwołuje się do globalnej jQuery)
$('.element').hide();

// Po przetworzeniu przez ProvidePlugin (Webpack wstawia import)
import $ from 'jquery';
$('.element').hide();

Dodatkowo imports-loader pozwala jawnie określić, jakie zależności powinien otrzymywać moduł. Jest to przydatne, gdy biblioteka używa this na najwyższym poziomie, oczekując, że this odnosi się do window, a nie do module.exports.

ProvidePlugin: zmienne globalne dla modułów

ProvidePlugin — wbudowana wtyczka Webpack, która automatycznie wczytuje moduły po wykryciu odwołania do określonych identyfikatorów. Konfiguracja to obiekt, w którym klucz to nazwa zmiennej, a wartość to ścieżka do modułu i eksportowane pole.

Konfiguracja wtyczki

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

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

ProvidePlugin obsługuje import punktowy przez składnię tablicową. Na przykład [lodash, debounce] importuje tylko funkcję debounce z lodash, co zmniejsza rozmiar końcowego pakietu. Jest to szczególnie ważne w projektach mobilnych, gdzie każdy kilobajt wpływa na czas ładowania.

imports-loader i exports-loader

imports-loader dodaje niezbędne importy na początku modułu, a exports-loader — ustawia eksportowane wartości dla modułów, które nie używają jawnie module.exports. Te loadery działają na poziomie pojedynczych plików, a nie globalnie, jak ProvidePlugin.

Naprawianie zależności za pomocą imports-loader

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

exports-loader jest używany, gdy biblioteka przypisuje wartość zmiennej globalnej, ale nie eksportuje jej przez system modułów. Loader wyodrębnia wartość i zamienia ją na eksport modułowy, co pozwala innym modułom importować ją przez import.

Konfiguracja shimmingu w konfiguracji Webpack

Shimming jest konfigurowany w webpack.config.js przez kombinację wtyczek i loaderów. Typowy scenariusz obejmuje ProvidePlugin dla zmiennych globalnych i imports-loader dla konkretnych modułów, które wymagają zmiany zakresu widoczności.

Podstawowa konfiguracja Webpack dla shimmingu

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',
    }),
  ],
};

Pole globalObject w output ustawia kontekst dla odwołań do this na najwyższym poziomie. Dla środowiska przeglądarki wartość 'this' odnosi się do window, a dla React Native lub Node.js — do global. Wybór prawidłowej wartości zapobiega błędom wykonania w środowisku docelowym.

Typowe błędy przy shimmingu

Shimming — potężne, ale niebezpieczne narzędzie. Nieprawidłowa konfiguracja prowadzi do duplikacji kodu w pakiecie, konfliktów nazw i nieoczekiwanych błędów wykonania. Programiści często zapominają, że ProvidePlugin działa na etapie kompilacji i nie może obsłużyć dynamicznych odwołań do zmiennych.

Konflikty zmiennych globalnych

Jeśli dwie wtyczki używają różnych wersji jQuery, ProvidePlugin wstawi tylko jedną z nich, wskazaną jako pierwszą w konfiguracji. Druga biblioteka otrzyma niezgodną wersję, co spowoduje trudne do zdebugowania błędy. Rozwiązaniem jest użycie exports-loader dla każdej biblioteki z jawnym wskazaniem wersji lub zastosowanie webpack.IgnorePlugin w celu wykluczenia zduplikowanych modułów.

Kolejnym częstym błędem jest próba shimmowania modułów, które używają synchronicznych wywołań CommonJS require w kontekście dynamicznym. ProvidePlugin obsługuje tylko statyczne identyfikatory, dlatego dynamiczne odwołania należy zastępować ręcznie lub używać NormalModuleReplacementPlugin.

Problemy z wydajnością przy nieprawidłowym shimmingu

Nieprawidłowa konfiguracja shimmingu może prowadzić do znacznego zwiększenia rozmiaru pakietu. Jeśli ProvidePlugin jest skonfigurowany na dziesiątki zmiennych globalnych, Webpack będzie wstawiał odpowiednie importy do wszystkich plików projektu, niezależnie od tego, czy te zmienne są używane w danym pliku. Tworzy to zbędny kod, zwłaszcza w dużych projektach z tysiącami modułów.

Do diagnozowania problemów z shimmingiem używaj webpack-bundle-analyzer — narzędzia do wizualizacji składu pakietu. Jeśli jQuery lub inna biblioteka pojawia się w pakiecie kilka razy, prawdopodobnie kolidują różne wersje lub ProvidePlugin jest skonfigurowany na kilka identyfikatorów prowadzących do różnych wersji pakietu. Rozwiązaniem jest ujednolicenie wersji zależności przez resolve.alias i sprawdzenie, czy wszystkie shimmowane identyfikatory wskazują ten sam moduł.

Alternatywy dla shimmingu: refaktoryzacja i aktualizacja zależności

Przed zastosowaniem shimmingu oceń możliwość aktualizacji biblioteki do wersji obsługującej system modułów. Wiele pakietów legacy ma nowoczesne alternatywy, które nie wymagają shimmowania. Na przykład wtyczki jQuery można zastąpić natywnymi API przeglądarki: $.ajaxfetch, $.eachArray.forEach. Refaktoryzacja daje długoterminową korzyść w utrzymaniu, podczas gdy shimming to rozwiązanie tymczasowe, które komplikuje konfigurację.

Jeśli aktualizacja nie jest możliwa, rozważ NormalModuleReplacementPlugin, który pozwala podmienić jeden moduł na inny na poziomie rozwiązywania, bez zmiany kodu źródłowego. Ta wtyczka działa na etapie budowania grafu zależności, przed zastosowaniem loaderów, i obsługuje wszystkie odwołania do modułu niezależnie od kontekstu. To czystsze rozwiązanie do zastępowania całych bibliotek niż punktowe loadery.

Shimming we współczesnym JavaScript: ESM i import maps

Wraz z rozwojem natywnych modułów ES w przeglądarkach i pojawieniem się import maps niektóre scenariusze shimmingu mogą zostać rozwiązane bez Webpack. Import maps pozwalają na bieżąco przypisywać nazwy modułów na poziomie przeglądarki, bez etapu budowania. Jednak to podejście nie jest obsługiwane w React Native i innych środowiskach bez ESM przeglądarki, dlatego shimming przez Webpack pozostaje aktualny w budowaniu produkcyjnym, gdzie wymagana jest pełna kontrola nad zależnościami i ich wersjami. Wybór między import maps a shimami Webpack zależy od platformy docelowej i wymagań dotyczących zgodności ze starymi przeglądarkami.

Często zadawane pytania

Czym różni się shimming od tree shaking?

Shimming dodaje kod w celu zapewnienia zgodności, a tree shaking usuwa nieużywany kod. Te techniki są przeciwstawne w celu: shimming zwiększa rozmiar pakietu, tree shaking zmniejsza. W budowaniu produkcyjnym obie są stosowane sekwencyjnie.

Czy można używać shimmingu bez Webpack?

Tak, shimming istnieje jako technika niezależnie od Webpack — na przykład przez globalne skrypty w HTML lub przez moduły ES z reeksportem. Jednak Webpack udostępnia najwygodniejsze narzędzia automatyzacji: ProvidePlugin i loadery, które nie wymagają ręcznych zmian w kodzie.

Jak shimming wpływa na wydajność budowania?

ProvidePlugin nie wpływa na szybkość budowania, ponieważ działa na etapie kompilacji AST. imports-loader i exports-loader dodają niewielki czas przetwarzania każdego pliku. Przy użyciu na setkach plików różnica może wynieść 5–15% czasu pełnego budowania.

Kiedy warto zrezygnować z shimmingu?

Jeśli wszystkie zależności obsługują moduły ES i system modułów, shimming jest zbędny. Rezygnacja z shimmingu upraszcza konfigurację, zmniejsza rozmiar pakietu i obniża ryzyko konfliktów nazw. Zaleca się sprawdzenie zależności na caniuse.com.

Jak shimming współpracuje z TypeScript?

TypeScript wymaga dodatkowych deklaracji typów dla shimmowanych zmiennych. Należy dodać declare const $: any lub zainstalować typy przez @types/jquery. ProvidePlugin wstawia importy na poziomie JavaScript po kompilacji TypeScript, dlatego typy są sprawdzane osobno.

Podsumowanie

  • Shimming — technika zapewniania zgodności modułów ze środowiskiem przez podmianę zmiennych globalnych i API.
  • ProvidePlugin automatycznie importuje moduły po wykryciu odwołania do określonych identyfikatorów w kodzie.
  • imports-loader dodaje importy na początku konkretnych plików, a exports-loader — ustawia eksportowane wartości.
  • Shim różni się od polyfill tym, że nie implementuje funkcjonalności, lecz przekierowuje wywołania na istniejące implementacje.
  • ProvidePlugin działa na etapie kompilacji i nie obsługuje dynamicznych odwołań do zmiennych.
  • Pole globalObject w output ustawia prawidłowy kontekst dla najwyższego poziomu w środowisku docelowym.
  • Używaj shimmingu tylko dla modułów, które nie obsługują nowoczesnego systemu modułów, i rezygnuj z niego przy pełnej obsłudze modułów ES.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również