أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
Optimizing بالعربي

تقسيم الكود للمتوسط: نزّل أول تحميل JavaScript لـ 210KB

📅 ٢٠ مايو ٢٠٢٦⏱ 5 دقائق قراءة
تقسيم الكود للمتوسط: نزّل أول تحميل JavaScript لـ 210KB

مستوى المقال: متوسط. الكلام ده موجّه لمطوّر يكتب JavaScript ويستخدم import/export، وعمل قبل كده build بأداة زي Vite أو webpack. لو لسه مبتدئ، في كل قسم تشبيه بسيط قبل الشرح التقني.

تقسيم الكود في JavaScript: حمّل أقل وافتح موقعك أسرع

لو موقعك بيحمّل ملف JavaScript حجمه أكتر من ميجابايت، والمستخدم بيبصّ في شاشة شبه فاضية 4 أو 5 ثواني — المشكلة غالبًا مش في السيرفر ولا في النت. المشكلة إنك بتبعت للمتصفح كل كود التطبيق دفعة واحدة، وهو محتاج جزء صغير منه علشان يعرض أول صفحة. تقسيم الكود (Code Splitting) بيحل ده، وفي حالة عملية وصل بأول تحميل من 1.83 ميجابايت لـ 210 كيلوبايت.

المشكلة باختصار

أغلب أدوات الـ build بتجمّع كل ملفاتك في bundle واحد. لوحة التحكم، صفحة التقارير، محرّر النصوص، مكتبة الرسوم البيانية — كله بيتحمّل أول ما المستخدم يفتح الموقع، حتى لو راح للصفحة الرئيسية وبس. النتيجة: المتصفح بيقف يحمّل ويفسّر كود مش محتاجه دلوقتي، وزمن التفاعل بيطول.

رسم توضيحي لتقسيم الكود: حزمة JavaScript واحدة تنقسم إلى ملف رئيسي صغير وثلاثة أجزاء تُحمَّل عند الطلب

ليه الـ bundle الواحد بيوقّف موقعك

تخيّل إنك طلبت كوباية مياه في مطعم. بدل ما النادل يجيبهالك على طول، بيستنى لحد ما يجهّز كل أطباق المنيو الـ 80 ويجيبهم على ترابيزتك مرة واحدة. انت محتاج حاجة واحدة، بس بتدفع وقت تجهيز الـ 80. ده بالظبط اللي بيحصل مع الـ bundle الواحد: المتصفح لازم ينزّل ويقرأ كل الكود قبل ما الصفحة تبقى قابلة للاستخدام.

تقنيًا، الـ JavaScript بيتنفّذ على الـ main thread — نفس الـ thread المسؤول عن رسم الصفحة والاستجابة للنقر. كل كيلوبايت JavaScript زيادة معناه وقت أطول في الـ parsing والـ compilation والـ execution على الـ main thread. والنتيجة تأخير في «زمن التفاعل» (Time to Interactive): اللحظة اللي الصفحة تبقى فيها مستجيبة فعلاً، مش بس ظاهرة على الشاشة.

الحل: قسّم الكود لأجزاء تتحمّل عند الطلب

ارجع لمثال المطعم. الطريقة الصح: النادل يجيبلك الكوباية على طول، وباقي الأطباق تتجهّز لما حد يطلبها فعلاً. تقسيم الكود بيعمل نفس الفكرة مع موقعك.

Code Splitting هو تقسيم الـ bundle الواحد لعدة ملفات منفصلة اسمها chunks، كل واحد بيتحمّل وقت الحاجة ليه بس. أداة الـ build بتقطع الكود عند كل نقطة import() ديناميكي وبتعمل chunk مستقل. أفضل طريقة عملية للبداية: قسّم على مستوى المسارات (routes) — كل صفحة في chunk لوحدها.

  1. حدّد المسارات التقيلة اللي مش بتظهر أول لحظة: التقارير، الإعدادات، المحرّر.
  2. استبدل الـ import العادي بـ import ديناميكي عن طريق React.lazy (أو defineAsyncComponent في Vue).
  3. لفّ المكوّنات الكسولة بـ <Suspense> وحدّد عنصر تحميل مؤقت (fallback).
  4. اعمل build وقِس أحجام الـ chunks الناتجة.
JSX
// قبل: كل المسارات في bundle واحد
import Dashboard from './pages/Dashboard';
import Reports from './pages/Reports';
import Editor from './pages/Editor';

// بعد: كل مسار في chunk منفصل يتحمّل عند الطلب
import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./pages/Dashboard'));
const Reports   = lazy(() => import('./pages/Reports'));
const Editor    = lazy(() => import('./pages/Editor'));

export default function App() {
  return (
    <Suspense fallback={<PageSpinner />}>
      <Routes>
        <Route path="/"        element={<Dashboard />} />
        <Route path="/reports" element={<Reports />} />
        <Route path="/editor"  element={<Editor />} />
      </Routes>
    </Suspense>
  );
}

بعد الـ build، قِس النتيجة بدل ما تخمّن:

Bash
# مع Vite: شوف أحجام الـ chunks بعد الـ build
npx vite build

# لتحليل محتوى كل chunk بالتفصيل
npx vite-bundle-visualizer

النتيجة بالأرقام

خد لوحة تحكم SaaS فيها 24 شاشة. قبل التقسيم كان الـ bundle الأساسي 1.83 ميجابايت، والمتصفح بياخد 6.4 ثانية على شبكة الجيل الرابع قبل ما الصفحة تبقى قابلة للاستخدام فعلاً.

رسم بياني يقارن قبل وبعد تقسيم الكود: شريطان طويلان للحالة قبل التقسيم مقابل شريطين قصيرين بعده

بعد تقسيم على مستوى المسارات، أول تحميل (main.js) نزل لـ 210 كيلوبايت — انخفاض 88%. باقي الكود اتوزّع على chunks بتتحمّل لما المستخدم يفتح الصفحة المعنية. زمن التفاعل نزل من 6.4 ثانية لـ 1.9 ثانية — أسرع 70% — وتقييم Lighthouse للأداء طلع من 41 لـ 88. الافتراض هنا مهم: التطبيق فيه مسارات متعددة وكل مسار له كود خاص ملموس. لو تطبيقك صفحة واحدة، المكسب هيكون أقل بكتير.

الـ trade-offs اللي لازم تعرفها

  • كل import() ديناميكي = طلب شبكة إضافي. لو قسّمت بزيادة على مستوى كل مكوّن صغير، هتعمل سلسلة طلبات (waterfall) بتأخّر التنقّل. بتكسب bundle أصغر، بتخسر بساطة طلب واحد. الوازنة: قسّم على مستوى المسار، مش كل زرار.
  • الـ fallback بيظهر لحظة التنقّل. لو الـ chunk كبير والشبكة بطيئة، المستخدم هيشوف spinner ثانية أو اتنين. الحل: استعمل prefetch للمسار المتوقّع عن طريق <link rel="prefetch"> أو حمّل الـ chunk وقت ما المستخدم يعدّي الماوس على اللينك.
  • بتكسب أول تحميل أسرع، بتخسر سرعة أول دخول لكل صفحة. أول مرة يفتح المستخدم صفحة بيستنى تحميل الـ chunk بتاعها — جزء من الثانية عادةً. ده مقبول لأن وقت قراءته للصفحة أطول بكتير من وقت الانتظار ده.
  • كود مشترك ممكن يتكرر. لو كذا chunk بيستخدموا نفس المكتبة، أداة البناء بتطلّع المشترك في chunk vendor تلقائيًا — بس راجع ده بـ bundle visualizer علشان تتأكد إنه مش بيتكرّر فعلاً.

متى متستخدمش تقسيم الكود

تقسيم الكود مش مجاني. لو التطبيق كله أقل من 150 كيلوبايت JavaScript، التقسيم بيضيف طلبات شبكة وتعقيد من غير فايدة محسوسة — سيبه bundle واحد. وكمان landing page بصفحة واحدة، أو موقع محتوى ثابت، مش محتاجين تقسيم على مستوى المسارات أصلاً. التقسيم بيلمع لما يكون عندك تطبيق كبير، بمسارات كتير ومكتبات تقيلة — محرّر نصوص، خرائط، رسوم بيانية — مش كل المستخدمين بيستخدموها.

الخطوة التالية

افتح مشروعك وشغّل npx vite build. بُصّ لأكبر chunk في القائمة. لو لقيت مسار تقيل مش بيظهر أول لحظة — صفحة إعدادات أو تقارير أو محرّر — لفّه بـ lazy() زي المثال فوق، اعمل build تاني، وقارن حجم أول تحميل. لو نزل بشكل ملحوظ، كمّل على باقي المسارات. لو ماتغيّرش، يبقى الكود التقيل موجود في الـ chunk الأساسي نفسه — وده يحتاج تحليل بـ bundle visualizer.

مصادر

  • توثيق React الرسمي — lazy و Suspense: react.dev/reference/react/lazy
  • توثيق Vite — Features و Build (Dynamic Import): vitejs.dev/guide/features
  • MDN — التعبير import() الديناميكي: developer.mozilla.org
  • web.dev — Reduce JavaScript payloads with code splitting: web.dev
  • توثيق webpack — Code Splitting: webpack.js.org/guides/code-splitting

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة