إنشاء تطبيقات Vue.js المقدمة من جانب الخادم باستخدام Nuxt.js

نشرت: 2022-03-11

يمكن أن توفر أطر عمل / مكتبات JavaScript مثل Vue تجربة مستخدم رائعة عند تصفح موقعك. يقدم معظمهم طريقة لتغيير محتوى الصفحة ديناميكيًا دون الحاجة إلى إرسال طلب إلى الخادم في كل مرة.

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

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

مقارنة مرئية بين العرض من جانب العميل والخادم

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

إذا كنت ترغب في مزيد من المعلومات حول مزايا SSR في بيئة Vue ، فيجب عليك مراجعة مقالة Vue الخاصة حول SSR. هناك مجموعة متنوعة من الخيارات لتحقيق هذه النتائج ، ولكن الخيار الأكثر شيوعًا ، والذي أوصى به فريق Vue أيضًا ، هو Nuxt.

لماذا Nuxt.js

يعتمد Nuxt.js على تطبيق SSR لمكتبة React الشهيرة التي تسمى Next. بعد رؤية مزايا هذا التصميم ، تم تصميم تطبيق مماثل لـ Vue يسمى Nuxt. أولئك الذين هم على دراية بتركيبة React + Next سوف يكتشفون مجموعة من أوجه التشابه في تصميم وتخطيط التطبيق. ومع ذلك ، تقدم Nuxt ميزات خاصة بـ Vue لإنشاء حل SSR قوي ومرن لـ Vue.

تم تحديث Nuxt إلى إصدار 1.0 جاهز للإنتاج في يناير 2018 وهو جزء من مجتمع نشط ومدعوم جيدًا. أحد الأشياء الرائعة هو أن بناء مشروع باستخدام Nuxt لا يختلف كثيرًا عن إنشاء أي مشروع Vue آخر. في الواقع ، يوفر مجموعة من الميزات التي تتيح لك إنشاء قواعد رموز جيدة التنظيم في فترة زمنية أقل.

شيء آخر مهم يجب ملاحظته هو أن Nuxt لا يجب استخدامه لـ SSR . تمت ترقيته كإطار عمل لإنشاء تطبيقات Vue.js عالمية ويتضمن أمرًا ( nuxt generate ) لإنشاء تطبيقات Vue ثابتة باستخدام نفس مصدر التعليمات البرمجية. لذلك إذا كنت قلقًا بشأن الغوص في أعماق SSR ، فلا داعي للذعر. يمكنك دائمًا إنشاء موقع ثابت بدلاً من ذلك مع الاستمرار في الاستفادة من ميزات Nuxt.

من أجل فهم إمكانات Nuxt ، دعنا ننشئ مشروعًا بسيطًا. تتم استضافة رمز المصدر النهائي لهذا المشروع على GitHub إذا كنت تريد رؤيته ، أو يمكنك عرض إصدار مباشر تم إنشاؤه باستخدام nuxt generate واستضافة على Netlify.

إنشاء مشروع Nuxt

للبدء ، دعنا نستخدم منشئ مشروع Vue يسمى vue-cli لإنشاء نموذج مشروع بسرعة:

 # install vue-cli globally npm install -g vue-cli # create a project using a nuxt template vue init nuxt-community/starter-template my-nuxt-project

بعد المرور بخيارين ، سيؤدي ذلك إلى إنشاء مشروع داخل المجلد my-nuxt-project أو أيًا كان ما حددته. ثم نحتاج فقط إلى تثبيت التبعيات وتشغيل الخادم:

 cd my-nuxt-project npm install # Or yarn npm run dev

هناك نذهب. افتح المستعرض الخاص بك على localhost:3000 ويجب أن يكون مشروعك قيد التشغيل. لا يختلف كثيرًا عن إنشاء مشروع Vue Webpack. ومع ذلك ، عندما ننظر إلى الهيكل الفعلي للتطبيق ، لا يوجد الكثير ، خاصة عند مقارنته بشيء مثل قالب Vue Webpack.

رسم تخطيطي لأدلة المشروع وعلاقتها بملف تكوين Nuxt

يُظهر البحث في package.json أيضًا أن لدينا تبعية واحدة فقط ، وهي Nuxt نفسها. هذا لأن كل إصدار من Nuxt مصمم للعمل مع إصدارات معينة من Vue و Vue-router و Vuex وجمعها معًا من أجلك.

يوجد أيضًا ملف nuxt.config.js في جذر المشروع. يتيح لك ذلك تخصيص مجموعة من الميزات التي يوفرها Nuxt. بشكل افتراضي ، يقوم بتعيين علامات الرأس ولون شريط التحميل وقواعد ESLint لك. إذا كنت حريصًا على معرفة ما يمكنك تكوينه ، فإليك الوثائق ؛ سنغطي بعض الخيارات في هذه المقالة.

إذن ما الذي يميز تلك الدلائل؟

تخطيط المشروع

إذا كنت تتصفح الدلائل التي تم إنشاؤها ، فكل منها يحتوي على ملف Readme مصاحب يوضح ملخصًا موجزًا ​​لما يتم إدخاله في هذا الدليل وغالبًا ما يكون رابطًا إلى المستندات.

هذه إحدى فوائد استخدام Nuxt: بنية افتراضية لتطبيقك. سيقوم أي مطور جيد للواجهة الأمامية ببناء تطبيق مشابه لهذا ، ولكن هناك العديد من الأفكار المختلفة حول الهياكل ، وعند العمل في فريق ، سوف يذهب بعض الوقت حتمًا لمناقشة أو اختيار هذا الهيكل. يوفر Nuxt واحدًا لك.

سيبحث Nuxt عن أدلة معينة ويبني التطبيق الخاص بك بناءً على ما يجده. دعنا نفحص هذه الدلائل واحدًا تلو الآخر.

الصفحات

هذا هو الدليل الوحيد المطلوب . تتم إضافة أي مكونات Vue في هذا الدليل تلقائيًا إلى vue-router بناءً على أسماء الملفات الخاصة بها وهيكل الدليل. هذا مريح للغاية . عادةً ما يكون لدي دليل Pages منفصل على أي حال ويجب أن أسجل يدويًا كل من هذه المكونات في ملف جهاز توجيه آخر. يمكن أن يصبح ملف جهاز التوجيه هذا معقدًا بالنسبة للمشاريع الكبيرة وقد يحتاج إلى تقسيم للحفاظ على قابلية القراءة. بدلاً من ذلك ، ستتعامل Nuxt مع كل هذا المنطق نيابةً عنك.

للتوضيح ، يمكننا إنشاء مكون Vue يسمى about.vue داخل دليل الصفحات. دعنا فقط نضيف نموذجًا بسيطًا مثل:

 <template> <h1>About Page</h1> </template>

عند الحفظ ، ستعيد Nuxt إنشاء المسارات نيابةً عنك. بالنظر كما أطلقنا على المكون الخاص بنا about.vue ، إذا انتقلت إلى /about ، يجب أن ترى هذا المكون. بسيط.

يوجد اسم ملف واحد خاص. ستؤدي تسمية ملف index.vue إلى إنشاء مسار جذر لذلك الدليل. عند إنشاء المشروع ، يوجد بالفعل مكون index.vue في دليل الصفحات يرتبط بالصفحة الرئيسية أو الصفحة المقصودة لموقعك. (في مثال التطوير ، سيكون هذا ببساطة localhost:3000 )

يقوم Nuxt بمسح ملفات Vue في دليل الصفحات وإخراج الصفحات المناسبة.

ماذا عن الطرق العميقة؟ تساعد الدلائل الفرعية الموجودة في دليل الصفحات في هيكلة مساراتك. لذلك إذا أردنا صفحة عرض المنتج ، فيمكننا هيكلة دليل الصفحات على النحو التالي:

 /pages --| /products ----| index.vue ----| view.vue

الآن ، إذا انتقلنا إلى /products/view ، فسنرى المكون view.vue داخل دليل المنتجات. إذا انتقلنا بدلاً من ذلك إلى /products ، فسنرى المكون index.vue داخل دليل المنتجات.

قد تسأل لماذا لم نقم فقط بإنشاء مكون products.vue في دليل الصفحات بدلاً من ذلك كما فعلنا للصفحة /about . قد تعتقد أن النتيجة ستكون هي نفسها ، لكن هناك فرق بين الهيكلين. دعنا نوضح ذلك عن طريق إضافة صفحة جديدة أخرى.

لنفترض أننا أردنا صفحة "حول" منفصلة لكل موظف. على سبيل المثال ، دعنا ننشئ صفحة "حول" لي. يجب أن يكون موجودًا في /about/ben-jones . في البداية ، قد نحاول هيكلة دليل الصفحات على النحو التالي:

 /pages --| about.vue --| /about ----| ben-jones.vue

عندما نحاول الوصول إلى /about/ben-jones ، نحصل بدلاً من ذلك على مكون about.vue ، مثل /about . ماذا يجري هنا؟

ومن المثير للاهتمام أن ما تفعله Nuxt هنا هو إنشاء مسار متداخل . تشير هذه البنية إلى أنك تريد مسارًا دائمًا /about ويجب أن يتداخل أي شيء داخل هذا المسار في منطقة العرض الخاصة به. في vue-router ، يمكن الإشارة إلى ذلك بتحديد مكون <router-view /> داخل المكون about.vue . في Nuxt ، هذا هو نفس المفهوم باستثناء ، بدلاً من <router-view /> ، نستخدم ببساطة <nuxt /> . لذلك دعونا نقوم بتحديث مكون about.vue للسماح بالمسارات المتداخلة:

 <template> <div> <h1>About Page</h1> <nuxt /> </div> </template>

الآن ، عندما ننتقل إلى /about ، نحصل على مكون about.vue الذي كان لدينا من قبل ، مع عنوان فقط. ومع ذلك ، عندما ننتقل إلى /about/ben-jones ، لدينا بدلاً من ذلك العنوان ومكون ben-jones.vue حيث كان العنصر النائب <nuxt/> .

لم يكن هذا ما أردناه في البداية ، ولكن فكرة وجود صفحة "حول" مع قائمة بالأشخاص الذين ، عند النقر فوقهم ، يملأون قسمًا على الصفحة بمعلوماتهم هو مفهوم مثير للاهتمام ، لذلك دعنا نترك الأمر كما هو الآن . إذا كنت تريد الخيار الآخر ، فكل ما سنفعله هو إعادة هيكلة أدلةنا. سنضطر فقط إلى نقل المكون about.vue داخل الدليل /about وإعادة تسميته index.vue ، وبالتالي فإن الهيكل الناتج سيكون:

 /pages --| /about ----| index.vue ----| ben-jones.vue

أخيرًا ، لنفترض أننا أردنا استخدام معلمات المسار لاسترداد منتج معين. على سبيل المثال ، نريد أن نكون قادرين على تحرير منتج بالانتقال إلى /products/edit/64 حيث 64 هو product_id . يمكننا القيام بذلك بالطريقة التالية:

 /pages --| /products ----| /edit ------| _product_id.vue

لاحظ أن الشرطة السفلية في بداية المكون _product_id.vue - تشير إلى معلمة المسار التي يمكن الوصول إليها بعد ذلك على الكائن $route.params أو على كائن params في سياق Nuxt (المزيد حول ذلك لاحقًا). لاحظ أن مفتاح المعلمة سيكون اسم المكون بدون الشرطة السفلية الأولية - في هذه الحالة ، product_id - لذا حاول إبقائها فريدة داخل المشروع. نتيجة لذلك ، في _product_id.vue ، قد يكون لدينا شيء مثل:

 <template> <h1>Editing Product {{ $route.params.product_id }}</h1> </template>

يمكنك أن تبدأ في تخيل تخطيطات أكثر تعقيدًا ، والتي سيكون من الصعب إعدادها باستخدام vue-router. على سبيل المثال ، يمكننا دمج كل ما سبق في مسار مثل:

 /pages --| /categories ----| /_category_id ------| products.vue ------| /products --------| _product_id.vue

ليس من الصعب جدًا التفكير في ما /categories/2/products/3 سيتم عرضها. سيكون لدينا مكون products.vue مع مكون _product_id.vue متداخل ، مع معلمتين للمسار: category_id و product_id . هذا أبسط بكثير من التفكير في تكوين جهاز توجيه مكافئ.

أثناء تواجدنا في هذا الموضوع ، هناك شيء واحد أميل إلى القيام به في تكوين جهاز التوجيه وهو إعداد حراس جهاز التوجيه. نظرًا لأن Nuxt تقوم ببناء جهاز التوجيه لنا ، فيمكن القيام بذلك بدلاً من ذلك على المكون نفسه باستخدام beforeRouteEnter . إذا كنت تريد التحقق من صحة معلمات المسار ، فإن Nuxt يوفر طريقة مكون تسمى validate الصحة. لذا إذا أردت التحقق مما إذا كان product_id رقمًا قبل محاولة عرض المكون ، يمكنك إضافة ما يلي إلى علامة البرنامج النصي لـ _product_id.vue :

 export default { validate ({ params }) { // Must be a number return /^\d+$/.test(params.product_id) } }

الآن ، يؤدي الانتقال إلى /categories/2/products/someproduct someproduct 404 لأن بعض المنتجات ليست رقمًا صالحًا.

هذا كل شيء في دليل الصفحات. يعد تعلم كيفية تنظيم مساراتك بشكل صحيح في هذا الدليل أمرًا ضروريًا ، لذا فإن قضاء القليل من الوقت في البداية مهم لتحقيق أقصى استفادة من Nuxt. إذا كنت تبحث عن نظرة عامة موجزة ، فمن المفيد دائمًا الرجوع إلى المستندات للتوجيه.

إذا كنت قلقًا بشأن عدم التحكم في جهاز التوجيه ، فلا تقلق. يعمل هذا الإعداد الافتراضي بشكل رائع مع مجموعة متنوعة من المشاريع ، بشرط أن تكون منظمة بشكل جيد. ومع ذلك ، هناك بعض الحالات التي قد تحتاج فيها إلى إضافة المزيد من المسارات إلى جهاز التوجيه أكثر مما تنشئه Nuxt تلقائيًا لك أو إعادة هيكلتها. يوفر Nuxt طريقة لتخصيص مثيل جهاز التوجيه في التكوين ، مما يسمح لك بإضافة مسارات جديدة وتخصيص المسارات التي تم إنشاؤها. يمكنك أيضًا تعديل الوظائف الأساسية لمثيل جهاز التوجيه ، بما في ذلك الخيارات الإضافية المضافة بواسطة Nuxt. لذلك إذا واجهت حالة حافة ، فلا يزال لديك المرونة للعثور على الحل المناسب.

متجر

يمكن لـ Nuxt بناء متجر Vuex الخاص بك بناءً على بنية دليل المتجر ، على غرار دليل Pages. إذا لم تكن بحاجة إلى متجر ، فما عليك سوى إزالة الدليل. هناك وضعان للمتجر ، Classic و Modules.

يتطلب Classic أن يكون لديك ملف index.js في دليل المتجر. هناك تحتاج إلى تصدير دالة تقوم بإرجاع مثيل Vuex:

 import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: ..., mutations: ..., actions: ... }) } export default createStore

يتيح لك هذا إنشاء المتجر كيفما تشاء ، تمامًا مثل استخدام Vuex في مشروع Vue العادي.

يتطلب منك وضع الوحدات النمطية أيضًا إنشاء ملف index.js في دليل المتجر. ومع ذلك ، يحتاج هذا الملف فقط إلى تصدير حالة الجذر / الطفرات / الإجراءات لمتجر Vuex الخاص بك. يحدد المثال أدناه حالة جذر فارغة:

 export const state = () => ({})

بعد ذلك ، سيتم إضافة كل ملف في دليل store إلى المخزن في مساحة الاسم أو الوحدة النمطية الخاصة به. على سبيل المثال ، لنقم بإنشاء مكان ما لتخزين المنتج الحالي. إذا أنشأنا ملفًا يسمى product.js في دليل المتجر ، فسيكون هناك قسم بمساحة اسم من المتجر متاحًا على $store.product . فيما يلي مثال بسيط لما قد يبدو عليه هذا الملف:

 export const state = () => ({ _id: 0, title: 'Unknown', price: 0 }) export const actions = { load ({ commit }) { setTimeout( commit, 1000, 'update', { _id: 1, title: 'Product', price: 99.99 } ) } } export const mutations = { update (state, product) { Object.assign(state, product) } }

يحاكي setTimeout في إجراء التحميل نوعًا من استدعاء واجهة برمجة التطبيقات ، والتي ستعمل على تحديث المتجر بالاستجابة ؛ في هذه الحالة ، يستغرق الأمر ثانية واحدة. الآن ، دعنا نستخدمه في صفحة products/view :

 <template> <div> <h1>View Product {{ product._id }}</h1> <p>{{ product.title }}</p> <p>Price: {{ product.price }}</p> </div> </template> <script> import { mapState } from 'vuex' export default { created () { this.$store.dispatch('product/load') }, computed: { ...mapState(['product']) } } </script>

بعض الأشياء التي يجب ملاحظتها: هنا ، نقوم باستدعاء API المزيف الخاص بنا عند إنشاء المكون. يمكنك أن ترى أن إجراء product/load الذي نرسله يقع ضمن نطاق اسم المنتج. هذا يوضح بالضبط أي قسم من المتجر نتعامل معه. بعد ذلك ، من خلال تعيين الولاية إلى خاصية محسوبة محلية ، يمكننا بسهولة استخدامها في نموذجنا.

هناك مشكلة: نرى الحالة الأصلية لمدة ثانية أثناء تشغيل API. لاحقًا ، سوف نستخدم الحل المقدم من Nuxt لإصلاح ذلك (المعروف باسم fetch ).

فقط للتأكيد على هذا مرة أخرى ، لم نضطر أبدًا إلى npm install vuex ، حيث تم تضمينه بالفعل في حزمة Nuxt. عند إضافة ملف index.js إلى دليل المتجر ، يتم فتح كل هذه الطرق لك تلقائيًا .

وأوضح أن الدلائل الرئيسية اثنين ؛ الباقي أبسط بكثير.

عناصر

يوجد دليل المكونات ليحتوي على المكونات التي يمكن إعادة استخدامها مثل شريط التنقل ، ومعرض الصور ، وترقيم الصفحات ، وجداول البيانات ، وما إلى ذلك. نظرًا لأن المكونات في دليل الصفحات يتم تحويلها إلى مسارات ، فأنت بحاجة إلى مكان آخر لتخزين هذه الأنواع من المكونات. يمكن الوصول إلى هذه المكونات في صفحات أو مكونات أخرى عن طريق استيرادها:

 import ComponentName from ~/components/ComponentName.vue

أصول

يحتوي هذا على أصول غير مجمعة وله علاقة أكثر بكيفية تحميل Webpack الملفات ومعالجتها ، بدلاً من كيفية عمل Nuxt. إذا كنت مهتمًا ، أقترح قراءة الدليل في الملف التمهيدي.

ثابتة

يحتوي هذا على ملفات ثابتة تم تعيينها إلى الدليل الجذر لموقعك. على سبيل المثال ، يؤدي وضع صورة تسمى logo.png في هذا الدليل إلى جعلها متاحة على /logo.png . هذا مفيد لملفات التعريف مثل robots.txt و favicon.ico والملفات الأخرى التي تحتاجها متوفرة.

التخطيطات

عادة ، في مشروع Vue ، لديك نوع من مكونات الجذر ، تسمى عادةً App.vue . هنا يمكنك إعداد تخطيط التطبيق (الثابت عادةً) ، والذي قد يتضمن شريط التنقل ، والتذييل ، ثم منطقة المحتوى لجهاز التوجيه الافتراضي الخاص بك. يقوم التخطيط default بذلك بالضبط ويتم توفيره لك في مجلد التخطيطات. في البداية ، كل ما يحتويه هو div مع مكون <nuxt /> (وهو ما يعادل <router-view /> ) ولكن يمكن تصميمه بالشكل الذي تريده. على سبيل المثال ، لقد أضفت شريط تنقل بسيطًا إلى مثال المشروع للتنقل حول صفحات العرض التوضيحي المختلفة.

يمكن تطبيق التخطيط على صفحات متعددة.

قد ترغب في الحصول على تنسيق مختلف لقسم معين من تطبيقك. ربما لديك نوع من CMS أو لوحة تحكم تبدو مختلفة. لحل هذه المشكلة ، قم بإنشاء تخطيط جديد في دليل التخطيطات. كمثال ، دعنا ننشئ تخطيط admin-layout.vue الذي يحتوي فقط على علامة رأس إضافية ولا يوجد شريط تنقل:

 <template> <div> <h1>Admin Layout</h1> <nuxt /> </div> </template>

بعد ذلك ، يمكننا إنشاء صفحة admin.vue في دليل الصفحات واستخدام خاصية مقدمة من Nuxt تسمى layout لتحديد الاسم (كسلسلة) للتخطيط الذي نريد استخدامه لهذا المكون:

 <template> <h1>Admin Page</h1> </template> <script> export default { layout: 'admin-layout' } </script>

هذا كل ما في الامر. ستستخدم مكونات الصفحة التخطيط default ما لم يتم تحديده ، ولكن عند الانتقال إلى /admin ، فإنه يستخدم الآن تخطيط admin-layout.vue . بالطبع ، يمكن مشاركة هذا التصميم عبر العديد من شاشات الإدارة إذا كنت ترغب في ذلك. الشيء الوحيد المهم الذي يجب تذكره هو أن التخطيطات يجب أن تحتوي على عنصر <nuxt /> .

هناك شيء أخير يجب ملاحظته حول التخطيطات. ربما لاحظت أثناء التجربة أنه إذا قمت بكتابة عنوان URL غير صالح ، فستظهر لك صفحة خطأ. صفحة الخطأ هذه ، في الواقع ، تخطيط آخر. يحتوي Nuxt على تخطيط الخطأ الخاص به (رمز المصدر هنا) ، ولكن إذا أردت تحريره ، فما عليك سوى إنشاء تخطيط error.vue وسيتم استخدامه بدلاً من ذلك. التحذير هنا هو أن تخطيط الخطأ يجب ألا يحتوي على عنصر <nuxt /> . سيكون لديك أيضًا وصول إلى كائن error في المكون مع بعض المعلومات الأساسية لعرضها. (تتم طباعة هذا في الجهاز الذي يعمل بنظام Nuxt إذا كنت تريد فحصه.)

الوسيطة

البرامج الوسيطة هي وظائف يمكن تنفيذها قبل عرض الصفحة أو التخطيط. هناك العديد من الأسباب التي قد تدفعك للقيام بذلك. يعد حماية المسار استخدامًا شائعًا حيث يمكنك التحقق من متجر Vuex للحصول على تسجيل دخول صالح أو التحقق من صحة بعض المعلمات (بدلاً من استخدام طريقة validate من صحة المكون نفسه). أحد المشاريع التي عملت عليها في البرامج الوسيطة المستخدمة مؤخرًا لإنشاء مسارات تنقل ديناميكية بناءً على المسار والمعلمات.

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

الإضافات

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

تحتوي معظم المكونات الإضافية الرئيسية على إصدار Nuxt يمكن تسجيله بسهولة في مثيل Vue باتباع مستنداتهم. ومع ذلك ، ستكون هناك ظروف عندما تقوم بتطوير مكون إضافي أو تحتاج إلى تكييف مكون إضافي موجود لهذا الغرض. مثال أقوم باستعارته من المستندات يوضح كيفية القيام بذلك vue-notifications . أولاً ، نحتاج إلى تثبيت الحزمة:

 npm install vue-notifications --save

ثم قم بإنشاء ملف في دليل الملحقات يسمى vue-notifications.js وقم بتضمين ما يلي:

 import Vue from 'vue' import VueNotifications from 'vue-notifications' Vue.use(VueNotifications)

مشابه جدًا لكيفية تسجيل مكون إضافي في بيئة Vue العادية. ثم قم بتحرير ملف nuxt.config.js في جذر مشروعك وأضف الإدخال التالي إلى كائن module.exports:

 plugins: ['~/plugins/vue-notifications']

هذا هو. يمكنك الآن استخدام vue-notifications جميع أنحاء تطبيقك. مثال على ذلك في /plugin في مثال المشروع.

بحيث يكمل ذلك المتهدمة لهيكل الدليل. قد يبدو أن تعلم الكثير ، ولكن إذا كنت تقوم بتطوير تطبيق Vue ، فأنت تقوم بالفعل بإعداد نفس النوع من المنطق. تساعد Nuxt في تجريد الإعداد وتساعدك على التركيز على البناء.

تعمل Nuxt أكثر من مجرد المساعدة في التطوير. إنه يشحن مكوناتك من خلال توفير وظائف إضافية.

مكونات Nuxt سوبر تشارج

عندما بدأت البحث عن Nuxt لأول مرة ، ظللت أقرأ عن كيفية زيادة شحن مكونات الصفحة. بدا الأمر رائعًا ، لكن لم يتضح على الفور ما الذي يعنيه ذلك بالضبط وما الفوائد التي يجلبها.

ما يعنيه ذلك هو أن جميع مكونات الصفحة لها طرق إضافية مرفقة بها يمكن لـ Nuxt استخدامها لتوفير وظائف إضافية. في الواقع ، لقد رأينا بالفعل واحدة من هذه في وقت سابق عندما استخدمنا طريقة validate للتحقق من المعلمات وإعادة توجيه المستخدم إذا كانت غير صالحة.

الطريقتان الرئيسيتان المستخدمتان في مشروع Nuxt هما asyncData و fetch . كلاهما متشابهان جدًا في المفهوم ، يتم تشغيلهما بشكل غير متزامن قبل إنشاء المكون ، ويمكن استخدامهما لملء بيانات المكون والمخزن. كما أنها تمكن من عرض الصفحة بالكامل على الخادم قبل إرسالها إلى العميل حتى عندما يتعين علينا انتظار بعض قواعد البيانات أو استدعاء واجهة برمجة التطبيقات.

ما الفرق بين البيانات غير fetch asyncData ؟

  • يتم استخدام البيانات غير asyncData لتعبئة بيانات مكون الصفحة. عند إرجاع كائن ، يتم دمجه بعد ذلك مع إخراج data قبل تقديمه.
  • يستخدم fetch لملء Vuex Store. إذا أعدت وعدًا ، فستنتظر Nuxt حتى يتم حله قبل تقديمه.

لذلك دعونا نستخدمها بشكل جيد. تذكر سابقًا في صفحة /products/view لدينا مشكلة حيث تم عرض الحالة الأولية للمتجر لفترة وجيزة أثناء إجراء استدعاء API الوهمي؟ تتمثل إحدى طرق إصلاح ذلك في وجود قيمة منطقية مخزنة في المكون أو في المتجر مثل loading = true ثم عرض مكون التحميل أثناء انتهاء استدعاء واجهة برمجة التطبيقات. بعد ذلك ، سنقوم بتعيين loading = false وعرض البيانات.

بدلاً من ذلك ، دعنا نستخدم fetch لملء المتجر قبل العرض. في صفحة جديدة تسمى /products/view-async ، دعنا نغير الطريقة created fetch ؛ يجب أن يعمل ، أليس كذلك؟

 export default { fetch () { // Unfortunately the below line throws an error // because 'this.$store' is undefined... this.$store.dispatch('product/load') }, computed: {...} }

وهنا تكمن المشكلة: تعمل هذه الطرق "فائقة الشحن" قبل إنشاء المكون ، this لا يشير هذا إلى المكون ولا يمكن الوصول إلى أي شيء عليه. فكيف نصل إلى المتجر هنا؟

واجهة برمجة تطبيقات السياق

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

أوصي بشدة بمراجعة مستندات السياق لمعرفة ما هو متاح. بعض التطبيقات المفيدة هي app ، حيث يمكنك الوصول إلى جميع المكونات الإضافية الخاصة بك ، redirect ، والتي يمكن استخدامها لتغيير المسارات ، error لعرض صفحة الخطأ ، وبعض تلك التي لا تحتاج إلى شرح مثل route query store .

لذلك ، للوصول إلى المتجر ، يمكننا تدمير السياق واستخراج المتجر منه. نحتاج أيضًا إلى التأكد من أننا نعيد وعدًا حتى تتمكن Nuxt من انتظار حله قبل تقديم المكون ، لذلك نحتاج إلى إجراء تعديل صغير على إجراء المتجر أيضًا.

 // Component export default { fetch ({ store }) { return store.dispatch('product/load') }, computed: {...} } // Store Action load ({ commit }) { return new Promise(resolve => { setTimeout(() => { commit('update', { _id: 1, title: 'Product', price: 99.99 }) resolve() }, 1000) }) }

يمكنك استخدام غير متزامن / انتظار أو طرق أخرى اعتمادًا على أسلوب الترميز الخاص بك ، ولكن المفهوم هو نفسه - نحن نطلب من Nuxt التأكد من انتهاء استدعاء واجهة برمجة التطبيقات وتحديث المتجر بالنتيجة قبل تجربة عرض المكون. إذا حاولت الانتقال إلى /products/view-async ، فلن ترى وميض المحتوى حيث يكون المنتج في حالته الأولية.

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

اعتبارات عند استخدام SSR

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

عند الوصول إلى صفحة في البداية ، يتم إرسال طلب إلى Nuxt ، ويبني الخادم أكبر قدر ممكن من تلك الصفحة وبقية التطبيق ، ثم يرسله الخادم إليك. ثم تقع المسؤولية على العميل لمواصلة التنقل وتحميل الأجزاء التي يحتاجها.

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

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

بعد قراءة مستندات Nuxt ، ترى أن هناك طريقة سهلة الاستخدام تسمى NuxtServerInit تتيح لك ملء المتجر بشكل غير متزامن بمجرد التحميل الأولي. هذا يبدو مثاليا! لذلك تقوم بإنشاء وحدة المستخدم الخاصة بك في المتجر وإضافة الإجراء المناسب في ملف index.js في دليل المتجر:

 export const actions = { nuxtServerInit ({ dispatch }) { // localStorage should work, right? const token = localStorage.getItem('token') if (token) return dispatch('user/load', token) } }

عند تحديث الصفحة ، تحصل على خطأ ، localStorage is not defined . التفكير في مكان حدوث ذلك ، فمن المنطقي. يتم تشغيل هذه الطريقة على الخادم ، وليس لديها فكرة عما يتم تخزينه في localStorage على العميل ؛ في الواقع ، لا يعرف حتى ما هو "localStorage"! لذلك هذا ليس خيارًا.

يحاول الخادم تنفيذ localStorage.getItem ("الرمز المميز") ولكنه يُلقي بخطأ ، ثم شرح أدناه يوضح المشكلة.

إذن ما هو الحل؟ هناك القليل ، في الواقع. يمكنك جعل العميل يقوم بتهيئة المتجر بدلاً من ذلك ولكن ينتهي به الأمر بفقدان مزايا SSR لأن العميل ينتهي به الأمر إلى القيام بكل العمل. يمكنك إعداد الجلسات على الخادم ثم استخدامها لمصادقة المستخدم ، ولكن هذه طبقة أخرى يجب إعدادها. أكثر ما يشبه طريقة localStorage هو استخدام ملفات تعريف الارتباط بدلاً من ذلك.

Nuxt لديه حق الوصول إلى ملفات تعريف الارتباط لأنه يتم إرسالها مع الطلب من العميل إلى الخادم. كما هو الحال مع طرق Nuxt الأخرى ، nuxtServerInit الوصول إلى السياق ، وهذه المرة كوسيطة ثانية لأن الأولى محجوزة للمخزن. في السياق ، يمكننا الوصول إلى كائن req ، الذي يخزن جميع الرؤوس والمعلومات الأخرى من طلب العميل. (سيكون هذا مألوفًا بشكل خاص إذا كنت قد استخدمت Node.js.)

لذلك بعد تخزين الرمز المميز في ملف تعريف ارتباط بدلاً من ذلك (يسمى "الرمز المميز" في هذه الحالة) ، فلنصل إليه على الخادم.

 import Cookie from 'cookie' export const actions = { nuxtServerInit ({ dispatch }, { req }) { const cookies = Cookie.parse(req.headers.cookie || '') const token = cookies['token'] || '' if (token) return dispatch('user/load', token) } }

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

تعيين

النشر باستخدام Nuxt بسيط للغاية. باستخدام نفس التعليمات البرمجية ، يمكنك إنشاء تطبيق SSR أو تطبيق من صفحة واحدة أو صفحة ثابتة.

تطبيق يتم عرضه من جانب الخادم (تطبيق SSR)

ربما كان هذا هو ما كنت تهدف إليه عند استخدام Nuxt. المفهوم الأساسي للنشر هنا هو تشغيل عملية build على أي نظام أساسي تختاره وتعيين بعض التكوينات. سأستخدم مثال Heroku من المستندات:

أولاً ، قم بإعداد البرامج النصية لـ Heroku في package.json :

 "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "heroku-postbuild": "npm run build" }

ثم قم بإعداد بيئة Heroku باستخدام heroku-cli (تعليمات الإعداد هنا:

 # set Heroku variables heroku config:set NPM_CONFIG_PRODUCTION=false heroku config:set HOST=0.0.0.0 heroku config:set NODE_ENV=production # deploy git push heroku master

هذا هو. الآن أصبح تطبيق SSR Vue جاهزًا ليراه العالم. الأنظمة الأساسية الأخرى لها إعدادات مختلفة ، لكن العملية متشابهة. طرق النشر الرسمية المدرجة حاليًا هي:

  • حاليا
  • دوكو (المحيط الرقمي)
  • Nginx

تطبيق من صفحة واحدة (واس)

إذا كنت ترغب في الاستفادة من بعض الميزات الإضافية التي يوفرها Nuxt ولكنك تتجنب محاولة الخادم عرض الصفحات ، فيمكنك النشر كمنتجع SPA بدلاً من ذلك.

أولاً ، من الأفضل اختبار تطبيقك بدون SSR حيث npm run dev بشكل افتراضي مع تشغيل SSR. لتغيير ذلك ، قم بتحرير ملف nuxt.config.js وأضف الخيار التالي:

 mode: 'spa',

الآن ، عند تشغيل npm run dev ، سيتم إيقاف تشغيل SSR وسيعمل التطبيق كـ SPA لتختبره. يتأكد هذا الإعداد أيضًا من عدم احتواء أي تصميمات مستقبلية على SSR.

إذا كان كل شيء يبدو جيدًا ، فسيكون النشر هو نفسه تمامًا لتطبيق SSR. فقط تذكر أنك بحاجة إلى ضبط mode: 'spa' أولاً لإعلام عملية البناء أنك تريد SPA.

صفحات ثابتة

إذا كنت لا ترغب في التعامل مع خادم على الإطلاق وتريد بدلاً من ذلك إنشاء صفحات لاستخدامها مع خدمات الاستضافة الثابتة مثل Surge أو Netlify ، فهذا هو الخيار الذي تختاره. فقط ضع في اعتبارك أنه بدون خادم ، لن تتمكن من الوصول إلى req و res في السياق ، لذلك إذا كانت التعليمات البرمجية الخاصة بك تعتمد على ذلك ، فتأكد من ملاءمتها. على سبيل المثال ، عند إنشاء مشروع المثال ، تُلقي الدالة nuxtServerInit خطأً لأنها تحاول جلب رمز مميز من ملفات تعريف الارتباط في رؤوس الطلب. في هذا المشروع ، لا يهم ، لأن هذه البيانات لا تُستخدم في أي مكان ، ولكن في تطبيق حقيقي ، يجب أن تكون هناك طريقة بديلة للوصول إلى تلك البيانات.

بمجرد فرز ذلك ، يصبح النشر أمرًا سهلاً. هناك شيء واحد ربما تحتاج إلى تغييره أولاً وهو إضافة خيار بحيث يقوم أمر nuxt generate أيضًا بإنشاء ملف احتياطي. سيطالب هذا الملف خدمة الاستضافة بالسماح لـ Nuxt بمعالجة التوجيه بدلاً من خدمة الاستضافة ، مما يؤدي إلى ظهور خطأ 404. للقيام بذلك ، أضف السطر التالي إلى nuxt.config.js :

 generate: { fallback: true },

فيما يلي مثال باستخدام Netlify ، وهو غير موجود حاليًا في مستندات Nuxt. فقط ضع في اعتبارك أنه إذا كانت هذه هي المرة الأولى التي تستخدم فيها netlify-cli منك المصادقة:

 # install netlify-cli globally npm install netlify-cli -g # generate the application (outputs to dist/ folder) npm run generate # deploy netlify deploy dist

إنها بهذه السهولة! كما ذكرنا في بداية المقال ، هناك نسخة من هذا المشروع هنا. توجد أيضًا وثائق نشر رسمية للخدمات التالية أدناه:

  • طفرة
  • صفحات جيثب

يتعلم أكثر

يتم تحديث Nuxt بسرعة ، وهذه ليست سوى مجموعة صغيرة من الميزات التي يقدمها. آمل أن تشجعك هذه المقالة على تجربتها ومعرفة ما إذا كان يمكن أن تساعد في تحسين إمكانات تطبيقات Vue ، مما يسمح لك بالتطوير بشكل أسرع والاستفادة من ميزاته القوية.

If you're looking for more information, then look no further than Nuxt's official links:

  • توثيق
  • Playground
  • جيثب
  • التعليمات

Looking to up your JavaScript game? Try reading The Comprehensive Guide to JavaScript Design Patterns by fellow Toptaler Marko Mišura.