استخدام GraphQL المتقدم في مواقع Gatsby الإلكترونية

نشرت: 2022-03-10
ملخص سريع ↬ في هذه المقالة ، يشرح Aleem Isiaka ماهية بنيات استعلام GraphQL ، وكيف يمكن استخدامها للتفاعل مع طبقة الوصول إلى البيانات في موقع Gatsby على الويب. دعنا نلقي نظرة على بعض حالات الاستخدام المتقدمة لـ GraphQL داخل موقع Gatsby على الويب باستخدام بيانات مطابقة من مصادر مختلفة.

قبل إصدار GraphQL في عام 2015 ، كان النقل التمثيلي للحالة (REST) ​​هو الطريقة الرئيسية للتفاعل مع واجهة برمجة التطبيقات. لذلك كان إدخال GraphQL بمثابة تغيير كبير في تطوير البرمجيات.

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

ما هي GraphQL؟

من خلال استخدام QL في اسمها ، فإن GraphQL هي لغة استعلام مدمجة مع مجموعة من الأدوات التي تم إنشاؤها لتوفير المرونة والكفاءة في طريقة سحب البيانات من المصدر. باستخدام GraphQL ، يمكن للعميل / المستهلك طلب البيانات التي يحتاجها بالضبط. يستجيب الخادم / المزود بتوقيع استجابة JSON المطابق للمتطلبات المحددة في الاستعلام. يسمح لنا بالتعبير عن احتياجاتنا من البيانات بشكل تصريحي.

لماذا نستخدم GraphQL؟

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

وفقًا لقائمة على gatsby.org ، فإن GraphQL مفيدة في Gatsby من أجل:

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

مفاهيم GraphQL

يحتفظ Gatsby بنفس أفكار GraphQL المستخدمة على نطاق واسع ؛ بعض هذه المفاهيم هي:

لغة تعريف المخطط

GraphQL SDL هو نظام نوع مدمج في GraphQL ، ويمكنك استخدامه لإنشاء أنواع جديدة لبياناتك.

يمكننا الإعلان عن نوع لبلد ما ، ويمكن أن تتضمن سماته الاسم والقارة والسكان والناتج المحلي الإجمالي وعدد الولايات.

كمثال أدناه ، قمنا بإنشاء نوع جديد باسم عليم . لديها hobbies وهي عبارة عن مجموعة من الأوتار وليست مطلوبة ، ولكن هناك حاجة إلى البلد والحالة الاجتماعية والمشاركات بسبب ! تشمل ، أيضًا منشورات المراجع من نوع آخر ، المنشور.

 type Author { name: String!, hobbies: [String] country: String! married: Boolean! posts: [Post!] } type Post { title: String! body: String! } type Query { author: Author } schema { query: Query }

استفسارات

يمكننا استخدام الاستعلامات لسحب البيانات من مصدر GraphQL.

النظر في مجموعة البيانات مثل أدناه

 { data: { author: [ { hobbies: ["travelling", "reading"], married: false, country: "Nigeria", name: "Aleem Isiaka", posts: [ { title: "Learn more about how to improve your Gatsby website", }, { title: "The ultimate guide to GatsbyJS", }, { title: "How to start a blog with only GatsbyJS", }, ], }, ], }, };

يمكن أن يكون لدينا استعلام لجلب الدولة والمشاركات من البيانات:

 query { authors { country, posts { title } } }

يجب أن يحتوي الرد الذي سنحصل عليه على بيانات JSON لمشاركات المدونة مع العنوان فقط وليس أكثر:

 [ { country: “Nigeria”, posts: [{...}, {...}, {...}] }, { country: “Tunisia”, posts: [] }, { title: “Ghana”, posts: []}, ]

يمكننا أيضًا استخدام الوسائط كشرط للاستعلام:

 query { authors (country: “Nigeria”) { country, posts { title } } }

الذي يجب أن يعود

 [ { country: “Nigeria”, posts: [{...}, {...}, {...}] } ]

يمكن أيضًا الاستعلام عن الحقول المتداخلة ، مثل المنشورات ذات نوع المنشور ، يمكنك طلب العناوين فقط:

 query { authors(country: 'Nigeria') { country, posts { title } } }

ويجب أن يُرجع أي نوع مؤلف يطابق نيجيريا ويعيد البلد ومصفوفة المشاركات التي تحتوي على كائنات مع حقل العنوان فقط.

Gatsby مع GraphQL

لتجنب العبء الناجم عن امتلاك خادم / خدمة تخدم البيانات التي يمكن لـ GraphQL تحويلها ، ينفذ Gatsby استعلامات GraphQL في وقت الإنشاء. يتم توفير البيانات للمكونات أثناء عملية الإنشاء ، مما يجعلها متاحة بسهولة داخل المتصفح بدون خادم.

ومع ذلك ، يمكن تشغيل Gatsby كخادم يمكن الاستعلام عنه بواسطة عملاء GraphQL الآخرين ، مثل GraphiQL ، في المتصفح.

طرق Gatsby للتفاعل مع GraphQL

هناك مكانان يمكن أن يتفاعل فيهما Gatsby مع GraphQL ، من خلال ملف واجهة برمجة تطبيقات gatsby-node.js ومن خلال مكونات الصفحة.

gatsby-node.js

يمكن تكوين createPage API كدالة ستتلقى مساعد graphql كجزء من العناصر الموجودة في الوسيطة الأولى التي يتم تمريرها إلى الوظيفة.

 // gatsby-node.js source: https://www.gatsbyjs.org/docs/node-apis/#createPages exports.createPages = async ({ graphql, actions }) => { const result = await graphql(` query loadPagesQuery ($limit: Int!) { allMarkdownRemark(limit: $limit) { edges { node { frontmatter { slug } } } } }`) }

في الكود أعلاه ، استخدمنا مساعد GraphQL لجلب ملفات markdown من طبقة بيانات Gatsby. ويمكننا حقن هذا لإنشاء صفحة وتعديل البيانات الموجودة داخل طبقة بيانات Gatsby.

مكونات الصفحة

يمكن لمكونات الصفحة داخل دليل / pages أو القوالب المقدمة بواسطة إجراء createPage API استيراد graphql من وحدة gatsby وتصدير pageQuery . بدوره ، سيضخ غاتسبي data خاصة جديدة في عناصر مكون الصفحة التي تحتوي على البيانات التي تم حلها.

 import React from "react"; import { graphql } from "gatsby"; const Page = props => { return
{JSON.stringify (props.data)}
؛ } ؛ تصدير صفحة constQuery = graphql` استفسار { ... } "؛ تصدير الصفحة الافتراضية ؛

في مكونات أخرى

يمكن للمكونات الأخرى استيراد مكونات graphql و StaticQuery من وحدة gatsby ، <StaticQuery/> دعائم استعلام المرور التي تنفذ مساعد Graphql وتقدمها للحصول على البيانات التي تم إرجاعها.

 import React from "react"; import { StaticQuery, graphql } from "gatsby"; const Brand = props => { return ( <div> <h1>{data.site.siteMetadata.title}</h1> </div> ); }; const Navbar = props => { return ( <StaticQuery query={graphql` query { site { siteMetadata { title } } } `} render={data => <Brand data={data} {...props} />} /> ); }; export default Navbar;

بناء مدونة Gatsby للنشر الحديثة والمتقدمة

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

يمكن العثور على الإصدار الأخير من المدونة التي سننشئها هنا ، كما تتم استضافة الكود على Github.

بدء المشروع

مثل أي موقع ويب لـ Gatsby ، نقوم بالتهيئة من بداية ، هنا سنستخدم المبدئ المتقدم ولكن تم تعديله ليلائم حالة الاستخدام الخاصة بنا.

قم أولاً باستنساخ Github repo ، وتغيير فرع العمل إلى dev-init ، ثم تشغيل npm run develop من مجلد المشروع لبدء خادم التطوير مما يجعل الموقع متاحًا على https: // localhost: 8000.

 git clone [email protected]:limistah/modern-gatsby-starter.git cd modern-gatsby-starter git checkout dev-init npm install npm run develop

ستظهر زيارة https: // localhost: 8000 الصفحة الرئيسية الافتراضية لهذا الفرع.

إنشاء محتوى مشاركات المدونة

يمكن الوصول إلى بعض محتوى المنشور المتضمن في مستودع المشروع في فرع dev-blog-content. يبدو تنظيم دليل المحتوى مثل هذا /content/YYYY_MM/DD.md ، والذي يقوم بتجميع المشاركات حسب الشهر الذي تم إنشاؤه من العام.

يحتوي محتوى منشور المدونة على title date author category tags باعتبارها المادة الأولى ، والتي سنستخدمها لتمييز المنشور وإجراء مزيد من المعالجة عليه ، بينما يكون باقي المحتوى هو نص المنشور.

 title: "Bold Mage" date: "2020-07-12" author: "Tunde Isiaka" category: "tech" tags: - programming - stuff - Ice cream - other --- # Donut I love macaroon chocolate bar Oat cake marshmallow lollipop fruitcake I love jelly-o. Gummi bears cake wafer chocolate bar pie. Marshmallow pastry powder chocolate cake candy chupa chups. Jelly beans powder souffle biscuit pie macaroon chocolate cake. Marzipan lemon drops chupa chups sweet cookie sesame snaps jelly halvah.

عرض محتوى المشاركة

قبل أن نتمكن من عرض منشورات Markdown الخاصة بنا بصيغة HTML ، يتعين علينا القيام ببعض المعالجة. أولاً ، تحميل الملفات في وحدة تخزين Gatsby ، وتحليل MD إلى HTML ، وربط تبعيات الصور ، والإعجابات. لتخفيف ذلك ، سنستخدم مجموعة من المكونات الإضافية بواسطة نظام Gatsby البيئي.

يمكننا استخدام هذه المكونات الإضافية عن طريق تحديث gatsby-config.js في جذر المشروع ليبدو كما يلي:

 module.exports = { siteMetadata: {}, plugins: [ { resolve: "gatsby-source-filesystem", options: { name: "assets", path: `${__dirname}/static/`, }, }, { resolve: "gatsby-source-filesystem", options: { name: "posts", path: `${__dirname}/content/`, }, }, { resolve: "gatsby-transformer-remark", options: { plugins: [ { resolve: `gatsby-remark-relative-images`, }, { resolve: "gatsby-remark-images", options: { maxWidth: 690, }, }, { resolve: "gatsby-remark-responsive-iframe", }, "gatsby-remark-copy-linked-files", "gatsby-remark-autolink-headers", "gatsby-remark-prismjs", ], }, }, ], };

لقد أصدرنا تعليمات لـ gatsby لتضمين المكونات الإضافية لمساعدتنا في تنفيذ بعض الإجراءات ، لا سيما سحب الملفات من المجلد / static للملفات الثابتة و / المحتوى لمنشورات المدونة الخاصة بنا. أيضًا ، قمنا بتضمين مكون إضافي لمحول الملاحظات لتحويل جميع الملفات التي تنتهي بـ .md أو .markdown إلى عقدة مع جميع حقول الملاحظة لتقديم علامة التبويب كـ HTML.

أخيرًا ، قمنا بتضمين المكونات الإضافية في التشغيل على العقد التي تم إنشاؤها بواسطة gatsby-transformer-remark .

تنفيذ ملف gatsby-config.js API

من الآن فصاعدًا ، داخل gatsby-node.js في جذر المشروع ، يمكننا تصدير وظيفة باسم createPage ولدينا محتوى الوظيفة لاستخدام مساعد GraphQL لسحب العقد من طبقة محتوى GatsbyJS.

سيتضمن التحديث الأول لهذه الصفحة التأكد من أن لدينا مجموعة ثابتة على عقد ملاحظات MarkDown. سنستمع إلى onCreateNode API ونحصل على العقدة التي تم إنشاؤها لتحديد ما إذا كان نوعًا من MarkdownRemark قبل أن نقوم بتحديث العقدة لتشمل slug والتاريخ وفقًا لذلك.

 const path = require("path"); const _ = require("lodash"); const moment = require("moment"); const config = require("./config"); // Called each time a new node is created exports.onCreateNode = ({ node, actions, getNode }) => { // A Gatsby API action to add a new field to a node const { createNodeField } = actions; // The field that would be included let slug; // The currently created node is a MarkdownRemark type if (node.internal.type === "MarkdownRemark") { // Recall, we are using gatsby-source-filesystem? // This pulls the parent(File) node, // instead of the current MarkdownRemark node const fileNode = getNode(node.parent); const parsedFilePath = path.parse(fileNode.relativePath); if ( Object.prototype.hasOwnProperty.call(node, "frontmatter") && Object.prototype.hasOwnProperty.call(node.frontmatter, "title") ) { // The node is a valid remark type and has a title, // Use the title as the slug for the node. slug = `/${_.kebabCase(node.frontmatter.title)}`; } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") { // File is in a directory and the name is not index // eg content/2020_02/learner/post.md slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`; } else if (parsedFilePath.dir === "") { // File is not in a subdirectory slug = `/${parsedFilePath.name}/`; } else { // File is in a subdirectory, and name of the file is index // eg content/2020_02/learner/index.md slug = `/${parsedFilePath.dir}/`; } if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) { if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug")) slug = `/${_.kebabCase(node.frontmatter.slug)}`; if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) { const date = moment(new Date(node.frontmatter.date), "DD/MM/YYYY"); if (!date.isValid) console.warn(`WARNING: Invalid date.`, node.frontmatter); // MarkdownRemark does not include date by default createNodeField({ node, name: "date", value: date.toISOString() }); } } createNodeField({ node, name: "slug", value: slug }); } };

قائمة البريد

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

 //gatsby-node.js // previous code // Create Pages Programatically! exports.createPages = async ({ graphql, actions }) => { // Pulls the createPage action from the Actions API const { createPage } = actions; // Template to use to render the post converted HTML const postPage = path.resolve("./src/templates/singlePost/index.js"); // Get all the markdown parsed through the help of gatsby-source-filesystem and gatsby-transformer-remark const allMarkdownResult = await graphql(` { allMarkdownRemark { edges { node { fields { slug } frontmatter { title tags category date author } } } } } `); // Throws if any error occur while fetching the markdown files if (allMarkdownResult.errors) { console.error(allMarkdownResult.errors); throw allMarkdownResult.errors; } // Items/Details are stored inside of edges const postsEdges = allMarkdownResult.data.allMarkdownRemark.edges; // Sort posts postsEdges.sort((postA, postB) => { const dateA = moment( postA.node.frontmatter.date, siteConfig.dateFromFormat ); const dateB = moment( postB.node.frontmatter.date, siteConfig.dateFromFormat ); if (dateA.isBefore(dateB)) return 1; if (dateB.isBefore(dateA)) return -1; return 0; }); // Pagination Support for posts const paginatedListingTemplate = path.resolve( "./src/templates/paginatedListing/index.js" ); const { postsPerPage } = config; if (postsPerPage) { // Get the number of pages that can be accommodated const pageCount = Math.ceil(postsEdges.length / postsPerPage); // Creates an empty array Array.from({ length: pageCount }).forEach((__value__, index) => { const pageNumber = index + 1; createPage({ path: index === 0 ? `/posts` : `/posts/${pageNumber}/`, component: paginatedListingTemplate, context: { limit: postsPerPage, skip: index * postsPerPage, pageCount, currentPageNumber: pageNumber, }, }); }); } else { // Load the landing page instead createPage({ path: `/`, component: landingPage, }); } };

في وظيفة createPages ، نستخدم مساعد graphql الذي يوفره Gatsby للاستعلام عن البيانات من طبقة المحتوى. استخدمنا استعلام Graphql القياسي للقيام بذلك وقمنا بتمرير استعلام للحصول على محتوى من نوع allMarkdownRemark . ثم انتقل إلى الأمام لفرز المشاركات حسب تاريخ الإنشاء.

قمنا بعد ذلك بسحب خاصية postPerPage من كائن التكوين المستورد ، والذي يتم استخدامه لتقسيم إجمالي التدوينات إلى العدد المحدد من التدوينات لصفحة واحدة.

لإنشاء صفحة قائمة تدعم ترقيم الصفحات ، نحتاج إلى تجاوز الحد ورقم pageNumber وعدد الصفحات المراد تخطيها إلى المكون الذي سيعرض القائمة. نحن نحقق ذلك باستخدام خاصية السياق لكائن التكوين createPage . سنصل إلى هذه الخصائص من الصفحة لإجراء استعلام آخر عن الرسم البياني لجلب المشاركات ضمن الحد المسموح به.

يمكننا أيضًا ملاحظة أننا نستخدم نفس مكون القالب للقائمة ، وأن المسار فقط هو الذي يتغير باستخدام فهرس المصفوفة المقتطعة التي حددناها مسبقًا. سيمرر Gatsby البيانات اللازمة لمطابقة عنوان URL معين /{chunkIndex} ، حتى نتمكن من الحصول على / للوظائف العشر الأولى ، و /2 للوظائف العشر التالية.

الصفحة الرئيسية للمدونة الحديثة
الصفحة الرئيسية للمدونة الحديثة (معاينة كبيرة)

تقديم قائمة ما بعد

يمكن العثور على المكون الذي يعرض هذه الصفحات في src/templates/singlePost/index.js من مجلد المشروع. كما أنها تصدر أيضًا مساعد graphql الذي يسحب الحد ومعلمة استعلام الصفحة التي تلقاها من عملية createPages إلى استعلام gatsby عن المنشورات داخل نطاق الصفحة الحالية.

 import React from "react"; import { graphql, Link } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; import "./index.css"; const Pagination = ({ currentPageNum, pageCount }) => { const prevPage = currentPageNum - 1 === 1 ? "/" : `/${currentPageNum - 1}/`; const nextPage = `/${currentPageNum + 1}/`; const isFirstPage = currentPageNum === 1; const isLastPage = currentPageNum === pageCount; return ( <div className="paging-container"> {!isFirstPage && <Link to={prevPage}>Previous</Link>} {[...Array(pageCount)].map((_val, index) => { const pageNum = index + 1; return ( <Link key={`listing-page-${pageNum}`} to={pageNum === 1 ? "/" : `/${pageNum}/`} > {pageNum} </Link> ); })} {!isLastPage && <Link to={nextPage}>Next</Link>} </div> ); }; export default (props) => { const { data, pageContext } = props; const postEdges = data.allMarkdownRemark.edges; const { currentPageNum, pageCount } = pageContext; return ( <Layout> <div className="listing-container"> <div className="posts-container"> <PostListing postEdges={postEdges} /> </div> <Pagination pageCount={pageCount} currentPageNum={currentPageNum} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query ListingQuery($skip: Int!, $limit: Int!) { allMarkdownRemark( sort: { fields: [fields___date], order: DESC } limit: $limit skip: $skip ) { edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author category date } } } } } `;

صفحة البريد

لعرض محتوى الصفحة ، نحتاج إلى إنشاء الصفحة برمجيًا داخل ملف واجهة برمجة التطبيقات gatsby-node.js . أولاً ، يتعين علينا تحديد مكون جديد لعرض المحتوى به ، ولهذا ، لدينا src/templates/singlePost/index.jsx .

 import React from "react"; import { graphql, Link } from "gatsby"; import _ from "lodash"; import Layout from "../../layout"; import "./b16-tomorrow-dark.css"; import "./index.css"; import PostTags from "../../components/PostTags"; export default class PostTemplate extends React.Component { render() { const { data, pageContext } = this.props; const { slug } = pageContext; const postNode = data.markdownRemark; const post = postNode.frontmatter; if (!post.id) { post.id = slug; } return ( <Layout> <div> <div> <h1>{post.title}</h1> <div className="category"> Posted to{" "} <em> <Link key={post.category} style={{ textDecoration: "none" }} to={`/category/${_.kebabCase(post.category)}`} > <a>{post.category}</a> </Link> </em> </div> <PostTags tags={post.tags} /> <div dangerouslySetInnerHTML={{ __html: postNode.html }} /> </div> </div> </Layout> ); } } /* eslint no-undef: "off" */ export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { markdownRemark(fields: { slug: { eq: $slug } }) { html timeToRead excerpt frontmatter { title date category tags } fields { slug date } } } `;

مرة أخرى ، نحن نستخدم مساعد GraphQL لسحب صفحة عن طريق استعلام slug الذي سيتم إرساله إلى الصفحة من خلال createPages API.

بعد ذلك ، يجب أن نضيف الكود أدناه إلى gatsby-node.js في نهاية وظيفة createPages API.

 // Template to use to render the post converted HTML const postPage = path.resolve("./src/templates/singlePost/index.jsx"); // Loops through all the post nodes postsEdges.forEach((edge, index) => { // Create post pages createPage({ path: edge.node.fields.slug, component: postPage, context: { slug: edge.node.fields.slug, }, }); });

ويمكننا زيارة '/ {pageSlug}' وجعله يعرض محتوى ملف markdown الخاص بهذه الصفحة بتنسيق HTML. كمثال ، يجب أن يقوم https: // localhost: 8000 / the-butterfly-of-the-edge بتحميل HTML المحول للعلامة التجارية على: content/2020_05/01.md ، على غرار جميع الرخويات الصالحة. رائعة!

صفحة مشاركة المدونة الحديثة
صفحة نشر مدونة حديثة (معاينة كبيرة)

تقديم الفئات والعلامات

يحتوي مكون قالب المنشور الفردي على ارتباط إلى صفحة بالتنسيق /categories/{categoryName} لإدراج المشاركات ذات الفئات المتشابهة.

يمكننا أولاً التقاط جميع الفئات والعلامات أثناء إنشاء صفحة المنشور الفردية في ملف gatsby-node.js ، ثم إنشاء صفحات لكل فئة / علامة تم التقاطها لتمرير اسم الفئة / العلامة.

يبدو تعديل القسم الخاص بإنشاء صفحة منشور واحدة في gatsby-node.js كما يلي:

 const categorySet = new Set(); const tagSet = new Set(); const categoriesListing = path.resolve( "./src/templates/categoriesListing/index.jsx" ); // Template to use to render posts based on categories const tagsListingPage = path.resolve("./src/templates/tagsListing/index.jsx"); // Loops through all the post nodes postsEdges.forEach((edge, index) => { // Generate a list of categories if (edge.node.frontmatter.category) { categorySet.add(edge.node.frontmatter.category); } // Generate a list of tags if (edge.node.frontmatter.tags) { edge.node.frontmatter.tags.forEach((tag) => { tagSet.add(tag); }); } // Create post pages createPage({ path: edge.node.fields.slug, component: postPage, context: { slug: edge.node.fields.slug, }, }); });

وداخل مكون سرد المنشورات حسب العلامات ، يمكننا الحصول على مخطط استعلام تصدير pageQuery للمنشورات ، بما في ذلك تلك العلامة في قائمة العلامات الخاصة بها. سنستخدم وظيفة filter لـ graphql وعامل التشغيل $ in لتحقيق ذلك:

 // src/templates/tagsListing/ import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; export default ({ pageContext, data }) => { const { tag } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div className="tag-container"> <div>Posts posted with {tag}</div> <PostListing postEdges={postEdges} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query TagPage($tag: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { tags: { in: [$tag] } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

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

 // src/templates/categoriesListing/index.jsx import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; export default ({ pageContext, data }) => { const { category } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div className="category-container"> <div>Posts posted to {category}</div> <PostListing postEdges={postEdges} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query CategoryPage($category: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { category: { eq: $category } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

ملحوظة ، داخل كل من مكونات العلامات والفئات ، نقوم بعرض روابط إلى صفحة المنشور الفردية لمزيد من القراءة لمحتوى المنشور.

مرحبا العالم صفحة وظيفة واحدة مع البطاقات
المنشور الحديث مع تصنيف الفئة (معاينة كبيرة)

إضافة دعم للمؤلفين

لدعم مؤلفين متعددين ، يتعين علينا إجراء بعض التعديلات على محتوى منشوراتنا وتقديم مفاهيم جديدة.

قم بتحميل ملفات JSON

أولاً ، يجب أن نكون قادرين على تخزين محتوى المؤلفين في ملف JSON مثل هذا:

 { "mdField": "aleem", "name": "Aleem Isiaka", "email": "[email protected]", "location": "Lagos, Nigeria", "avatar": "https://api.adorable.io/avatars/55/[email protected]", "description": "Yeah, I like animals better than people sometimes... Especially dogs. Dogs are the best. Every time you come home, they act like they haven't seen you in a year. And the good thing about dogs... is they got different dogs for different people.", "userLinks": [ { "label": "GitHub", "url": "https://github.com/limistah/modern-gatsby-starter", "iconClassName": "fa fa-github" }, { "label": "Twitter", "url": "https://twitter.com/limistah", "iconClassName": "fa fa-twitter" }, { "label": "Email", "url": "mailto:[email protected]", "iconClassName": "fa fa-envelope" } ] }

سنقوم بتخزينها في دليل المؤلف في جذر مشروعنا /authors . لاحظ أن المؤلف JSON لديه mdField الذي سيكون المعرف الفريد لحقل المؤلف الذي سنقدمه لمحتوى مدونة markdown ؛ هذا يضمن أن المؤلفين يمكنهم الحصول على ملفات تعريف متعددة.

بعد ذلك ، يتعين علينا تحديث المكونات الإضافية gatsby-config.js لإرشاد gatsby-source-filesystem إلى تحميل المحتوى من authors/ الدليل إلى عقدة الملفات.

 // gatsby-config.js { resolve: `gatsby-source-filesystem`, options: { name: "authors", path: `${__dirname}/authors/`, }, }

أخيرًا ، سنقوم بتثبيت gatsby-transform-json لتحويل ملفات JSON التي تم إنشاؤها لسهولة التعامل معها ومعالجتها بشكل صحيح.

 npm install gatsby-transformer-json --save

وقم بتضمينه داخل المكونات الإضافية لـ gatsby-config.js ،

 module.exports = { plugins: [ // ...other plugins `gatsby-transformer-json` ], };

صفحة الاستعلام عن المؤلفين وتكوينهم

بادئ ذي بدء ، نحتاج إلى الاستعلام عن جميع المؤلفين في authors/ الدليل داخل gatsby-config.js الذين تم تحميلهم في طبقة البيانات ، يجب أن نلحق الكود أدناه لإنشاء وظيفة API createPages

 const authorsListingPage = path.resolve( "./src/templates/authorsListing/index.jsx" ); const allAuthorsJson = await graphql(` { allAuthorsJson { edges { node { id avatar mdField location name email description userLinks { iconClassName label url } } } } } `); const authorsEdges = allAuthorsJson.data.allAuthorsJson.edges; authorsEdges.forEach((author) => { createPage({ path: `/authors/${_.kebabCase(author.node.mdField)}/`, component: authorsListingPage, context: { authorMdField: author.node.mdField, authorDetails: author.node, }, }); });

في هذا المقتطف ، نقوم بسحب جميع المؤلفين من النوع allAuthorsJson ، ثم ندعو كل على العقد لإنشاء صفحة حيث نقوم بتمرير mdField للتمييز بين تفاصيل المؤلف authorDetails للحصول على معلومات كاملة عن المؤلف.

تقديم مشاركات المؤلف

في عرض المكون للصفحة التي يمكن العثور عليها في src/templates/authorsListing/index.jsx ، لدينا المحتوى أدناه للملف

 import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; import AuthorInfo from "../../components/AuthorInfo"; export default ({ pageContext, data }) => { const { authorDetails } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div> <h1 style={{ textAlign: "center" }}>Author Roll</h1> <div className="category-container"> <AuthorInfo author={authorDetails} /> <PostListing postEdges={postEdges} /> </div> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query AuthorPage($authorMdField: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { author: { eq: $authorMdField } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

في الكود أعلاه ، قمنا بتصدير pageQuery كما نفعل ، لإنشاء استعلام GraphQL لجلب المنشورات المطابقة للمؤلف ، نستخدم عامل التشغيل $eq لتحقيق ذلك ، وهو إنشاء روابط إلى صفحة منشور واحدة لمزيد من القراءة.

صفحة مؤلف المدونة الحديثة
صفحة مؤلف المدونة الحديثة (معاينة كبيرة)

خاتمة

في Gatsby ، يمكننا الاستعلام عن أي بيانات موجودة داخل طبقة الوصول إلى البيانات الخاصة بها باستخدام استعلام GraphQL وتمرير المتغيرات حول استخدام بعض التركيبات المحددة بواسطة بنية Gatsby. لقد رأينا كيف يمكننا استخدام مساعد graphql في أماكن مختلفة وفهم الأنماط المستخدمة على نطاق واسع للاستعلام عن البيانات في مواقع الويب الخاصة بـ Gatsby بمساعدة GraphQL.

تعد GraphQL قوية جدًا ويمكنها القيام بأشياء أخرى مثل تغيير البيانات على الخادم. لا يحتاج Gatsby إلى تحديث بياناته في وقت التشغيل ، لذلك فهو لا يدعم ميزة التحول في GraphQL.

تُعد GraphQL تقنية رائعة ، ويجعلها Gatsby ممتعة جدًا لاستخدامها في إطارها.

مراجع

  • دعم Gatsby لـ GraphQL
  • لماذا يستخدم Gatsby GraphQL
  • مفاهيم GraphQL في Gatsby
  • كيفية استخدام GraphQL: مفاهيم أساسية
  • لغة تعريف المخطط في GraphQL
  • مقدمة إلى GraphQL
  • غاتسبي المتقدم كاتب