15
Blogging with GatsbyJS
π This article was originally posted on my site, MihaiBojin.com. π
This post is a simple introduction to Gatsby's most common feature (probably): blogging with Remark JS.
Hopefully, by the end of this article, you'll have a basic understanding of some of the usual plugins used for configuring the blogging functionality and what benefits they bring to the table!
The core plugin needed to achieve our goal is the official gatsby-transformer-remark plugin.
This post aims to explain a few of the usual plugins you can use for setting up your very own blog with GatsbyJS. Since the configuration is generic, you can target any audience, but if you don't plan to include code, you can safely skip the PrismJS plugin.
Let's begin!
Assuming you already have a GatsbyJS site, start by installing the plugin with:
npm install gatsby-transformer-remark
The gatsby-transformer-remark
plugin supports multiple input sources (e.g., various content management systems), but the easiest option is to host markdown files locally. To do that, you will need the following plugin:
npm install gatsby-source-filesystem
You will most likely want to include images in your markdown content. The gatsby-remark-images
plugin has several nifty features such as:
- resizing the image to the target's container size
- generating a srcset of multiple image sizes (support multiple device widths)
- "blur-up" while the image is loading
npm install gatsby-remark-images gatsby-plugin-sharp gatsby-transformer-sharp
The gatsby-remark-autolink-headers
plugin automatically generates HTML IDs for each heading, allowing your readers to link to a specific section in your posts.
npm install gatsby-remark-autolink-headers
Since links in markdown content are not making use of React's reach router, you'll also want to convert them for faster navigation:
npm install gatsby-plugin-catch-links
If you link any files in your markdown (such as PDFs), you'll want them to be copied along with any other static resources.
npm install gatsby-remark-copy-linked-files
And assuming you will include some code in your content, you will want to integrate with PrismJS:
npm install gatsby-transformer-remark gatsby-remark-prismjs prismjs
Before proceeding, you need to decide where to host your files. One common choice is /content
. You can create .md
files directly in that directory, or you can create any number of subdirectories. The path you use will determine the slugs at which your content will be hosted. E.g., creating a page under /content/my/article.md
will render to the following page: https://SITE_URL/my/article
.
A slug is a common term used to denote the part of a URL identifying a page.
First, add the following configuration to your gatsby-config.js
.
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content`,
name: `blog`,
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 730,
},
},
`gatsby-remark-autolink-headers`,
`gatsby-plugin-catch-links`,
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
],
},
},
`gatsby-transformer-sharp`,
{
resolve: `gatsby-plugin-sharp`,
options: {
defaults: {
formats: [`auto`, `webp`],
placeholder: `blurred`,
quality: 95,
breakpoints: [750, 1080, 1366, 1920],
backgroundColor: `transparent`,
tracedSVGOptions: {},
blurredOptions: {},
jpgOptions: {},
pngOptions: {},
webpOptions: {},
avifOptions: {},
},
},
},
],
};
With all of that behind us, the final step is to read all the markdown from GraphQL and generate the pages.
Edit your gatsby-node.js
file and add the following (if one does not exist, create it):
const path = require(`path`);
const { createFilePath } = require(`gatsby-source-filesystem`);
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
if (node.internal.type === `MarkdownRemark`) {
// generate post slug
const value = createFilePath({ node, getNode });
createNodeField({
name: `slug`,
node,
value,
});
}
};
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions;
// Get all markdown blog posts sorted by date
const result = await graphql(
`
{
allMarkdownRemark(sort: { fields: [frontmatter___date], order: ASC }) {
nodes {
id
fields {
slug
}
}
}
}
`
);
if (result.errors) {
reporter.panicOnBuild(
`There was an error loading your blog posts`,
result.errors
);
return;
}
// Create blog posts pages only if there's at least one markdown file
const posts = result.data.allMarkdownRemark.nodes;
if (posts.length == 0) {
reporter.warn(`No blog posts found`);
return;
}
// Define a template for blog post
const component = path.resolve(`./src/components/blog-post.js`);
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index - 1].id;
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id;
console.log(`Creating blog page: ${post.fields.slug}`);
createPage({
path: post.fields.slug,
component,
context: {
id: post.id,
previousPostId,
nextPostId,
},
});
});
};
Each page is based on a template, ./src/templates/blog-post.js
. Go ahead and create this file and populate it with a React component that will display the rendered markdown and other elements. Here's an example.
Congratulations! At this point, you should have a working blogging feature that enables you to write simple markdown and transform it into pages such as the one you're reading right now.
If you have any follow-up questions or feedback, please add them on this Twitter thread!
If you liked this article and want to read more like it, please subscribe to my newsletter; I send one out every few weeks!
15