رفقای خوب (Gatsby+Netlify)

goodfellasاحتمالا عنوان این پست شما رو به یاد یکی از شاهکار های مارتین اسکورسیزی بندازه ! اگه حتی این فیلم رو ندیدید و یا رابرت دنیرو رو یادتون نمیاد نگران نباشید :) قراره این بار یک رفقای خوب دیگه رو بخونید به کارگردانی جاوا اسکریپت و تولد یک ستاره ی جدید به نام گتسبی !اول از همه باید بهتون بگم که این پست خیلی طولانی میشه چون قراره یک پروژه رو با گتسبی و نتلیفای بالا بیاریم و کامل توضیح بدیم پس اگه الان فرصتش رو ندارید حتما این مقاله رو بوکمارک کنید تا بعد ها به سراغش بیاید.مقدمهچند وقتی هست که مبحثی به نام JAM Stack روز به روز ترند تر میشه. قطعا تا الان با استک های مختلفی مثل MERN،MEAN و یا حتی LAMP آشنایی دارید.اما JAM Stack مخفف شده ی عبارت Javascript API Markup هست که برخلاف باقی استک ها قصد معرفی ابزار نداره و یک جور طرز تفکرهقسمت که خب کاملا مشخصه قراره بر محور جاوا اسکریپت و فریمورک ها و کتابخونه هاش بچرخیم.قسمت API : یه سری reusable API ها هست که عمدتا می تونید از api as service ها استفاده کنید.قسمت Markup : اگه با مجموعه زبان Markup آشنایی ندارید توصیه میکنم این مقاله رو بخونید. اما به صورت خلاصه می تونم بگم که یک مجموعه زبان نشانه گذاری هست برای توصیف متن ها در علم کامپیوتر که بهش شبه زبان برنامه نویسی ام میگن.حالا JAM Stack مگه چیه که داره ترند میشه؟خب این معماری وب یک سری مزایایی داره که دیگر معماری ها ندارن مثل :پرفومنس بیشترخیلی خیلی ایمن ترارزانترسرعت توسعه و تجربه ی توسعه ی بهترمقیاس پذیریبرای توضیح بیشتر هر کدوم از این دلایل می تونید به این سایت مراجعه کنید و یا منتظر بمونید تا انتهای مقاله که موارد بالا رو درک کنیم باهم :)تیتراژ ابتدایی با گتسبیخب ما واسه ی پیاده سازی یک JAM Stack ساده از گتسبی و نتلیفای استفاده می کنیم.گتسبی چیه : گتسبی یک فریمورک بر پایه ی ری اکت هست که باهاش می تونید SSG درست کنید.نتلیفای چیه: یک شرکت کلاود کامپیوتینگ هست که به automate کردن وب اپلیکیشن های مدرن می پردازه.ما قصد داریم با استفاده از Gatsby به عنوان بخش Javasciprt و Netlify CMS به عنوان بخش reusable API به تولید Markup بپردازیم و یک وبلاگ ساده رو با این معماری وب بسازیم.قبل از هرچیزی چند خط بالاتر از کلمه ی SSG استفاده کردم که برای اینکه هم بیشتر با گتسبی آشنا بشید و هم برخی از مزیت های استفاده از اون رو درک کنید توصیه میکنم ابتدا دموی پروژه مون رو ببینید و مقاله ی مندرج شده در اون رو بخونید و دوباره به همین جا برگردید.دموی پروژه( برای خوندن مقاله روی عنوان مقاله کلیک کنید )شروع پروژه با ایجاد ساختارخب برگشتید؟ چطور بود دمو؟ بنظر من که این SSG ها ( در vue.js مانند Gridsome ) خیلی حس بهتری به کاربر ارائه میدن :دی !اول از همه باید بگم پیش نیاز این پروژه آشنایی شما با ری اکت هست و بسو اما چیز هایی که برای شروع این پروژه نیاز دارید :یک پروژه ی گتسبی ( که باهم ایجادش می کنیم )یک اکانت گیت هابیک اکانت Netlifyایجاد یک پروژه گتسبیابتدا لازم هست که gatsby-cli رو نصب کنید مانند دستور زیر :npm install -g gatsby-cliببینید گتسبی یه سری استارتر داره یعنی یه سری پروژه های از قبل کانفیگ شده ی آماده برای شروع کارشما با دستور زیر می تونید یک پروژه گتسبی بسازید که از استارتر دیفالت استفاده می کنه اما من توصیه میکنم این کار رو نکنید و برای این پروژه از استارتر hello world استفاده کنید تا تموم فایل ها و کانفیگ های پروژه رو خودمون انجام بدیم ( بنده به بیماری خود کانفیگی دچار هستم )// uses default starter gatsby new [project-name] // Follow these instructions gatsby new hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world cd hello-world gatsby developخب تا الان شما یک پروژه گتسبی رو بالا آوردید و ظاهرش رو مشاهده می کنید.بریم به قسمت دوم و پروژه رو بیاریم روی گیت :git remote add origin https://github.com/[YOUR-GITHUB-USERNAME]/[YOUR-REPO-NAME].git git push -u origin masterحالا بریم سراغ ساخت یک اکانت توی نتلیفایبه سایت نتلیفای برید.یک اکانت بسازید و لاگین کنید.روی New site from Git کلیک کنید.روی گیت هاب که زیر Continuous Deployment قرار داره کلیک کنید. ( خب الان نیازه که به نتلیفای اجازه بدید تا به گیت هابتون دسترسی داشته باشه )حالا ریپوی مربوط به پروژتون رو انتخاب کنید.و در آخر روی Deploy site کلیک کنید.خب الان برای شما یک سابدومین ساخته شده در نتلیفای و همچنین لینک شده به برنچ مستر ریپوی پروژتون به این منظور که هر تغییراتی که توی برنچ مستر ریپوی شما انجام بشه به صورت اتوماتیک نتلیفای یک بیلد میگیره و شما نتایج رو توی این سابدومین مشاهده خواهید کرد.اما این رو باید هم به گیتهاب هم به نتلیفای بفهمونیمچطوری به گیتهاب بفهمونیم : وارد گیتاب بشید در قسمت setting و developer setting روی OAuth app کلیک کنید و یکی جدید بسازید. اسمش هرچیزی می تونه باشه و برای home page url همون آدرس سابدومینی که نتلیفای براتون ساخته رو بزارید و در قسمت authorisation callback URL مقدار زیر رو بزارید و روی Register Application بزنید.https://api.netlify.com/auth/doneخب حالا بهتون یک client ID و یک client secret میده که داشته باشیدش نیازش داریم :دیچطوری به نتلیفای بفهمونیم: وارد نتلیفای بشید و به قسمت تنظیمات سایتتون برید در منوی Access control بر روی OAuth کلیک کنید. روی Install Provider کلیک کنید و پس از انتخاب گیتهاب client ID و client secret رو وارد کنید.نصب کردن Netlify CMSخب دوستان قبل از نصب سیستم مدیریت محتوای نتلیفای ( یا خدا فارسیش چقدر طولانیه :)) ) باید بهتون بگم که گتسبی یک سری پلاگین داره که برای ارتباط با API هاش ازشون استفاده می کنه و تقریبا برای هرچیزی که فکرشو بکنید یک پلاگین داره اما اگر نداشت هم نگران نباشید چون به راحتی میتونید براش بنویسید :)برای نصب Netlify CMS و پلاگینش از دستور زیر استفاده می کنیم:npm install --save netlify-cms gatsby-plugin-netlify-cmsپس از نصب هر پلاگین در گتسبی شما باید به گتسبی بفهمونید که این پلاگین نصب شده پس در فایل gatsby-config.js باید کانفیگ پلاگین رو وارد کنید ( نگران نباشید چون همه ی این کانفیگ ها به همراه پلاگین در اینجا قرار دارند )پس تنظیمات زیر رو در فایل gatsby-config.js خودتون وارد کنید :// In your gatsby-config.js file module.exports = { plugins: [ // ... other plugins `gatsby-plugin-netlify-cms` // ... other plugins ], }خب دست به گیرنده هاتون نزنید تا اینجا ما ساختار پروژمون رو ساختیم و اما یه توضیح کوچیک در مورد فایل هایی که توی گتسبی می بینید بدم و بریم سراغ ادامه ی پروژه :src : هسته ی تمام کدهایی که شما می نویسید توی این پوشه است که از چند زیر پوشه تشکیل شدهsrc/components : دقیقا مثل ری اکت اینجا هم قراره کامپوننت بنویسیمsrc/pages : هر فایلی که در این پوشه قرار بگیره یک صفحه جداگانه میسازه و دیگه لازم نیست شما از پکیج های روتر استفاده کنید.git-config.js : منبع اصلی کانفیگ پلاگین های شما و همچنین به صورت کلی هر کانفیگی که در مورد اپ دارید.و باقی فایل ها که فایل های مرسوم پروژه ها هست و فایل هایی که بعد ها به پروژمون اضافه خواهد شد.تا اینجا ساختار فایل های پروژه ی شما باید مثل زیر باشه :-node_modules - src -components -pages .gitignore .prettierignore .prettierrc gatsby-config.js LICENSE package-lock.json package.json README.mdخب تازه میخوایم پروژه رو شروع کنیم و امیدوارم که خسته نشده باشید :دیواکنش اون دسته از دوستانی که خسته شدنپیکربندی Netlify CMSبعد از یک سری اتفاقات هیجان انگیز حالا وقت اون رسیده که Netlify CMS رو کانفیگ کنیم.و اما این فایل کانفیگ نمی تونه هرجایی قرار داشته باشه و یک مکان خاص میخواد.در روت پروژتون یک پوشه به نام static بسازید و داخل اون یک پوشه به نام admin بسازید و داخل admin یک فایل به نام config.yml ( اگه کنجکاو شدید که yml چیه این لینک رو بخونید )# In your static/admin/config.yml file backend: name: github repo: [YOUR-GITHUB-USERNAME]/[YOUR-REPO-NAME] media_folder: static/assets public_folder: assetsنام ریپو و یوزنیم گیتهابتون رو در تنظیمات جایگذاری کنید.حالا وقت اون رسیده که یکی از انواع collection ها رو برای ادامه ی پروژه انتخاب کنیم.در Netlify CMS دو جور کالکشن داریم ۱- فولدر کالکشن و ۲- فایل کالکشناما فرقشون چیه؟فولدر کالکشن بیشتر زمانی استفاده میشن که محتوای شما از یک جنس و شبیه به هم باشه ( به عنوان مثال وبلاگ که از چندین پست با یک فرمت یکسان تشکیل میشه و یا یک سایت فروشگاهی که از چندین محصول با یک فرمت یکسان تشکیل میشه )فایل کالکشن بیشتر مربوط به زمانی هست که محتوای شما منحصر به فرد هستند.در این آموزش ما از فولدر کالکشن استفاده می کنیم و کانفیگ زیر رو به فایل config.yml اضافه می کنیم :متاسفانه ویرگول تورفتگی ها رو درست نمایش نمیداد و مجبورم کدها رو اینطوری بزارم.خب و اما معنی این ها چیه؟در این نوع پیکربندی ها هرچیزی نیاز داره که یک label و name داشته باشه.چیزی که در ادمین پنل نشون داده میشه label هست و چیزی که ما توی کد باهاش به عنوان متغیر کار داریم اسمش name هست.پس ما اومدیم لیبل و نام کالکشن رو Pages گذاشتیم.نوع کالکشنمون رو با :files مشخص کردیم که از نوع فایل کالکشن هست و مجددا همونطور که بالا گفتم نیاز داریم تا لیبل و نام رو بهش اختصاص بدیم.و زیرش یکی از پیج هامون رو معرفی کردیم بهش ( همون پیجی که ابتدای مطلب مقاله ی مفهوم SSG رو مطالعه کردید )و با :fields مشخص کردیم که چه فیلد هایی رو نیاز داریم تا در ادمین پنل این پیج قرار داشته باشن ( اگه متوجه نشدید مشکلی نداره، جلوتر که بریم با چشم خیلی چیزها رو می بینیم )یک نکته ی مهم : زمانی که از فایل کالکشن استفاده می کنید دقت داشته باشید که فایلی که تعریفش می کنید حتما باید وجود داشته حتی اگه خالی باشه ( در اینجا فایلی که ما تعریف کردیم content/ssg-concept.md هست ) پس یک پوشه در روت پروژتون به نام content بسازید و داخلش یک فایل خالی به نام ssg-concept.md رو بسازید.خب همه چیز خوبه. الان به آدرس زیر برید و لاگین کنید :[YOUR-NETLIFY-SUBDOMAIN]/admin/ // for example: https://frontcampigan.netlify.com/admin/الان باید تصویر زیر رو ببینید :داشبورد ادمین پنل مدیریت محتواو با کلیک کردن روی SSG Concept به حکمت اون field ها و widget هایی که تعریف کردیم پی می برید:ویجت هایی که تعریف کردیم در فیلدهای بالا اینجا کاملا خودنمایی می کننیکی از ضعف هایی که Netlify CMS داره اینه که ادیتور قدرتمندی مثل strapi نداره.و اما شاید الان براتون این سوال پیش بیاد که اگر بخواید فیلد ها و ویجت های متنوع تری اضافه کنید باید چیکار کنید که مفتخرم عرض کنم Netlify CMS یک داکیومنت خوب داره که در این قسمت می تونید فیلد ها و ویجت های مختلف رو ببینید و استفاده کنید.وارد کردن اطلاعاتدر این مرحله فیلد های مورد نظر رو پر کنید و به روی publish کلیک کنید.خطر ذوق مرگی: پس از publish کردن به ریپوی گیتهاب خود رفته و ببینید که چطور commit جدیدی خوردهنکته ی گیتی: وقتی ریپوی شما commit جدیدی میخوره اما کد لوکال شما همچنان sync نیست باید حتما دستور زیر رو اجرا کنید تا مطابق با آخرین تغییرات ریپو پیش برید و کد بزنید :git pullپس از انجام دستور بالا به همون فایلی که در config.yml تعریف کردیم برید و میبینید که اون فایل دیگه خالی نیست !گرفتن اطلاعاتخب تجربتون تا اینجا از این استک چی بوده؟ می دونید اگر قرار بود به صورت فرانت معمولی و عادی این پروسه رو طی کنیم باید فقط چه مدت زمانی منتظر می موندیم تا به این فاز برسیم؟ پس سرعت توسعه به شکل محسوسی بالا رفتهابتدای شروع نوشتن این مقاله فکر میکردم نمی تونم انقدر تایپ کنم :|خب تا اینجا ما تونستیم اطلاعات رو از پنل ادمین به ریپوی گیتهابمون بفرستیم اما همچنان چیزی در سایتمون نمی بینیم چون به گتسبی نگفتیم که این اطلاعات و دیتا رو چطور پیدا کنه و به صفحات ما اضافه کنه.برای این که بتونیم به گتسبی بگیم چطور این اعمال رو انجام بده نیاز داریم تا دوتا از پر کاربردترین پلاگین های گتسبی رو نصب کنیم پس دستور زیر رو بزنید :npm install --save gatsby-source-filesystem gatsby-transformer-remarkما از پلاگین gatsby-source-filesystem استفاده می کنیم تا به گتسبی بگیم فایل هامون کجاست.طبق فیلد هایی که گذاشتیم و تعریف کردیم ما دو جور فایل داریم یکی فایل های markup یا همون md. و یکی هم فایل های عکسمونپس توی فایل gatsby-config.js کدهای زیر رو اضافه می کنیماگه واستون سوال پیش اومد که dirname__ چی هست باید بگم این عبارت به پوشه ای که توش این فایل رو می نویسیم برمیگرده اولین نمونه ی کانفیگ ما در کدهای بالا به دنبال تصاویر میگرده و دومیش به دنبال فایل های markdown ای که توسط CMS ساخته میشه.همچنین در مورد gatsby-transformer-remark نقش یک parse کننده برای فایل های markdown رو داره.بریم سراغ GraphQL ؟گراف کیوال یک Query Language برای API هاست که بر خلاف REST بسیار منعطف تر و بهینه تر و قدرتمند تره که در سال ۲۰۱۲ توسط فیسبوک ساخته شده و اگه باهاش آشنایی ندارید و میخواید یک مرور سریع بهش داشته باشید از این سایت دیدن کنید و تمرین هاش رو انجام بدید و بیاید بریم سراغ ادامه ی مقاله.ما اینطوری منتظر میمونیم تا شما برید بخونید و تمرین کنید و بیاید :))چون در این مقاله قرار نیست به آموزش گراف کیوال بپردازیم می تونید تموم کوئری ها رو کپی کنید و بنویسید.یکی از ابزارهایی که گتسبی داره و به نوعی کوئری زدن رو راحت تر کرده ابزاری هست به نام GraphiQL که می تونید اون رو در آدرس زیر پیدا کنید :http://localhost:8000/___graphqlحالا ما میخوایم node ای رو پیدا کنیم که بهمون ssg-concept.md رو بده.یه راه اینه با استفاده از sourceInstance فیلتر کنیم و بگیم دقیقا چه فایلی رو میخوایم اما این راه به قول برنامه نویس ها بدبوعه و زیاد خوشایند نیست.allFile (filter: {sourceInstanceName: {eq: &quotcontent&quot} name: {eq: &quotssg-concept&quot}})پس ما یک کار زیباتر انجام میدیم و با استفاده از نود childMarkdownRemark شروع به خوندن فایل های markdown می کنیم این فایل ها رو توی frontmatter و html جداسازی می کنیم.اینطوری بدنه ی فایل های Markdown از طریق html در دسترس خواهد بود و چیزهای دیگر مثل رشته ها تاریخ و .. از طریق frontmatter در دسترس خواهد بود.از اونجایی که ما در body فایل های markdown چیزی نداشتیم پس به frontmatter کوئری می زنیم: نتیجه ای که به ما برمیگرده یک object هست که حاوی مقادیری هست که میخواستیم ( نه کمتر و نه بیشتر ) این دقیقا یکی از قدرت های GraphQL هست.نمایش اطلاعاتاین دیتایی که به ما برمیگرده در props قرار میگیره و ما می تونیم ازش برای نمایش اطلاعات استفاده کنیم.نکته مهم : حواستون باشه که edges یک ارایه است و باید روش map بزنید.پی نوشت : من چون یکم به سبک ری اکت نوشتم و از کامپوننت های مختلفی استفاده کردم جهت نمایش گذاشتن کدهام شما رو گیج می کنه اما اگه بخواید می تونید آدرس گیت پروژه که در انتهای مطلب میگذارم رو بخونید و روش انتقال دیتا رو توسط من ببینید و خب حالا میریم سراغ قسمت آخر مقاله..حس دوستانی که بی وقفه تا اینجا مطالعه کردن مطلب رو :))ایجاد داینامیک صفحات با استفاده از اطلاعاتخب تا الان یک صفحه ی ایندکس خیلی قشنگ ساختیم که عنوان ، زمان مطالعه ( طبق تعداد کاراکتر می تونید با استفاده از این سایت زمان خوندن رو محاسبه کنید ) و یک خلاصه ی مقاله رو نمایش میده.اما ما نمی خوایم که فقط خلاصه یک مقاله رو بخونیم و تمایل داریم تا تموم مقاله رو بخونیم. درست مثل همون چیزی که در دمو دیدید تصمیم داریم یک صفحه ی کامل مقاله با استفاده از دیتا بسازیم.یک راهش اینه که به مسیر src/pages بریم و برای هر مقاله جداگانه یک صفحه بسازیم اما این خیلی هاردکده و از یه برنامه نویس به دوره پس ما راه دوم رو انتخاب می کنیم.راه دوم چیه؟ این که یک صفحه ی داینامیک بسازیم.مراحل ساخت یک صفحه ی داینامیک :ساخت یک مسیر یا path یا slug برای URL هر صفحهساختن صفحهساخت مسیر یا path یا slug برای URL هر صفحهاکثر Headless CMS ها این مورد رو به عنوان یک دیتا برمیگردونن و می تونید با کوئری زدن بهش دیتای مورد نظرتون رو دریافت کنید اما ما باز هم از Netlify CMS ها استفاده کردیم تا این مورد هم دستی انجام بدیم و بگیم ترسی نداره :دیبرای ساخت markdown page ها از دو API گتسبی به نام های onCreateNode و createPages استفاده می کنیم که در بسیاری از سایت ها و پلاگین ها این دو API رو مشاهده می کنید.اما برای کار با API های خود گتسبی مثل مواردی که بالا برشمردم لازمه که کانفیگ ها رو در فایلی به نام gatsby-node.js بنویسیم . پس این فایل رو در روت پروژه بسازید.سپس کد زیر رو در اون قرار بدید :exports.onCreateNode = ({ node }) => { console.log(node.internal.type) }خب ما از onCreateNode استفاده کردیم تا به گتسبی بگیم هر زمان یک node جدید ساخته شد و یا آپدیت شد به ما خبر بده.برای اینکه دقیق تر متوجه بشید یک بار development server رو متوقف و سپس مجدد ران کنید.حالا به ترمینال نگاه کنید و چیز هایی که لاگ انداخته شده رو ببینید.در مرحله ی بعدی ما میخوایم با استفاده از این API توسط Markdown Remark هامون به صفحات Markdown لینک بدیم و مسیر یا همون slug رو بسازیم.پس دوباره کد موجود در gatsby-node.js رو به کد زیر تغییر بدید :exports.onCreateNode = ({ node }) => { if (node.internal.type === `MarkdownRemark`) { console.log(node.internal.type) } }اما هدف صالی ما از این کار چیه؟ ما میخواهیم که اسم فایلمون اگر ssg-concept.md هست مسیر یا slug مورد نظرمون /ssg-concept/ باشه.اما بنظر شما باید چیکار کنیم تا اسم فایل markdown رو از node مورد نظرمون دریافت کنیم؟شما باید node graph رو مرور کنید و با استفاده از node-parent به نام فایل دسترسی پیدا کنید.برای این منظور فایل gatsby-node.js رو مجدد تغییر بدید:exports.onCreateNode = ({ node, getNode }) => { if (node.internal.type === `MarkdownRemark`) { const fileNode = getNode(node.parent) console.log(`\n`, fileNode.relativePath) } }مجددا development server تون رو ری استارت کنید و در ترمینال لاگ مربوط به مسیر فایل markdown رو مشاهده می کنید.خب حالا زندگی شیرین شد نه؟ :دیالان با استفاده از gatsby-source-filesystem میایم و مسیر مدنظر برای URL هامون رو می سازیم:const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode }) => { if (node.internal.type === `MarkdownRemark`) { console.log(createFilePath({ node, getNode, basePath: `pages` })) } }مجددا development server رو ری استارت کنید و به من بگید که لذت بخش بود یا نه؟ :)بسیار هم عالی الان شما یک مسیر دارید که باهاش می تونید به صورت داینامیک پیج بسازید و فقط لازمه که این مسیر رو به عنوان یک فیلد اضافه به node اضافه کنیم که این کار رو با createNodeField انجام میدیم پس دوباره به gatsby-node.js برید و این بار به صورت زیر ویرایشش کنید :const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const slug = createFilePath({ node, getNode, basePath: `pages` }) createNodeField({ node, name: `slug`, value: slug, }) } }پس از ری استارت کردن development server این بار ابزار GraphiQL رو باز کنید و نتیجه ی کوئری زیر رو ببینید:هووورررراااا ! شما مسیر رو ساختید ! دمتون گرم که تا اینجا اومدید.ساختن صفحاتبا استفاده از createPages API و کد زیر که در gatsby-node.js می نویسیم ( پایین تر از کدهای قبل ) به مسیر مورد نظرمون کوئری می زنیم و دوباره توی terminal لاگ می زنیم ( یادتون نره که development server رو حتما ری استارت کنید )خب حالا ما همه ی دیتایی که می خوایم رو داریم پس کافیه که دیتامون رو map بزنیم و صفحات رو داینامیک بسازیم. برای این منظور یک template برای پست هامون می سازیم که یک کامپوننت ری اکتی هست و اون رو در مسیر src/template ایجاد می کنیم و نام دلخواهی مانند single-post.js براش انتخاب می کنیم. ( نوشتن این کامپوننت رو به سلیقه ی خودتون واگذار می کنم )و حالا این فایل رو به gatsby-node.js معرفی می کنیم و مجدد کل فایل رو بدین شکل آپدیت می کنیم :حالا development server رو ری استارت کنید و می بینید که پیجتون ساخته شده :)برای گرفتن دیتا در template post type مدنظر می تونید یه همچین کوئری ای بزنید :شما می تونید مقادیر دیگه ای رو هم بگیرید ( غیب گویی با چشمان بسته )الان صفحات شما کامل ساخته شدند :) فقط کافیه به title مقاله هاتون که در صفحه ی اصلی لیست شدند یک لینک با استفاده از Link خود گتسبی بدید و در صفحه ی اصلیتون کوئری بزنید و slug رو دریافت کنید تا به اون مسیر مورد نظر لینک بزنید.کوئری مورد نظر تقریبا یه همچین چیزی میشه ( بسته به نوع کامپوننت نویسی شما و همچنین مواردی که ممکنه کوئری بزنید قطعا متفاوت خواهد بود و کوئری زیر صرفا جهت اینه که نحوه ی کوئری زدن slug رو ببینیم ولی شما می تونید سورس کامل پروژه رو توی گیت ببینید )خط پایانرابرت دنیرو توی رفقای خوب میگه هیچوقت چغلی رفتار دوستانت رو نکن و همیشه دهنت رو بسته نگه داراما خب من توی این پست سعی کردم تا می تونم چغلی این دو رفیق رو بکنمکمی و کاستی های نگارش رو ببخشید سعی کردم خودمونی صحبت کنم تا خستتون نکنم و قطعا توی این حجم مقاله ممکنه برخی جاها براتون مبهم باشه که من با کمال میل به تمام سوالاتتون پاسخ میدم در نظرات بپرسید ازم :)سورس کامل پروژه رو می تونید از لینک زیر ببینید :https://github.com/Mvahedii/frontcampLinkedin | Github |