Polyfill هو كود يحاكي الوظائف المفقودة (API، طرق، كائنات) في البيئات التي لا تحتوي على تطبيق أصلي لها. يتيح Polyfill استخدام ميزات JavaScript أو CSS أو Web API الحديثة في المتصفحات القديمة وبيئات التشغيل. وفقًا لـ MDN Web Docs، تعتبر polyfills أداة رئيسية للتحسين التدريجي وضمان التوافق عبر المتصفحات.
النقاط الرئيسية
Polyfill هو جزء من الكود (عادة JavaScript) يطبق وظائف لا تدعمها بيئة التشغيل بشكل أصلي. صاغ المصطلح ريمي شارب في عام 2009 كلعبة كلمات: Polyfill مشابه لـ Polyfilla، وهي مادة حشو تملأ الشقوق في الجدار. يملأ Polyfill الفجوات بين المعيار ودعمه في متصفح أو بيئة تشغيل محددة.
Polyfill لا يعدل الكود الموجود — بل يوسع بيئة التشغيل. إذا كان المتصفح لا يدعم Array.prototype.includes، يضيف polyfill هذه الطريقة إلى النموذج الأولي Array قبل تنفيذ الكود الرئيسي. يمكن للـ polyfills محاكاة كائنات عامة جديدة (Promise، Map، Set، Symbol)، طرق ثابتة (Array.from، Object.assign) وطرق النماذج الأولية.
كشف الميزات (Feature detection) هو آلية إلزامية قبل تثبيت polyfill. بدلاً من التحقق من user-agent (أي متصفح)، يجب التحقق من وجود الطريقة: if (!Array.prototype.includes) { Array.prototype.includes = ... }. يضمن ذلك عدم استبدال polyfill للتطبيق الأصلي إذا كان موجودًا بالفعل. تجمع Google Analytics وخدمات أخرى بيانات دعم API للتحليل.
ظهرت أول polyfills في عصر Internet Explorer 6–8 (2005–2009)، عندما اكتشف المطورون فجوة بين معايير W3C وتطبيقات المتصفحات. قدم المصطلح ريمي شارب في عام 2009 في BarCamp London. كان أول polyfill جماهيري هو html5shiv (2009) — مكتبة تضيف دعمًا لعلامات HTML5 (<section>، <article>، <nav>) في Internet Explorer.
مع ظهور ES6 (2015) ودورة التحديث السنوية لـ ECMAScript، زاد عدد polyfills المطلوبة. كل عام يضيف المعيار طرقًا جديدة (Array.includes، String.padStart، Object.fromEntries، Promise.allSettled) لا تدعمها المتصفحات القديمة. أصبح core-js، الذي بدأ كـ es6-shim في 2014، حلاً عالميًا. في عام 2026، يحتوي core-js على أكثر من 5000 وحدة polyfill لـ ES5–ES2025.
| الفئة | يمكن عمل polyfill | لا يمكن عمل polyfill |
|---|---|---|
| طرق النماذج الأولية | Array.includes, String.startsWith | — |
| كائنات عامة | Promise, Map, Set, Symbol | — |
| طرق ثابتة | Object.assign, Array.from | — |
| صياغة اللغة | — | Arrow functions, async/await, class |
| Web API | fetch, IntersectionObserver | Service Worker (يتطلب دعمًا أصليًا) |
التجميع (Transpilation) يحول الصياغة الجديدة إلى صياغة قديمة (const → var، () => {} → function() {}). Polyfill يضيف طرقًا وكائنات مفقودة (Promise، Array.includes). تكمل هاتان الآليتان بعضهما البعض: التجميع يجعل الكود متوافقًا نحويًا، وتضمن polyfills اكتمال API. Babel + core-js هو المزيج القياسي للدعم الكامل.
يحدد Babel @babel/preset-env مع خيار useBuiltIns أي polyfills مطلوبة بناءً على المتصفحات المستهدفة. useBuiltIns: "usage" يحلل أي API تُستخدم في الكود ويستورد فقط polyfills الضرورية من core-js. useBuiltIns: "entry" يستورد جميع polyfills للمتصفحات المستهدفة من خلال استيراد واحد core-js/stable.
// التحقق من الوجود وإضافة polyfill
if (typeof Array.prototype.includes !== "function") {
Object.defineProperty(Array.prototype, "includes", {
value: function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError("Array.prototype.includes called on null or undefined");
}
var arr = Object(this);
var len = arr.length >>> 0;
if (len === 0) { return false; }
var start = fromIndex | 0;
var k = Math.max(start >= 0 ? start : len + start, 0);
while (k < len) {
if (arr[k] === searchElement) { return true; }
k++;
}
return false;
},
writable: true,
configurable: true,
});
}
// الاستخدام — الآن آمن في أي متصفح
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // truePolyfill لـ Array.prototype.includes يتحقق مما إذا كانت الطريقة محددة في النموذج الأولي Array. إذا لم تكن كذلك، ينشئ الخاصية عبر Object.defineProperty مع الأعلام writable: true، configurable: true. يتبع التنفيذ مواصفات ES2016: التحقق من null/undefined، التحويل إلى كائن، التعامل مع fromIndex السالب. بعد إضافة polyfill، يعمل استدعاء arr.includes(3) في جميع المتصفحات، بما في ذلك Internet Explorer 11.
core-js هي أشمل مكتبة polyfills لجافا سكريبت، تدعم جميع مقترحات TC39 المرحلة 4 (معيار ECMAScript). تتضمن core-js polyfills لـ Promise، Symbol، Map، Set، WeakMap، WeakSet، طرق Array، طرق String، طرق Object، طرق Number، طرق Math، Reflect، globalThis وجميع مقترحات المرحلة 4. الإصدار الحالي core-js 3.38+ يغطي ES5–ES2025.
تتكامل core-js مع Babel من خلال @babel/preset-env وخيار useBuiltIns. بدون هذا التكامل، كان على المطورين استيراد كل polyfill يدويًا: import "core-js/stable/array/includes". يضيف @babel/preset-env تلقائيًا الواردات الضرورية بناءً على المتصفحات المستهدفة من .browserslistrc. هذا يقلل حجم الحزمة — يتم تضمين polyfills الضرورية فقط.
Fetch API هي واحدة من أكثر Web API شيوعًا لعمل polyfill لها. التطبيق الأصلي لـ fetch متاح في Chrome 42+ (2015)، Safari 10.1+ (2017)، Firefox 39+ (2015)، لكنه غائب في Internet Explorer و WebViews القديمة. يحاكي polyfill whatwg-fetch fetch عبر XMLHttpRequest. بديل — استخدام isomorphic-fetch (polyfill لـ Node.js والمتصفح) أو المكتبة العالمية axios التي لا تتطلب polyfills.
// تحميل polyfill fetch فقط للمتصفحات القديمة
if (typeof self.fetch !== "function") {
import("whatwg-fetch").then(module => {
self.fetch = module.fetch;
console.log("fetch polyfill loaded");
});
}
// استخدام fetch (يعمل مع كل من polyfill و API الأصلي)
async function loadData() {
try {
const response = await fetch("https://api.example.com/data");
const json = await response.json();
return json;
} catch (error) {
console.error("Failed to load:", error);
}
}الاستيراد الديناميكي لـ polyfill fetch عبر import() يضمن أن المتصفحات الحديثة لا تحمل كودًا غير ضروري. يتم تحميل polyfill بشكل غير متزامن ولا يعوق الخيط الرئيسي. بعد التحميل، يستبدل self.fetch التطبيق الأصلي أو يضيف المفقود. هذه تقنية تحسين تدريجي: المتصفحات الحديثة تحصل على كود أصلي فقط، القديمة تحصل على polyfill إضافي.
// babel.config.js — core-js + preset-env
module.exports = {
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
corejs: {
version: "3.38",
proposals: true,
},
targets: {
browsers: ["> 0.5%", "not dead", "not op_mini all"],
},
}],
],
};# .browserslistrc — المتصفحات المستهدفة
> 0.5%
last 2 versions
not dead
not op_mini all
ie >= 11
not ios_saf < 12useBuiltIns: "usage" يحلل الكود ويضيف فقط polyfills المستخدمة فعليًا. corejs.version يحدد إصدار core-js في المشروع. targets.browsers يحدد المستوى الأدنى للمتصفحات — كلما كانت المتصفحات المستهدفة أقدم، زادت polyfills المضمنة. يتم استخدام .browserslistrc ليس فقط بواسطة Babel ولكن أيضًا بواسطة Autoprefixer و PostCSS و Stylelint للاستهداف المتناسق.
Polyfill.io هي خدمة (ومكتبة بنفس الاسم) تحدد ديناميكيًا polyfills التي يحتاجها متصفح المستخدم وتعيد فقط تلك. يستخدم Polyfill.io رأس User-Agent لتحديد إصدار المتصفح ويقدم مجموعة أدنى من polyfills. هذا يقلل حجم البيانات المنقولة مقارنة بحزمة polyfills الشاملة.
يتم توصيل Polyfill.io عبر علامة <script> قبل الكود الرئيسي للتطبيق. تحلل الخدمة User-Agent وتعيد ملف JavaScript مع polyfills فقط لذلك المتصفح. لن يحصل Chrome على أي polyfill، بينما سيحصل IE 11 على المجموعة الكاملة. هذا نهج أمثل للأداء: المتصفحات الحديثة لا تحمل كودًا غير ضروري.
<!-- Polyfill.io: تحميل ديناميكي -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes%2CObject.assign%2Cfetch"></script>
<!-- الإصدار المحلي من Polyfill.io -->
<script src="/js/polyfill.js"></script>
<script>
// feature detection for fetch
if (!self.fetch) {
loadScript("/js/fetch-polyfill.js");
}
</script>المعامل features في عنوان URL لـ Polyfill.io يحدد polyfills المطلوب تحميلها. القيم الممكنة: أسماء الطرق (Array.prototype.includes)، الكائنات العامة (Promise)، أو أعلام (es6، es2016). العلم "default" يحمل مجموعة أساسية لجافا سكريبت الحديث. لمشاريع الإنتاج، يُوصى باستضافة Polyfill.io على CDN خاص أو استخدام إصدار محلي من المكتبة للتحكم في التوفر.
WebView في التطبيقات المحمولة (Android WebView، WKWebView على iOS) هو بيئة خاصة للـ polyfills. يعتمد إصدار WebView على إصدار نظام التشغيل وتحديث Chrome System WebView المثبت (Android) أو WKWebView من iOS Safari. في الإصدارات القديمة من Android (4.4، 5.0)، يعتمد WebView على Chromium 30–37 — بدون دعم fetch، Promise، IntersectionObserver.
React Native يستخدم JavaScriptCore (iOS) أو Hermes (Android) — هذه المحركات تنفذ ES6+ بشكل مختلف. يدعم JavaScriptCore على iOS معظم ميزات ES6 لكنه قد يفتقد بعض مقترحات المرحلة 3. Hermes (المستخدم افتراضيًا في React Native 0.70+) يدعم مجموعة محدودة من معيار ES — polyfills إلزامية له.
// feature detection لـ WebView
const polyfills = [];
// Promise
if (typeof Promise === "undefined") {
polyfills.push("Promise");
}
// Fetch API
if (typeof self.fetch === "undefined") {
polyfills.push("fetch");
}
// IntersectionObserver (مطلوب للتحميل البطيء)
if (typeof IntersectionObserver === "undefined") {
polyfills.push("IntersectionObserver");
}
// تحميل ديناميكي للـ polyfills
if (polyfills.length > 0) {
const script = document.createElement("script");
script.src = "https://cdn.polyfill.io/v3/polyfill.min.js"
+ "?features=" + polyfills.join(",");
document.head.appendChild(script);
}كشف الميزات (Feature detection) لـ WebView يتحقق من وجود API حرجة (Promise، fetch، IntersectionObserver) ويحمل polyfills ديناميكيًا فقط للمفقودة. يضمن ذلك أن WebViews الحديثة (Chrome 100+ على Android 12) لا تحمل كودًا غير ضروري، بينما تحصل WebViews القديمة (Android 5.0) على الدعم المطلوب.
الأسئلة الشائعة
React Native على Hermes يتطلب polyfills لبعض طرق ES: Array.flat، Array.flatMap، globalThis، TextEncoder. يُوصى بتضمين core-js أو react-native-polyfill-globals لإصدارات الإنتاج. يدعم JavaScriptCore على iOS ميزات أكثر، لكنه قد يتطلب أيضًا polyfills لمقترحات المرحلة 3.
Polyfills تقلل الأداء بنسبة 1–5%، لأن تطبيق JavaScript أبطأ من تطبيق C++ الأصلي في المحرك. على سبيل المثال، polyfill لـ Promise في JS الخالص أبطأ من Promise الأصلي في V8. ومع ذلك، بالنسبة لمعظم التطبيقات، الفرق غير ملحوظ. للكود الحرج، يُوصى بالتحقق من وجود التطبيق الأصلي من خلال كشف الميزات.
التجميع (Transpilation) يحول الصياغة: const → var، دوال الأسهم → function. Polyfill يضيف كائنات/طرق جديدة: Promise، Array.includes، fetch. يعمل التجميع في وقت البناء، بينما يُحمَّل polyfill في وقت التشغيل. كلا الآليتين ضروريتان للدعم الكامل للكود الحديث في البيئات القديمة.
نعم، إذا كان جمهورك المستهدف يستخدم فقط المتصفحات الحديثة (Chrome 90+، Safari 15+، Firefox 90+). للمشاريع التي تدعم الأجهزة القديمة أو المستخدمين في المؤسسات (Internet Explorer 11 لا يزال مستخدمًا في القطاع الحكومي)، الـ polyfills إلزامية. حلل إحصائيات متصفحات جمهورك عبر Google Analytics.
core-js في build كامل يزن ~85 كيلوبايت (gzip). عند استخدام useBuiltIns: "usage" في Babel، يتم تضمين polyfills الضرورية فقط، مما يقلل الحجم إلى 5–30 كيلوبايت حسب المتصفحات المستهدفة. للمتصفحات الحديثة (Chrome 100+)، قد لا تكون هناك حاجة لأي polyfill.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا