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 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.
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.
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.
// 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 — 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.
// 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 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.
// 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.
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.
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.
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.
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.
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ł.
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: $.ajax → fetch, $.each → Array.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.
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
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.
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.
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.
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.
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
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.
Przeczytaj również