Blog w Gatsby - podstawy<!-- --> · blogweb.pl
Link do strony głównej

Blog o programowaniu, informatyce i elektronice.

Blog w Gatsby - podstawy

Tomek

Jak zrobić prosty blog w Gatsby ?

Założenia:

  • artykuły napisane w Markdown,
  • fragmenty artykułów na stronie głównej,
  • każdy artykuł z obrazkiem tytułowym,
  • możliwość umieszczania obrazków w treści,
  • kolorowanie składni dla bloga o programowaniu.

Nowy projekt w Gatsby

Nowy projekt można rozpocząć na dwa sposoby.

Sposób A (niezalecany)

Można użyć polecenia:

npx gatsby new blog-w-gatsby

To polecenie utworzy cały projekt za nas. Zainstaluje wszystkie potrzebne pakiety i dużo innych niepotrzebnych.

Sposób B (zalecany)

Lepiej zbudować projekt samemu od podstaw. Na początek tworzę katalog i inicjuję projekt. Instaluję też podstawowe pakiety.

mkdir blog-w-gatsby
cd blog-w-gatsby
npm init -y
npm i gatsby react react-dom

W package.json zamieniam wpis scripts na:

"scripts": {
    "start": "gatsby develop"
},

Zakładam katalogi:

  • src - katalog ze źródłami
  • src/pages - miejsce na strony internetowe - w tym przypadku, będzie to tylko strona startowa z listą artykułów (index)
  • src/images - katalog z obrazkami
  • src/markdown-pages - miejsce na nasze artykuły napisane w markdown
  • src/templates - szablon strony z artykułem, na podstawie którego będą generowane strony z plików markdown
mkdir src
mkdir src/pages
mkdir src/images
mkdir src/markdown-pages
mkdir src/templates

Instalacja linterów, formatmerów kodu (opcjonalnie)

Zainstaluję dwa lintery i jeden formatter kodu, aby nasz kod był bardziej zgodny z zasadami dobrych praktyk. Polecam też dodanie pluginów odpowiedzialnych za ich obsługę w edytorze kodu. Ja używam Visual Studio Code i pluginów: ESLint, Prettier - Code formatter i stylelint-plus.

ESLint

Instaluję ESLint i dwie konfiguracje eslint-config-airbnb i eslint-config-prettier.

npm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier

Tworzę też plik konfiguracyjny eslinta - ".eslintrc" w katalogu głównym projektu.

{
	"extends": ["airbnb", "airbnb/hooks", "prettier", "prettier/react"],
	"rules": {
		"no-console": 0,
		"react/prop-types": 0
	}
}

Konfiguracje:

  • airbnb - zestaw dobrych praktyk Airbnb,
  • airbnb/hooks - dla obsługi React Hooks,
  • prettier - dla zgodności z Prettierem, którego zainstaluję za chwilę
  • prettier/react - zgodnie z dokumentacją eslint-config-airbnb używa pluginu eslint-plugin-react, który wymaga prettier/react .

Do tego dwa wpisy:

  • "no-console": 0 - aby można było używać console.log w kodzie,
  • "react/prop-types": 0 - aby nie trzeba było używać prop-types (tylko na potrzeby tego przykładu).

Prettier

Instaluję formater kodu Prettier.

npm install --save-dev --save-exact prettier

Tworzę jego konfigurację w katalogu głównym - ".prettierrc"

{
	"singleQuote": true,
	"endOfLine": "lf",
	"semi": true,
	"tabWidth": 2,
	"trailingComma": "es5",
	"useTabs": true
}

Stylelint

I kolejny linter, tym razem do styli.

npm install  --save-dev stylelint stylelint-config-recommended stylelint-order

Konfiguracja Stylelint-a w katalogu głównym projektu - ".stylelintrc".

{
	"extends": ["stylelint-config-recommended"],
	"plugins": ["stylelint-order"],
	"rules": {
		"order/order": ["custom-properties", "declarations"],
		"order/properties-alphabetical-order": true
	}
}

Posty w markdown

Posty będą umieszczane w katalogu "src/markdown-pages". Tu przykładowe dwa posty:

post-1.md

---
slug: 'posty/post-1'
date: '2021-02-14'
title: 'Post testowy 1'
featuredImage: ../images/post-1.png
---

Tu jest wstęp to posta testowego nr 1.

<!-- endexcerpt -->

## O tym poście

To jest treść posta 1.
![alt image](../images/image.png)

post-2.md

---
slug: 'posty/post-2'
date: '2021-02-15'
title: 'Post testowy 2'
featuredImage: ../images/post-2.png
---

Tu jest wstęp to posta testowego nr 2.

<!-- endexcerpt -->

## O tym poście

To jest treść posta 2.

```javascript
const x = 1;
const y = 2;
console.log(x + y);
```

Na początku każdego z powyższych plików znajdują się dane posta między liniami "---" (ang. frontmatter). Dane wpisujemy w formie par klucz-wartość. Znajdują się tu: sług - ścieżka do posta, date - data, title - tytuł, featuredImage - obrazek tytułowy. To co znajduje się dalej to Markdown, który będzie zamieniany na HTML. Dodatkowo linia < !-- endexcerpt -- > pozwoli nam podzielić posta na dwie części - wstęp i całą resztę. Wstęp możemy wyświetlić na stronie z listą postów (src/pages/index.jsx).

Instalacja pluginów w Gatsby

Potrzebne będzie kilka pluginów do Gatsby:

  • gatsby-source-filesystem - potrzebny do odczytu plików z dysku przez pozostałe pluginy,
  • gatsby-transformer-remark - zamienia plik markdown na dane z frontmatter-a i dane HTML,
  • gatsby-remark-images - plugin do obsługi obrazków w markdown-ie, obsługuje tylko formaty jpeg i png,
  • gatsby-plugin-sharp - wymagany przez gatsby-remark-images,
  • gatsby-transformer-sharp - potrzebny do obrazka tytułowego - obsługuje formaty jpeg, png, webp, tiff.
  • gatsby-remark-prismjs - dodaje podświetlanie składni

Instalacja pluginów i prismjs do kolorowania składni.

npm install gatsby-source-filesystem gatsby-transformer-remark gatsby-plugin-sharp gatsby-remark-images gatsby-transformer-sharp gatsby-remark-prismjs prismjs

Konfiguracja pluginów w pliku gatsby-config.js:

module.exports = {
	plugins: [
		`gatsby-plugin-sharp`,
		`gatsby-transformer-sharp`,
		{
			resolve: `gatsby-transformer-remark`,
			options: {
				excerpt_separator: `<!-- endexcerpt -->`,
				plugins: [
					`gatsby-remark-prismjs`,
					{
						resolve: `gatsby-remark-images`,
						options: {
							maxWidth: 800,
						},
					},
				],
			},
		},
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				path: `${__dirname}/src/markdown-pages`,
			},
		},
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				path: `${__dirname}/src/images`,
			},
		},
	],
};

Dodaję wyświetlanie listy postów na stronie głównej src/pages/index.jsx

/* eslint-disable react/no-danger */
import React from 'react';
import { graphql } from 'gatsby';

const IndexPage = ({
	data: {
		allMarkdownRemark: { edges },
	},
}) => (
	<ul>
		{edges.map((edge) => (
			<li key={edge.node.id}>
				<a href={edge.node.frontmatter.slug}>{edge.node.frontmatter.title}</a>
				<br />
				<p dangerouslySetInnerHTML={{ __html: edge.node.excerpt }} />
			</li>
		))}
	</ul>
);
export default IndexPage;

export const pageQuery = graphql`
	query {
		allMarkdownRemark(sort: { order: DESC, fields: frontmatter___date }) {
			edges {
				node {
					id
					excerpt(format: HTML)
					frontmatter {
						slug
						title
					}
				}
			}
		}
	}
`;

Do wyświetlania obrazków będzie potrzebny gatsby-image:

 npm i gatsby-image

Teraz utworzę templatkę dla posta:

src/templates/blogTemplate.jsx

/* eslint-disable react/no-danger */
import Img from 'gatsby-image';
import React from 'react';
import { graphql } from 'gatsby';

export default function BlogPost({ data }) {
	const post = data.markdownRemark;
	const featuredImgFluid = post.frontmatter.featuredImage.childImageSharp.fluid;
	return (
		<div>
			<h1>{post.frontmatter.title}</h1>
			<Img fluid={featuredImgFluid} />
			<div dangerouslySetInnerHTML={{ __html: post.html }} />
		</div>
	);
}

export const query = graphql`
	query($slug: String!) {
		markdownRemark(frontmatter: { slug: { eq: $slug } }) {
			html
			frontmatter {
				title
				featuredImage {
					childImageSharp {
						fluid(maxWidth: 320) {
							...GatsbyImageSharpFluid
						}
					}
				}
			}
		}
	}
`;

Templatkę tę wykorzystam w pliku gatsby-node.js, który będzie odpowiadał za tworzenie strony z postami. Tzn każdy plik .md z katalogu src/markdown-pages zostanie przerobiony na stronę z postem wg powyższego szablonu.

exports.createPages = async ({ actions, graphql, reporter }) => {
	const { createPage } = actions;
	const blogPostTemplate = require.resolve(`./src/templates/blogTemplate.jsx`);
	const result = await graphql(`
		{
			allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
				edges {
					node {
						frontmatter {
							slug
						}
					}
				}
			}
		}
	`);
	if (result.errors) {
		reporter.panicOnBuild(`Error while running GraphQL query.`);
		return;
	}
	result.data.allMarkdownRemark.edges.forEach(({ node }) => {
		createPage({
			path: node.frontmatter.slug,
			component: blogPostTemplate,
			context: {
				slug: node.frontmatter.slug,
			},
		});
	});
};

Na koniec w pliku gatsby-browser.js dodaję css odpowiedzialny za kolorowanie składni:

require('prismjs/themes/prism-solarizedlight.css');

Komentarze


Napisz komentarz: