من Parcel إلى Vite: قصة قصيرة عن انتقال 100 ألف سطر من التعليمات البرمجية
لقد قمنا بنقل مشاريعنا الثلاثة للواجهة الأمامية من Parcel إلى Vite ، وكانت العملية سلسة...
القصة الخلفية
لدينا ثلاثة مشاريع رئيسية للواجهة الأمامية في Logto: تجربة تسجيل الدخول، لوحة التحكم والمعاينة الحية. هذه المشاريع كلها في TypeScript وReact وSASS modules؛ في المجمل، تحتوي على حوالي 100 ألف سطر من التعليمات البرمجية.
لقد أحببنا Parcel لبساطته وإعداده الخالي من التكوينات. ما زلت أذكر اليوم الذي صُدمت فيه بمدى سهولة إعداد مشروع جديد باستخدام Parcel. يمكنك فقط تشغيل parcel index.html
وبوم، يتم تثبيت جميع التبعيات اللازمة ويعمل المشروع. إذا كنت مطورًا "متمرسًا"، قد تشعر بنفس الطريقة عند مقارنته بالأيام السابقة لإعداد Gulp وWebpack. Parcel يشبه العصا السحرية.
بساطة Parcel كانت السبب الرئيسي لبقائنا معه لفترة طويلة، رغم أنه قد يكون مزاجيًا في بعض الأحيان. على سبيل المثال:
- كان Parcel يفشل أحيانًا في تجميع المشروع لأنه لا يمكنه العثور على بعض الملفات التي كانت موجودة بالفعل.
- كان يحتاج لبعض الإعدادات الخاصة لجعله يعمل مع إعدادنا للمونوريبوس.
- ليس لديه دعم أصلي لـ MDX 3، لذا كان علينا إنشاء محول مخصص لذلك.
- لا يدعم القطع اليدوية (في وقت كتابة هذا المقال، ميزة القطع اليدوية لا تزال في مرحلة تجريبية)، وهو أمر جيد في معظم الظروف، ولكن في بعض الأحيان تحتاجها.
لماذا قررنا الانتقال إلى شيء آخر؟
- علقنا مع Parcel 2.9.3، الذي صدر في يونيو 2023. في كل مرة تصدر نسخة جديدة بعد ذلك، كنا نحاول الترقية، لكنها كانت تفشل دائمًا مع أخطاء في البناء.
- أحدث إصدار من Parcel كان 2.12.0، صدر في فبراير 2024. رغم أن لديها تحديثات يومية تقريبًا، لم يتم إصدار أي تحديثات جديدة منذ ذلك الحين.
فتح شخص ما حتى مناقشة ليسأل إن كان Parcel ميتًا. الإجابة الرسمية هي لا، Parcel لا يزال حيًا، لكنه في حالة "نحن نعمل على إعادة بناء كبيرة وليس لدينا وقت لإصدارات أصغر". بالنسبة لنا، كان الأمر يشبه "موت البط": أحدث إصدار يمكننا استخدامه من أكثر من عام مضى، ولا نعرف متى سيتم إصدار النسخة القادمة. يبدو كأنه ميت، يتصرف كالميت، لذا فهو ميت بالنسبة لنا.
لماذا Vite؟
عرفنا Vite من Vitest. قبل عدة أشهر، كنا متعبين من دعم ESM في Jest (في الاختبار) وأردنا تجربة شيء جديد. تفوق Vitest بفضل الدعم الأصلي لـ ESM والتوافق مع Jest. لديه تجربة مستخدم رائعة وقوى بـ Vite.
الوضع الراهن
قد تكون لديك إعدادات مختلفة في مشروعك، ولكن عادة ستجد بدائل الإضافات مع ازدهار النظام البيئي لـ Vite. هنا هي إعداداتنا في لحظة الانتقال:
- مونوريبوس: نستخدم PNPM (الإصدار 9) لإدارة المونوريبوس لدينا.
- الوحدات: نستخدم وحدات ESM لجميع مشاريعنا.
- TypeScript: نستخدم TypeScript 5.5.3) لجميع مشاريعنا مع مسارات مستعارة.
- React: نستخدم React 18.3.1) لجميع مشاريع الواجهة الأمامية.
- التنسيق: نستخدم وحدات SASS.
- SVG: نستخدم SVGs كـ React components.
- MDX: لدينا MDX مع دعم ترميز GitHub وMermaid.
- التحميل الكسول: نحتاج إلى تحميل الكسول لبعض صفحاتنا وعناصرنا.
- الضغط: ننتج أصول مضغوطة (gzip وbrotli) للإصدارات الإنتاجية.
الهجرة
بدأنا الهجرة بإنشاء مشروع Vite جديد واستكشافه لمعرفة كيفية عمله. كانت العملية سلسة واستغر قت الهجرة الحقيقية بضعة أيام فقط.
دعم مدمج
لدى Vite دعم مدمج لـ.monorepo وESM وTypeScript وReact وSASS. لم نكن بحاجة إلا لتثبيت الإضافات والتكوينات اللازمة لجعلها تعمل.
مسار الاستعارات
لدى Vite دعم مدمج لمسارات الاستعارات، على سبيل المثال، في ملف tsconfig.json
لدينا:
كنا بحاجة فقط إلى إضافة نفس القرار في ملف vite.config.ts
لدينا:
لاحظ أن مسار الاستعاضة يجب أن يكون مسارًا مطلقًا، بينما يكون نسبيًا إلى جذر المشروع. بدلاً من ذلك، يمكنك استخدام vite-tsconfig-paths plugin لقراءة مسارات الاستعارات من tsconfig.json
.
React Fast Refresh وHMR
على الرغم من أن Vite يحتوي على دعم مدمج لـ HMR، إلا أنه يتطلب تركيب مكون إضافي لتفعيل React Fast Refresh. استخدمنا @vitejs/plugin-react plugin الذي توفره فريق Vite ويدعم ميزات React بشكل ممتاز مثل Fast Refresh:
SVG كمكون React
نستخدم vite-plugin-svgr plugin لتحويل SVGs إلى React components. إنه بسيط كما هو الحال في إضافة المكون إلى تكوين Vite:
ومع ذلك، لم نحدد على أي شرط يجب أن يتم تحويل SVGs إلى مكونات React، لذلك تم تحويل جميع الاستيرادات. يوفر المكون إعداد تكوين افتراضي أفضل: تحويل SVGs التي تم استيرادها بامتداد .svg?react
. قمنا بتحديث الاستيرادات لدينا وفقًا لذلك.
وحدات SASS
على الرغم من أن Vite يحتوي على دعم مدمج لوحدات SASS، هناك شيء واحد يجب أن تهتم به: كيفية تنسيق أسماء الصفوف. قد يكون الأمر مزعجًا للمستخدمين واختبارات التكامل لدينا إذا لم يتم تنسيق أسماء الصفوف بشكل متسق. يمكن حل المشكلة بإعداد تكوين في سطر واحد في vite.config.ts
:
بالمناسبة، لدى Parcel وVite نكهات مختلفة لاستيراد ملفات SASS:
ولكن syntax * as
يعمل في Vite، لكنه سيتسبب في فقدان أسماء الصفوف الممركبة عندما تستخدم مفاتيح ديناميكية للوصول إلى كائن styles
. على سبيل المثال:
دعم MDX
بما أن Vite يستخدم Rollup تحت الغطاء، يمكننا استخدام المكون الرسمي @mdx-js/rollup لدعم MDX وكذلك ملحقاتها. يبدو التكوين كما يلي:
يستخدم مكون remarkGfm
لدعم ترميز GitHub، ويُستخدم مكون rehypeMdxCodeProps
لتمرير الخصائص إلى الكتل البرمجية في ملفات MDX مثلما يفعل Docusaurus.
دعم Mermaid داخل MDX
نود استخدام رسوم Mermaid البيانية في ملفات MDX الخاصة بنا مثل لغات البرمجة الأخرى. يجب أن يكون الاستخدام بسيطًا مثل الكتل البرمجية الأخرى:
يجب أن يتم تصييره كالتالي:
بما أن تطبيقنا يدعم الثيمات الفاتحة والداكنة، كتبنا قليلاً لجعل رسوم Mermaid البيانية تعمل مع الثيمة الداكنة. تم إنشاء مكون React:
useTheme
هو خطاف مخصص للحصول على الثيمة الحالية من السياق. يتم استيراد مكتبة mermaid
بشكل غير متزامن لتقليل حجم التحميل لأول مرة.
بالنسبة للكتلة البرمجية في ملف MDX، لدينا مكون موحد للقيام بالمهمة:
وأخيرًا نقوم بتعريف موفر MDX كما يلي:
التحميل الكسول
هذا ليس شيئًا خاصًا بـ Vite، لكنه يستحق الذكر حيث قمنا بتحديث صفحاتنا لاستخدام التحميل الكسول أثناء الهجرة، ولم ينكسر أي شيء بعد ذلك.
لدى React وظيفة React.lazy
البنائية لتحميل المكونات بشكل كسول. ومع ذلك، قد يسبب بعض المشاكل عندما تكون سريعًا في التكرار. قمنا بإعداد مكتبة صغيرة تسمى react-safe-lazy لحل المشاكل. إنها بديل جاهز لـ React.lazy
وتوجد توضيحات مفصلة في هذا المنشور.
الضغط
هناك مكون لطيف يسمى vite-plugin-compression لإنتاج أصول مضغوطة. يدعم الضغطين gzip وbrotli. التكوين بسيط:
القطع اليدوية
إحدى الميزات الرائعة في Vite (أو Rollup التي تحته) هي القطع اليدوية. بينما يتم استخدام React.lazy
لتحميل المكونات بشكل كسول، يمكننا أن نحظى بمزيد من التحكم بفضل توزيع وتحديد أي مكونات أو وحدات يجب تجميعها معًا.
على سبيل المثال، يمكننا أولاً استخدام vite-bundle-visualizer لتحليل حجم التجميع والتبعيات. ثم يمكننا كتابة دالة مناسبة لتقسيم القطع:
خادم التطوير
على عكس بناء الإنتاج، لن يقوم Vite بدمج التعليمات البرمجية المصدرية في وضع التطوير (بما في ذلك التبعيات المربوطة في نفس المونوريبوس) ويعامل كل وحدة كملف. بالنسبة لنا، سيقوم المتصفح بتحميل مئات الوحدات لأول مرة، مما يبدو جنونيًا لكنه في الواقع يعمل بشكل جيد في معظم الحالات. يمكنك رؤية النقاش هنا.
إذا كان هذا أمرًا يهمك، فالحل البديل ولكنه ليس مثاليًا هو إدراج التبعيات المربوطة في خيار optimizeDeps
في vite.config.ts
:
سيقوم هذا بـ "تجميع مبدئي" للتبعيات المربوطة وجعل خادم التطوير أسرع. العملة السلبية هي أن HMR قد لا يعمل كما هو متوقع للتبعيات المربوطة.
بالإضافة إلى ذلك، نستخدم وكيلًا يخدم الملفات الثابتة في الإنتاج ويوجه الطلبات إلى خادم Vitest في التطوير. لدينا بعض المنافذ المحددة لتجنب تعارضات، ومن السهل أيضًا إعدادها في vite.config.ts
:
المتغيرات البيئية
على عكس Parcel، يستخدم Vite نهجًا حديثًا للتعامل مع المتغيرات البيئية باستخدام import.meta.env
. ستحمل تلقائيًا ملفات .env
وتستبدل المتغيرات في الشيفرة. ومع ذلك، يتطلب أن تكون جميع المتغيرات البيئية مميزة بالمقدمة VITE_
(قابل للتكوين).
بينما كنا نستخدم Parcel، كانت تستبدل ببساطة متغيرات process.env
دون التحقق من المقدمة. لذا توصلنا إلى حل بديل باستخدام حقل define
لتسهيل الهجرة:
هذا يسمح لنا بإضافة المقدمة تدريجيًا إلى المتغيرات البيئية وإزالة حقل define
.
الخاتمة
هذا كل ما في الأمر! لقد نجحنا في نقل مشاريع الواجهة الأمامية الثلاثة من Parcel إلى Vite، ونأمل أن تساعدك هذه القصة القصيرة في هجرتك. هكذا يبدو التكوين في النهاية: