آشنایی با گتسبی - بخش دو
ساختار گتسبی و کار ابتدایی با گراف کیوال 😎
توی مطلب قبلی درمورد شروع کار با گتسبی، در حد اینکه چطور از این فریمورک برای ایجاد یک پروژه استارتر استفاده کنیم، کمی نوشتم. اما این بخشی میخوام جزییات بیشتری درمورد ادامه همون بخش بنویسم و توضیح بدم که چی به چیه و چطور با پلاگینها و یه سری تنظیمات، گتسبی رو میشه برد مثلا به سمت JAMStack. فراموش نکنید داکیومنت خود گتسبی همه چی رو بهخوبی و کامل توضیح داده و فقط من به زبون عامیانه توضیح میدم ماجرا از چه قراره و برای بازسازی هایلنو تقریبا چیکارا انجام دادم.
بررسی محتوای پروژه
اون چیزی که من فهمیدم، ساختار پروژههای گتسبی رو میشه بهصورت پایه به دو بخش اصلی فایلهای تنظیمات (فایلهایی JSی که اسمشون با gatsby شروع میشه، یعنی gatsby-node.js, gatsby-browser.js, gatsby-config.js و gatsby-ssr.js) و کدهای پروژه (همون محتوای فولدر src که خودمون باید بنویسیمشون) تقسیم کرد.
حالا بخش عمدهای که توی شروع اغلب پروژهها لازمه غالبا باهاش سروکله بزنیم، فایلهای تنظیماتمونه؛ سادهتر بخوام بگم، فایلهای تنظیمات در واقع به فریمورک گتسبی میگن که چه چیزی رو از کجا، بر چه اساس و برای چی لود کنه، حتی پلاگینهایی که نصب کردیم و الی آخر.
مثلا توی فایل gatsby-config.js پروژه استارتر، بجز siteMetadata، در زیر مجموعه پلاگینها، ما gatsby-source-filesystem رو داریم که به فریمورک ما میگه برای فایلهای تصاویر در مسیر تعریف شده، نود «Node» ایجاد کنه تا از این نودهای ایجاد شده با استفاده از کوئریهای گرافکیول، بتونیم فایلهای تصاویرمون رو داخل پروژهمون بخونیم.
تقریبا میشه گفت gatsby-source-filesystem یکی از پایهترین و مهمترین پلاگینهاست برای ایجاد سایتهای محتوا محور که دادههای مختلفشون قراره توسط فریمورک خونده بشه و برپایه اون سایت تولید بشه. مثلا براساس مثال خود داکیومنت گتسبی، اگه بخواییم مثل Jekyll برای خوندن فایلهامون، پترن فایل سیستمی تعریف کنیم، چنین ساختاری رو باید برای این پلاگین داشته باشیم.
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages/`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `data`,
path: `${__dirname}/src/data/`,
ignore: [`**/\.*`], // ignore files starting with a dot
},
},
],
}
بخش اول این کانفیگ میگه pagesها رو از فلان جا بخون و بخش دوم فایلهای دیتا که میشه json, yaml و csv از فلان جا؛ یک چیز کاملا ساده.
یا مثلا من برای وبلاگ خودم (اینجا) از دو سورس سیستمی دارم استفاده میکنم، یکی برای assets از مسیر static/assets داخل روت پروژهام و یکی هم برای postها، از مسیر content که باز داخل فهرست روت پروژه قرار گرفته (پس الزامی به قرار گرفتن تمام محتوا داخل فولدر src نیست و میشه براساس سلیقه و نیاز، از جاهای مختلف دیتا رو خوند).
module.exports = {
...
plugins: [
...
{
resolve: `gatsby-source-filesystem`,
options: {
name: 'assets',
path: `${ __dirname }/static/assets/`
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: 'posts',
path: `${ __dirname }/content`
}
...
],
}
اما در کنار این پلاگین، دوتا پلاگین مهم دیگه هم هست که لازمه براساس نوع پروژه و نیاز، حتما نصبشون کنید. یک gatsby-transformer-remark که فایلهای مارکداون رو میخونه و پردازش میکنه و دو gatsby-transformer-json که با فایلهای جیسون سر و کار داره.
این وسط gatsby-transformer-remark در ظاهر تنظیمات سختی نداره، اما از اونجایی که براساس پروژه شاید لازم باشه، پلاگینهای دیگه رو باهاش مچ کنید، یه کمی پیچیده میشه! من خودم سر این یه مورد اولش یه عالمه گیج زدم، چون خیلی تو در تو شد 😅
مثلا چندتا پلاگین لازم بود که ازشون استفاده کنم تا همزمان با ترانسفورمر ریمارک، اونها هم روی محتوای فایلهای مارکداونم پردازششون رو برای خروجی انجام بدن.
module.exports = {
...
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: 'gatsby-remark-code-titles',
options: {
className: 'code-title'
}
},
{
resolve: `gatsby-remark-relative-images`,
options: {
name: `assets`,
},
},
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 1000,
withWebp: true,
quality: 100,
linkImagesToOriginal: false
}
},
`gatsby-plugin-netlify-cms-paths`,
{
resolve: `gatsby-remark-responsive-iframe`
},
{
resolve: `gatsby-remark-copy-linked-files`,
options: {
destinationDir: 'files',
ignoreFileExtensions: ['png', 'jpg', 'bmp', 'tiff']
}
},
{
resolve: `gatsby-remark-autolink-headers`,
options: {
offsetY: `0`,
maintainCase: false,
},
},
`gatsby-remark-prismjs`,
{
resolve: `gatsby-remark-external-links`,
options: {
target: '_blank',
rel: 'noopener noreferrer'
}
},
`gatsby-remark-numbered-footnotes`
]
}
},
...
از پلاگین gatsby-plugin-react-helmet, gatsby-plugin-sharp, gatsby-remark-images تا پلاگینهای sitemap, offline, feed و حتی manifest، چیزهایی هستن که برای اغلب پروژهها لازمه ازشون استفاده بشه که همهشون بعد از نصب، داخل فایل gatsby-config.js باید تعریف بشن. بعضیهاشون هم تنظیمات و اولویتهای خاص خودشون رو دارن (قبل از پلاگین فلان و بعد از پلاگین فلان باید باشن) که حتما داکیومنتشون رو بخونید.
تا یادم نرفته این رو هم بگم که تا به امروز برای گتسبی بیش از ۶۰۰ تا پلاگین ساخته شده که برای کارهای مختلف میشه ازشون استفاده کرد و همین مساله به تسریع روند توسعه پروژههای کوچیک، مثل وبلاگها و وبسایتهای متداول، خیلی خیلی کمک میکنه.
تا اینجای کار فکر کنم gatsby-config.js رو کمی درموردش توضیح دادم که داستانش چهجوریاست؛ اما gatsby-browser.js رو بخوام ساده بگم چیه، میشه فایل و اسکریپتی که با API مرورگرها همزمان با رندر سایت سمت کلاینت، دستورات مختلف رو هندل میکنه... البته بهصورت پیشفرض داخلش هیچ کدی نیست، اگه براساس پروژهتون نیاز به تعامل با API مرورگر کاربر داشتید، باید برید سراغ این فایل.
مثلا من یه اسکریپت خیلی ساده برای توییت کردن متن انتخابی داخل پستها رو توی فایل gatsby-browser گذاشتم! البته میشد جای دیگه هم ازش استفاده کرد، اما خب برای تست و کار من، جواب داد.
مورد بعد فایل gatsby-node.js هست که تنظیمات نودها رو برعهده داره؛ در اصل gatsby-node به گتسبی میگه چه فایل و دیتایی رو با چه آدرسی نمایش بده؛ مثلا اگه ما توی gatsby-config.js بگیم دیتاهای مارکداون رو بخون از سیستم فایل، توی gatsby.node.js باید تعریف کنیم که اون مارکداون فایلها چجوری تبدیل بشن به صفحات پستهامون و کجا نمایش داده بشن.
مثلا من صفحات وبلاگم که محتواش یا همون سورسش فایلهای مارکداون هست رو با این تنظیمات توی فایل gatsby-node.js، مشخص کردم که ایجاد بشن:
...
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve, reject) => {
const postPage = path.resolve('src/templates/post.jsx')
const tagPage = path.resolve('src/templates/tag.jsx')
const categoryPage = path.resolve('src/templates/category.jsx')
resolve(
graphql(
`
{
allMarkdownRemark(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
) {
edges {
node {
frontmatter {
tags
category
categoryTitle
categoryColor
title
date
}
fields {
slug
}
}
}
}
}
`
).then(result => {
if (result.errors) {
/* eslint no-console: "off" */
console.log(result.errors)
reject(result.errors)
}
const tagSet = new Set()
const categorySet = new Set()
result.data.allMarkdownRemark.edges.forEach(edge => {
if (edge.node.frontmatter.tags) {
edge.node.frontmatter.tags.forEach(tag => {
tagSet.add(tag)
})
}
if (edge.node.frontmatter.category) {
categorySet.add(edge.node.frontmatter.category)
}
createPage({
path: edge.node.fields.slug,
component: postPage,
context: {
slug: edge.node.fields.slug
}
})
})
const tagList = Array.from(tagSet)
tagList.forEach(tag => {
createPage({
path: `/keyword/${ _.kebabCase(tag) }/`,
component: tagPage,
context: {
tag
}
})
})
const categoryList = Array.from(categorySet)
categoryList.forEach(category => {
createPage({
path: `/topic/${ _.kebabCase(category) }/`,
component: categoryPage,
context: {
category
}
})
})
})
)
})
}
به نظرم gatsby-node.js یکی از پیچیدهترین بخشهای مفهومی توی تنظیمات گتسبی به حساب میاد! من خودمم خیلی فلسفهاش رو کامل درک نکردم؛ اما از اونجایی که پروژههای استارتر زیادی برای گتسبی هست و اغلب براساس کارکردهاشون از gatsby-node.js استفاده کردن، با خوندن کدهاشون میشه فهمید که مثلا برای درست کردن صفحات و بخشهای مختلف مثل post، tag و... چیکار باید کرد.
و اما در نهایت فایل تنظیمات gatsby-ssr.js، چیزیه که به فریمورک گتسبی میگه همزمان با جنریت سایت، چه دستوراتی اجرا بشن مثلا برای تغییر محتوا و... که از اونجایی که من ریاکت و جاوا اسکریپت خیلی بلد نیستم، توی پروژه وبلاگم خیلی ازش استفاده نکردم؛ اما فکر کنم میشه باهاش کارهای زیادی انجام داد.
مثلا من برای تزریق فونت بهصورت preload به هدر صفحات سایت از gatsby-ssr استفاده کردم.
بخش جذاب، گرافکیوال!
خب بخش جذابمون! همزمان با اجرای دستور npm run develop که بهصورت لوکال، گتسبی رو روی سیستممون اجرا میکنه، یک IDE تحت وب برای کار با GraphQL هم برامون اجرا میشه.
برای کار کردن باهاش کافیه آدرس http://localhost:8000/___graphql رو داخل مرورگرتون باز کنید.
اما قبلش اگه یادتون باشه توی بخش اول آشنایی با گتسبی، به پروژه استارتر گتسبی اشاره کردم که چهجوری میشه ایجادش کرد. داخل فولدر همون پروژه استارتر، اگه فایل gatsby-config.js رو باز کنید، ما چنین چیزی داریم که خب گفتم این بخش میشه تنظیمات پایه گتسبی!
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
...
توی این تنظیمات گفته شده که تصاویر ما از فلان جا خونده بشه، حالا این فایلهای تصاویرمون رو بخواییم داخل IDE وب گرافکیوال کوئری بگیریم، چنین نتایجی رو خواهیم داشت:
حالا داخل پروژه استاتر، فایل image.js رو از توی فولدر components اگه باز کنید، میبینید که چطوری میشه بهعنوان مثال یه عکس رو کوئری گرفت و آوردش توی جاوا اسکریپت! 🤔
همین کوئری و چند خط کد، توی خروجی سایت زمان جنریت شدن، برای ما چنین چیزی رو ایجاد میکنه:
به همین ترتیب برای مارکداون و سایر محتوا هم میشه کوئری و اسکریپت نوشت! اولش کمی سخت به نظر میرسه، اما بعدش واقعا شیرین میشه 😍
مثلا من برای پروژه وبلاگ خودم تصاویر کاور رو با ترکیب پلاگین پردازش تصویر خود گتسبی، اینجوری کوئری میگیرم:
...
<StaticQuery
query={graphql`
query PageCoverQuery {
allFile {
edges {
node {
id
absolutePath
childImageSharp {
fluid(maxWidth: 1600, maxHeight: 536, quality: 100) {
...GatsbyImageSharpFluid
...GatsbyImageSharpFluid_withWebp
}
}
}
}
}
}
`}
...
کلیتش این بخش ماجرا، کار آنچنانی برای کسی که جاوا اسکریپت و ریاکت بلده نداره و کل سختی کار با گتسبی به همون درک مفهوم تنظیماتش برمیگرده که اون هم واقعا سخت نیست.
اما از همه اینا که بگذریم، اگه همه چی رو درست توی پروژهمون تعریف کنیم، سرعت خروجی کار واقعا بهنظرم شاهکار خواهد شد! 😍
از طرفی، مزیت امنیت بالا رو هم به این سرعت اضافه کنیم، میبینیم که واقعا گتسبی ارزشش رو داره! ضمنا تا یادم نرفته بگم که در حال حاضر دارم روی همین پروژه وبلاگم کار میکنم تا یه سری ریزهکاریهاش رو یواش یواش کامل کنم که اون هم سورسش روی گیتهاب (اینجا) گذاشتم تا بقیه هم اگه خواستن ازش استفاده کنن. احتمالا براش یه داکیومنت جمعوجور بنویسم که خیلی راحتتر بقیه بتونن جداگانه برای خودشون وبلاگ راه بندازن.
هیچ هزینهای نداره، هاستش روی cdnها خواهد بود و اینکه سرچ سریع، پنل مدیریت و خیلی چیزهای دیگهاش رو تا اینجای کار کامل کردم 😉
شاید بعدا بازم درمورد گتسبی بنویسم. فعلا همین!