Skip to main content

Hello Docusaurus!

· 6 min read
Alex

Docusaurus

I've investigated different static site generators — SSGs — in order to set up a proper blog for this website. I've read about a lot of them, tried a few. My favourite by far is Docusaurus, the one this site is now built with.

Quick comparaison

As I'm working on complex web apps during the day, SSGs make evening projects feel like holiday.

Still, I found that many of them require quite some tinkering before achieving desired results. In theory, to have a quick website set up, we can start from a template. But unfortunately this is where most of the pain come from. Many templates I looked at where incomplete, old, unmaintained, or simply ugly.

Docusaurus is the one which has the best of both:

  • A great template to start with.

There is only one at the moment. It has basically everything I wanted and it's very nice. So it's much better than a choice of 100 useless templates. It might be a bit of a problem for someone really not liking it... but still, wait for the next point.

  • A great way to tinker and customise it.

Docusaurus provides multiple ways to customise the styling and layout, depending on what we want to change, and how deep we want to change it. From creating React components and use them in MDX, to the brilliant swizzling method allowing to easily cherry pick a component to wrap it or replace it (there is an example in the Add comment system section below).

Setup

note

I will write about the choices I've made during the building of this blog. I won't detail every steps — official docs are better sources and will stay up to date.

Create a new Docusaurus project

npx create-docusaurus@latest your-project-name classic --typescript

This is all what's needed to have a complete website with dummy pages ready to be filled with content.

tip

If you're sick of having a new browser tab being opened everytime you run the start command, append --no-open.

Setup Prettier

Prettier formats Markdown well, it will be appreciated while writing blog posts.

Set up redirect to /blog

I wanted the blog to be the only content of the site for the moment. But I didn't want to make the blog base URL simply /, as all the post links would be in the format <domain>/<post>, which could potentially become annoying if I wanted to add other types of content to the site in the future.

So I kept the blog base URL /blog (post links are <domain>/blog/<post>), and I created a redirect from / to /blog.

info

Server-side redirects are best, but as I'm hosting the site on GitHub Pages, this isn't an option.

Docusaurus provides a plugin for client-side redirects:

npm i @docusaurus/plugin-client-redirects
Extract from 'docusaurus.config.js'
plugins: [
[
"@docusaurus/plugin-client-redirects",
/** @type {import('@docusaurus/plugin-client-redirects').Options} */
({
redirects: [
{
from: "/",
to: "/blog",
},
],
}),
],
],

Deactivate docs

Extract from 'docusaurus.config.js'
presets: [
[
"classic",
...
docs: false,

Add metadata

Adding the following makes links to the blog look pretty when shared.

Extract from 'docusaurus.config.js'
presets: [
[
"classic",
...
blog: {
blogTitle: "<Blog title>",
blogDescription: "<Blog description>",
Extract from 'docusaurus.config.js'
themeConfig:
...
image: "<Image path>",

Activate all feed types

Just because I want all the shiny new stuff, I activated all the types of feeds.

Extract from 'docusaurus.config.js'
presets: [
[
"classic",
...
blog: {
feedOptions: {
type: "all",
title: "<Blog title>", // By default, it's in the format `<Site name> Blog`
description: "<Blog description>", // Same here
},

Add comment system

Giscus is a great comment system powered by GitHub Discussions.

Install its React component:

npm i @giscus/react

Use giscus.app to set up and retrieve your configuration for Giscus, then create the file src/components/GiscusComments.tsx:

src/components/GiscusComments.tsx
import { useColorMode } from "@docusaurus/theme-common";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Giscus from "@giscus/react";
import React from "react";

export default function GiscusComments() {
const {
siteConfig: {
customFields: {
giscusRepo,
giscusRepoId,
giscusCategory,
giscusCategoryId,
},
},
} = useDocusaurusContext();

const { colorMode } = useColorMode();

if (
typeof giscusRepo !== "string" ||
typeof giscusRepoId !== "string" ||
typeof giscusCategory !== "string" ||
typeof giscusCategoryId !== "string"
) {
return null;
}

return (
<Giscus
repo={giscusRepo as `${string}/${string}`}
repoId={giscusRepoId}
category={giscusCategory}
categoryId={giscusCategoryId}
mapping="pathname"
strict="0"
reactionsEnabled="1"
emitMetadata="0"
inputPosition="bottom"
theme={colorMode}
lang="en"
/>
);
}
tip

I used Docusaurus' custom fields to retrieve Giscus configuration from Docusaurus' config (itself retrieving these values using dotenv)

In order to add the Giscus component to our blog posts, we are going to use Docusaurus' swizzling method to wrap one component of the template (read about swizzling here):

npm run swizzle @docusaurus/theme-classic BlogPostItem --wrap

This command creates a new file:

src/theme/BlogPostItem/index.js

which we can directly rename to .tsx:

src/theme/BlogPostItem/index.tsx
info

Now we need to restart Docusaurus' dev server, in order for it to take the new custom component into account.

This file is a wrapper for the BlogPostItem component. We can very easily add our new GiscusComments component just below it:

src/theme/BlogPostItem/index.tsx
import useIsBrowser from "@docusaurus/useIsBrowser";
import GiscusComments from "@site/src/components/GiscusComments";
import BlogPostItem from "@theme-original/BlogPostItem";
import React from "react";

const POST_REGEX = /^\/blog\/.+$/;

export default function BlogPostItemWrapper(props) {
const isBrowser = useIsBrowser();

return (
<>
<BlogPostItem {...props} />

{isBrowser && window.location.pathname.match(POST_REGEX) && (
<>
<div style={{ marginTop: "32px" }} />

<GiscusComments />

<div style={{ marginTop: "-24px" }} />
</>
)}
</>
);
}
Details
  • We check that the pathname matches /blog/... to not show the Giscus component below all the posts on the main listing page (/blog).
  • isBrowser is to prevent evaluating window at build time, which would creates an error.

Last thing, to be done once your local testing is finish, is to add a file giscus.json at the root of the repository to prevent other websites from showing your discussions:

giscus.json
{
"origins": ["https://<your-domain>"]
}

Giscus will stop showing on your localhost:3000 after this file is committed.

Automatically deploy to GitHub Pages, Netlify, etc.

The site is deployed on very push to the main branch. The code should be self-explanatory with enough knowledge on GitHub Actions and GitHub Pages.