الواجهة الأمامية: استخدام Gatsby.js و Node.js لتحديثات الموقع الثابتة
نشرت: 2022-03-11بالنسبة لبعض متطلبات المشروع ، لا يكون إنشاء الصفحات الثابتة كافيًا فحسب ، بل هو أيضًا الأكثر كفاءة من حيث السرعة وقابلية التوسع.
في النصف الأول من هذه السلسلة ، قمنا بدمج Node.js و Express و MongoDB و cron و Heroku لتقديم واجهة خلفية جاهزة لـ CI تستهلك واجهة برمجة تطبيقات GitHub وفقًا لجدول زمني يومي. نحن الآن جاهزون لإضافة Gatsby إلى المزيج لإكمال مشروع إنشاء الصفحات الثابتة.
تطوير الواجهة الأمامية: اجعله أحد مواقع Gatsby
نظرًا لأن مواقع Gatsby تستند إلى React ، فمن المفيد أن تكون على دراية بكيفية إنشاء موقع ويب باستخدام React.
بالنسبة للتصميم ، فضلت Bootstrap ، و rebstrap ، و React-markdown. قد تعلم أن ملاحظات الإصدار في GitHub مخزنة في تنسيق Markdown ، ومن هنا جاءت حاجتنا إلى محول.
هيكل مشروع موقع الويب الثابت
ستكون بنية الملف / المجلد على النحو التالي:
ما هي هذه الملفات ل؟ دعنا نرى:
-
env.development
وenv.production
هي ملفات تكوين متغيرات البيئة. - سيتم استخدام نموذج
all-repositories.js
لصفحتنا الرئيسية التي تحتوي على قائمة بالمستودعات. - سيتم استخدام نموذج
repository.js
لإظهار التفاصيل لمستودع تخزين معين. -
gatsby-node.js
هو المكان الذي نستهلك فيه نقطة النهايةcreatePage
طرق createPage. - يحتوي
package.json
، كما هو الحال دائمًا ، على التبعيات وخصائص المشروع. -
global.css
هو ملف ورقة الأنماط الرئيسي لدينا.
تنفيذ موقع جاتسبي
كما هو الحال مع نهايتنا الخلفية ، قم بتشغيل npm install
(أو yarn
، إذا كان لديك Yarn مثبتًا) بعد إضافة التبعيات المطلوبة إلى حزمة الواجهة package.json
.
{ // ... "dependencies": { "axios": "^0.18.0", "bootstrap": "^4.3.1", "gatsby": "^2.0.0", "react": "^16.5.1", "react-dom": "^16.5.1", "react-markdown": "^4.0.6", "reactstrap": "^7.1.0" } // ... }
تحتوي ملفات env.development
و env.production
على عنوان URL الخلفي للبيئات المقابلة فقط. السابق لديه:
API_URL=http://localhost:3000
... بينما يحتوي الإنتاج على:
API_URL=https://[YOUR_UNIQUE_APP_NAME].herokuapp.com
سيتم تشغيل gatsby-node.js
مرة واحدة فقط أثناء قيامك بإنشاء الكود الخاص بك. لذلك علينا أن نجمع كل المعلومات الضرورية من نهايتنا الخلفية هنا. بعد ذلك ، سيتم استخدام الاستجابة مع القوالب الخاصة بنا لإنشاء الصفحات الثابتة المناسبة.
في حالتنا ، تحتاج all all-repositories.js
إلى جميع المستودعات ، وتحتاج repository.js
إلى المستودع المقابل لكل تكرار. أخيرًا ، يمكننا إنشاء مسارات الصفحات ديناميكيًا ، وتمرير owner
المستودع ومعلمات name
كجزء من حقل path
:
const axios = require('axios'); require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }); const getRepositoryData = async () => { console.log(process.env.API_URL); return axios.get(`${process.env.API_URL}/repositories`); }; exports.createPages = async ({ actions: { createPage } }) => { let repositories = await getRepositoryData(); repositories = repositories.data; // Create a page that lists all repositories. createPage({ path: `/`, component: require.resolve('./src/templates/all-repositories.js'), context: { repositories } }); // Create a page for each repository. repositories.forEach(repository => { createPage({ path: `/repository/${repository.owner}/${repository.name}`, component: require.resolve('./src/templates/repository.js'), context: { repository } }); }); };
بالنسبة all-repositories.js
و repository.js
، إذا أغفلنا التصميم ، فإننا ببساطة نجمع البيانات من pageContext
عندما نستخدم المعلمات في React.
في all-repositories.js
، سنستخدم حقل repositories
الخاص بـ pageContext
مثل هذا:
export default ({pageContext: {repositories}}) => ( // ... <ListGroup> {/* Because the repositories parameter is a list, we are iterating over all items and using their fields */} {repositories.map(repository => (repository.tagName && <ListGroupItem className="repository-list-item"> // ... <Row> {`${repository.repositoryDescription}`} </Row> // ... </ListGroupItem> ))} </ListGroup> // ... );
بالنسبة إلى repository.js
، فسنستخدم بدلاً من ذلك حقل repository
الخاص بـ pageContext
:
export default ({pageContext: {repository}}) => ( <div className="layout"> {repository.tagName && <ListGroupItem className="repository-list-item"> // ... <h1 className="release-notes">{`Release notes`}</h1> <hr/> {/* This the place where we will use Markdown-formatted release notes */} <ReactMarkdown source={`${repository.releaseDescription}`}/> </ListGroupItem> } // ... </div> );
الآن ، تأكد من تشغيل الطرف الخلفي الخاص بك. ستتذكر لهذا المشروع قمنا بتعيينه كـ http: // localhost: 3000.
بعد ذلك ، قم بتشغيل gatsby develop
من جذر مشروع الواجهة الأمامية وافتح http: // localhost: 8000.
إذا أضفت بعض المستودعات (المالك / الاسم) إلى نهايتك الخلفية وقمت بتشغيل ميزة التحديث عبر GitHub-API مرة واحدة على الأقل ، يجب أن ترى شيئًا مثل هذا:
وبعد النقر فوق أحد المستودعات ، يجب أن ترى شيئًا مثل هذا:
بعد التغييرات التي أجريناها أعلاه ، يتم تنفيذ الواجهة الأمامية.
رائعة! الآن علينا فقط أن ننشر.
نشر الواجهة الأمامية
لا نحتاج إلى إجراء أي تغييرات في تطبيق الواجهة الأمامية في هذا الجزء. سنقوم ببساطة بنشره على Netlify - ستحتاج إلى حساب هناك.
لكن أولاً ، يتعين علينا نشر الكود الخاص بنا على GitHub أو GitLab أو Bitbucket. كما هو الحال مع النهاية الخلفية ، قمت بنشر الكود الخاص بي على GitHub.
بعد ذلك ، قم بتسجيل الدخول إلى Netlify وانقر فوق الزر "موقع جديد من Git" في لوحة القيادة. اتبع الخطوات التي تظهر على الشاشة لتحديد موفر Git الخاص بك والعثور على المستودع الخاص بك.
بالنسبة للخطوة الأخيرة ، إذا قمت ببناء الكود الخاص بك بشكل صحيح ، فسيقوم Netlify تلقائيًا بتعيين أمر الإنشاء ونشر الدليل بشكل صحيح على النحو التالي:

ثم انقر على "نشر الموقع". سيتم نشر موقعك على نطاق فرعي Netlify تم إنشاؤه عشوائيًا ، ولكن يمكنك تغييره في أي وقت - لقد غيرت النشر الخاص بي إلى https://sample-create-page-api-gatsby.netlify.com ، حيث يمكنك العثور على عرض توضيحي مباشر من التطبيق المكتمل.
حتى الان جيدة جدا. ولكن نظرًا لأنه تطبيق صفحة ثابتة ، يتعين علينا إعادة بنائه يوميًا لتحديثه باستمرار.
التحديث اليومي باستخدام خطاف البناء
بناء الخطافات في Netlify تعمل كمحفزات بناء ، بحيث يمكنك تشغيلها من نهايتك الخلفية بعد انتهاء مهمة cron. للقيام بذلك ، قم أولاً بإنشاء خطاف بناء في Netlify.
ضمن قسم "الإنشاء والنشر ← النشر المستمر" ، يمكنك العثور على "إنشاء خطافات". انقر فوق "إضافة خطاف البناء".
أعطه اسما واحفظه. (لقد اتصلت بـ build-from-backend
.) ثم انسخ الرابط الذي ينشئه.
لنفتح الآن مشروعنا الخلفي ونضيف هذه الأسطر القليلة إلى ملف cron.controller.js
. نحن ببساطة نرسل طلب POST
إلى عنوان URL الخاص ببناء Netlify.
const Axios = require('axios'); const Config = require('../config/env.config'); const NETLIFY_BUILD_HOOK_URI = Config.netlifyEndpoint; function updateGatsby() { if (NETLIFY_BUILD_HOOK_URI) { console.log('Gatsby build request will be send'); Axios.post(NETLIFY_BUILD_HOOK_URI).then(() => { console.log('Gatsby build request was successful'); }); } }
ثم قم بتحديث وظيفة updateDaily
بنا:
function updateDaily() { RepositoryController.updateRepositories().then(() => { updateGatsby(); }); }
أخيرًا ، قم بتحديث ملف env.config.js
بنا لتعيين خاصية netlifyEndpoint
ليتم تجميعها من متغيرات البيئة:
"netlifyEndpoint": process.env.NETLIFY_BUILD_HOOK || ""
الآن ، ستحتاج إلى تعيين متغير البيئة NETLIFY_BUILD_HOOK
الذي نسخته من Netlify منذ لحظة. في Heroku ، يمكنك تعيين متغيرات البيئة من قسم "الإعدادات" في تطبيقك.
بعد دفع الالتزام ، سيرسل التطبيق الخلفي طلب إنشاء إلى Netlify وسيتم تحديث صفحاتك يوميًا ، في نهاية مهمة cron الخاصة بك. إليك ما يجب أن يبدو عليه الريبو بعد إضافة وظيفة ربط البناء ، جنبًا إلى جنب مع الإصدارات النهائية من الريبو الخلفي و الريبو الأمامي.
بصفتها اللمسة الأخيرة على المشروع ، سنعرض كيفية استخدام وظيفة AWS Lambda التي يتم تشغيلها بواسطة AWS CloudWatch والتي ستنشط نهايتك الخلفية في الوقت المناسب لكل تحديث يومي.
طلب AWS Lambda و AWS CloudWatch البسيط
AWS Lambda عبارة عن نظام أساسي للحوسبة بدون خادم. نحتاج فقط إلى أساسيات هذه المنصة لأغراضنا هنا. ستحتاج إلى حساب AWS.
أولاً ، قم بتسجيل الدخول إلى AWS باستخدام حسابك وابحث عن Lambda Management Console. على سبيل المثال ، بالنسبة لـ us-east-2
، يمكن العثور عليها على https://us-east-2.console.aws.amazon.com/lambda/home.
إذا لم تكن محددة بالفعل ، فانتقل إلى قسم "الوظائف":
هنا ، سننشئ وظيفتنا من البداية بالنقر على "إنشاء وظيفة". دعونا نعطيه اسمًا توضيحيًا. سوف نستخدم Node.js كلغة وقت تشغيل. ثم انقر فوق "إنشاء وظيفة" التالية لإنهائها.
سيعيد توجيهنا إلى صفحة الوظيفة الجديدة حيث يمكننا كتابة الكود الخاص بنا في index.js
.
دعنا ننفذ أول دالة لامدا. نظرًا لعدم وجود أي تبعيات لجهات خارجية ، يتعين علينا استخدام الوحدات الأساسية لـ Node.js. (إذا كنت ترغب في تمكين تبعيات الجهات الخارجية بدلاً من ذلك ، فيرجى اتباع هذا الدليل من AWS.)
تأكد من أن اسم الطريقة التي تم تصديرها ( handler
في هذه الحالة) يطابق معلمة "المعالج" في الصفحة:
الباقي هو طلب GET
بسيط إلى نهايتك الخلفية:
const https = require('https'); exports.handler = async (event) => { return new Promise((resolve, reject) => { https.get(process.env.HEROKU_APP_URL, (resp) => { let data = ''; resp.on('data', (chunk) => { data += chunk; }); resp.on('end', () => { resolve(JSON.parse(data)); }); }).on("error", (err) => { reject("Error: " + err.message); }); }); };
تأكد من تعيين متغير البيئة HEROKU_APP_URL
في الصفحة ، واحفظ التكوين الخاص بك:
تتمثل الخطوة الأخيرة في إضافة قاعدة تشغيل CloudWatch لتشغيل هذه الوظيفة قبل عشر دقائق من كل تحديث يومي — في سلسلة المقالات هذه ، تعمل حتى 23:50:
سيكون نوع قاعدة مشغل CloudWatch الخاص بنا هو "تعبير جدول" ، ووفقًا للتنسيق المقبول ، سيكون تعبير cron الخاص بنا هو cron(50 23 * * ? *)
.
لقد قمنا الآن بتكوين وظيفة AWS Lambda الخاصة بنا ليتم تشغيلها بواسطة قاعدة CloudWatch الخاصة بنا.
الآن تشغيل صفحات الويب الثابتة لدينا: Gatsby / React و Netlify
مع إضافة اندفاعة من AWS Lambda / CloudWatch إلى نهايتنا الخلفية Node.js / MongoDB / Heroku ، وإنشاء Gatsby و Netlify للواجهة الأمامية واستضافتها ، اكتمل تطبيقنا!
لقد قمت بمشاركة رابط عرض توضيحي مباشر سابقًا ، ولكن لا تتردد أيضًا في الاطلاع على نسخة محسّنة من النموذج الأولي - يحتوي على بعض التغييرات الإضافية التي أعلم أنك ستحبها.
يمكنك استخدام هذا كمخطط لمشاريع مماثلة - آمل أن تساعدك هذه المقالات في وضع نماذج أولية لتطبيقاتك بطريقة أسرع وأكثر فعالية من حيث التكلفة. شكرا للقراءة!