Shimming تکنیکی برای تضمین سازگاری ماژولهایی است که به متغیرهای سراسری یا API خاصی نیاز دارند. در اکوسیستم Webpack، shimming از طریق ProvidePlugin، imports-loader و exports-loader پیادهسازی میشود و امکان اتصال کتابخانههای قدیمی بدون تغییر کد منبع آنها را فراهم میکند. طبق مستندات Webpack (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 به window اشاره کند، نه به module.exports.
ProvidePlugin افزونه داخلی Webpack است که هنگام شناسایی دسترسی به شناسههای مشخص، ماژولها را بهطور خودکار بارگذاری میکند. پیکربندی یک شیء است که در آن کلید نام متغیر و مقدار آن مسیر ماژول و فیلد صادرشده است.
// 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 مقادیر صادرشده را برای ماژولهایی که بهطور صریح از module.exports استفاده نمیکنند تعیین میکند. این loaderها در سطح فایلهای جداگانه کار میکنند، نه در سطح جهانی مانند ProvidePlugin.
// webpack.config.js — پیکربندی imports-loader
module.exports = {
module: {
rules: [
{
test: /legacy-module\.js$/,
use: [
{
loader: 'imports-loader',
options: {
imports: [
'jquery',
'$',
],
},
},
],
},
],
},
};
exports-loader زمانی استفاده میشود که کتابخانه مقداری را به متغیر سراسری اختصاص میدهد اما آن را از طریق سیستم ماژول صادر نمیکند. loader مقدار را استخراج میکند و آن را به خروجی ماژولی تبدیل میکند تا سایر ماژولها بتوانند آن را از طریق import وارد کنند.
Shimming در webpack.config.js از طریق ترکیب افزونهها و loaderها پیکربندی میشود. سناریوی معمول شامل 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',
}),
],
};
فیلد globalObject در output، بافت دسترسی به this در سطح بالایی را تعیین میکند. برای محیط مرورگر، مقدار 'this' به window اشاره میکند و برای React Native یا Node.js به global. انتخاب مقدار صحیح از خطاهای اجرا در محیط هدف جلوگیری میکند.
Shimming ابزاری قدرتمند اما خطرناک است. پیکربندی نادرست منجر به تکرار کد در باندل، تداخل نامها و خطاهای اجرای غیرمنتظره میشود. توسعهدهندگان اغلب فراموش میکنند که ProvidePlugin در مرحله کامپایل کار میکند و نمیتواند دسترسیهای پویا به متغیرها را پردازش کند.
اگر دو افزونه از نسخههای مختلف jQuery استفاده کنند، ProvidePlugin فقط یکی از آنها را که در پیکربندی اول آمده اضافه میکند. کتابخانه دوم نسخه ناسازگار دریافت میکند که خطاهایی سختبرایاشکالزدایی ایجاد میکند. راهحل استفاده از exports-loader برای هر کتابخانه با ذکر صریح نسخه یا اعمال webpack.IgnorePlugin برای حذف ماژولهای تکراری است.
خطای رایج دیگر تلاش برای shimming ماژولهایی است که از فراخوانیهای همگام CommonJS require در بافت پویا استفاده میکنند. 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 را در نظر بگیرید که امکان جایگزینی یک ماژول با ماژول دیگر را در سطح resolution بدون تغییر کد منبع فراهم میکند. این افزونه در مرحله ساخت گراف وابستگیها، قبل از اعمال loaderها کار میکند و همه دسترسیها به ماژول را بدون توجه به بافت پردازش میکند. این راهحلی تمیزتر برای جایگزینی کل کتابخانهها نسبت به loaderهای نقطهای است.
با توسعه ماژولهای ES بومی در مرورگرها و ظهور import maps، برخی سناریوهای shimming را میتوان بدون Webpack حل کرد. import maps به شما امکان میدهد نام ماژولها را در سطح مرورگر، بدون مرحله باندلسازی، تغییر دهید. اما این رویکرد در React Native و سایر محیطهای بدون ESM مرورگر پشتیبانی نمیشود، بنابراین shimming از طریق Webpack برای باندلهای production که نیاز به کنترل کامل وابستگیها و نسخههای آنها دارند، همچنان مرتبط است. انتخاب بین import maps و shimهای Webpack به پلتفرم هدف و الزامات سازگاری با مرورگرهای قدیمی بستگی دارد.
سوالات متداول
Shimming برای تضمین سازگاری کد اضافه میکند و tree shaking کد استفادهنشده را حذف میکند. این تکنیکها از نظر هدف متضاد هستند: shimming اندازه باندل را افزایش میدهد، tree shaking آن را کاهش میدهد. در باندل production هر دو بهصورت متوالی اعمال میشوند.
بله، shimming بهعنوان یک تکنیک مستقل از Webpack وجود دارد — مثلاً از طریق اسکریپتهای سراسری در HTML یا ماژولهای ES با re-export. با این حال، Webpack راحتترین ابزارهای اتوماسیون را فراهم میکند: ProvidePlugin و loaderهایی که نیاز به تغییر دستی کد ندارند.
ProvidePlugin بر سرعت باندلسازی تأثیر نمیگذارد، زیرا در مرحله کامپایل AST کار میکند. imports-loader و exports-loader زمان اندکی به پردازش هر فایل اضافه میکنند. هنگام استفاده در صدها فایل، تفاوت میتواند ۵–۱۵٪ از زمان باندلسازی کامل باشد.
اگر همه وابستگیها از ماژولهای ES و سیستم ماژول پشتیبانی کنند، shimming غیرضروری است. صرفنظر از shimming پیکربندی را ساده میکند، اندازه باندل را کاهش میدهد و خطر تداخل نامها را کم میکند. توصیه میشود وابستگیها را در caniuse.com بررسی کنید.
TypeScript برای متغیرهای shim شده به اعلامیههای نوع اضافی نیاز دارد. باید declare const $: any اضافه کنید یا نوعها را از طریق @types/jquery نصب کنید. ProvidePlugin ایمپورتها را در سطح JavaScript پس از کامپایل TypeScript اضافه میکند، بنابراین نوعها بهصورت جداگانه بررسی میشوند.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید