このシリーズでは、ドキュメントサイトをつくりながら Docusaurus の使い方を説明しています。

前回「Markdown 編」では、Markdown や MDX の機能を見てきました。今回は以下の公式ドキュメントをベースにブログの機能を見ていきます。

本記事の完成後のデータ一式は以下の GitHub リポジトリにアップしています。

変更点は以下のとおりです。

  • docusaurus.config.js のブログの設定を変更
  • static/img/blog 以下に著者画像を追加
  • blog 以下の著者データおよび記事データを差し替え

順番に説明していきます。

docusaurus.config.js の設定

この見出しのリンク

現在、docusaurus.config.js 内のブログの設定は以下のとおりです。

docusaurus.config.js
// ...
const config = {
  // ...
  presets: [
    [
      'classic',
      /** @type {import('@docusaurus/preset-classic').Options} */
      ({
        // ...
        blog: {
          showReadingTime: true,
        },
        // ...
      }),
    ],
  ],
  // ...
};

module.exports = config;

記事の読了時間の目安を表示する showReadingTime の機能が有効になっているだけなので、以下のように指定を追加します。

docusaurus.config.js
// ...
const config = {
  // ...
  presets: [
    [
      'classic',
      /** @type {import('@docusaurus/preset-classic').Options} */
      ({
        // ...
        blog: {
          showReadingTime: true,
          blogSidebarTitle: '記事一覧',
          truncateMarker: /<!--\s*(more)\s*-->/,
          remarkPlugins: [
            [require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
          ],
        },
        // ...
      }),
    ],
  ],
  // ...
};

module.exports = config;

まず、サイドバーの見出し(blogSidebarTitle)を「記事一覧」と指定しました。

また、記事一覧に表示する範囲(記事の抜粋)をコメントで制御できるのですが、デフォルトの <!--truncate--> から、より入力しやすい <!--more--> に変更しました。

remarkPlugins の指定は、前回の Markdown 編で docs に指定した Docusaurus npm2yarn remark plugin を、blog 以下でも使用できるようにしています。

docusaurus.config.js でブログに設定できるすべての項目は、以下をご確認ください。

ブログには著者データを管理するための、blog/authors.yml というファイルがあります。

以下の内容が指定できますが、name もしくは image_url のいずれかが必須です。

キー内容
name名前
title肩書きなどのテキストを指定
urlリンク先 URL
emailメールアドレス
image_url画像ファイルパス
  • url を指定せずに email を指定すると、mailto: でリンクが設定されます。
  • email を指定すると、RSS フィードの <authors> に反映されます。

後述する Front Matter でも個別に指定できますが、メンテナンス性を考慮すると、blog/authors.yml で一元管理することが望ましいでしょう。

今回は以下の 3 名の著者データを登録します。なお、画像ファイルは static/img/blog 以下に追加しています。

blog/authors.yml
brackets:
  name: Brackets
  title: デザイナー
  image_url: /img/blog/avatar-brackets.svg

duck:
  name: Duck
  title: フロントエンドエンジニア
  image_url: /img/blog/avatar-duck.svg

professor:
  name: Professor
  title: フロントエンドエンジニア
  image_url: /img/blog/avatar-professor.svg
追加する著者データのアバター画像、名前、肩書き。左から Brackets(デザイナー)、Duck(フロントエンドエンジニア)、Professor(フロントエンドエンジニア)
追加する著者データ

ブログでは、ファイル名やディレクトリ名のフォーマットから、日付を指定することができます。例えば、以下のファイルパスで「2023年4月3日」という日付を指定することができます。

  • blog/2023-04-03-markdown.md
  • blog/2023-04-03/markdown.md
  • blog/2023/04/03/markdown.md
  • blog/2023/04-03-markdown.md

拡張子は .mdx でも同様です。

また、このとき、URL はすべて /blog/2023/04/03/markdown/ となります。

日付は後述する Front Matter でも指定することができますが、両方とも指定した場合には Front Matter の日付が優先されます。

ファイル名を index.md とした場合、直上のディレクトリ名までが URL となります。

以下は、どちらとも URL は /blog/2023/04/03/markdown/ です。

  • blog/2023-04-03-markdown.md
  • blog/2023-04-03-markdown/index.md

拡張子は .mdx でも同様です。

記事に関する画像ファイルがある場合には、ディレクトリを設けて管理するとよいでしょう。

ドキュメント同様に、ブログ記事でも Front Matter を指定できます。

キー内容デフォルト
authors著者情報(配列で指定)undefined
titleタイトルh1 もしくはファイル名
description概要Markdown の最初の行
date日付ファイル名もしくは作成日
imageSNS シェア画像undefined
slugカスタム URLファイルパス
tagsタグ(配列で指定)undefined
draft下書きfalse

すべてのフィールドの詳細な説明は、公式ドキュメントをご確認ください。

authors には、blog/authors.yml に記載されている著者データのキーを配列で指定します。

---
authors: 
  - brackets
  - duck
---
ブログ記事のスクリーンショット
記事に著者情報が反映される

slug はブログ記事の URL です。前述したように、ファイル名やディレクトリ名から自動的に URL が決まりますが、Front Matter で明示的に指定することができます。

日付ベースの URL だと階層が深くなるので、シンプルな URL にしたい場合に活用できます。

例えば、blog/2023-04-03-markdown.mdx というファイルの Front Matter に以下の slug を指定をすると、URL は /blog/markdown/ になります。

---
slug: markdown
---

tags は、ブログ記事が属するタグを配列で指定します。

---
tags:
  - Markdown
  - MDX
---

タグのテンプレートはあらかじめ用意されているので、タグを追加すると以下のページが自動で生成されます。

  • タグに属する記事一覧
  • タグ一覧

タグに属する記事一覧

見出し「タグに属する記事一覧」

例えば、「お知らせ」というタグに属する記事一覧の見え方は以下のようになります。

タグ「お知らせ」に属する記事一覧のスクリーンショット

見出しの部分に注目すると『「お知らせ」タグの記事が1件件あります』と、「件」の表記が重複しますが、これは Docusaurus のローカライズの問題だと考えられます。

詳しい説明は割愛しますが、これを修正する方法としては以下が考えられます。

  1. docusaurus write-translations コマンドを実行して翻訳データ(JSON ファイル)を取得
  2. i18n/ja/code.jsontheme.blog.tagTitle を調整

注意する点としては、今後のアップデートでこの実装が変わった場合に影響を及ぼす可能性がある点と、翻訳データを取得すると、さきほど docusaurus.config.js で指定したサイドバーの見出し(blogSidebarTitle)が上書きされてしまう点です。

サイドバーの見出しについては、i18n/ja/docusaurus-plugin-content-blog/options.jsonsidebar.title を変更します。

タグ一覧は以下のようにタグの頭文字ごとに分類されます。

ただ、日本語で始まるタグの場合には、カタカナ・ひらがな・漢字で頭文字が分かれてしまうため、若干体裁が悪くなります。

タグ一覧のスクリーンショット
タグの頭文字ごとに分類される

Markdown は、基本的に「Markdown 編」で説明したのと同じ機能が使用できます。

blog/2023-04-03-markdown.mdx に、「Markdown 編」で作ったページと同等のサンプルページを追加していますが、具体的なコードは以下のとおりです。

サンプルページ
blog/2023-04-03-markdown.mdx
---
slug: markdown
authors:
  - brackets
  - duck
tags:
  - Markdown
  - MDX
draft: true
---

# Markdown サンプル

このページでは、ブログ記事で使用できる Markdown の記法をまとめています。

---

## 見出し

# 見出しレベル 1
## 見出しレベル 2
### 見出しレベル 3
#### 見出しレベル 4
##### 見出しレベル 5
###### 見出しレベル 6

<!--more-->

---

## 画像

![代替テキスト](/img/docusaurus.png)

画像は、以下の参照形式にも対応しています。

![代替テキスト][1]

[1]: /img/docusaurus.png

---

## テキスト

次の空行までのテキストのまとまりが段落テキストとして扱われます。

行末の半角スペース 2 つで  
改行できます。

**強調テキスト**(strong)

*強調テキスト*(em)

~~取り消し線~~(del)

---

## リンク

[Markdown Features | Docusaurus](https://docusaurus.io/docs/markdown-features)

リンクは、以下の参照形式にも対応しています。

[Markdown Features | Docusaurus][2]

[2]: https://docusaurus.io/docs/markdown-features

URL 形式やメール形式のテキストは、自動的にリンクが付与されます。

www.example.com  
https://example.com  
[email protected]

---

## リスト

- リスト項目
- リスト項目
    - リスト項目
- リスト項目

1. リスト項目
2. リスト項目
3. リスト項目

---

## コード

以下は `sidebars.js` の例です。

```js
const sidebars = {
  tutorialSidebar: [
    {
      type: 'autogenerated',
      dirName: '.'
    }
  ],
};

module.exports = sidebars;
```

---

## 引用

> The power of the Web is in its universality.  
> Access by everyone regardless of disability is an essential aspect.

— Tim Berners-Lee, W3C Director and inventor of the World Wide Web

---

## タスクリスト

- [x] タスク 1
- [ ] タスク 2
- [x] タスク 3

---

## 表

| 見出しセル | 見出しセル |
| --- | --- |
| データセル | データセル |
| データセル | データセル |
| データセル | データセル |

| 左揃え | 中央揃え | 右揃え |
| :--- | :---: | ---: |
| foo | foo | foo |
| foo bar | foo bar | foo bar |
| foo bar baz | foo bar baz | foo bar baz |

---

## コードブロック(拡張機能)

### タイトル

```js title="sidebars.js"
const sidebars = {
  tutorialSidebar: [
    {
      type: 'autogenerated',
      dirName: '.'
    }
  ],
};

module.exports = sidebars;
```

### 行ハイライト

```js
const sidebars = {
  tutorialSidebar: [
    {
      type: 'doc',
      // highlight-next-line
      id: 'index',
    },
    {
      type: 'doc',
      id: 'information',
    },
    // highlight-start
    {
      type: 'doc',
      id: 'markdown',
    },
    // highlight-end
  ],
};

module.exports = sidebars;
```

### 行番号

```js showLineNumbers
const sidebars = {
  tutorialSidebar: [
    {
      type: 'doc',
      id: 'index',
    },
    {
      type: 'doc',
      id: 'information',
    },
    {
      type: 'doc',
      id: 'markdown',
    },
  ],
};

module.exports = sidebars;
```

### Docusaurus npm2yarn remark plugin

```bash npm2yarn
npm install @docusaurus/remark-plugin-npm2yarn
```

---

## 折りたたみ要素

<details>
  <summary>アコーディオン</summary>
  <p><code>&lt;details&gt;</code> と <code>&lt;summary&gt;</code> のスタイルが用意されています。</p>
</details>

---

## Admonitions

:::note

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

:::tip

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

:::info

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

:::caution

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

:::danger

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

:::note メモ

[Docusaurus](#) は、*React ベース*でつくられた**ドキュメントサイト**に特化した `SSG` です。

:::

---

## 脚注

脚注[^1]を加えることができます[^2]

[^1]: 脚注の例です。
[^2]: **脚注内***一部*[`Markdown` 記法](#)を使用できます。

---

## タブ

<Tabs>
  <TabItem value="html" label="HTML" default>
    HTML は HyperText Markup Language の略語です。
  </TabItem>
  <TabItem value="css" label="CSS">
    CSS は Cascading Style Sheets の略語です。
  </TabItem>
  <TabItem value="svg" label="SVG">
    SVG は Scalable Vector Graphics の略語です。
  </TabItem>
</Tabs>

`groupId` 属性の値をそろえることで、タブの切り替えを同期させることができます。

<Tabs groupId="operating-systems">
  <TabItem value="win" label="Windows">
    <b>Ctrl + C</b> で選択したテキストをコピーできます。
  </TabItem>
  <TabItem value="mac" label="macOS">
    <b>Command + C</b> で選択したテキストをコピーできます。
  </TabItem>
</Tabs>

<Tabs groupId="operating-systems">
  <TabItem value="win" label="Windows">
    <b>Ctrl + V</b> でコピーしたテキストをペーストできます。
  </TabItem>
  <TabItem value="mac" label="macOS">
    <b>Command + V</b> でコピーしたテキストをペーストできます。
  </TabItem>
</Tabs>

---

## カスタムコンポーネント

import Marker from '@site/src/components/Marker';

HTML は <Marker>HyperText Markup Language</Marker> の略語です。

CSS は <Marker color="cyan">Cascading Style Sheets</Marker> の略語です。

SVG は <Marker color="pink">Scalable Vector Graphics</Marker> の略語です。

前回も述べましたが、Markdown の記法で画像を指定した場合、Docusaurus では loading="lazy"widthheight が自動的に付与されます。

パフォーマンスの向上が見込める反面、ファーストビュー(Above the fold)に配置される画像の LCP を悪化させる要因にもなるので注意が必要です。

解決案としては、ファーストビューに表示されるヒーローイメージを、Markdown 形式ではなく <img /> タグで直接指定する方法や、画像最適化のプラグイン「plugin-ideal-image」を使用する方法が考えられます。

以下はプラグインを使用する方法です。

ヒーローイメージをプラグインで指定する例
import Image from '@theme/IdealImage';
import heroImage from './img-docusaurus-site.webp'

<Figure
  img={heroImage}
  alt="Docusaurus 公式サイトのスクリーンショット"
  loading="eager"
  fetchpriority="high"
/>

しかし、この指定は記事一覧でも反映されてしまうため、スクロールして表示される下方に位置する記事の画像についても、loading="eager"fetchpriority="high" の指定が有効になり、パフォーマンスを悪化させる副作用があります。

ブログではヒーローイメージを使用するケースが多いので、LCP の課題については認識しておいたほうがよいでしょう。

なお、この課題は以下の GitHub Issue でも取り上げられており、Docusaurus の MDX を v2 にアップグレードした後に検討するようです。ただし、対応できるかどうかは未定のようです。

最後に docusaurus.config.js で設定した、truncateMarker の機能を確認します。

設定ファイルでは、正規表現で /<!--\s*(more)\s*-->/ と指定しましたが、これは more の前後に空白文字が含まれていても許容される指定です。

以下のように指定することで、記事一覧で表示されるのは <!--more--> より後ろの部分が省略されます。

blog/2023-04-18-docusaurus/index.mdx
# Docusaurus について

この「CMS 操作ガイド」は [Docusaurus](https://docusaurus.io/) でつくられています。

Docusaurus は、Meta 社が開発する、React ベースのドキュメントサイトに特化した静的サイトジェネレータ(SSG、Static Site Generator)です。

![Docusaurus 公式サイトのスクリーンショット](./img-docusaurus-site.webp)

<!--more-->

## Docusaurus の特徴

Docusaurus のおもな特徴や機能は以下のとおりです。
ブログ記事一覧のスクリーンショット
記事一覧では <!—more—> より後ろが省略される

このシリーズでは、Docusaurus の基本機能を取り上げてきました。

初回の「導入編」でも書きましたが、ドキュメントサイト向けの気の利いた機能がそろっており、ほとんど迷うことなく、直感的にサイトを構築できました。

その反面、コンポーネントやスタイルを細かくコントロールするのは難しいようです。カスタマイズ性は決して低くないのですが、Docusaurus の作法から外れると複雑になる印象です。その辺は割り切って使うのがよいのかもしれません。

コンポーネントのカスタマイズ(Swizzling)や、スタイルを調整する手段もありますが、アップデート時の影響を受ける可能性があるので、メンテナンス性とのトレードオフになります。

なお、このシリーズでは、以下の機能にはほとんど触れられなかったので、興味があれば公式ドキュメントで調べてみてください。

  • 多言語対応(i18n)
  • バージョニング
  • 検索機能(Algolia)
  • コンポーネントの高度なカスタマイズ(Swizzling)
  • プラグインの使い方

このシリーズの記事を書くきっかけは、自身の Docusaurus の知識を深めるためでしたが、これを読んだ方にとっても、なんらかのヒントになれば幸いです。

ここまでお読みいただきありがとうございました。