FullStackReact

كيفية إطلاق تطبيقات React : رؤية تفصيلية

كتب بواسطة: 17/12/2019 One Comment

العديد من شركات تطوير الـ Front End تستخدم React لتطوير البرامج. إن  نشر التطبيقات يهدف لإتاحة الوصول لها من خلال شبكة الانترنت. نناقش في هذا المقال الطرق المختلفة لنشر تطبيقات React ، بيئة نشرها واختبارها.

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

المقال يفترض وجود حزمة ويب (webpack module bundler) لتكوين الأصول (assets) اللازمة للتطوير في جانب العميل (client side).

إلى ماذا يشير التطوير ؟ ( للمبتدئين)

عندما تنشئ تطبيق React  الخاص بك فإنك ترغب بنشره للجميع. لذلك لن ترغب باخبار كل مستخدم على حدة ليقوم بتحميل المستودع (repository) لتشغيل تطبيقك محلياً على جهازه. لإتاحة التطبيق للجميع لتحميله يجب نشره على الانترنت. كذلك من الممكن إطلاق نسخ جديدة للتحديثات الحاصلة على النسخة ( مثل: إصلاح أخطاء، إضافات ومزايا.. ) يجب أن يحدث هذا بدون إعلام المستخدم.

ما الذي يجب أن يكون محور التركيز في نشر التطبيق ؟

التركيز الرئيسي في نشر تطبيقات (Front End) في مقالنا (في حالتنا هذه تطبيقات React ) على سرعة تحميل التطبيق بدون إحداث ضغط على السيرفر. ويمكن ذلك عن طريق تقليل ملفات JavaScript وتحسين أصول (assets) التطبيق الثابتة. تخيل تحميل 15 ميجا في كل عملية طلب على الانترنت في التطبيق!، هذا سيولد شعور بصعوبة الاستخدام للمستخدم.

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

بماذا تختلف عملية النشر عن التطوير؟

عادة ما نعرّف (بيئة النشر) و (بيئة التطوير) للتمييز بين نشر التطبيق ومرحلة تطوير التطبيق.

التركيز الرئيسي في مرحلة التطوير هي جعل عملية التطوير أسهل من خلال دمج عدة أدوات. على سبيل المثال، التتبع الجيد للتكدّس (Stack trace) يساعد في تحديد الأخطاء بسهولة.

من الممكن استخدام السجلات (Loggers) لتشخيص المشكلة، وهذه لا نستخدمها في مرحلة النشر لانها تستهلك الذاكرة وتبطئ من الأداء.

تكمن الفكرة بوجود الكثير من التحسينات في التطبيقات المنشورة.

كيف يعمل النشر؟

في عملية نشر التطبيق من جانب العميل (client side)، ننتج ملفات يتم تقديمها فعلياً عبر الشبكة.

في المثال يمكن ملاحظة جلب ملفات  الضرورية ( Javascript , static assets) عبر الشبكة.

عادة وأثناء عملية التطوير باستخدام حزمة الويب Webpack dev server يقوم الخادم (server) بتخزين هذه الملفات في الذاكرة، حيث يوفر الخدمة أثناء التطوير، أما أثناء نشر التطبيق فيتم توليد الملفات التالية:

1- ملف Html الجذر.

2- ملف أو عدة ملفات ( javascript) [تتضمن التنسيق].

3- أصول (assets) التطبيق مثل ( الصور، ملفات SVG )

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

تحسينات أثناء إنشاء الحزمة

لا يمكننا إجراء تغييرات كثيرة على ملف html لأنه سيكون له ملف JS مرتبط به. حتى وإن كان حجمه أقل من 1Kb. عادة ما نستهدف ملفات Javascript في عملية التحسين، لذلك إن سألتني ما هو الحجم المناسب لحزمة ملفات Javascript ، فإن الإجابة هي عدم وجود رقم سحري! ، فكلما زاد حجم ملف Javascript كلما زاد بطء تطبيقك. كجزء من التحسين يمكنك تجزئة الحزمة واستخدام التخزين المؤقت (Cache) مما يؤدي لخدمة أسرع لتطبيقك. لمعرفة الأرقام بدقة دعونا نلقي نظرة على الكمية التي تجلبها تطبيقات React المشهورة . افتح أداة Devtools واختر المواقع التالية 

Airbnb : 3.1 MB

Bitbucket: 1 MB

Clashofclans: 3.3MB

معظم هذه التطبيقات تستخدم تقنيات محسنة لتقليل الضغط على الخادم (server) أثناء جلب الملفات أول مرة . مثلاً فيسبوك ونتفلكس تجلب الحد الأدنى من البيانات (حوالي 1 ميجا) عند تحميلها أول مرة. بناءاً على تفاعل المستخدم يقوم التطبيق بجلب الملفات الأخرى. لذلك عندما تشعر أن تطبيقك بطيء و لديك حزمة  حجمها كبير، حتى بعد عمليات التحسين، فإن أفضل تقنية يمكن اتباعها هي تجزئة تحميل الملفات والحزم لحين طلبها.

دعونا ننظر إلى تقنيات التحسين المختلفة واحده تلو الأخرى. تذكر لست بحاجة لاستخدامها كلها . هذه فقط أفضل الخيارات. يمكنك اختيار أفضل الخيارات المتوافقة مع تطبيقك. نحن  في Codebrahma عادةً ما ننتقي خيارات التحسين حسب حالات الاستخدام.

إعداد بيئة العقدة (node) المناسبة

بالرغم من أن React لديها نظام جيد للتحذيرات والأخطاء (errors)، إلا أنك لا تحتاجه في التطبيقات المنشورة. (إنه مفيد فعلاً في التطبيقات تحت التطوير). إذا بإعداد بيئة العقدة (Node Environmen) لتطبيقك، نحن بالضبط نقول لـReact تجاهلي إظهار التحذيرات. أيضاً المكتبات التي تستخدمها (ليست كلها)،سوف تتجنب التطويرات للكود الذي له علاقة بهذا.

إذا كنت رأيت كود المصدر لـ React  سوف تجد الكثير من الشروط التحققية (process.env.NODE_ENV != ‘production’). معظم هذه الشروط تكون لأهداف التطوير. ولتفادي ذلك يمكننا استخدام definePlugin في الـwebpack  كالتالي:

هذا سوف يتفادى كل الأكواد المعنية فعلاً بالتطوير.

تصغير الحجم (Minification)

يقلل التصغير من ملف الكود لكل البيانات غير المطلوبة حتى يتم تنفيذ الملف. والقراءة عموماً ليست مصدر قلق للكود المنشور والمُستخدم على المتصفح. عن طريق التصغير، نضغط حجم الملف بإزالة المسافات، الأسطر الجديدة مما يجعل البرمجة قبيحة. كما يربط Uglify الجمل باستخدام الفواصل ويزيل الكود الميت ويزيل سجلات وحدة التحكم. ويبسط أيضاً البيانات المشروطة (إذا) (if)، والعمليات المنطقية (Boolean)، والثوابت، وتعريف الدوال، إلخ.

يمكننا إستخدام ملحق Uglify JS لتصغير الكود الخاص بك. على الرغم من وجود العديد من الإعدادات، يمكنك بسهولة تحديد أي منها يعمل بشكل أفضل بالنسبة لك.

إزالة الكود الميت باستخدام هز الشجرة (Tree Shaking):

هز الشجرة (tree shaking) هي تقنية تتيح لك إزالة الأكواد غير المُستدعاة. هذا يعمل فقط في وحدة (module) ES2015 ، استيراد/ تصدير (import/export). باستخدام هذه الطريقة يمكننا إزالة الأكواد من المكتبات التي لا يتم استدعائها. إذاً، كيف يعمل؟ خلال عملية إنشاء الحزمة (bundel)، يقوم Webpack بضم جميع الوحدات (modules) الخاصة بك ووضعها في ملف واحد ولكنه يزيل كود الـ exportfrom الذي لا يتم استدعائه  في أي مكان.

على الرغم من أن هذه التقنية جيدة، إلا أن غالبية المكتبات لا تنشر أكوادها في ES2015. ونتيجة لذلك، قد تجد أن النتيجة ليست كما تتوقع.

Dedupe-plugin

يمنع إلغاء البيانات المكررة (Deduplication) وكما يوحي الاسم، من  تضمين الملفات المكررة في الكود المُجمع عن طريق إنشاء نسخ من الدوال المكررة بدلاً من إعادة تعريفها. لذلك في وقت التشغيل، يضمن وجود نسخة واحدة فقط من كل دالة وبالتالي إزالة أي تكرار.

Ignore – plugin

باستخدام هذه الإضافة (plugin) يمكننا تجاهل الوحدات لاستيراد التعابير النمطية (regular expressions) التالية.

على سبيل المثال، في المكتبة moment يتم تجميع كل المواقع (locals) مع المكتبة الرئيسية. يمكنك استخدام IgnorePlugin لإيقاف أي موقع (local) يتم تجميعه مع مكتبة moment:

OccurrenceOrderPlugin

تعيين الوحدة (module)، ومعرفات القطع (chunks)، بعدد مرات الحدوث. المُعرّفات (ids) المستخدمة غالباً تأخذ معرّفات أقل (أقصر).  هذا يجعل المعرّفات (ids) يمكن تنبؤها، ويقلل الحجم الكلي للملف، وهذا ما يُوصى به.

التحميل البطيئ والاستيرادات الديناميكية

توفر Webpack نظاماً أساسياً رائعاً لتحقيق عمليات الاستيراد الديناميكية بسلاسة تامة. حاول فتح موقعي Facebook.com و netflix.com وحاول استخدام بعض الميزات. يمكنك أن ترى العديد من طلبات الشبكة لإحضار ملفات JS. لن تكون هذه الملفات متاحة إلا عند الحاجة. مثال بسيط

تسمح لك Webpack  باستيراد مكتبة فقط عندما تستخدمها بالفعل. على سبيل المثال، moment هي مكتبة ثقيلة قد لا تستخدم في كل مكان. إذا كان هناك مركب حيث تستخدم مكتبة moment ويتم تجسيد هذا المركب في مسار واحد فقط، يمكنك إدراجه ديناميكياً هكذا

يمكننا استخدام مكتبة moment، فقط في اللحظة التي يتم احتياجها فعلياً.

إذاً، إذا كان بإمكانك تعريف الوحدات (modules) بناءً على الاستخدام ، سوف يكون بإمكاننا تقليل حجم الحزمة (bundle) بشكل كبير لمعظم الحالات التي تستخدم هذه الإضافة (plugin).

CommonChunk plugin

غالباً لن يكون لديك نقاط إدخال متعددة في إعدادات الـwebpack الخاصة بك. أريد مناقشة هذا الأمر فقط لأريك مدى قوة الـ commonChunksPlugin. إذا كان لديك تطبيق من عدة صفحات، يمكنك بسهولة أن تربط بين مع عدة نقاط إدخال، تُنشئ عدة قطع (chunks)، ويتم تحميلهم حسب الطلب.

هذا سوف ينشئ عدة قطع (chunks) إدخال:  index.entry.chunk.js و dashboard.entry.chunk.js.

إذا كانت قطع (chunks) الإدخال الخاصة بك لها بعض الوحدات (modules) المشتركة، فإن CommonsChunkPlugin  يحدد الوحدات (modules) المشتركة، ويضعهم في قطعة (chunk) مشتركة. تحتاج لإضافة علامتي نص برمجي (script) في صفحتك، واحدة للقطعة (chunk) المشتركة، وأخرى لقطعة (chunk) الإدخال.

هذا سوف ينشئ كل الـJS أعلاه بالإضافة إلى واحد من commons.chunk.js.أولاً يتم تحميل commons.chunk.js، بعد ذلك يتم تحميل كل الملفات الأخرى في الـhtml ؛ لجعلها تعمل.

والآن يأتي السؤال، كيف يتم استخدامه مع react، حيث سيكون صفحة تطبيق واحدة. يمكننا حقيقةً إنشاء عدة مدخلات، واحدة تكون  لملف vendor JS (كل مكتباتك)، والآخرين لملف app JS. المتصفحات عامة تقوم بحفط ملفات الـJS بشكل مؤقت (cache)، وتُرجع نفس الملف الذي تم استدعاءه من الطلب السابق، إذا كان اسم الملف لم يتغير. غالباً ما تكون نفس المكتبات التي سنستخدمها بمجرد نشر التطبيق للتحديثات. لذا يمكننا فعلياً استخدام معرفّات التجزئة (hash IDs) الخاصة بالبناء لتغيير اسم التطبيقapp.bundle.js بشكل ديناميكي، وبالتالي تخزين ملفات الـ vendor  والتي يمكنك من خلالها تجنب إعادة تحميلها أثناء إطلاق الإصدارات الجديدة.

ModuleConcatenation Plugin

في السابق، كانت إحدى المقايضات لحزمة webpack، هي أن كل وحدة (module) في الحزمة سوف تُغلف بدوال فردية مغلقة. هذه الدوال التغليفية تجعل من تنفيذ JavaScript في المتصفح أبطأ. بالمقارنة مع أدوات مثل  Closure Compiler وRollupJS ‘hoist’ أو concatenate تعمل على جعل نطاق جميع الوحدات (modules) الخاصة بك في إغلاق (Closure) واحد، وتسمح لبرنامجك بإنجاز وقت تنفيذ أسرع في المتصفح.

ستسمح هذه الإضافة بسلوك متسلسل مشابه في الـwebpack.

Compression-webpack-plugin:

هذه الإضافة (plugin) هي الأهم. بمجرد ضغطك مع GZIP، سوف يقل حجم الحزمة بشكل جذري. سوف أترك لك المجال لتبحث في google ما الذي تفعله هذه الإضافة (plugin) بالضبط

بمجرد بنائك لملفاتك بهذه الإضافات (plugins)، سيكون لك الكثير من الخيارات لنشر تطبيقك. لنشر تطبيقك وجعله متاح للجميع، كل ما تحتاجه هو الخادم (server) للتعامل مع الاستجابة (response) ومرفق لاستضافة الخادم. هناك خيارات مختلفة للقيام بذلك.

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

AWS S3

السعر: مجاناً لمدة عام باستخدام الطبقة المجانية.

يعد Amazon S3 بمثابة وحدة تخزين للكائنات تم تصميمها لتخزين وجلب أي كمية من البيانات من أي مكان. باستخدام S3 يمكننا تخزين ملفات HTML و JS و CSS، وبذلك نقوم بخدمتها كموقع ثابت. كل ما تحصل عليه هو مجلد عام به دلو (bucket)  (يمكن استخدام كل دلو (bucket) كصفحة ويب ثابتة مختلفة). من أجل هذا يجب إنشاء دلو (bucket). مع AWS يمكنك الحصول على 11 شهراً من الطبقة المجانية التي يمكنك إنشاء واحدة منها.

كيف تستضيف؟

  1. لفهرسة الملف، اكتب اسم ملف index html والذي يسمى بالعادة index.html. عندما تقوم بإعداد دلو (bucket) لاستضافة موقع الويب، يجب تحديد مستند فهرس (index). يُرجع  Amazon S3 مستند الفهرس هذا عند إجراء الطلبات إلى الدومين الأصلي (root) أو أي من المجلدات الفرعية.
  2. (اختياري) للأخطاء من فئة (class) ـ4XX ، يمكنك تقديم مستند خطأ خاص، يزود المستخدمين بتوجيهات معينة.لملف الأخطاء، اكتب اسم الملف الذي يحتوي على الأخطاء المخصصة. إذا حدث خطأ، سوف يُرجع  Amazon S3 ملف أخطاء HTML. لمزيد من المعلومات، راجع دعم مستند الخطأ المخصص(Custom Error Document Support) في التخزين البسيط لـ Amazon .
  3. (اختياري) إذا كنت تريد تعيين قواعد إعادة توجيه محددة، في منطقة النص الخاصة بتحرير قواعد إعادة التوجيه،  استخدم XML لوصف القواعد. يمكنك توجيه الطلبات بناءً على أسماء مفاتيح الكائن (object) المحددة، أو عن طريق البادئات  (prefix) في الطلب. يمكنك الحصول على قواعد إعادة توجيه متقدمة من هنا.
  4. يمكنك أيضاً إعداد الـ cloudfront للتوصيل والتخزين المؤقت (caching) بناءً على المنطقة.

إذا واجهتك أي مشكلة في إعادة التوجيه في react باستخدام S3 يمكننا استخدام قاعدة إعادة توجيه متقدمة لحل هذه المشكلة. على سبيل المثال، إذا قمت بالضغط على المسار المتداخل كما هو معرّف في React فلن تحصل على النتائج.  وذلك لأنه في عمليات النشر الثابتة، يبحث أولاً عن المجلد استناداً إلى المسار. لتجنب هذا، يمكنك كتابة قاعدة إعادة التوجيه المتقدمة لـ 404 واستخدام عنوان Hash URL بناء على طريقة stackoverflow.

AWS EC2 أو المحيط الرقمي (digital ocean) :

AWS: طبقة مجانية لعام واحد. ما بعد ذلك يتم إعادة الشحن ( تقريباً > 6 دولار لكل شهر).

EC2: أقل من 5 دولار لكل شهر بناءً على الإعدادات.

يوفر هذا مثيل (instance)  لنظام التشغيل المفضل لديك (من ubuntu إلى Windows) ويسمح لك بنشر التطبيق الخاص بك. وتحصل على عنوان IP،  يمكنك من خلاله تشغيل المثيل (instance) والوصول إليه. الخطوات التي تتم أثناء النشر هي

  1. SSH  إلى الجهاز
  2. قم بنسخ مستودع (github repository) الخاص بك وقم بسحب أحدث كود.
  3. تحميل npm 
  4. إنشاء خادم Node بسيط لخدمة ملفاتك
  5. استخدم مدير العمليات مثل PM2 لمعالجة أخطاء الخادم وإعادة تشغيله.
  6. يمكننا استخدام خدمات مثل “nginx” لموازنة التحميل وإنشاء الوكلاء (proxying). لعمل التوجيه الخاص بـreact والذي يعمل مع مسارات متداخلة، يمكننا إعداد nginx لإعادة توجيهه إلى الجذر(root) إذا حصل أي خطأ.

بما أن هذا النشر ثابت، يمكنك استخدام أي خادم ترغب به. نحن نستخدم العقدة (Node) لأننا مرتاحون مع Javascript. هذا بالضبط مشابه للخدمة من جهازك المحلي. بدلاً من استخدام الجهاز نقوم بذلك على جهاز بعيد. هذه إحدى أفضل الطرق وأكثرها استخداماً في النشر. وتتمثل مزايا هذه الطريقة في حرية اختيار أدواتنا وأمان متقدم  للشبكة وخيارات أفضل للنشر.

Heroku.

السعر: لديه حساب مجاني يمكنك من خلاله إنشاء 5 تطبيقات. يمكننا الحصول على dynos أقل من 7 دولارات في الشهر.

يعد Heroku منصة مشهورة كخدمة تُمكن المطورين من تشغيل تطبيقات البناء والتشغيل التلقائي عبر الويب. الميزة الرئيسية في استخدام Heroku هي أنه إذا اتبعت مجموعة تعليماتها فإنها ستحدد تلقائيا أي نوع من التطبيقات وتنشرها من تلقاء نفسها. إذا استخدمنا خادم Node مماثل لما استخدمناه في  AWS EC2، عندها يمكننا اتباع هذا المقال لنشر تطبيقنا. تتضمن هذه العملية النموذجية:

  1. إنشاء حساب Heroku 
  2. إنشاء تطبيق سريع لمعالجة المسارات
  3. إنشاء تطبيق heroku.
  4. إضافة عنونة عن بعد (remote url) لـ heroku
  5. الرفع إلى الـheroku  الرئيسي (master)
  6. سيتم نشر التطبيق تلقائياً

مكافأة

أدوات تسجيل المُنتج.

هناك بعض الأدوات التي تساعدنا على مراقبة التطبيقات المنتشرة. على سبيل المثال، إذا كان هناك خلل في الإصدار المنتشر وحين نقوم بتسجيل هذا الخلل يمكننا استخدام تتبع التكدس (stack) لحل ذلك بسهولة.

Sentry:

باستخدام Sentry، يمكننا تسجيل كل الأخطاء والحفاظ على تتبع تكدسها (stack). كل ما نحتاج إليه هو تضمين كود CDN / source مع بيانات حسابنا المعتمدة على ملف JS. نحتاج إلى الرفع على sentry في كل مكان يتوقع وجود أخطاء فيه (يمكننا استخدام نمط try catch عند جلب البيانات غير المتزامن  أو في أي مواقع محتملة أخرى).

Log Rocket

هو آخر أداة يمكننا من خلالها إعادة تشغيل حالات الاسترجاع (redux states) عندما يحدث خلل. وهي تكتسب شعبيتها في وقت متأخر.

شارك في النقاش One Comment

اترك تعليق