🏗️ أدوات بناء Frontend بتتضرب في حائط — ده اللي جاي بعد كدا
العبقرية في السرعة
لمدة خمس سنوات، كان النظام البيئي لأدوات الجانب الأمامي في سباق تسلح حول السرعة. مقاييس البداية الباردة. مللي ثانية في HMR. وقت الحزمة إلى العشرة. Webpack مُحسّن التجميع. Vite مُحسّن التطوير. Rolldown يحسن Rollup نفسه. لقد كنا نطارد الصفر — وقت انتظار صفر، إعادة بناء صفر، احتكاك صفر. ولكن هنا الحقيقة المزعجة: معظم أدوات البناء الرئيسية لا تزال تشترك في نفس افتراض الهندسة المعمارية — يبدأ البناء من الصفر كل مرة. هذا الافتراض عمل بشكل جميل عندما كان للمشاريع بضع مئات من الوحدات. ولكن قواعد البيانات الحديثة تتجاوز بانتظام 10,000 وحدة. Monorepos مع تطبيقات متعددة، مكتبات واجهة مستخدم مشتركة، ونعم — رمز تم إنشاؤه بواسطة الذكاء الاصطناعي يعني أن عمليات إعادة البناء تحدث أكثر من أي وقت مضى. والمنهج الذي يبدأ من الصفر يبدأ في التصدع.
أين الجدار
مقال حديث على Dev.to أشار إليه بشكل مثالي: أدوات بناء الجانب الأمامي تصل إلى حائط. مقاييس الأداء مثيرة للإعجاب للمشاريع الجديدة، ولكنها لا تعكس الواقع. المشاريع الحقيقية لها:
- 10 آلاف وحدة+ في مخطط بناء واحد
- رابط Monorepo حيث يتسبب التغيير في حزمة مشتركة في عمليات إعادة بناء متسلسلة في تطبيقات متعددة
- رمز تم إنشاؤه بواسطة الذكاء الاصطناعي يتغير بسرعة من تكرار إلى تكرار
- دورات إعادة البناء المستمرة أثناء التطوير التي تعاقب أخطاء الذاكرة المؤقتة لقد عشت هذا بشكل مباشر في مشروع مع 30+ واجهة أمامية دقيقة ومكتبة مكونات مشتركة. ما كان ينبغي أن يكون تحديث HMR لمدة 300 مللي ثانية تحول إلى 3-4 ثوان من وقت إعادة البناء لأن التغيير في المكتبة المشتركة أبطل نصف مخطط الوحدة.
لماذا Vite (وأصدقاؤها) لا تزال تعاني
منهج Vite ذكي — ESM الأصلي في التطوير، بدون تجميع حتى الإنتاج. إنه يتجاوز المشكلة في وضع التطوير من خلال السماح للمتصفح بإجراء حل الوحدة. ولكن عملية البناء للإنتاج لا تزال تصل إلى نفس الحائط. وحتى في وضع التطوير، عندما يكون لديك آلاف الوحدات، ي đấu المتصفح نفسه مع شلال HTTP — يعني كل استيراد طلبًا جديدًا. العرق الرئيسي ليس خوارزمية التجميع بعد الآن. إنه نعومة الذاكرة المؤقتة وإبطال الصلاحية. عندما يتغير ملف واحد، كم من مخطط البناء يتم إبطال صلاحيته؟ لا تزال معظم الأدوات تبطل الصلاحية على مستوى الوحدة، مما يعني أن تغيير حرف واحد يمكن أن يتسبب في تسرب عبر مئات من التبعيات.
ما تبدو عليه الجيل القادم
بناءً على ما رأيته من التجارب مثل Rolldown (مجمّع Rust المملوك لشركة ByteDance) و Turbopack (مجمّع Rust المملوك لشركة Next.js) والاتجاهات الناشئة في النظام البيئي، هذا حيث أعتقد أننا متجهين:
خوادم البناء المستدامة
بدلاً من البدء من الصفر كل مرة، سوف تقوم أدوات الجيل القادم بتشغيل ديمون بناء مستدام في الخلفية — مشابه لما يفعله esbuild مع وضع المراقبة، ولكن تم إتخاذها إلى استنتاجها المنطقي. يبقى مخطط البناء في الذاكرة، ويتم إعادة حساب الفرق الأدنى فقط.
الذاكرة المؤقتة القابلة للموضوع على مستوى الوحدة
تخيل أن كل مكون لبناء الوحدة يحصل على مفتاح تشفير المحتوى. إذا لم يتغير المصدر، يتم إعادة استخدام الإخراج المخزّن في الذاكرة المؤقتة على الفور — حتى عبر الفروع وعمليات تشغيل CI. لقد قام Turbopack بتجربة هذا، والأرقام واعدة.
تقسيم مخطط البناء
بدلاً من معاملة قاعدة البيانات بأكملها كمحفظة ضخمة، يمكن أن يؤدي التقسيم الذكي إلى عزل التغييرات. إذا قمت بتغيير دالة مرافق تستخدمها تطبيق A ولكن ليس تطبيق B، يجب فقط إعادة بناء تطبيق A. بسيط في النظرية، مفاجئ الصعوبة في الممارسة مع الأدوات الحالية.
// مفاهيمي: حدود تقسيم البناء
const buildConfig = {
partitions: [
{ name: 'shared-ui', entry: './packages/ui', isolated: true },
{ name: 'app-admin', entry: './apps/admin', dependsOn: ['shared-ui'] },
{ name: 'app-public', entry: './apps/public', dependsOn: ['shared-ui'] },
],
caching: 'content-addressable' as const,
};
ما يمكنك فعله الآن
بينما ننتظر الجيل القادم من الأدوات، هذا ما ساعدني على الحفاظ على أوقات البناء قابلة للإدارة:
- استخدم
npm queryأو فلتر pnpm لتوجيه أوامر البناء إلى الحزم المتأثرة في Monorepos. - استفد من
optimizeDeps.excludeفي Vite لمنع التجميع المسبق غير الضروري للتبعيات الكبيرة. - اقسم تطبيقك إلى نقاط دخول — قم بتحميل الكسل لكل شيء ليس مرئيًا فوق الطية.
- فكر في استخدام esbuild أو rolldown لعمليات البناء للإنتاج إذا كان إعدادك الحالي بطيئًا جدًا. أدوات Rust/Go المبنية بشكل حقيقي أسرع للبناء الخام.
- قم بفحص مخطط الوحدة بشكل دوري. سوف تتفاجأ من كمية النسخ المكررة من نفس المكتبة التي تنتهي في حزمتك.
# تحقق من تركيبة الحزمة (Next.js)
npx next build --debug
# قم بتصوير حزمتك
npx source-map-explorer .next/static/chunks/*.js
الخلاصة
أدوات بناء الجانب الأمامي حققت تقدمًا رائعًا، ولكن افتراض البداية من الصفر يصبح عائقًا للمشاريع التي نبنيها اليوم. الأدوات التي سوف تفوز في الدورة القادمة هي تلك التي تعامل مخطط البناء ككائن مستدام — مخزّن في الذاكرة المؤقتة، مقسم، محدث بشكل متزايد — بدلاً من شيء لإعادة بناؤه من الصفر في كل استدعاء. الجدار حقيقي، ولكننا ضربنا جدران من قبل (تذكر حقبة ما قبل Webpack؟)، والنظام البيئي دائمًا يتكيف. أنا مراهن على مجمّعات Rust المبنية مع الذاكرة المؤقتة المستدامة لتقود الطريق.