Merhaba Dünya! GatsbyJS'e Başlangıç Kılavuzu
React, NodeJS ve GraphQL'le Statik HTML Siteler Oluşturma
Yazdıklarımın okunmayarak boşa gideceği gibi yersiz bir fikre kapıldığımdan, bugüne dek bir blog dahi açmadım. Sonra bir gün, her nereden estiyse, Etiya içinde yayınlamak üzere hazırladığım Frontend Teknolojileri Konferansı 2018 notlarını Twitter’dan paylaştım. Bu paylaşım, yeniden paylaşan ve beğenenlerin de katkısıyla 10 binin üzerinde insana ulaştı, yüzlerce kez de okundu. 😳 Yanılmıştım!
O gün karar verdim: Bir blog açıp, -artık ne kadar olursa- elimden geldiğince Türkçe içerik üretecektim. Günlük işlerimden vakit bulabildiğim kadarıyla blogumu hazırlamaya başladım. Altyapı olarak bir süredir severek kullandığım GatsbyJS‘te karar kıldım ve vakit kaybetmemek açısından bir başlangıç kitinden hareketle ziyaret etmiş olduğunuz siteyi kurdum. Okuduğunuz bu ilk makalede de Gatsby ile basit bir blogun nasıl kurulabileceğini adım adım anlatmaya çalışacağım.
Uyarı: Doğası gereği biraz uzun bir yazı oldu. Özür dilerim. 😞
Blogum için GatsbyJS’i Neden Seçtim?
Bu sorunun benim açımdan cevabı net: JavaScript.
GatsbyJS.org’da sıralanan avantajlarsa şöyle:
- Modern web teknolojilerine dayanıyor. Anlayacağınız işin içinde Webpack var.
- GraphQL ve plugin sisteminden yararlanarak verilerinizi çok çeşitli kaynaktan (DB, CMS, SaaS, Markdown, vs.) içeri alarak başlayabilirsiniz.
- JAMstack ile ilgili ağdalı bir şeyler… 😩
- Çıktısı kademeli ağ uygulaması (progressive web app, PWA) oluyor.
- Rakiplerine kıyasla hızlı yüklenen siteler üretiyor.
- Ölçeklendirmesi zahmetsiz. Sonuçta statik sitelerden bahsediyoruz.
GatsbyJS Nasıl Çalışıyor?
Aşağıdaki kaynakların herhangi birinden GraphQL sorgularıyla veri çekiyor:
- SQL veya NoSQL veritabanları
- Markdown, JSON, YAML, CSV, vb. dosyalar
- Wordpress, Drupal, Contentful, CosmicJS, vb. CMS’ler
- Servisler
Sonra da bunları sunucu taraflı (server-side) React ve NodeJS’in yardımıyla statik HTML, CSS ve istemci taraflı (client-side) React’e derliyor. Ortaya çıkan sonuç, dizin ve dosya yapısı tüm sunuculara uygun olduğundan, başka adım gerektirmeksizin hemen yayına alınabiliyor.
GatsbyJS ile Statik Site Oluşturmaya Nasıl Başlarsınız?
NodeJS yoksa önce onu kurarsınız. Varsa terminalinizde şunu yazıp çalıştırmanız yeterli:
npx gatsby-cli new benim-gatsby-projem https://github.com/gatsbyjs/gatsby-starter-default#v2
📘 npx yürütülebilir NodeJS paketlerini sisteminize kurmanıza gerek duymaksızın çalıştırabilen bir npm CLI’ı ve 5.2.0 versiyonundan beri npm’e dahil olduğundan, Node’un çok eski sürümlerinden biriyle çalışmıyorsanız, sisteminizde büyük olasılıkla zaten mevcut. Değilse de yükleyin; nitekim deneme projesi için sisteminize global bir paket yükleyip ortamınızı kirletmekten %83.75 daha iyidir. Kesin bilgi…
CLI, belirttiğimiz şablonu (gatsby-starter-default#v2
) sisteminize kopyaladıktan sonra içindeki package.json
‘a göre bağımlılıkları (dependency) kuruyor. Sonunda sanki sihir yapmış gibi terminale mesaj basıyor. Bkz. ✨
Kısa bir kurulumdan sonra, cd benim-gatsby-projem
yazarak yeni dizine girip npm start
komutunu çalıştırıyoruz…
Ve hata alıyoruz, çünkü projede böyle bir komut dizisi (script) tanımlı değil. 🤣
Gatsby, ezbere kullandığımız start
komut dizisini boşta bırakmış, geliştirme sunucusunu develop
ile başlatıyor. O yüzden npm run develop
yazıp serçe parmağımızla Enter
tuşuna basıyoruz. CLI’ın temizlik ve derleme işlemlerini bitirip webpack-dev-serverı ayağa kaldırmasını bekledikten sonra, tarayıcımızla http://localhost:8000
adresine giriyoruz.
Tadaaaaa!!! 🎉
Projeyi açıp göz gezdirin. Ana dizindeki gatsby-
ile başlayan JavaScript dosyalarıyla iki dizin hemen dikkatinizi çekecektir: pages
ve components
. Bunları inceleyin; ama fazla vakit harcamayın; çünkü henüz pek bir numaraları yok.
📘 React’e bağımlı olduğu için, Gatsby IE9+ ve diğer popüler tarayıcılarda çalışıyor. IE8’i desteklemek gibi bir derdiniz varsa, üzgünüm… 🙄
GatsbyJS’te Tüketmek Üzere İçerik Üretme
Eğer pages
dizinini açıp incelediyseniz, Gatsby’nin iki yol (route) arasında geçişi nasıl yönettiğini anlamışsınızdır:
<Link to="/page-2/">Go to page 2</Link>
Kısacası ziyaretçiyi sitenizde gezdirmek Gatsby’nin <Link>
bileşeninden geçiyor. Lakin bu kullanım statik. Bizim yazacağımız makalelerinse adının veya yolunun ne olacağı bile belli değil. Yazılarımızı listelemenin dinamik bir yöntemini bulmalıyız.
O zaman önce saçmasapan bir makale yaratalım. Hemen src
‘nin altına posts
adlı bir dizin açıp, onun da altına merhaba-dunya
dizinini oluşturuyor, içine de şöyle bir index.md
dosyası ekliyoruz:
---
title: "Merhaba Dünya"
date: "2018-08-14T19:29:22.587Z"
---
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quis optio corrupti quae commodi ipsam nesciunt natus aliquam dignissimos suscipit nostrum libero voluptatibus ab iure quibusdam, nemo quia assumenda modi!
Rerum corrupti ratione molestiae porro qui laboriosam quo voluptates quisquam quaerat recusandae suscipit quidem, quae nobis! Quis illo excepturi repellat laudantium distinctio, vel recusandae, eius iusto molestias suscipit nihil. Dolorum.
Suscipit itaque quod inventore magnam harum sunt illum quaerat nihil consectetur sed veniam dignissimos, est blanditiis alias, doloremque corrupti. Eos laboriosam voluptas officiis quos non aut excepturi saepe amet asperiores.
Soluta tenetur quidem unde nisi nostrum inventore. Corrupti expedita omnis maiores illo, doloribus culpa reprehenderit fugiat illum error recusandae animi ut consequuntur vero, quia provident laudantium eum, ratione quae aspernatur.
Markdown ile hazırladığımız /src/posts/merhaba-dunya/index.md
yolundaki ilk makalemiz hazır. Mıgırca yazılardan oluşuyor, ama işimizi görür. Şimdi bunu tüketilebilir hale getirelim.
GatsbyJS ile Dinamik İçerik Nasıl Çekilir?
Gatsby’de hemen her şey için bir eklenti (plugin) bulmak mümkün. Dosyaları veri kaynağına çevirmekte “gatsby-source-filesystem” kaynak eklentisini (source plugin), Markdown’ı HTML ve ön bilgiye (frontmatter) çevirmekteyse “gatsby-transformer-remark” dönüştürücü eklentisini (transformer plugin) kullanabiliyoruz. Şunları projemize bir kuralım:
npm install gatsby-source-filesystem gatsby-transformer-remark
Sonra da gatsby.config.js
dosyasını açıp plugins
kısmının sonuna yeni eklentilerimizi yerleştirelim.
.
.
.
plugins: [
.
.
.
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`,
},
},
'gatsby-transformer-remark'
],
.
.
.
☠️ Noktalarla gösterilen yerlerde projenizin çalışması için gerekli başka yapılandırmalar var. Silmeyin lütfen!
Şimdi, terminalden geliştirme sunucusunu Ctrl + C
ile kapatıp npm run develop
ile yeniden çalıştırdıktan sonra GraphiQL arayüzüne şu adresten ulaşabiliriz: http://localhost:8000/___graphql
Bu arayüzü, hatta GraphQL’i daha önce görmemiş olabilirsiniz. Hiç sorun değil. Kullanacağımız sorgu şöyle bir şey:
query NewestPosts {
posts: allMarkdownRemark(
filter: {frontmatter: { title: { ne: "" }, date: { ne: "" } }},
sort: {fields: [frontmatter___date], order: DESC},
limit: 5,
skip: 0
) {
edges {
node {
id
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
excerpt
}
}
totalCount
}
}
Fazla detaya inmeden sorgumuzun ne yaptığını açıklayayım:
- En baştaki
query NewestPosts
sorguya adıyla başvurabilmek amaçlı ve zorunlu değil. - Kurduğumuz iki eklenti,
allMarkdownRemark
adında sorgulanabilir bir bağlantı (connection) sunuyor. - Bağlantıyı
posts
olarak rumuzluyoruz (alias), çünkü paşa gönlüm öyle istedi. -
Çekmek istediğimiz sonuçları şunlarla belirliyoruz:
filter
ile hangi sonuçların elenmeyeceğini (başlık ve tarih ön bilgisi boş olmayanlar)sort
ile sonuçların nasıl sıralanacağını (tarihe göre yeniden eskiye)limit
ile en fazla kaç sonuç döneceğini (5)skip
ile kaç kayıt atlanarak başlanacağını (0)
edges
meselesine bu yazıda girmeyeceğim. 🤐 Daha fazlası için şimdilik bkz. Explaining GraphQL Connectionsnode
GatsbyJS’in veri modelini üzerine kurguladığı özel bir nesne (object).id
hernode
‘da bulunan bir alan (field). Makaleleri React’le listelerkenkey
olarak kullanacağız.frontmatter
veexcerpt
çevirici eklentimizin bize güzellikleri. Birincisi makalenin en üstüne yerleştirdiğimiz ön bilgileri getirirken, ikincisi ana metnin ilk 137 karakterlik kısmını sunuyor.date
alanındakiformatString
ise ön bilgiden gelen tarihi biçimlendirebilmenizi sağlıyor.- Son olarak filtremizden geçen toplam sonuç sayısını
totalCount
ile çekebiliyoruz.
Yukarıdaki kodu kopyalayıp GraphiQL’in sol penceresine yapıştırın ve en üstte duran tipsiz oynat tuşuna basın. ▶️ Sağ tarafta aşağıdaki JSON sonuç çıkacak:
{
"data": {
"posts": {
"edges": [
{
"node": {
"id": "/Users/LeventArmanOzak/armanozak/benim-gatsby-projem/src/posts/merhaba-dunya/index.md absPath of file >>> MarkdownRemark",
"frontmatter": {
"title": "Merhaba Dünya",
"date": "14 Ağustos 2018, 19:29"
},
"excerpt": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quis optio corrupti quae commodi ipsam nesciunt natus aliquam dignissimos..."
}
}
],
"totalCount": 1
}
}
}
GraphQL ile veri sorgulamanın ne kadar basit olduğunu görüyorsunuz. Şimdi bu veriyi sitemizde nasıl gösterebileceğimize bir bakalım.
Gatsby’de Dinamik İçeriği Nasıl Tüketirsiniz?
Yine pages
dizininin altındaki index.js
dosyasını açın, en alta yukarıdaki sorguyu ekleyerek başlayın ve bileşenin içeriğini şöyle güncelleyin:
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/layout'
const IndexPage = ({
data: {
posts: {
edges,
totalCount
}
},
}) => (
<Layout>
<small>
Toplam {totalCount} makale
</small>
<ul>
{edges.map(({ node }) => (
<li key={node.id}>
<h2>{node.frontmatter.title}</h2>
<small>{node.frontmatter.date}</small>
<p>{node.excerpt}</p>
</li>
))}
</ul>
</Layout>
)
export default IndexPage
export const pageQuery = graphql`
query NewestPosts {
posts: allMarkdownRemark(
filter: { frontmatter: { title: { ne: "" }, date: { ne: "" } } }
sort: { fields: [frontmatter___date], order: DESC }
limit: 5
skip: 0
) {
edges {
node {
id
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
excerpt
}
}
totalCount
}
}
`
Neler yaptık?
pageQuery
adında bir sabit oluşturup daha önce hazırladığımız sorguyugraphql
etiketli şablon kalıbını (tagged template literal) kullanarak çalışır hale getirdik ve sabitimizi dışa verdik (export) ki Gatsby bunu okuyup ilgili veriyi sağlasın.IndexPage
fonksiyonel bileşeninin (functional component) argüman olarak aldığı özelliklerden (props) bize gerekenleri çıkardık (destructure).Layout
bileşeninin içerisini değiştirip kaç kayıt olduğunu ve çektiğimiz makale özetlerini listeledik.
🔎 İç içe çıkarma (nested destructuring) işlemi tanıdık gelmeyebilir. Yaptığımız aslında şundan pek de farklı değil:
const { edges, totalCount } = props.data.posts
Eğer geliştirme sunucusu hala ayaktaysa, tarayıcınızı açtığınızda hazırdaki tek makalenin başlığını, tarihini ve özet bilgisini görüyorsunuzdur. 🤮 Çirkin, biliyorum; ama bu yazının konusu kozmetik unsurlar değil.
Peki neleri yapmadık?
- Dinamik içerik üretiyoruz, ancak ürettiğimiz içeriğe nasıl bağlantı vereceğimizi bilmiyoruz. Bunun için bir yöntem geliştirmeliyiz.
- Yazımızı okuyabileceğimiz bir sayfa da üretmedik. Ne bir şablonumuz, ne de otomatik olarak görüntülenebilir bir
.js
dosyamız mevcut. - Sayfalama (pagination) yapmadık. Evet, toplam kayıt sayısını gösterebiliyoruz; ama makalelerimizin bir bölümünü listelemek üzere ayarlanmış sayfalarımız bulunmuyor. Ayrıca imleç (cursor) kaçıncı kayıtta, bunu da bilmiyoruz.
Belli ki daha çok işimiz var. 😒 Adım adım eksiklerimizi giderme zamanı.
Gatsby’de SEO Dostu Temiz Adresler Oluşturma
Yazımızın yolunu oluşturup çektiğimiz veriye dahil etmek amacıyla gatsby-node.js
dosyasını açıp içine aşağıdaki kodu ekliyoruz:
const { createFilePath } = require('gatsby-source-filesystem')
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode, trailingSlash: false })
createNodeField({
name: `slug`,
node,
value,
})
}
}
Burada node
daha önce GraphQL sorgumuzda da adı geçen Gatsby’ye özel nesne, getNode
bunları yakalamaya yarayan metot, actions
ise çağırıldıklarında Redux eylemi (action) oluşturup fırlatan (dispatch) fonksiyonlar kümesi. Bunlardan biri olan createNodeField
ile eklentimizden içe aldığımız (import) createFilePath
fonksiyonunu birlikte kullanarak slug
adında özel bir alan yaratıyoruz ve onCreateNode
adıyla dışa veriyoruz. Sebebi için bkz. GatsbyJS Node API
Artık GraphiQL arayüzünden şöyle bir sorgu yapabiliyoruz:
query NewestPosts {
posts: allMarkdownRemark(
filter: {frontmatter: { title: { ne: "" }, date: { ne: "" } }},
sort: {fields: [frontmatter___date], order: DESC},
limit: 5,
skip: 0
) {
edges {
node {
fields {
slug
}
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
excerpt
}
}
totalCount
}
}
Ve şu cevabı alıyoruz:
{
"data": {
"posts": {
"edges": [
{
"node": {
"fields": {
"slug": "/merhaba-dunya"
},
"frontmatter": {
"title": "Merhaba Dünya",
"date": "14 Ağustos 2018, 19:29"
},
"excerpt": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quis optio corrupti quae commodi ipsam nesciunt natus aliquam dignissimos…"
}
}
],
"totalCount": 1
}
}
}
Çok güzel! Haydi makale sayfamızı üretelim.
GatsbyJS’te Şablon Sayfa Oluşturma
Şablon yaratmak çok basit. Bunun için src
‘nin altına templates
adında bir dizin açın ve içerisine PostTemplate.js
adlı bir dosya ekleyin. Dosyanın içeriği şöyle olacak:
import React from 'react'
import { graphql, Link } from 'gatsby'
import Layout from '../components/layout'
const PostTemplate = ({
data: {
post: {
frontmatter,
html,
timeToRead
}
}
}) => (
<Layout>
<h1>{frontmatter.title}</h1>
<small>📅{frontmatter.date} 🕑{timeToRead} dakika</small>
<div dangerouslySetInnerHTML={{ __html: html }} />
<Link to="..">Anasayfaya dön</Link>
</Layout>
)
export default PostTemplate
export const pageQuery = graphql`
query PostBySlug($slug: String!) {
post: markdownRemark(
fields: { slug: { eq: $slug } }
) {
html
timeToRead
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
}
}
`
Burada, yukarıda anlatılanlara göre iki fark var:
- Niyetimiz tekil sonuç almak olduğu için,
allMarkdownRemark
bağlantısını değil,markdownRemark
bağlantısını sorguluyoruz. - Bu sorgu,
fields
ın altındakislug
alanıyla karşılaştırmak içinString
tipinde bir$slug
parametresi alıyor.
📘 Sorgu parametreleri
$
işaretiyle başlıyor ve sonunda!
olması parametrenin zorunlu olduğunu ifade ediyor.
Gatsby’de Şablonları Kullanarak Statik Sayfalar Derleme
gatsby-node.js
dosyasını tekrar açıp, aşağıda işaretli kısımları ekleyin:
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode, trailingSlash: false })
createNodeField({
name: `slug`,
node,
value,
})
}
}
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const postTemplate = path.resolve('./src/templates/PostTemplate.js')
return new Promise((resolve, reject) => {
resolve(
graphql(`
{
posts: allMarkdownRemark(
filter: { frontmatter: { title: { ne: "" }, date: { ne: "" } } }
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
}
}
}
}
`).then(({errors, data}) => {
if (errors) {
console.log(errors)
reject(errors)
}
const { edges } = data.posts
edges.forEach(({ node: { fields: context } }) =>
createPage({
context,
path: context.slug,
component: postTemplate,
})
)
})
)
})
}
Bu noktada geliştirme sunucusunu yeniden başlatmanız gerekecektir. Kısaca açıklamak gerekirse, GraphQL ile son 1000 kaydı çekip, her bir kayıt için yeni oluşturduğumuz şablonu ve slug
alanını createPage
Redux eylem üreticisine (action creator) geçirerek ilgili makalenin sayfasını üretiyoruz.
CLI işini bitirdikten sonra http://localhost:8000/merhaba-dunya
adresine girdiğinizde aşağıdaki tabloyla karşılaşacaksınız:
Bu sayfa işimizi görüyor. Şimdi ona nasıl ulaşacağımızı görelim.
GatsbyJS’te İçeriğe Bağlantı Verme
pages
dizinindeki index.js
dosyasını yeniden açıp, içerisinde aşağıda gösterilen değişiklikleri yapalım.
import React from 'react'
import { graphql, Link } from 'gatsby'
import Layout from '../components/layout'
const IndexPage = ({
data: {
posts: {
edges,
totalCount
}
},
}) => (
<Layout>
<small>
Toplam {totalCount} makale
</small>
<ul>
{edges.map(({ node }) => (
<li key={node.fields.slug}>
<Link to={node.fields.slug}>
<h2>{node.frontmatter.title}</h2>
</Link>
<small>{node.frontmatter.date}</small>
<p>{node.excerpt}</p>
</li>
))}
</ul>
</Layout>
)
export default IndexPage
export const pageQuery = graphql`
query NewestPosts {
posts: allMarkdownRemark(
filter: { frontmatter: { title: { ne: "" }, date: { ne: "" } } }
sort: { fields: [frontmatter___date], order: DESC }
limit: 5
skip: 0
) {
edges {
node {
fields {
slug
}
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
excerpt
}
}
totalCount
}
}
`
Tarayıcınızı açıp http://localhost:8000
adresine yeniden bakarsanız, başlığın tıklanabilir hale geldiğini, başlığa tıklandığındaysa az önce derlediğimiz makale sayfasına ulaşılabildiğini göreceksiniz.
❓ Aynı bağlantıyı,
<Link>
bileşenini yerine,<a>
etiketi ile verdiğinizde ne değişiyor?
GatsbyJS’te Sayfalama Nasıl Yapılır?
Ne demiştik? Her şey için bir GatsbyJS eklentisi bulmak mümkün. Sayfalama istisna değil. Geliştirme sunucusunu kapatıp, “gatsby-paginate” paketini kuralım:
npm install gatsby-paginate
Ardından gatsby-node.js
dosyasını yeniden açıp aşağıda gösterilen değişiklikleri yapalım:
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
const paginate = require('gatsby-paginate')
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode, trailingSlash: false })
createNodeField({
name: `slug`,
node,
value,
})
}
}
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const postTemplate = path.resolve('./src/templates/PostTemplate.js')
return new Promise((resolve, reject) => {
resolve(
graphql(`
{
posts: allMarkdownRemark(
filter: { frontmatter: { title: { ne: "" }, date: { ne: "" } } }
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
title
date(formatString: "DD MMMM YYYY, HH:mm", locale: "tr")
}
excerpt
}
}
totalCount
}
}
`).then(({ errors, data }) => {
if (errors) {
console.log(errors)
reject(errors)
}
const { edges, totalCount } = data.posts
edges.forEach(({ node: { fields: context } }) =>
createPage({
context,
path: context.slug,
component: postTemplate,
})
)
paginate({
createPage,
edges,
pageTemplate: './src/templates/IndexTemplate.js',
pageLength: 5,
context: {
size: 5,
totalCount,
},
// Aşağıdakiler opsiyonel. Varsayılanları böyle.
pathPrefix: '',
buildPath: (index, pathPrefix) =>
index > 1 ? `${pathPrefix}/${index}` : `/${pathPrefix}`,
})
})
)
})
}
Ne yaptık? Eklentimizi paginate
adıyla içe aldık ve sorgumuz çözümlendiğinde (resolve) kayıtlarımızı sayfalara bölmekte kullandık. Yanında kullanmak isteyebileceğimiz öğeleri context
olarak eklentiye ilettik. Ayrıca, pageTemplate
olarak IndexTemplate.js
adında henüz bulunmayan bir dosyaya işaret ettik.
Şu an pages
‘ın altında duran index.js
‘i templates
dizinine taşıyıp yeniden adlandıralım:
# Bu komut sadece Unix tabanlı işletim sistemlerinde çalışır.
# Komutun Microsoft karşılığı yanılmıyorsam "move".
mv src/pages/index.js src/templates/IndexTemplate.js
Ve açıp içeriğini şu şekilde değiştirelim:
import React from 'react'
import { Link } from 'gatsby'
import Layout from '../components/layout'
const createURL = (index, shift) =>
index + shift === 1 ? '' : String(index + shift)
const nextLink = (Go, {index, next}) => (
<Go to={createURL(index, +1)}>{next}</Go>
)
const prevLink = (Go, {index, prev}) => (
<Go to={createURL(index, -1)}>{prev}</Go>
)
const pageLinks = (Go, { index, pageCount, next, prev }) =>
index > 1
? index < pageCount
? (<div>
{nextLink(Go, {index, next})}
{prevLink(Go, {index, prev})}
</div>)
: (<div>{prevLink(Go, {index, prev})}</div>)
: (<div>{nextLink(Go, {index, next})}</div>)
const PostNumbers = ({index, size, total}) => (
<span style={{ marginLeft: '1ex' }}>
[
{Math.max(0, total - index * size) + 1}
{' - '}
{total - (index - 1) * size}
]
</span>
)
const IndexPage = ({
pageContext: {
group,
index,
pageCount,
additionalContext: {
size,
totalCount,
},
},
}) => (
<Layout>
<small>
Toplam {totalCount} makale
<PostNumbers
index={index}
size={size}
total={totalCount}
/>
</small>
<ul>
{group.map(({ node }) => (
<li key={node.fields.slug}>
<Link to={node.fields.slug}>
<h2>{node.frontmatter.title}</h2>
</Link>
<small>{node.frontmatter.date}</small>
<p>{node.excerpt}</p>
</li>
))}
</ul>
{pageCount > 1 &&
pageLinks(
Link,
{
index,
pageCount,
next: "◂ Eski Makaleler",
prev: "Yeni Makaleler ▸"
}
)
}
</Layout>
)
export default IndexPage
// Gömülü sorguya artık gerek yok, onu silin.
Yukarıdaki kodu biraz açıklayayım:
createURL
eklentimizin varsayılanbuildPath
ayarına uygun adresler üreten bir yardımcı fonksiyon.nextLink
,prevLink
vepageLinks
, GatsbyJS’inLink
‘ini alıp bulunulan sayfaya göre donatmaya yarayan üst seviye bileşenler (higher-order component).PostNumbers
listede kaçıncı makaleden kaçıncıya kadar gösterdiğimizi ekrana yansıtmakta kullandığımız basit bir bileşen.data
yerinepageContext
‘e başvurduk, çünkü veriyi bu yolla sunan bir eklentiden alıyoruz artık.- Yeni eklentiden kaynaklı önemli bir değişiklik de şu: Listeleyeceğimiz bilgiler artık
edges
değil,group
adıyla geliyor, ama içerik aynı. - Eğer sayfa sayımız
1
‘den fazlaysa, bağlantı(lar) veriyoruz.
🔎 Dikkat ederseniz, sayfalamada yürütülen mantık ters çalışıyor. Sebebi, bloglarda makale sıralamasının yeniden eskiye doğru gitmesi. Bunu istediğiniz gibi yorumlayıp kendinize göre yeniden şekillendirebilirsiniz.
Makale sayınızı artırıp geliştirme sunucunuzu yeniden başlattığınızda ortaya çıkan sonuçsa şöyle bir şey:
GatsbyJS Projenizi Nasıl Yayına Alırsınız?
Geliştirme sunucusunu kapatın. Terminalden ayrılmadan Gatsby CLI’ın kurulum esnasında package.json
‘a yerleştirdiği build
komut dizisini çalıştırın:
npm run build
Projemiz içerik fakiri olduğundan, kısa bir süre sonra derleme tamamlanacaktır. Her şey yolunda gittiyse, aşağıdaki tabloyla karşılaşacaksınız:
Derleyici public
adında bir dizin oluşturup, onun altında her yazıya ayrı HTML üretti ve sitenizi yapılandırdı. Artık, aşağıda gösterildiği gibi, bu dizine girip bir HTTP sunucusu başlatırsanız, derlenen siteyi gezebilirsiniz.
cd public && npx http-server
Şimdi tek yapmanız gereken, bu çıktıyı şunlardan birine yüklemek: 💁♂️
- Statik sunucunuz (paylaşılan sunucular dahil)
- Netlify
- Now.sh
- Surge.sh
- GitHub Pages
- Azure Storage
- Google Cloud Storage
- Amazon S3
- Diğer
Bu kadar. Artık içeriğiniz yayında.
Kapanış
Sonunda içerisinde gezinebildiğimiz, makalelerimizi okuyabildiğimiz bir blog kurmayı başardık. Aferin bize. 💯 Gelgelelim, görsel düzenlemeler bir yana, çağdaş bir blog için bazı fonksiyonlar katmanız gerekecek:
- Statik resim sunma (Evet, bunu anlatmadım. Belki başka yazıya…)
- Sayfa üst bilgileri (meta data)
- Site ikonu (favicon)
- “Hakkımda”, “İletişim” gibi yardımcı sayfalar
- Site içi arama
- Ziyaretçi yorumları
- Sosyal paylaşım tuşları
- Arama motoru iyileştirmeleri (search engine optimization, SEO)
- Metrik toplama (analytics)
- Blogunuz yazılımla ilgiliyse, kod vurgulaması (highlight)
Bütün bunları yapmak zahmetli görünüyorsa, ki öyle, siz de benim bu blogda yaptığım gibi Gatsby başlangıç kitlerinden yararlanabilirsiniz. Bu makaleyeyse, hem kiti kendinize göre düzenlerken, hem de GatsbyJS’le başka işler yaparken başvurabilirsiniz.
Bitti. 🙏