إضافة إمكانيات تقسيم الشفرة إلى موقع ويب WordPress من خلال PoP
نشرت: 2022-03-10تعد السرعة من بين الأولويات القصوى لأي موقع ويب في الوقت الحاضر. تتمثل إحدى طرق زيادة سرعة تحميل موقع ويب في تقسيم الكود: تقسيم التطبيق إلى أجزاء يمكن تحميلها عند الطلب - تحميل JavaScript المطلوب فقط ولا شيء غير ذلك. يمكن لمواقع الويب التي تستند إلى أطر عمل JavaScript تنفيذ تقسيم الشفرة على الفور من خلال Webpack ، حزمة JavaScript الشائعة. ومع ذلك ، بالنسبة لمواقع WordPress ، فإن الأمر ليس بهذه السهولة. أولاً ، لم يتم إنشاء Webpack عن قصد للعمل مع WordPress ، لذا فإن إعداده سيتطلب بعض الحلول ؛ ثانيًا ، لا توجد أدوات متوفرة توفر إمكانات تحميل الأصول عند الطلب لـ WordPress.
نظرًا لعدم وجود حل مناسب لـ WordPress ، قررت تنفيذ إصداري الخاص من تقسيم التعليمات البرمجية لـ PoP ، وهو إطار مفتوح المصدر لبناء مواقع WordPress التي قمت بإنشائها. سيحتوي موقع WordPress المثبت عليه PoP على إمكانيات تقسيم التعليمات البرمجية محليًا ، لذلك لن يحتاج إلى الاعتماد على Webpack أو أي حزمة أخرى. في هذه المقالة ، سأوضح لك كيف يتم ذلك ، موضحًا القرارات التي تم اتخاذها بناءً على جوانب بنية إطار العمل. في النهاية ، سوف أقوم بتحليل أداء موقع الويب مع أو بدون تقسيم الكود ، ومزايا وعيوب استخدام تطبيق مخصص على مجمع خارجي. أتمنى أن تستمتع بالرحلة!
تحديد الإستراتيجية
يمكن تقسيم تقسيم الشفرة على نطاق واسع إلى هاتين الخطوتين:
- حساب الأصول التي يجب تحميلها لكل مسار ،
- تحميل هذه الأصول ديناميكيًا عند الطلب.
لمعالجة الخطوة الأولى ، سنحتاج إلى إنتاج خريطة تبعية الأصول ، بما في ذلك جميع الأصول الموجودة في تطبيقنا. يجب إضافة الأصول بشكل متكرر إلى هذه الخريطة - يجب أيضًا إضافة تبعيات التبعيات ، حتى لا تكون هناك حاجة إلى أصول أخرى. يمكننا بعد ذلك حساب جميع التبعيات المطلوبة لمسار معين من خلال اجتياز خريطة التبعية للأصول ، بدءًا من نقطة دخول المسار (أي الملف أو جزء من الكود الذي يبدأ منه التنفيذ) وصولاً إلى المستوى الأخير.
لمعالجة الخطوة الثانية ، يمكننا حساب الأصول المطلوبة لعنوان URL المطلوب على جانب الخادم ، ثم إرسال قائمة الأصول المطلوبة في الاستجابة ، والتي سيحتاج التطبيق على أساسها إلى تحميلها ، أو إرسال HTTP / مباشرة 2 دفع الموارد إلى جانب الاستجابة.
هذه الحلول ، ومع ذلك ، ليست الأمثل. في الحالة الأولى ، يجب أن يطلب التطبيق جميع الأصول بعد إرجاع الاستجابة ، لذلك ستكون هناك سلسلة إضافية من طلبات الذهاب والإياب لجلب الأصول ، ولا يمكن إنشاء العرض قبل تحميلها جميعًا ، مما يؤدي إلى يتعين على المستخدم الانتظار (يتم تخفيف هذه المشكلة من خلال تسليم جميع الأصول مسبقًا من خلال عمال الخدمة ، وبالتالي يتم تقليل وقت الانتظار ، ولكن لا يمكننا تجنب تحليل الأصول الذي يحدث فقط بعد عودة الاستجابة). في الحالة الثانية ، قد نقوم بدفع نفس الأصول بشكل متكرر (ما لم نضيف بعض المنطق الإضافي ، مثل الإشارة إلى الموارد التي قمنا بتحميلها بالفعل من خلال ملفات تعريف الارتباط ، ولكن هذا بالفعل يضيف تعقيدًا غير مرغوب فيه ويمنع الاستجابة من التخزين المؤقت) ، ونحن لا يمكن أن تخدم الأصول من CDN.
لهذا السبب ، قررت التعامل مع هذا المنطق من جانب العميل. يتم توفير قائمة بالأصول المطلوبة لكل مسار للتطبيق الموجود على العميل ، بحيث يعرف بالفعل الأصول المطلوبة لعنوان URL المطلوب. هذا يعالج المشاكل المذكورة أعلاه:
- يمكن تحميل الأصول على الفور ، دون الحاجة إلى انتظار استجابة الخادم. (عندما نقرن ذلك بعاملين في الخدمة ، يمكننا أن نكون على يقين من أنه بحلول وقت عودة الاستجابة ، سيتم تحميل جميع الموارد وتحليلها ، لذلك لا يوجد وقت انتظار إضافي.)
- يعرف التطبيق الأصول التي تم تحميلها بالفعل ؛ وبالتالي ، لن يطلب جميع الأصول المطلوبة لهذا المسار ، ولكن فقط تلك الأصول التي لم يتم تحميلها بعد.
الجانب السلبي لإيصال هذه القائمة إلى الواجهة الأمامية هو أنها قد تصبح ثقيلة ، اعتمادًا على حجم موقع الويب (مثل عدد المسارات التي تتيحها). نحتاج إلى إيجاد طريقة لتحميله دون زيادة وقت التحميل المتصور للتطبيق. المزيد عن هذا لاحقًا.
بعد اتخاذ هذه القرارات ، يمكننا المضي قدمًا في تصميم ثم تنفيذ تقسيم الكود في التطبيق. لتسهيل الفهم ، تم تقسيم العملية إلى الخطوات التالية:
- فهم بنية التطبيق ،
- تعيين تبعيات الأصول ،
- سرد جميع طرق التطبيق ،
- إنشاء قائمة تحدد الأصول المطلوبة لكل مسار ،
- تحميل الأصول ديناميكيًا ،
- تطبيق التحسينات.
دعونا ندخله مباشرة!
0. فهم هندسة التطبيق
سنحتاج إلى تعيين علاقة جميع الأصول ببعضها البعض. دعنا نتناول خصوصيات بنية PoP من أجل تصميم الحل الأنسب لتحقيق هذا الهدف.
PoP عبارة عن طبقة تلتف حول WordPress ، مما يمكننا من استخدام WordPress باعتباره CMS الذي يشغل التطبيق ، مع توفير إطار عمل JavaScript مخصص لعرض المحتوى على جانب العميل لإنشاء مواقع ويب ديناميكية. إنه يعيد تعريف مكونات بناء صفحة الويب: في حين أن WordPress يعتمد حاليًا على مفهوم القوالب الهرمية التي تنتج HTML (مثل single.php
و home.php
و archive.php
) ، يعتمد PoP على مفهوم "الوحدات النمطية ، والتي هي إما وظيفة ذرية أو تكوين وحدات أخرى. يشبه بناء تطبيق PoP اللعب باستخدام وحدات LEGO - تجميع الوحدات فوق بعضها البعض أو التفاف بعضها البعض ، مما يؤدي في النهاية إلى إنشاء بنية أكثر تعقيدًا. يمكن اعتباره أيضًا تنفيذًا للتصميم الذري لبراد فروست ، ويبدو كالتالي:
يمكن تجميع الوحدات النمطية في كيانات ذات ترتيب أعلى ، وهي: الكتل ، والمجموعات ، وأقسام الصفحة ، والمستويات العليا. هذه الكيانات عبارة عن وحدات ، أيضًا ، لها خصائص ومسؤوليات إضافية فقط ، وتحتوي على بعضها البعض باتباع بنية من أعلى إلى أسفل بشكل صارم حيث يمكن لكل وحدة رؤية خصائص جميع وحداتها الداخلية وتغييرها. العلاقة بين الوحدات هي كما يلي:
- 1 المستوى الأعلى يحتوي على N أقسام ،
- يحتوي القسم 1 صفحة على كتل N أو blockGroups ،
- 1 blockGroup يحتوي على N كتل أو blockGroups ،
- كتلة واحدة تحتوي على وحدات N ،
- 1 وحدة تحتوي على وحدات N ، إلى ما لا نهاية.
تنفيذ كود JavaScript في PoP
يقوم PoP بإنشاء HTML ديناميكيًا ، بدءًا من مستوى قسم الصفحة ، بالتكرار خلال جميع الوحدات أسفل السطر ، وعرض كل منها من خلال نموذج المقاود المحدد مسبقًا للوحدة ، وأخيرًا إضافة العناصر التي تم إنشاؤها حديثًا المقابلة للوحدة في DOM. بمجرد القيام بذلك ، فإنه ينفذ وظائف JavaScript عليها ، والتي تم تحديدها مسبقًا على أساس كل وحدة على حدة.
يختلف PoP عن أطر عمل JavaScript (مثل React و AngularJS) من حيث أن تدفق التطبيق لا ينشأ من العميل ، ولكنه لا يزال مهيئًا في النهاية الخلفية ، داخل تكوين الوحدة (التي يتم ترميزها في كائن PHP). يتأثر PoP بخطافات عمل WordPress ، وينفذ نمط النشر والاشتراك:
- تحدد كل وحدة وظائف JavaScript التي يجب تنفيذها على عناصر DOM التي تم إنشاؤها حديثًا المقابلة لها ، وليس بالضرورة معرفة مسبقًا ما الذي سينفذ هذه الشفرة أو من أين ستأتي.
- يجب أن تسجل كائنات JavaScript وظائف JavaScript التي يتم تنفيذها.
- أخيرًا ، في وقت التشغيل ، يحسب PoP كائنات JavaScript التي يجب أن تنفذ وظائف JavaScript ، ويستدعيها بشكل مناسب.
على سبيل المثال ، من خلال كائن PHP المقابل ، تشير وحدة التقويم إلى أنها تحتاج إلى تنفيذ وظيفة calendar
على عناصر DOM الخاصة بها مثل هذا:
class CalendarModule { function get_jsmethods() { $methods = parent::get_jsmethods(); $this->add_jsmethod($methods, 'calendar'); return $methods; } ... }
بعد ذلك ، يعلن كائن JavaScript - في هذه الحالة popFullCalendar
- أنه تم تنفيذ وظيفة calendar
. يتم ذلك عن طريق استدعاء popJSLibraryManager.register
:
window.popFullCalendar = { calendar : function(elements) { ... } }; popJSLibraryManager.register(popFullCalendar, ['calendar', ...]);
أخيرًا ، يقوم popJSLibraryManager
على ما ينفذ أي كود. يسمح لكائنات JavaScript بتسجيل الوظائف التي تنفذها ، ويوفر طريقة لتنفيذ وظيفة معينة من جميع كائنات JavaScript المُشتركة:
window.popJSLibraryManager = { libraries: [], methods: {}, register : function(library, methods) { this.libraries.push(library); for (var i = 0; i < methods.length; i++) { var method = methods[i]; this.methods[method] = this.methods[method] || []; this.methods[method].push(library); } }, execute : function(method, elements) { var libraries = this.methods[method] || []; for (var i = 0; i < libraries.length; i++) { var library = libraries[i]; library[method](elements); } } }
بعد إضافة عنصر تقويم جديد إلى DOM ، الذي يحتوي على معرف calendar-293
، سيقوم PoP ببساطة بتنفيذ الوظيفة التالية:
popJSLibraryManager.execute("calendar", document.getElementById("calendar-293"));
نقطة الدخول
بالنسبة إلى PoP ، فإن نقطة الدخول إلى تنفيذ كود JavaScript هي هذا السطر في نهاية إخراج HTML:
<script type="text/javascript">popManager.init();</script>
popManager.init()
أولاً بتهيئة إطار عمل الواجهة الأمامية ، ثم يقوم بتنفيذ وظائف JavaScript المحددة بواسطة جميع الوحدات النمطية المعروضة ، كما هو موضح أعلاه. يوجد أدناه نموذج مبسط جدًا لهذه الوظيفة (الكود الأصلي موجود على GitHub). من خلال استدعاء popJSLibraryManager.execute('pageSectionInitialized', pageSection)
و popJSLibraryManager.execute('documentInitialized')
، ستقوم جميع كائنات JavaScript التي تنفذ هذه الوظائف ( pageSectionInitialized
و documentInitialized
) بتنفيذها.
(function($){ window.popManager = { // The configuration for all the modules (including pageSections and blocks) in the application configuration : {...}, init : function() { var that = this; $.each(this.configuration, function(pageSectionId, configuration) { // Obtain the pageSection element in the DOM from the ID var pageSection = $('#'+pageSectionId); // Run all required JavaScript methods on it this.runJSMethods(pageSection, configuration); // Trigger an event marking the block as initialized popJSLibraryManager.execute('pageSectionInitialized', pageSection); }); // Trigger an event marking the document as initialized popJSLibraryManager.execute('documentInitialized'); }, ... }; })(jQuery);
تنفذ الدالة runJSMethods
طرق جافا سكريبت المحددة لكل وحدة نمطية ، بدءًا من قسم الصفحة ، وهو أعلى وحدة نمطية ، ثم أسفل السطر لجميع الكتل الداخلية ووحداتها الداخلية:
(function($){ window.popManager = { ... runJSMethods : function(pageSection, configuration) { // Initialize the heap with "modules", starting from the top one, and recursively iterate over its inner modules var heap = [pageSection.data('module')], i; while (heap.length > 0) { // Get the first element of the heap var module = heap.pop(); // The configuration for that module contains which JavaScript methods to execute, and which are the module's inner modules var moduleConfiguration = configuration[module]; // The list of all JavaScript functions that must be executed on the module's newly created DOM elements var jsMethods = moduleConfiguration['js-methods']; // Get all of the elements added to the DOM for that module, which have been stored in JavaScript object `popJSRuntimeManager` upon creation var elements = popJSRuntimeManager.getDOMElements(module); // Iterate through all of the JavaScript methods and execute them, passing the elements as argument for (i = 0; i < jsMethods.length; i++) { popJSLibraryManager.execute(jsMethods[i], elements); } // Finally, add the inner-modules to the heap heap = heap.concat(moduleConfiguration['inner-modules']); } }, }; })(jQuery);
باختصار ، تنفيذ JavaScript في PoP مرتبط بشكل فضفاض: بدلاً من وجود تبعيات ثابتة ، نقوم بتنفيذ وظائف JavaScript من خلال الخطافات التي يمكن لأي كائن JavaScript الاشتراك فيها.
صفحات الويب وواجهات برمجة التطبيقات
موقع PoP هو واجهة برمجة تطبيقات ذاتية الاستهلاك. في PoP ، لا يوجد تمييز بين صفحة الويب وواجهة برمجة التطبيقات: يُرجع كل عنوان URL صفحة الويب افتراضيًا ، وبإضافة معلمة output=json
، فإنها تُرجع واجهة برمجة التطبيقات بدلاً من ذلك (على سبيل المثال ، getpop.org/en/ هي صفحة الويب ، و getpop.org/en/؟output=json هي واجهة برمجة التطبيقات الخاصة بها). يتم استخدام API لعرض المحتوى ديناميكيًا في PoP ؛ لذلك ، عند النقر فوق ارتباط إلى صفحة أخرى ، فإن واجهة برمجة التطبيقات هي ما يتم طلبه ، لأنه بحلول ذلك الوقت سيتم تحميل إطار موقع الويب (مثل التنقل العلوي والجانبي) - ثم مجموعة الموارد اللازمة لوضع واجهة برمجة التطبيقات تكون مجموعة فرعية من ذلك من صفحة الويب. سنحتاج إلى أخذ ذلك في الاعتبار عند حساب التبعيات لطريق ما: تحميل المسار عند تحميل موقع الويب لأول مرة أو تحميله ديناميكيًا بالنقر فوق بعض الارتباطات سينتج مجموعات مختلفة من الأصول المطلوبة.
هذه هي أهم جوانب PoP التي ستحدد تصميم وتنفيذ تقسيم الكود. دعنا ننتقل إلى الخطوة التالية.
1. تعيين تبعيات الأصول
يمكننا إضافة ملف تكوين لكل ملف JavaScript ، مع توضيح التبعيات الصريحة الخاصة بهم. ومع ذلك ، قد يؤدي هذا إلى تكرار الكود وسيكون من الصعب الحفاظ على اتساقها. سيكون الحل الأنظف هو الاحتفاظ بملفات JavaScript كمصدر وحيد للحقيقة ، واستخراج الكود من داخلها ثم تحليل هذا الرمز لإعادة إنشاء التبعيات.
البيانات الوصفية التي نبحث عنها في ملفات مصدر JavaScript ، حتى نتمكن من إعادة إنشاء التعيين ، هي كما يلي:
- استدعاءات الطريقة الداخلية ، مثل
this.runJSMethods(...)
؛ - استدعاءات الطريقة الخارجية ، مثل
popJSRuntimeManager.getDOMElements(...)
؛ - جميع تكرارات
popJSLibraryManager.execute(...)
، والتي تنفذ وظيفة JavaScript في كل تلك الكائنات التي تنفذها ؛ - جميع تكرارات
popJSLibraryManager.register(...)
، للحصول على كائنات JavaScript التي تنفذ طرق JavaScript.
سنستخدم jParser و jTokenizer لترميز ملفات مصدر JavaScript الخاصة بنا في PHP واستخراج البيانات الوصفية ، على النحو التالي:
- يتم استنتاج استدعاءات الطريقة الداخلية (مثل
this.runJSMethods
) عند إيجاد التسلسل التالي: إما الرمز المميزthis
أوthat
+.
+ بعض الرموز الأخرى ، وهو اسم الطريقة الداخلية (runJSMethods
). - يتم استنتاج استدعاءات الطريقة الخارجية (مثل
popJSRuntimeManager.getDOMElements
) عند العثور على التسلسل التالي: رمز مميز مدرج في قائمة جميع كائنات JavaScript في تطبيقنا (سنحتاج إلى هذه القائمة مسبقًا ؛ في هذه الحالة ، ستحتوي على الكائنpopJSRuntimeManager
) +.
+ بعض الرموز الأخرى ، وهو اسم الطريقة الخارجية (getDOMElements
). - كلما وجدنا
popJSLibraryManager.execute("someFunctionName")
نستنتج أن طريقة Javascript هيsomeFunctionName
. - كلما وجدنا
popJSLibraryManager.register(someJSObject, ["someFunctionName1", "someFunctionName2"])
نستنتج كائن جافا سكريبتsomeJSObject
لتنفيذ الأساليبsomeFunctionName1
،someFunctionName2
.
لقد نفذت البرنامج النصي لكنني لن أصفه هنا. (إنها طويلة جدًا ولا تضيف قيمة كبيرة ، ولكن يمكن العثور عليها في مستودع PoP). سينشئ البرنامج النصي ، الذي يتم تشغيله عند طلب صفحة داخلية على خادم تطوير الموقع (المنهجية التي كتبت عنها في مقال سابق عن عمال الخدمة) ، ملف التعيين وتخزينه على الخادم. لقد أعددت مثالاً لملف الخرائط الذي تم إنشاؤه. إنه ملف JSON بسيط يحتوي على السمات التالية:
-
internalMethodCalls
لكل كائن JavaScript ، قم بسرد التبعيات من الوظائف الداخلية فيما بينها. -
externalMethodCalls
لكل كائن JavaScript ، قم بسرد التبعيات من الوظائف الداخلية إلى الوظائف من كائنات JavaScript الأخرى. -
publicMethods
أدرج جميع الطرق المسجلة ولكل طريقة ، ما هي كائنات JavaScript التي تنفذها. -
methodExecutions
لكل كائن JavaScript وكل وظيفة داخلية ، قم بسرد جميع الطرق المنفذة من خلالpopJSLibraryManager.execute('someMethodName')
.
يرجى ملاحظة أن النتيجة ليست خريطة تبعية أصل حتى الآن ، بل خريطة تبعية كائن JavaScript. من هذه الخريطة ، يمكننا تحديد ، عند تنفيذ وظيفة من كائن ما ، ما هي الكائنات الأخرى المطلوبة أيضًا. ما زلنا بحاجة إلى تكوين كائنات JavaScript المضمنة في كل أصل ، لجميع الأصول (في البرنامج النصي jTokenizer ، كائنات JavaScript هي الرموز المميزة التي نبحث عنها لتحديد استدعاءات الطريقة الخارجية ، لذلك هذه المعلومات هي إدخال إلى البرنامج النصي ويمكن يتم الحصول عليها من ملفات المصدر نفسها). يتم ذلك من خلال كائنات PHP ResourceLoaderProcessor
، مثل resourceloader-processor.php.
أخيرًا ، من خلال الجمع بين الخريطة والتكوين ، سنتمكن من حساب جميع الأصول المطلوبة لكل مسار في التطبيق.
2. سرد جميع طرق التطبيق
نحتاج إلى تحديد جميع المسارات المتاحة في تطبيقنا. بالنسبة إلى موقع WordPress على الويب ، ستبدأ هذه القائمة بعنوان URL من كل تسلسل هرمي للقالب. تلك التي تم تنفيذها لـ PoP هي:
- الصفحة الرئيسية: https://getpop.org/en/
- المؤلف: https://getpop.org/en/u/leo/
- مفرد: https://getpop.org/en/blog/new-feature-code-splitting/
- العلامة: https://getpop.org/en/tags/internet/
- الصفحة: https://getpop.org/en/philosophy/
- الفئة: https://getpop.org/en/blog/ (تم تنفيذ الفئة فعليًا كصفحة ، لإزالة
category/
من مسار URL) - 404: https://getpop.org/en/this-page-does-not-exist/
لكل من هذه التدرجات الهرمية ، يجب أن نحصل على جميع المسارات التي تنتج تكوينًا فريدًا (أي يتطلب مجموعة فريدة من الأصول). في حالة PoP ، لدينا ما يلي:
- الصفحة الرئيسية و 404 فريدة من نوعها.
- تحتوي صفحات العلامات دائمًا على نفس التكوين لأي علامة. وبالتالي ، يكفي عنوان URL واحد لأي علامة.
- يعتمد المنشور الفردي على مجموعة نوع المنشور (مثل "حدث" أو "منشور") والفئة الرئيسية للمنشور (مثل "مدونة" أو "مقالة"). بعد ذلك ، نحتاج إلى عنوان URL لكل مجموعة من هذه المجموعات.
- يعتمد تكوين صفحة الفئة على الفئة. لذلك ، سنحتاج إلى عنوان URL لكل فئة مشاركة.
- تعتمد صفحة المؤلف على دور المؤلف ("فرد" أو "منظمة" أو "مجتمع"). لذلك ، سنحتاج إلى عناوين URL لثلاثة مؤلفين ، لكل منهم أحد هذه الأدوار.
- يمكن أن يكون لكل صفحة تكوينها الخاص ("تسجيل الدخول" ، "اتصل بنا" ، "مهمتنا" ، إلخ). لذلك ، يجب إضافة جميع عناوين URL للصفحة إلى القائمة.
كما نرى ، فإن القائمة طويلة بالفعل. بالإضافة إلى ذلك ، قد يضيف تطبيقنا معلمات إلى عنوان URL تعمل على تغيير التكوين ، ومن المحتمل أيضًا تغيير الأصول المطلوبة. تقدم PoP ، على سبيل المثال ، إضافة معلمات URL التالية:
- علامة التبويب (
?tab=…
) ، لإظهار جزء من المعلومات ذات الصلة: https://getpop.org/en/blog/new-feature-code-splitting/؟tab=authors؛ - تنسيق (
?format=…
) لتغيير طريقة عرض البيانات: https://getpop.org/en/blog/؟format=list؛ - target (
?target=…
) ، لفتح الصفحة في قسم صفحات مختلف: https://getpop.org/en/add-post/؟target=addons.
يمكن أن تحتوي بعض المسارات الأولية على واحد أو اثنين أو حتى ثلاثة من المعلمات أعلاه ، مما يؤدي إلى إنشاء مجموعة واسعة من المجموعات:
- مشاركة واحدة: https://getpop.org/en/blog/new-feature-code-splitting/
- مؤلفو المنشور الفردي: https://getpop.org/en/blog/new-feature-code-splitting/؟
- مؤلفو المنشور الفردي كقائمة: https://getpop.org/en/blog/new-feature-code-splitting/؟tab=authors&format=list
- مؤلفو المنشور الفردي كقائمة في نافذة مشروطة: https://getpop.org/en/blog/new-feature-code-splitting/؟tab=authors&format=list&target=modals
باختصار ، بالنسبة لـ PoP ، فإن جميع المسارات الممكنة هي مزيج من العناصر التالية:
- جميع مسارات التسلسل الهرمي الأولي للقالب ؛
- جميع القيم المختلفة التي سينتج عنها التسلسل الهرمي تكوينًا مختلفًا ؛
- جميع علامات التبويب الممكنة لكل تسلسل هرمي (قد تحتوي التدرجات الهرمية المختلفة على قيم علامة تبويب مختلفة: يمكن أن تحتوي المنشور الواحد على علامتي التبويب "المؤلفون" و "الردود" ، بينما يمكن أن يكون للمؤلف علامتا التبويب "المنشورات" و "المتابعون") ؛
- جميع التنسيقات الممكنة لكل علامة تبويب (يمكن تطبيق علامات تبويب مختلفة تنسيقات مختلفة: قد تحتوي علامة التبويب "المؤلفون" على التنسيق "خريطة" ، ولكن قد لا تحتوي علامة التبويب "الردود") ؛
- تشير جميع الأهداف المحتملة إلى أقسام الصفحة حيث يمكن عرض كل مسار (بينما يمكن إنشاء منشور في القسم الرئيسي أو في نافذة عائمة ، قد يتم تعيين صفحة "المشاركة مع أصدقائك" لتفتح في نافذة مشروطة).
وبالتالي ، بالنسبة لتطبيق معقد قليلاً ، لا يمكن عمل قائمة بجميع المسارات يدويًا. يجب علينا ، إذن ، إنشاء برنامج نصي لاستخراج هذه المعلومات من قاعدة البيانات ، ومعالجتها ، وأخيراً إخراجها بالتنسيق المطلوب. سيحصل هذا البرنامج النصي على جميع فئات المنشورات ، والتي يمكننا من خلالها إنتاج قائمة بجميع عناوين URL لصفحات الفئات المختلفة ، وبعد ذلك ، لكل فئة ، الاستعلام عن قاعدة البيانات لأي منشور تحت نفس الشيء ، والذي سينتج عنوان URL لصفحة واحدة نشر تحت كل فئة ، وما إلى ذلك. النص الكامل متاح ، بدءًا من function get_resources()
، والتي تعرض الخطافات ليتم تنفيذها بواسطة كل حالة من حالات التسلسل الهرمي.
3. إنشاء القائمة التي تحدد الأصول المطلوبة لكل مسار
الآن ، لدينا خريطة تبعية الأصول وقائمة بجميع المسارات في التطبيق. حان الوقت الآن لدمج هذين الأمرين وإنشاء قائمة تشير ، لكل مسار ، إلى الأصول المطلوبة.
لإنشاء هذه القائمة ، نطبق الإجراء التالي:
- قم بإنشاء قائمة تحتوي على جميع طرق JavaScript ليتم تنفيذها لكل مسار:
احسب وحدات المسار ، ثم احصل على التكوين لكل وحدة ، ثم استخرج من التكوين وظائف JavaScript التي تحتاج الوحدة النمطية لتنفيذه ، وأضفهم جميعًا معًا. - بعد ذلك ، اجتياز خريطة تبعية الأصول لكل وظيفة JavaScript ، وجمع قائمة بجميع التبعيات المطلوبة ، وإضافتها جميعًا معًا.
- أخيرًا ، أضف قوالب المقاود اللازمة لعرض كل وحدة داخل هذا المسار.
بالإضافة إلى ذلك ، كما ذكرنا سابقًا ، يحتوي كل عنوان URL على صفحة ويب وأوضاع واجهة برمجة التطبيقات ، لذلك نحتاج إلى تشغيل الإجراء أعلاه مرتين ، مرة واحدة لكل وضع (على سبيل المثال ، بمجرد إضافة معلمة output=json
إلى عنوان URL ، والتي تمثل المسار لوضع واجهة برمجة التطبيقات ، ومرة واحدة الاحتفاظ بعنوان URL دون تغيير لوضع صفحة الويب). سننتج بعد ذلك قائمتين سيكون لهما استخدامات مختلفة:
- سيتم استخدام قائمة وضع صفحة الويب عند تحميل موقع الويب مبدئيًا ، بحيث يتم تضمين البرامج النصية المقابلة لهذا المسار في استجابة HTML الأولية. سيتم تخزين هذه القائمة على الخادم.
- سيتم استخدام قائمة وضع واجهة برمجة التطبيقات عند التحميل الديناميكي لصفحة على موقع الويب. سيتم تحميل هذه القائمة على العميل ، لتمكين التطبيق من حساب الأصول الإضافية التي يجب تحميلها ، عند الطلب ، عند النقر فوق الارتباط.
تم تنفيذ الجزء الأكبر من المنطق بدءًا من function add_resources_from_settingsprocessors($fetching_json, ...)
، (يمكنك العثور عليه في المستودع). تُفرّق المعلمة $fetching_json
بين وضعي صفحة الويب ( false
) وواجهة برمجة التطبيقات ( true
).
عند تشغيل البرنامج النصي الخاص بوضع صفحة الويب ، فإنه سينتج resourceloader-bundle-mapping.json ، وهو كائن JSON بالخصائص التالية:
-
bundle-ids
هذه مجموعة تصل إلى أربعة موارد (تم تشويه أسمائها لبيئة الإنتاج:eq
=>handlebars
،er
=>handlebars-helpers
، وما إلى ذلك) ، مجمعة تحت معرّف الحزمة. -
bundlegroup-ids
هذه مجموعة منbundle-ids
. تمثل كل bundleGroup مجموعة فريدة من الموارد. -
key-ids
هذا هو التعيين بين المسارات (يتم تمثيله بواسطة التجزئة الخاصة بهم ، والتي تحدد مجموعة جميع السمات التي تجعل المسار فريدًا) ومجموعة bundleGroup المقابلة لها.
كما يمكن ملاحظته ، فإن رسم الخرائط بين الطريق وموارده ليس مستقيماً. بدلاً من تعيين key-ids
لقائمة من الموارد ، يقوم بتعيينها إلى bundleGroup فريدة ، والتي هي نفسها قائمة من bundles
، وكل حزمة فقط هي قائمة resources
(تصل إلى أربعة عناصر لكل حزمة). لماذا تم القيام به على هذا النحو؟ يخدم هذا غرضين:
- إنها تمكننا من تحديد جميع الموارد ضمن bundleGroup فريدة. وبالتالي ، بدلاً من تضمين جميع الموارد في استجابة HTML ، يمكننا تضمين أصل JavaScript فريد ، وهو ملف bundleGroup المقابل بدلاً من ذلك ، والذي يتم تجميعه داخل جميع الموارد المقابلة. يكون هذا مفيدًا عند عرض الأجهزة التي لا تزال لا تدعم HTTP / 2 ، كما أنه سيزيد من وقت التحميل ، لأن Gzip هو ملف مجمع واحد أكثر فاعلية من ضغط الملفات المكونة له من تلقاء نفسه ثم إضافتها معًا. بدلاً من ذلك ، يمكننا أيضًا تحميل سلسلة من الحزم بدلاً من bundleGroup فريدة ، وهو حل وسط بين الموارد و bundleGroups (تحميل الحزم أبطأ من bundleGroups بسبب Gzip'ing ، لكنه يكون أكثر أداءً إذا حدث الإبطال كثيرًا ، لذلك نحن سيتم تنزيل الحزمة المحدثة فقط وليس حزمة bundleGroup بأكملها). تم العثور على البرامج النصية لتجميع جميع الموارد في حزم و bundleGroups في filegenerator-bundles.php و filegenerator-bundlegroups.php.
- يتيح لنا تقسيم مجموعات الموارد إلى حزم تحديد الأنماط الشائعة (على سبيل المثال ، تحديد مجموعات من أربعة موارد مشتركة بين العديد من المسارات) ، وبالتالي السماح للمسارات المختلفة بالارتباط بالحزمة نفسها. نتيجة لذلك ، سيكون حجم القائمة التي تم إنشاؤها أصغر. قد لا يكون هذا مفيدًا لقائمة صفحات الويب ، التي توجد على الخادم ، ولكنها رائعة لقائمة واجهة برمجة التطبيقات ، والتي سيتم تحميلها على العميل ، كما سنرى لاحقًا.
عند تشغيل البرنامج النصي الخاص بوضع API ، سيخرج ملف resources.js بالخصائص التالية:
- تخدم
bundles
bundle-groups
نفس الغرض كما هو مذكور في وضع صفحة الويب - تخدم
keys
أيضًا نفس الغرض مثلkey-ids
لوضع صفحة الويب. ومع ذلك ، بدلاً من استخدام التجزئة كمفتاح لتمثيل المسار ، فهي عبارة عن سلسلة من كل السمات التي تجعل المسار فريدًا - في حالتنا ، التنسيق (f
) وعلامة التبويب (t
) والهدف (r
). -
sources
هي ملف المصدر لكل مصدر. -
types
هي CSS أو JavaScript لكل مورد (على الرغم من أنه من أجل البساطة ، لم نقم بتغطية في هذه المقالة أن موارد JavaScript قد تعين أيضًا موارد CSS على أنها تبعيات ، ويمكن للوحدات النمطية تحميل أصول CSS الخاصة بها ، وتنفيذ إستراتيجية التحميل التدريجي لـ CSS ). -
resources
تلتقط أي bundleGroups يجب تحميلها لكل تسلسل هرمي. - تحتوي موارد التحميل المرتبة على
ordered-load-resources
التي يجب تحميلها بالترتيب ، وذلك لمنع البرامج النصية من التحميل قبل البرامج النصية المعتمدة عليها (بشكل افتراضي ، تكون غير متزامنة).
سوف نستكشف كيفية استخدام هذا الملف في القسم التالي.
4. تحميل الأصول ديناميكيًا
كما ذكرنا ، سيتم تحميل قائمة واجهة برمجة التطبيقات على العميل ، حتى نتمكن من البدء في تحميل الأصول المطلوبة للطريق فورًا بعد أن ينقر المستخدم على الرابط.
تحميل البرنامج النصي لرسم الخرائط
ملف JavaScript الذي تم إنشاؤه مع قائمة الموارد لجميع المسارات في التطبيق ليس خفيفًا - في هذه الحالة ، وصل حجمه إلى 85 كيلوبايت (والذي تم تحسينه بحد ذاته ، بعد أن أفسد أسماء الموارد وأنتج حزمًا لتحديد الأنماط الشائعة عبر المسارات) . لا ينبغي أن يمثل تحليل الوقت عنق زجاجة كبيرة ، لأن تحليل JSON أسرع 10 مرات من تحليل JavaScript لنفس البيانات. ومع ذلك ، فإن الحجم يمثل مشكلة من نقل الشبكة ، لذلك يجب علينا تحميل هذا البرنامج النصي بطريقة لا تؤثر على وقت التحميل المتصور للتطبيق أو تجعل المستخدم ينتظر.
الحل الذي قمت بتطبيقه هو تخزين هذا الملف مؤقتًا باستخدام عمال الخدمة ، وتحميله باستخدام defer
بحيث لا يحظر السلسلة الرئيسية أثناء تنفيذ أساليب JavaScript المهمة ، ثم إظهار رسالة إعلام احتياطية إذا نقر المستخدم على ارتباط قبل تحميل النص البرمجي: "لا يزال موقع الويب قيد التحميل ، يرجى الانتظار بضع لحظات للنقر على الروابط." يتم تحقيق ذلك عن طريق إضافة div ثابت بفئة من شاشة loadingscreen
موضوعة فوق كل شيء أثناء تحميل البرامج النصية ، ثم إضافة رسالة الإشعار ، مع فئة من notificationmsg
، داخل div ، وهذه الأسطر القليلة من CSS:
.loadingscreen > .notificationmsg { display: none; } .loadingscreen:focus > .notificationmsg, .loadingscreen:active > .notificationmsg { display: block; }
حل آخر هو تقسيم هذا الملف إلى عدة ملفات وتحميلها تدريجياً حسب الحاجة (استراتيجية قمت بترميزها بالفعل). علاوة على ذلك ، يشتمل ملف 85 كيلوبايت على جميع المسارات الممكنة في التطبيق ، بما في ذلك مسارات مثل "إعلانات المؤلف ، المعروضة في الصور المصغرة ، المعروضة في نافذة النماذج" ، والتي يمكن الوصول إليها مرة واحدة في القمر الأزرق ، إن وجدت. المسارات التي يتم الوصول إليها في الغالب قليلة بالكاد (الصفحة الرئيسية ، الفردي ، المؤلف ، العلامة وجميع الصفحات ، كلها بدون سمات إضافية) ، والتي يجب أن تنتج ملفًا أصغر بكثير ، في حدود 30 كيلوبايت.
الحصول على المسار من URL المطلوب
يجب أن نكون قادرين على تحديد المسار من عنوان URL المطلوب. على سبيل المثال:
-
https://getpop.org/en/u/leo/
خرائط للطريق "المؤلف" ، -
https://getpop.org/en/u/leo/?tab=followers
خرائط لطريق "أتباع المؤلف" ، -
https://getpop.org/en/tags/internet/
خرائط لعلامة الطريق ، -
https://getpop.org/en/tags/
خرائط للطريق "صفحة/tags/
" ، - وما إلى ذلك وهلم جرا.
لتحقيق ذلك ، سنحتاج إلى تقييم عنوان URL ، والاستنتاج منه العناصر التي تجعل المسار فريدًا: التسلسل الهرمي وجميع السمات (التنسيق وعلامة التبويب والهدف). لا يمثل تحديد السمات مشكلة ، لأنها معلمات في عنوان URL. التحدي الوحيد هو استنتاج التسلسل الهرمي (الصفحة الرئيسية ، المؤلف ، الفردي ، الصفحة أو العلامة) من عنوان URL ، عن طريق مطابقة عنوان URL مع عدة أنماط. علي سبيل المثال،
- أي شيء يبدأ بـ
https://getpop.org/en/u/
هو مؤلف. - أي شيء يبدأ بـ
https://getpop.org/en/tags/
وليس بالضبط هو علامة. إذا كانتhttps://getpop.org/en/tags/
بالضبط ، فهي صفحة. - وما إلى ذلك وهلم جرا.
يجب تغذية الوظيفة أدناه ، التي تم تنفيذها بدءًا من السطر 321 من resourceloader.js ، بتكوين مع الأنماط لجميع هذه التدرجات الهرمية. يتحقق أولاً من عدم وجود مسار فرعي في عنوان URL - وفي هذه الحالة ، يكون "المنزل". بعد ذلك ، يتحقق واحدًا تلو الآخر لمطابقة التسلسلات الهرمية لكل من "المؤلف" و "العلامة" و "الفردي". إذا لم تنجح مع أي من هؤلاء ، فهذه هي الحالة الافتراضية ، وهي "الصفحة":
window.popResourceLoader = { // The config will be populated externally, using a config.js file, generated by a script config : {}, getPath : function(url) { var parser = document.createElement('a'); parser.href = url; return parser.pathname; }, getHierarchy : function(url) { var path = this.getPath(url); if (!path) { return 'home'; } var config = this.config; if (path.startsWith(config.paths.author) && path != config.paths.author) { return 'author'; } if (path.startsWith(config.paths.tag) && path != config.paths.tag) { return 'tag'; } // We must also check that this path is, itself, not a potential page (https://getpop.org/en/posts/articles/ is "page", but https://getpop.org/en/posts/this-is-a-post/ is "single") if (config.paths.single.indexOf(path) === -1 && config.paths.single.some(function(single_path) { return path.startsWith(single_path) && path != single_path;})) { return 'single'; } return 'page'; }, ... };
نظرًا لأن جميع البيانات المطلوبة موجودة بالفعل في قاعدة البيانات (جميع الفئات ، كل الأجزاء الثابتة للصفحة ، وما إلى ذلك) ، سنقوم بتنفيذ برنامج نصي لإنشاء ملف التكوين هذا تلقائيًا في بيئة تطوير أو مرحلة مرحلية. The implemented script is resourceloader-config.php, which produces config.js with the URL patterns for the hierarchies “author”, “tag” and “single”, under the key “paths”:
popResourceLoader.config = { "paths": { "author": "u/", "tag": "tags/", "single": ["posts/articles/", "posts/announcements/", ...] }, ... };
Loading Resources for the Route
Once we have identified the route, we can obtain the required assets from the generated JavaScript file under the key “resources”, which looks like this:
config.resources = { "home": { "1": [1, 110, ...], "2": [2, 111, ...], ... }, "author": { "7": [6, 114, ...], "8": [7, 114, ...], ... }, "tag": { "119": [66, 127, ...], "120": [66, 127, ...], ... }, "single": { "posts/": { "7": [190, 142, ...], "3": [190, 142, ...], ... }, "events/": { "7": [213, 389, ...], "3": [213, 389, ...], ... }, ... }, "page": { "log-in/": { "3": [233, 115, ...] }, "log-out/": { "3": [234, 115, ...] }, "add-post/": { "3": [239, 398, ...] }, "posts/": { "120": [268, 127, ...], "122": [268, 127, ...], ... }, ... } };
At the first level, we have the hierarchy (home, author, tag, single or page). Hierarchies are divided into two groups: those that have only one set of resources (home, author and tag), and those that have a specific subpath (page permalink for the pages, custom post type or category for the single). Finally, at the last level, for each key ID (which represents a unique combination of the possible values of “format”, “tab” and “target”, stored under “keys”), we have an array of two elements: [JS bundleGroup ID, CSS bundleGroup ID], plus additional bundleGroup IDs if executing progressive booting (JS bundleGroups to be loaded as "async" or "defer" are bundled separately; this will be explained in the optimizations section below).
Please note: For the single
hierarchy, we have different configurations depending on the custom post type. This can be reflected in the subpath indicated above (for example, events
and posts
) because this information is in the URL (for example, https://getpop.org/en/posts/the-winners-of-climate-change-techno-fixes/
and https://getpop.org/en/events/debate-post-fork/
), so that, when clicking on a link, we will know the corresponding post type and can thus infer the corresponding route. However, this is not the case with the author
hierarchy. As indicated earlier, an author may have three different configurations, depending on the user role ( individual
, organization
or community
); however, in this file, we've defined only one configuration for the author hierarchy, not three. That is because we are not able to tell from the URL what is the role of the author: user leo
(under https://getpop.org/en/u/leo/
) is an individual, whereas user pop
(under https://getpop.org/en/u/pop/
) is a community; however, their URLs have the same pattern. If we could instead have the URLs https://getpop.org/en/u/individuals/leo/
and https://getpop.org/en/u/communities/pop/
, then we could add a configuration for each user role. However, I've found no way to achieve this in WordPress. As a consequence, only for the API mode, we must merge the three routes (individuals, organizations and communities) into one, which will have all of the resources for the three cases; and clicking on the link for user leo
will also load the resources for organizations and communities, even if we don't need them.
Finally, when a URL is requested, we obtain its route, from which we obtain the bundleGroup IDs (for both JavaScript and CSS assets). From each bundleGroup, we find the corresponding bundles under bundlegroups
. Then, for each bundle, we obtain all resources under the key bundles
. Finally, we identify which assets have not yet been loaded, and we load them by getting their source, which is stored under the key sources
. The whole logic is coded starting from line 472 in resourceloader.js.
And with that, we have implemented code-splitting for our application! From now on, we can get better loading times by applying optimizations. Let's tackle that next.
5. Applying Optimizations
The objective is to load as little code as possible, as delayed as possible, and to cache as much of it as possible. Let's explore how to do this.
Splitting Up the Code Into Smaller Units
A single JavaScript asset may implement several functions (by calling popJSLibraryManager.register
), yet maybe only one of those functions is actually needed by the route. Thus, it makes sense to split up the asset into several subassets, implementing a single function on each of them, and extracting all common code from all of the functions into yet another asset, depended upon by all of them.
For instance, in the past, there was a unique file, waypoints.js
, that implemented the functions waypointsFetchMore
, waypointsTheater
and a few more. However, in most cases, only the function waypointsFetchMore
was needed, so I was loading the code for the function waypointsTheater
unnecessarily. Then, I split up waypoints.js
into the following assets:
- waypoints.js, with all common code and implementing no public functions;
- waypoints-fetchmore.js, which implements just the public function
waypointsFetchMore
; - waypoints-theater.js, which implements just the public function
waypointsTheater
.
Evaluating how to split the files is a manual job. Luckily, there is a tool that greatly eases the task: Chrome Developer Tools' “Coverage” tab, which displays in red those portions of JavaScript code that have not been invoked:
By using this tool, we can better understand how to split our JavaScript files into more granular units, thus reducing the amount of unneeded code that is loaded.
Integration With Service Workers
By precaching all of the resources using service workers, we can be pretty sure that, by the time the response is back from the server, all of the required assets will have been loaded and parsed. I wrote an article on Smashing Magazine on how to accomplish this.
Progressive Booting
PoP's architecture plays very nice with the concept of loading assets in different stages. When defining the JavaScript methods to execute on each module (by doing $this->add_jsmethod($methods, 'calendar')
), these can be set as either critical
or non-critical
. By default, all methods are set as non-critical, and critical methods must be explicitly defined by the developer, by adding an extra parameter: $this->add_jsmethod($methods, 'calendar', 'critical')
. Then, we will be able to load scripts immediately for critical functions, and wait until the page is loaded to load non-critical functions, the JavaScript files of which are loaded using defer
.
(function($){ window.popManager = { init : function() { var that = this; $.each(this.configuration, function(pageSectionId, configuration) { ... this.runJSMethods(pageSection, configuration, 'critical'); ... }); window.addEventListener('load', function() { $.each(this.configuration, function(pageSectionId, configuration) { ... this.runJSMethods(pageSection, configuration, 'non-critical'); ... }); }); ... }, ... }; })(jQuery);
The gains from progressive booting are major: The JavaScript engine needs not spend time parsing non-critical JavaScript initially, when a quick response to the user is most important, and overall reduces the time to interactive.
Testing And Analizying Performance Gains
We can use https://getpop.org/en/, a PoP website, for testing purposes. When loading the home page, opening Chrome Developer Tools' “Elements” tab and searching for “defer”, it shows 4 occurrences. Thanks to progressive booting, that is 4 bundleGroup JavaScript files containing the contents of 57 Javascript files with non-critical methods that could wait until the website finished loading to be loaded:
If we now switch to the “Network” tab and click on a link, we can see which assets get loaded. For instance, click on the link “Application/UX Features” on the left side. Filtering by JavaScript, we see it loaded 38 files, including JavaScript libraries and Handlebars templates. Filtering by CSS, we see it loaded 9 files. These 47 files have all been loaded on demand:
Let's check whether the loading time got boosted. We can use WebPagetest to measure the application with and without code-splitting, and calculate the difference.
- Without code-splitting: testing URL, WebPagetest results
- With code-splitting, loading resources: testing URL, WebPagetest Results
- With code-splitting, loading a bundleGroup: testing URL, WebPagetest Results
We can see that when loading the app bundle with all resources or when doing code-splitting and loading resources, there is not so much gain. However, when doing code-splitting and loading a bundleGroup, the gains are significant: 1.7 seconds in loading time, 500 milliseconds to the first meaningful paint, and 1 second to interactive.
Conclusion: Is It Worth It?
You might be thinking, Is it worth it all this trouble? Let's analyze the advantages and disadvantages of implementing our own code-splitting features.
سلبيات
- يجب أن نحافظ عليه.
إذا استخدمنا Webpack للتو ، فيمكننا الاعتماد على مجتمعه للحفاظ على البرنامج محدثًا ويمكننا الاستفادة من النظام البيئي للمكون الإضافي الخاص به. - تستغرق البرامج النصية وقتًا للتشغيل.
يحتوي موقع PoP على الويب ، أجندة أوربانا ، على 304 مسارًا مختلفًا ، ينتج منها 422 مجموعة من الموارد الفريدة. بالنسبة إلى موقع الويب هذا ، يستغرق تشغيل البرنامج النصي الذي ينشئ خريطة تبعية الأصول ، باستخدام MacBook Pro من عام 2012 ، حوالي 8 دقائق ، ويستغرق تشغيل البرنامج النصي الذي ينشئ القوائم بجميع الموارد وإنشاء ملفات الحِزمة والمجموعة BundleGroup 15 دقيقة . هذا أكثر من الوقت الكافي لتناول القهوة! - يتطلب بيئة انطلاق.
إذا احتجنا إلى الانتظار حوالي 25 دقيقة لتشغيل البرامج النصية ، فلا يمكننا تشغيلها على الإنتاج. سنحتاج إلى بيئة مرحلية بنفس التكوين تمامًا مثل نظام الإنتاج. - تمت إضافة كود إضافي إلى الموقع ، فقط للإدارة.
85 كيلو بايت من الكود لا يعمل في حد ذاته ، ولكن ببساطة رمز لإدارة التعليمات البرمجية الأخرى. - يضاف التعقيد.
هذا أمر لا مفر منه في أي حال إذا أردنا تقسيم أصولنا إلى وحدات أصغر. سيضيف Webpack أيضًا تعقيدًا إلى التطبيق.
مزايا
- يعمل مع WordPress.
لا يعمل Webpack مع WordPress خارج الصندوق ، ولجعله يعمل يحتاج إلى بعض الحلول. يعمل هذا الحل خارج منطقة الجزاء في WordPress (طالما تم تثبيت PoP). - إنها قابلة للتطوير والتوسيع.
يمكن أن يزداد حجم التطبيق وتعقيده بدون حدود ، لأنه يتم تحميل ملفات JavaScript عند الطلب. - وهو يدعم Gutenberg (المعروف أيضًا باسم WordPress للغد).
نظرًا لأنه يسمح لنا بتحميل أطر عمل JavaScript عند الطلب ، فإنه سيدعم كتل Gutenberg (تسمى Gutenblocks) ، والتي من المتوقع أن يتم ترميزها في إطار العمل الذي يختاره المطور ، مع النتيجة المحتملة لأطر عمل مختلفة مطلوبة لنفس التطبيق. - هذا منطقي.
تهتم أداة الإنشاء بإنشاء ملفات التكوين. بصرف النظر عن الانتظار ، لا حاجة منا إلى بذل جهد إضافي. - يجعل التحسين سهلاً.
حاليًا ، إذا أراد مكون WordPress الإضافي تحميل أصول JavaScript بشكل انتقائي ، فسيستخدم الكثير من الشروط للتحقق مما إذا كان معرف الصفحة هو الصحيح. مع هذه الأداة ، ليست هناك حاجة لذلك ؛ العملية تلقائية. - سيتم تحميل التطبيق بسرعة أكبر.
كان هذا هو السبب الكامل وراء تشفيرنا لهذه الأداة. - يتطلب بيئة انطلاق.
التأثير الجانبي الإيجابي هو زيادة الموثوقية: لن نقوم بتشغيل البرامج النصية على الإنتاج ، لذلك لن نكسر أي شيء هناك ؛ لن تفشل عملية النشر من سلوك غير متوقع ؛ وسيضطر المطور إلى اختبار التطبيق باستخدام نفس التكوين كما هو الحال في الإنتاج. - تم تخصيصه لتطبيقنا.
لا يوجد النفقات العامة أو الحلول. ما نحصل عليه هو بالضبط ما نحتاجه ، بناءً على الهندسة المعمارية التي نعمل معها.
في الختام: نعم ، الأمر يستحق ذلك ، لأننا الآن قادرون على تطبيق أصول التحميل عند الطلب على موقع WordPress الخاص بنا وجعله يتم تحميله بشكل أسرع.
مزيد من الموارد
- حزمة الويب ، بما في ذلك دليل "" رمز تقسيم "
- "Better Webpack Builds" (فيديو) ، ك. آدم وايت
تكامل Webpack مع WordPress - "جوتنبرج ووردبريس الغد ،" مورتن راند هندريكسن ، WP Tavern
- "يستكشف WordPress أسلوب JavaScript الحيادي لبناء كتل Gutenberg ،" Sarah Gooding ، WP Tavern