Shimming: суть, підходи та принцип роботи

Автор: IT Sectr Опубліковано: 2026-05-19 Час читання: 8 хв

Shimming — техніка забезпечення сумісності модулів, які очікують певні глобальні змінні або API. В екосистемі Webpack shimming реалізується через ProvidePlugin, imports-loader та exports-loader, дозволяючи підключати legacy-бібліотеки без зміни їхнього вихідного коду. За даними Webpack Documentation (2026), shimming залишається ключовим інструментом для інтеграції jQuery-плагінів та інших залежностей, які не підтримують модульну систему.

Головне

  • Shimming — техніка підміни глобальних змінних та API для забезпечення сумісності модулів у збірці.
  • ProvidePlugin автоматично імпортує модуль при виявленні звернення до глобальної змінної в коді.
  • imports-loader та exports-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 чи несумісність інтерфейсів.

Як працює Shimming у Webpack

Webpack обробляє кожен модуль як ізольовану одиницю з власною областю видимості. Якщо бібліотека звертається до глобальної змінної jQuery як до window.$, збірка завершиться помилкою, оскільки в модульному контексті цієї змінної немає. ProvidePlugin вирішує проблему на етапі компіляції: при виявленні ідентифікатора $ у коді плагін автоматично вставляє import $ from 'jquery' на початку файлу.

js
// Вихідний код (legacy-модуль звертається до глобальної jQuery)
$('.element').hide();

// Після обробки ProvidePlugin (Webpack вставляє import)
import $ from 'jquery';
$('.element').hide();

Додатково imports-loader дозволяє явно вказати, які залежності має отримувати модуль. Це корисно, коли бібліотека використовує this на верхньому рівні, очікуючи, що this посилається на window, а не на module.exports.

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] імпортує лише функцію debounce з lodash, що зменшує розмір фінального бандла. Це особливо важливо для мобільних проєктів, де кожен кілобайт впливає на час завантаження.

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.

Налаштування shimming у конфігурації Webpack

Shimming конфігурується в webpack.config.js через комбінацію плагінів і лоадерів. Типовий сценарій включає ProvidePlugin для глобальних змінних та imports-loader для конкретних модулів, які потребують зміни області видимості.

Базова конфігурація Webpack для shimming

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

Поле globalObject у output задає контекст для звернень до this на верхньому рівні. Для браузерного середовища значення 'this' посилається на window, а для React Native або Node.js — на global. Вибір правильного значення запобігає помилкам виконання в цільовому середовищі.

Типові помилки при shimming

Shimming — потужний, але небезпечний інструмент. Неправильне налаштування призводить до дублювання коду в бандлі, конфліктів імен та несподіваних помилок виконання. Розробники часто забувають, що ProvidePlugin працює на етапі компіляції та не може обробити динамічні звернення до змінних.

Конфлікти глобальних змінних

Якщо два плагіни використовують різні версії jQuery, ProvidePlugin підставить лише одну з них, вказану першою в конфігурації. Друга бібліотека отримає несумісну версію, що викличе помилки, які важко налагодити. Рішення — використовувати exports-loader для кожної бібліотеки з явним зазначенням версії або застосовувати webpack.IgnorePlugin для виключення дубльованих модулів.

Ще одна поширена помилка — спроба зашимувати модулі, які використовують CommonJS синхронні виклики require у динамічному контексті. ProvidePlugin обробляє лише статичні ідентифікатори, тому динамічні звернення необхідно замінювати вручну або використовувати NormalModuleReplacementPlugin.

Проблеми з продуктивністю при неправильному shimming

Неправильне налаштування shimming може призвести до значного збільшення розміру бандла. Якщо ProvidePlugin налаштований на десятки глобальних змінних, Webpack вставлятиме відповідні імпорти у всі файли проєкту, незалежно від того, чи використовуються ці змінні в кожному конкретному файлі. Це створює надлишковий код, особливо у великих проєктах із тисячами модулів.

Для діагностики проблем із shimming використовуйте webpack-bundle-analyzer — інструмент візуалізації складу бандла. Якщо jQuery чи інша бібліотека з'являється в бандлі кілька разів, імовірно, конфліктують різні версії або ProvidePlugin налаштований на кілька ідентифікаторів, що ведуть до різних версій пакета. Рішення — уніфікувати версії залежностей через resolve.alias та перевірити, що всі зашимовані ідентифікатори вказують на один і той самий модуль.

Альтернативи shimming: рефакторинг та оновлення залежностей

Перш ніж застосовувати shimming, оцініть можливість оновлення бібліотеки до версії, що підтримує модульну систему. Багато legacy-пакетів мають сучасні альтернативи, які не потребують шимування. Наприклад, jQuery-плагіни можна замінити на нативні браузерні API: $.ajaxfetch, $.eachArray.forEach. Рефакторинг дає довгостроковий виграш у підтримці, тоді як shimming — тимчасове рішення, яке ускладнює конфігурацію.

Якщо оновлення неможливе, розгляньте NormalModuleReplacementPlugin, який дозволяє підміняти один модуль іншим на рівні резолвінгу, без зміни вихідного коду. Цей плагін працює на етапі побудови графа залежностей, до застосування лоадерів, і обробляє всі звернення до модуля незалежно від контексту. Це чистіше рішення для заміни цілих бібліотек, ніж точкові лоадери.

Shimming у сучасному JavaScript: ESM та import maps

З розвитком нативних ES-модулів у браузерах та появою import maps деякі сценарії shimming можуть бути вирішені без Webpack. Import maps дозволяють переназначати імена модулів на льоту на рівні браузера, без етапу збірки. Однак цей підхід не підтримується в React Native та інших середовищах без браузерного ESM, тому shimming через Webpack залишається актуальним для production-збірок, де потрібен повний контроль над залежностями та їхніми версіями. Вибір між import maps та Webpack-шимами залежить від цільової платформи та вимог до сумісності зі старими браузерами.

Часті запитання

Чим shimming відрізняється від tree shaking?

Shimming додає код для забезпечення сумісності, а tree shaking видаляє невикористаний код. Ці техніки протилежні за метою: shimming збільшує розмір бандла, tree shaking зменшує. У production-збірці обидві застосовуються послідовно.

Чи можна використовувати shimming без Webpack?

Так, shimming існує як техніка незалежно від Webpack — наприклад, через глобальні скрипти в HTML або через ES-модулі з реекспортом. Однак Webpack надає найзручніші інструменти автоматизації: ProvidePlugin та лоадери, які не вимагають ручного змінення коду.

Як shimming впливає на продуктивність збірки?

ProvidePlugin не впливає на швидкість збірки, оскільки працює на етапі компіляції AST. imports-loader та exports-loader додають невеликий час обробки кожного файлу. При використанні на сотнях файлів різниця може становити 5–15% часу повної збірки.

Коли варто відмовитися від shimming?

Якщо всі залежності підтримують ES-модулі та модульну систему, shimming надлишковий. Відмова від shimming спрощує конфігурацію, зменшує розмір бандла та знижує ризик конфліктів імен. Рекомендується перевіряти залежності на caniuse.com.

Як shimming працює з TypeScript?

TypeScript вимагає додаткових оголошень типів для зашимованих змінних. Необхідно додати declare const $: any або встановити типи через @types/jquery. ProvidePlugin підставляє імпорти на рівні JavaScript після компіляції TypeScript, тому типи перевіряються окремо.

Підсумки

  • Shimming — техніка забезпечення сумісності модулів із середовищем через підміну глобальних змінних та API.
  • ProvidePlugin автоматично імпортує модулі при виявленні звернення до заданих ідентифікаторів у коді.
  • imports-loader додає імпорти на початок конкретних файлів, а exports-loader — задає значення, що експортуються.
  • Shim відрізняється від polyfill тим, що не реалізує функціональність, а перенаправляє виклики на наявні реалізації.
  • ProvidePlugin працює на етапі компіляції та не обробляє динамічні звернення до змінних.
  • Поле globalObject у output задає правильний контекст для верхнього рівня в цільовому середовищі.
  • Використовуйте shimming лише для модулів, які не підтримують сучасну модульну систему, і відмовляйтеся від нього при повній підтримці ES-модулів.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також