هذه المقالة للعديد من المطورين ومبدعي السمات الذين يجدون المساعدين القياسيين المقدمة من Ghost (https://ghost.org/docs/themes/helpers/) غير كاف. من الطبيعي تمامًا البحث عن طرق لتوسيع قدرات موضوعاتنا التي تستخدم المقاود التي توفرها Ghost. قبل نشر هذه المقالة وإيجاد حل لموضوعتي ، بحثت عن الإنترنت بأكمله وأجرت تحليلًا لرمز مصدر Ghost بنفسي.
اكتشفت أنه من الممكن تمديد رمز مصدر Ghost مع مساعدين إضافيين. لقد حققت هذا عن طريق إضافة دليل جديد في الحالي/الأساسي/الواجهة/التطبيقات. لقد استخدمت مثال "تطبيق" موجود يسمى AMP ، الذي يكون رمزه بسيطًا للغاية ، لبدء إنشاء مساعد جديد متاح في السمة. في هذه التطبيقات الحالية ، يكون الهيكل واضحًا لأن المساعدين مسجلون في LIB/مساعدين. في نهاية العملية ، تحتاج إلى إضافة اسم الدليل الخاص بك في التطبيقات إلى Current/Core/Config/Overrides.json في قسم Apps.internal JSON.
مثال على محتوى ملف index.js في تطبيقنا سيكون:
const path = require('path'); module.exports = { activate: function activate(ghost) { ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers')); } };
بعد ذلك ، في دليل LIB لهذا التطبيق ، نقوم بإنشاء مجلد مساعدين يدعى. في الداخل ، نقوم بإنشاء ملف جديد ، والذي سيكون اسم المساعد ليتم استدعاؤه في قالب المقود. على سبيل المثال ، دعنا نسميها agresscase.js.
أدناه مثال على رمز هذا المساعد ، والذي يحول ببساطة حروف النص المعطى في وسيطة المساعد إلى الكبير:
const {SafeString, escapeExpression} = require('../../../../services/handlebars'); module.exports = function uppercase(text) { return `${text.toUpperCase()}`; };
لا تنس إضافة اسم دليل التطبيق إلى الحالي/Core/Shared/Config/Overrides.json. بعد إعادة تشغيل الشبح ، يجب أن يكون كل شيء جاهزًا.
لقد طورت هذه الطريقة مؤخرًا ، ويمكنك تطبيقها ليس فقط على الأشباح المستضافة ذاتيًا ولكن أيضًا على مثيلات الأشباح التي يقدمها مقدمي الاستضافة. في الحالة الأخيرة ، يتطلب الأمر التخطيط المعماري المناسب وشراء خادم صغير سيكون بمثابة وكيل لمثيل الشبح النهائي الخاص بك.
البنية التي سنستخدمها في هذه الطريقة:
Nginx Server ← Node.js الوسيطة ← مثيل الأشباح
يرسل متصفح المستخدم طلبًا إلى خادم Nginx ، الذي يحتوي على المنبع من الوسيطة. جميع الطلبات ، بغض النظر عن الموقع ، سيتم إنشاؤها إلى الوسيطة.
الوسيطة عبارة عن خادم صريح يعمل في Node.js مع مكتبة Express-HTTP-Proxy (https://github.com/villadora/express-http-proxy) ، والتي تبسط العمل بشكل كبير. نقوم بتكوين الوكيل للتواصل مع مثيل الأشباح. تحتوي مكتبة Express-HTTP-Proxy على خاصية userresDecorator التي يمكننا استخدامها "لتزيين استجابة الخادم Proxied." ببساطة ، يمكننا تعديل الاستجابة من Ghost قبل إرسالها إلى متصفح المستخدم.
سيكون UserresDecorator الخاص بنا غير متزامن حتى لا يحظر الخيط الرئيسي. سنعود إلى موضوع المعالجة غير المتزامنة عند إنشاء مساعدين. في الوقت الحالي ، تحتاج إلى معرفة أنه ليس كل ما يجب تزيين طلبات متصفح المستخدم. لذلك ، ستكون الخطوة الأولى هي التحقق من رأس نوع المحتوى للاستجابة من Ghost. يمكنك القيام بذلك على النحو التالي ، ثم مقارنة ما إذا كان النص/HTML لتزيين مستندات HTML فقط التي يتم إرجاعها إلى المستخدم:
// Where 'proxyRes' is your proxy response inside 'userResDecorator' const contentType = proxyRes.headers['content-type'] || ''; if (!contentType.includes('text/html')) { // Return original content if response is not 'text/html' return proxyResData; } let htmlContent = proxyResData.toString('utf8'); // Do something with 'htmlContent' and return return htmlContent;
في هذا البيان الشرطي ، يمكننا البدء في تعديل htmlcontent ، ولكن لماذا نحتاجه؟ لنبدأ ببناء الأساس لمساعدنا المخصص في موضوع الأشباح!
في هذه المقالة ، سأقوم بإنشاء مساعد مخصص في ملف index.hbs (الصفحة الرئيسية) من موضوعي. في موقع مرئي في قالب المقاود ، أضيف مثالًا مساعدًا مخصصًا ، وأسميته {{hello_world}}.
⚠ بعد ذلك ، أضعها في بقعة مرئية على الصفحة الرئيسية - لكن لاحظ ما يحدث عندما أقوم بتحديث صفحة الأشباح!
{{!After refreshing, I get an error message from Ghost because the {{hello_world}} helper doesn’t exist in Ghost's default helpers. For our logic to work, we must escape this helper so that it’s not treated as a helper by Ghost’s built-in Handlebars.
The correct way is to write this helper as \{{hello_world}}. This way, Ghost treats it as plain text. After refreshing the Ghost homepage, you should see the plain text {{hello_world}}. If this happens, you are on the right track. Let’s now return to the middleware server file, where we will use the response decorator.
⚠️ Remember to escape custom helpers in your theme! Don’t forget to add the \ character.
let htmlContent = proxyResData.toString('utf8');في هذا المتغير ، لدينا استجابة من مثيل الأشباح باعتباره HTML الكامل للصفحة. تخيل أن هذا الرد هو الصفحة الرئيسية لمثيل شبحك. سيتضمن محتوى HTML أيضًا نصنا العادي {{hello_world}} ، والذي يتم عرضه كنص عادي. إذا كان المساعد المخصص لدينا في هذا النموذج ، فيمكننا تجميعه باستخدام المقابض. تذكر تثبيت المكتبة أولاً عبر مدير الحزمة ، على سبيل المثال ، NPM: NPM تثبيت المقابض وإضافته إلى الكود الخاص بك: Const Gwilkbars = require ("Handlebars") ؛.
// Compile response HTML with Handlebars, and return rendered template let htmlContent = proxyResData.toString('utf8'); const template = handlebars.compile(htmlContent); htmlContent = template({});رائع! لقد قمنا الآن بتجميع وأصدرنا HTML باستخدام Handbars.js - لكننا لم ننتهي بعد. ما زلنا بحاجة إلى تسجيل المساعد المخصص لدينا {{hello_world}}. أضف الكود التالي ، ويفضل أن يكون ذلك بعد تهيئة المقود. js:
// Returns 'Hello from middleware!' with the current timestamp handlebars.registerHelper('hello_world', function (options) { return `Hello from middleware! ${new Date().toISOString()}`; });بعد إعادة تشغيل خادم الوسيطة وتسجيل المساعد أعلاه ، يجب أن ترى المساعد المقدم في المتصفح مع النص الذي تم إرجاعه بواسطة المساعد لدينا والتاريخ والوقت الحاليين.
في هذه المرحلة ، يمكنك تمديد موضوع Ghost الخاص بك بمساعدين مخصصين إضافيين ، والتي ستضيفها إلى رمز خادم الوسيطة.
حماية
في مرحلة ما ، قد ترغب في إعادة أشياء مختلفة مع مساعديك. بشكل افتراضي ، تحمي المكتبة من هجمات XSS ، ولكن عند استخدام طريقة الصراف ، تتوقف هذه الحماية عن العمل. تجنب استخدامه كلما كان ذلك ممكنًا.
شيء آخر! تخيل أن المستخدم يضيف مثل هذا المساعد في قسم التعليقات تحت منشور ويضيف محتوى ضار في المعلمة. كن على دراية بالأمن. على سبيل المثال ، إذا قمت بتقديم كل HTML تمامًا ، فقد تكون عرضة لهجمات XSS. يوصى بتجميع وتقديم المقود في مناطق محددة مغلقة. يمكنك استخدام مكتبة Cheerio (https://cheerio.js.org/) لتحليل HTML وتقديم المقابض عند الضرورة. إليك مثال على كيفية تأمين نفسك من خلال تعديل رمز العرض السابق:
// Render handlebars only insidewith>In this code, our custom helpers and Handlebars are rendered only within a
container with>Asynchronous Processing
If you intend to create dynamic helpers that return more complex data, you’ll probably need to implement asynchronous helpers in Handlebars over time. This is useful in cases like:
- Fetching values from a database (e.g., Ghost database)
- Sending API requests and processing their responses
You can use an extension called handlebars-async-helpers (https://www.npmjs.com/package/handlebars-async-helpers) for this purpose. It enables asynchronous operations in Handlebars.js, making potentially lengthy and dynamic tasks possible. Here’s a simple example of how you can implement asynchronous processing in your middleware:
// Register async helpers with Handlebars const hb = asyncHelpers(handlebars); hb.registerHelper('hello_world', async function (options) { // You can use await's here! // ... });تذكر إضافة تهيئة المكتبة في بداية البرنامج النصي الخاص بك: const Asynchelpers = require ('Handbars-async-helpers') ؛. إذا واجهت مشكلات في تثبيته بسبب تعارضات الإصدار بين المقاود-المقاود والتعدين ، ما عليك سوى خفض المقاود إلى ^4.7.6. لسوء الحظ ، لم يتم الحفاظ على مكتبة Async Helper Library لفترة من الوقت ، لكنها لا تزال تعمل في الممارسة العملية.
اتصالات قاعدة البيانات والكائنات
إذا كنت ترغب في جعل استفسارات قاعدة البيانات في Ghost لجلب ، على سبيل المثال ، المنشور الحالي ، فهذا ممكن وليس صعبًا. يمكنك استخدام مكتبة مثل Knex (https://knexjs.org/) ، وهو منشئ استعلام واضح وسريع. تذكر أنك ستحتاج إلى مقابض-مقاوم المقانين لهذا الغرض. قم بتكوين Knex بشكل صحيح للاتصال بقاعدة بيانات Ghost.
تهيئة Knex كمتغير DB وجرب الكود التالي:
// Return current post title from database hb.registerHelper('post_title', async function (options) { const uuid = options.hash.uuid; try { const { title } = await db("posts") .select("title") .where("uuid", uuid) .limit(1) .first(); return title; } catch (error) { return `Error: ${error.message}`; } });ثم ، في قالب post.hbs لموضوع الشبح ، أضف المساعد التالي: \ {{post_title uuid = "{{uuid}}"}}. في هذا المثال ، سيتم استرداد {{uuid}} وتمريره كمساعد متاح في Ghost ، وملء حقل Uuid الخاص بمساعدنا ويتسبب في عرض عنوان المنشور بواسطة المساعد المخصص.
يمكنك أيضًا استخدام AxiOS لإنشاء طلبات HTTP إلى واجهة برمجة تطبيقات محتوى الأشباح ، ولكن هذا أبطأ بكثير من اتصال قاعدة البيانات المباشر.
أداء
أعلم أن الحل القائم على الوسيطة قد لا يكون الأفضل من حيث السرعة ، لكنني شخصياً أستخدم هذا الحل ولم ألاحظ انخفاضًا كبيرًا في أوقات تحميل الصفحة. كان متوسط وقت الاستجابة لطلب واحد أقل من 100 مللي ثانية (وفقًا لـ Express-Status-Monitor) ، وأنا أستخدم مساعد مخصص يسترجع بعض القيم من قاعدة البيانات في كل صفحة.
يمكنك ، بالطبع ، إضافة آليات التخزين المؤقت لتحسين أداء البرامج الوسيطة أو استخدام حلول بديلة بدلاً من Express-HTTP-proxy.
تنفيذ العمارة
استخدم Docker أو آلية حاوية أخرى. لقد استخدمته في مشروعي ، وهو يعمل بشكل رائع. أضف صور Ghost و Database لـ Ghost و Nginx وصورة Node.js. قم بتوصيلها بشبكة مشتركة (برنامج التشغيل: الجسر) ، وتكوين Nginx وخادم Node.js وفقًا لذلك - كل شيء بسيط للغاية!
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3