التقيت شفرة تقسيم منذ فترة طويلة جدا ، في عام 2008 ، عندما تم تعليق ياندكس قليلا ، والنصوص Yandex.Direct متصلة متزامن مع الموقع ببساطة قتل هذا الموقع. بشكل عام ، كان من الطبيعي في تلك الأيام إذا كانت "البرامج النصية" الخاصة بك تحتوي على 10 ملفات تتصل بها بالترتيب الصحيح الوحيد ، الذي لا يزال يعمل بشكل جيد.
ثم بدأت العمل بنشاط مع البطاقات ، وما زالت متصلة كنصوص خارجية ، بالطبع كسلان التحميل. بعد ذلك ، بصفتي عضوًا في فريق Yandex.Maps ، استخدمت بنشاط وحدات ymodules لاستخدام اهتزاز الأشجار على العميل ، مما وفر تقسيمًا مثاليًا للشفرة.
ثم انتقلت إلى webpack
و webpack
، إلى بلد البلهاء الخائفين الذين نظروا إلى require.ensure
مثل كبش عند بوابة جديدة ، وما زلت أفعل ذلك.
تقسيم الرمز ليس ميزة نجاح باهر ، بل يجب أن يكون. لا يزال SSR
لن تتدخل ...

مقدمة صغيرة
في الوقت الحاضر ، عندما تنمو الحزم كل يوم ، يصبح تقسيم الشفرة أكثر أهمية من أي وقت مضى. في البداية ، خرج الأشخاص من هذا الموقف ببساطة عن طريق إنشاء نقاط دخول منفصلة لكل صفحة من طلباتهم ، وهو أمر جيد عمومًا ، لكنه لن يعمل لصالح SPA.
ثم جاءت وظيفة require.ensure
، والمعروفة اليوم باسم dynamic import
(مجرد الاستيراد) ، والتي يمكنك من خلالها ببساطة طلب وحدة نمطية ، والتي ستتلقىها لاحقًا بعض الشيء.
كانت المكتبة الأولى حول هذه الحالة الخاصة بـ React قابلة للتحميل ، وهذه الضجة التي لا تزال غير واضحة جدًا بالنسبة لي ، والتي ماتت بالفعل (لقد توقفت فقط عن إرضاء المؤلف).
في الوقت الحالي ، سيكون الخيار "الرسمي" أكثر أو أقل هو React.lazy
القابلة للتحميل (فقط @loadable
) ، والخيار بينهما واضح:
- React.lazy غير قادر تمامًا على SSR (تقديم جانب الخادم) ، من الكلمة بشكل عام. حتى في الاختبارات ، ستقع دون رقصات خاصة مع الدف ، مثل "الوعود المتزامنة".
- لا يمكن أن يكون SSR القابل للتحميل ، وأثناء دعمه للتشويق ، أسوأ من React.Lazy.
على وجه الخصوص ، يدعم برنامج loadable برامج التعبئة الجميلة لمكتبات التحميل (loadable.lib ، يمكنك أن تأخذ moment.js في React renderProp) ، ويساعد حزمة الويب على جانب الخادم لجمع قائمة من البرامج النصية المستخدمة ، والأنماط ، والموارد اللازمة للتجميع المسبق (الذي لا يعرف webpack نفسه حقًا). بشكل عام ، اقرأ الوثائق الرسمية .
SSR
بشكل عام ، والمشكلة كلها في SSR. بالنسبة للمسؤولية الاجتماعية للشركات (Client Side Render) ، إما أن React.lazy أو نص برمجي صغير يحتوي على 10 أسطر سيكون ملائمًا - سيكون هذا بالتأكيد كافٍ ، ومن غير المنطقي توصيل مكتبة خارجية كبيرة. ولكن على الخادم هذا لن يكون كافيا. وإذا كنت لا تحتاج حقًا إلى SSR ، فيمكنك تخطي القراءة أكثر. ليس لديك أي مشاكل تحتاج إلى حل طويل وشاق.
SSR هو الألم. أنا (بطريقة ما) هي واحدة من صانعي المكونات القابلة للتحميل ومن الرهيبة أن يخرج العديد من الأخطاء من أماكن مختلفة. ومع كل تحديث webpack يطير أكثر من ذلك.
SSR + CSS
يعد CSS مصدرًا أكبر للمشاكل في SSRs.
إذا كانت لديك مكونات Styled - لا تتأذى كثيرًا - فهي تأتي مع مجموعة transform-stream
والتي في حد ذاتها ستضيف ما هو مطلوب إلى الرمز النهائي. الشيء الرئيسي هو أنه يجب أن يكون هناك إصدار واحد من SC في كل مكان ، وإلا فلن يعمل التركيز - لن تتمكن إصدار واحد من SC من معرفة أي شيء آخر عن نفسها ، و SC يحب الضرب (تحقق من الحزمة الخاصة بك). أن نكون صادقين ، وهذا هو بالضبط بسبب هذا القيد الذي عادة ما يفشل التركيز.
C العاطفة أكثر بساطة - المحول styled
يبصق خارج <style>
أمام المكون نفسه ، ويتم حل المشكلة. بسيطة ورخيصة ومبهجة. من حيث المبدأ ، إنه سهل الحمل للغاية ، ويحسن بشكل كبير العرض الأول. لكن القليل يفسد الثاني. وشخصي ، لا يسمح لي ضميري بتضمين أنماط من هذا القبيل.
مع CSS العادي (بما في ذلك التي تم الحصول عليها من مختلف مكتبات CSS-in-JS ذات السحر المتنوع) ، أصبح الأمر أسهل - المعلومات الموجودة عليها موجودة في عمود حزمة الويب ، ومن المعروف أن CSS تحتاج إلى الاتصال.
ترتيب الاتصال
هنا الكلب دفن نفسه. متى يجب علي الاتصال؟
معنى تقسيم الشفرة الصديقة لـ SSR هو أنه قبل الاتصال بـ ReactDOM.hydrate
تحتاج إلى تنزيل جميع "المكونات" الموجودة بالفعل في استجابة الخادم ، لكن البرامج النصية التي تم تحميلها حاليًا على العميل لا يمكن تحملها.
لذلك ، تقدم جميع المكتبات رد اتصال معينًا سيتم استدعاؤه عند الحاجة إلى تحميل الكل ، ويمكنك بدء تشغيل المخ . هذا هو معنى عمل مكتبات SSR من المدونات.
يمكن تحميل JS في أي وقت ، وعادةً ما تتم إضافة قائمتهم إلى نهاية HTML ، ولكن يجب إضافة CSS ، بحيث لا يوجد FOUC ، إلى البداية.
جميع المكتبات قادرة على القيام بذلك من أجل renderToString
القديم ، وجميع المكتبات غير قادرة على القيام بذلك من أجل renderToNodeStream
.
لا يهم إذا كان لديك JS فقط (هذا لا يحدث) ، أو SC / Emotion (والتي ستضيف نفسها). ولكن - إذا كان لديك "CSS فقط" - هذا كل شيء. إما سيكونون في النهاية ، أو سيتعين عليهم استخدام renderToString
، أو التخزين المؤقت الآخر ، مما سيوفر تأخير TTFB (Time To First Byte) ويقلل قليلاً من الشعور بوجود SSR بشكل عام.
وبالطبع - كل هذا مرتبط بحزمة الويب وليس بأي طريقة أخرى. لذلك ، مع كل الاحترام الواجب لجريج ، مؤلف المكونات القابلة للتحميل - أقترح النظر في خيارات أخرى.
التالي هو جدول أعمال من ثلاثة أجزاء ، والفكرة الرئيسية منها هي القيام بشيء لا يقتل ولا يعتمد على المجمّع.
1. رد فعل المستوردة المكون
إن React-Imported-Component ليس "أداة تحميل" سيئة ، مع واجهة قياسية أكثر أو أقل ، تشبه إلى حد كبير المكونات القابلة للتحميل ، والتي يمكن أن SSR لكل شيء يتحرك.
الفكرة بسيطة جدا.
لا حاجة إلى stats.json
، والتكيف مع تحسين حزمة الويب (تسلسل ، أو رمز شائع) - كل ما تحتاجه هو مطابقة "تسمية" لاستيراد واحد في المفتاح في الصفيف والاستيراد مرة أخرى. كيف سيتم تنفيذ ذلك كجزء من حزمة محددة ، وعدد الملفات التي سيتم تنزيلها بالفعل ومن أين لا يمثل مشكلته.
ناقص - تحدث بداية تحميل القطع "المستخدمة" بعد تحميل الحزمة الرئيسية ، التي تخزن الخرائط ، والتي تكون "متأخرة" قليلاً عن حالة المكونات القابلة للتحميل ، والتي ستضيف هذه المعلومات مباشرةً إلى HTML.
نعم ، مع CCS أنها لا تعمل من الكلمة بأي شكل من الأشكال.
2. الأساليب المستخدمة
لكن الأنماط المستخدمة لا تعمل إلا مع CSS ، ولكن بنفس طريقة تفاعل المكونات المستوردة.
- بمسح جميع المغلق (في دليل البناء)
- يتذكر أين يتم تعريف أي فئة
- بمسح إخراج renderToNodeStream (أو استجابة
renderToString
) - يجد class = 'XXX' ، يطابق الملف ويبصق عليه في استجابة الخادم.
- (جيدًا ، ثم تنقل كل هذه الأنماط إلى الرأس حتى لا تكسر الهيدرات). مكونات النمط تعمل بنفس الطريقة.
لا يوجد أي تأخير في TTBT ، وهو غير مرتبط بالمجمع - حكاية خرافية. يعمل مثل الساعة إذا كانت الأنماط مكتوبة بشكل جيد.
React-import-component + used-Styles + لا يتجزأ مثال العمل.
ليست المكافأة الأكثر وضوحًا - على الخادم ، ستعمل كلتا المكتبات "كل ما هو مطلوب" أثناء بدء التشغيل ، حتى يتمكن الخادم السريع من استقبال العميل الأول ، وسيتم مزامنته تمامًا على الخادم وخلال الاختبارات.
3. رد فعل مكون مسبقا
وتغلق المكتبة المراكز الثلاثة الأولى ، التي تعمل "الإماهة الجزئية" ، وتقوم بذلك بطريقة جد أتساءل على الفور. انها حقا يضيف "المغنيات".
- على الخادم:
- يلف قطعة من الخشب في div مع "معرف مشهور"
- على العميل:
- يجد المكون المكون div الخاص به
- ينسخ innerHTML قبل أن يأخذها React.
- يستخدم HTML هذا حتى يكون العميل جاهزًا
hydrate
- من الناحية الفنية ، يسمح ذلك باستخدام Hybrid SSR (Rendertron)
const AsyncLoadedComponent = loadable(() => import('./deferredComponent')); const AsyncLoadedComponent = imported(() => import('./deferredComponent')); <PrerenderedComponent live={AsyncLoadedComponent.preload()} // when Promise got resolve - component will go "live" > <AsyncLoadedComponent /> // meanwhile you will see "preexisting" content </PrerenderedComponent>
لا يعمل هذا التركيز مع المكونات القابلة للتحميل ، نظرًا لأنه لا يرجع من وعد التحميل المسبق . يعد هذا مهمًا بشكل خاص للمكتبات ، مثل تفاعل التفاعل (و "متطلبات العرض المسبقة") التي تحتوي على "محتوى" ولكنها لم تمر عبر SSR "حقيقي".

من وجهة نظر الكود ، هذا هو 10 سطور ، بالإضافة إلى أكثر بقليل للحصول على ثوابت SSR-CSR ثابتة مع مراعاة الترتيب العشوائي لتحميل الكود وتنفيذه.
المكافآت:
- لا يتعين عليك انتظار "تحميل جميع النصوص" قبل بدء العقول - ستبدأ العقول لأنها جاهزة
- ليس عليك تحميل العقول على الإطلاق ، وترك بيانات SSR-ed (إذا لم يكن هناك إصدار SSR ، فلا يزال يتم تحميل العقول). تماما كما هو الحال في أوقات مسج.
- يمكنك أيضًا تنفيذ التخزين المؤقت للتيار لكتل التجسيد الكبيرة (متوافقة نظريًا مع Suspension) - مرة أخرى باستخدام دفق التحويل.
- وتسلسل / إلغاء تسلسل الحالة إلى / من HTML ، كما هو الحال أثناء مسج
من حيث المبدأ ، كانت التسلسل وإلغاء التسلسل هي الفكرة الأساسية لإنشاء مكتبة لحل مشكلة تكرار الحالة (صورة من مقالة حول SSR). التخزين المؤقت وصل في وقت لاحق.

المجموع
في المجموع ، هناك ثلاثة أساليب يمكن أن تغير وجهة نظرك من SSR وتقسيم الشفرة. الأول يعمل مع JS codeplitting ، ولا ينكسر. والثاني يعمل مع CSS codeplitting ، ولا ينكسر. يعمل الثالث على مستوى HTML في تبسيط وتسريع بعض العمليات ، ومرة أخرى ، لا ينكسر.
روابط للمكتبات:
مقالات (باللغة الإنجليزية)