microCMSブログ

microCMSの最新情報や活用事例などをお届けします。

エンジニアリング

リッチエディタをより扱いやすくするライブラリの紹介

リッチエディタをより扱いやすくするライブラリの紹介
千葉大輔 千葉大輔

はじめに

microCMSのリッチエディタは、見出し、太字、リンク、画像、コードブロックなどを管理画面上で直感的に入力でき、APIからは表示に使いやすいHTMLとして受け取ることができます。

一方で、実際のWebサイトに組み込むときには、HTMLをそのまま表示するだけでは少し物足りない場面があります。

たとえば、次のようなことをやりたくなるのではないでしょうか。

  • リッチエディタ内の画像をレスポンシブ画像にしたい
  • WebPなどのフォーマットを使って画像配信を最適化したい
  • コードブロックにシンタックスハイライトを適用したい
  • 見出しから目次を作りたい
  • リッチエディタHTMLに対する独自の加工処理を追加したい

こうした処理は、もちろんアプリケーション側で個別に実装することもできます。(それがしやすいのもヘッドレスCMSの良さでもありますよね)

ただ、プロジェクトごとに同じようなHTML加工処理を書いていたり、ページコンポーネントの中に後処理のロジックが散らばっていたりすると、だんだん見通しが悪くなっていきます。

これらの課題に対して、microCMS公式が提供している microcms-rich-editor-handler を使用することで、よりシンプルで簡単にHTMLをカスタマイズすることができますので、このパッケージの使用方法や具体的なコード例の紹介をさせていただきます。

前提知識

次の内容について、ある程度理解していることを想定して進めます。

  • microCMSのリッチエディタと、APIからHTML文字列を取得する流れ
  • npmによるパッケージのインストール
  • TypeScriptおよびReactコンポーネントの基本的な書き方

microcms-rich-editor-handler とは

microcms-rich-editor-handler は、microCMSのリッチエディタHTMLを処理するためのユーティリティパッケージです。

大きく分けると、次の2種類の処理を扱えます。

  • HTMLを変換する処理
  • HTMLからデータを抽出する処理

HTMLを変換する処理は、 img タグを picture タグに変換したり、コードブロックにシンタックスハイライトを適用したりする用途で使えます。

HTMLからデータを抽出する処理は、見出し要素から目次データを作るといった用途で使えます。

このように、リッチエディタに対する「表示前のひと手間」を、アプリケーション側に散らばらせず、まとまった形で扱えるのが特徴です。

インストール

まずはパッケージをインストールします。
(npm以外を使用している方は適宜それらのパッケージマネージャのやり方でインストールしてください)

npm install microcms-rich-editor-handler

基本的な使い方

基本的な使い方は、microCMSから取得したリッチエディタのHTML文字列を microCMSRichEditorHandler に渡すだけです。

import {
  microCMSRichEditorHandler,
  responsiveImageTransformer,
  tocExtractor,
} from 'microcms-rich-editor-handler';

const { html, data } = await microCMSRichEditorHandler(content, {
  transformers: [responsiveImageTransformer()],
  extractors: {
    toc: [tocExtractor(), { phase: 'before' }],
  },
});

console.log(html);
console.log(data.toc);

html には変換後のHTML文字列が入ります。

data には、Extractor によって抽出されたデータが入ります。上の例では tocExtractor を使っているため、data.toc から目次データを取得できます。

Transformer と Extractor

microcms-rich-editor-handler の根幹の仕組みとして、TransformerExtractor があります。

Transformer

Transformer は、HTMLを変換するための処理です。
HTMLをそのまま表示するのではなく、サイト側の表示要件に合わせて調整したいときに使います。

Extractor

Extractor は、HTMLから必要なデータを抽出するための処理です。
HTMLそのものを変換するのではなく、HTMLをもとに別のデータを作りたいときに使います。

またphaseはbeforeとafterを指定でき、Transformerの処理を動かした後に抽出処理を行うのか、動かす前に行うのかを決定するためのものです。
抽出処理がTransformerの処理に影響を受ける場合はbeforeを設定したり、逆にTransformerの処理後に抽出したい場合はafterを指定します。
(デフォルトはafterです)


この2つが分かれていることで、「HTMLをどう変換するか」と「HTMLから何を取り出すか」を整理して扱えるようになります。

次のセクションからは、ユースケースごとに具体的なコード例を交えて紹介していきます。

ユースケース1:画像を最適化する

リッチエディタ内で画像を扱う場合、APIから取得したHTMLには img タグが含まれます。

そのまま表示しても問題ありませんが、実際のサイトでは次のようなことを考えたくなることがあります。

  • 画面幅に応じて適切な画像サイズを配信したい
  • WebPなどのフォーマットを使いたい
  • 不要に大きな画像を読み込まないようにしたい
  • 表示パフォーマンスを改善したい

こうしたときに responsiveImageTransformer を使うと、リッチエディタ内の画像をレスポンシブ画像に変換できます。
(ここでのレスポンシブ画像は解像度の切り替えを指します)

import {
  microCMSRichEditorHandler,
  responsiveImageTransformer,
} from 'microcms-rich-editor-handler';

const { html } = await microCMSRichEditorHandler(content, {
  transformers: [responsiveImageTransformer({
    attributes: {
      sizes: 'auto', // sourceやimgタグに指定されるsizes属性を指定します。何も指定しない場合は100vwがデフォルトで入ります。
    },
    formats: ['default', 'avif'], // サポートする画像の拡張子を指定します。右に行くほど優先度的に表示を試みる拡張子になります。
    deviceSizes: [640, 768, 1024, 1280], // srcsetに含める画像の幅のリストを指定します。
  })],
});

上記の例だと取得できるHTMLは以下のようになります。

<picture>
 <source 
   type="image/avif"
   srcset="https://images.microcms-assets.io/assets/image.png?w=640&fm=avif 640w, https://images.microcms-assets.io/assets/image.png?w=768&fm=avif 768w, https://images.microcms-assets.io/assets/image.png?w=1024&fm=avif 1024w, https://images.microcms-assets.io/assets/image.png?w=1280&fm=avif 1280w"
   width="1200"
   height="600"
   sizes="auto"
 >
 <img 
   src="https://images.microcms-assets.io/assets/image.png?w=1200"
   srcset="https://images.microcms-assets.io/assets/image.png?w=640 640w, https://images.microcms-assets.io/assets/image.png?w=768 768w, https://images.microcms-assets.io/assets/image.png?w=1024 1024w, https://images.microcms-assets.io/assets/image.png?w=1280 1280w"
   alt=""
   loading="lazy"
   decoding="async"
   sizes="auto"
   width="1200"
   height="600"
 >
</picture>

AVIFをサポートしているブラウザにおいてはそちらを優先して表示して、それ以外のブラウザではmicroCMSにアップロードされている拡張子のまま配信します。
そして、sizesauto なのでその img タグが配置されているレイアウトサイズに応じて、640から1280サイズの画像から自動的に選択されます。
またデフォルトで loading=lazy に設定されるので遅延読み込みになります。

※microCMSにアップロードした画像はImgixのRendering APIを利用してフォーマットやサイズ変換を行うことができ、それを活用することでレスポンシブ画像を実現しています。画像APIの詳細についてはドキュメントサイトをご確認ください。

ユースケース2:コードブロックにシンタックスハイライトを適用する

技術ブログやドキュメントサイトでは、本文中にコードブロックを載せたい場面がありますよね。
microCMSのリッチエディタではコードブロックを入力できますが、表示側ではシンタックスハイライトを適用したいかと思います。

microcms-rich-editor-handler を使うと、コードブロックに対する変換処理も Transformer として扱えます。

import {
  microCMSRichEditorHandler,
  syntaxHighlightingByShikiTransformer,
} from 'microcms-rich-editor-handler';

const { html } = await microCMSRichEditorHandler(content, {
  transformers: [
    syntaxHighlightingByShikiTransformer({
      highlightOptions: {
        javascript: {
          lang: "javascript",
          theme: "github-dark",
        },
      },
      defaultHighlightOptions: {
        lang: "text",
        theme: "vitesse-dark",
      },
    }),
  ],
});

また、この syntaxHighlightingByShikiTransformer を使用する場合は shiki というパッケージが追加で必要になります。

npm install shiki

使えるテーマは shiki のドキュメントサイトをご確認ください。

補足:Shiki とクライアントバンドル

syntaxHighlightingByShikiTransformer を使う場合、追加で shiki パッケージが必要です。
Shiki はテーマや言語定義を含むため、ブラウザ向けの JavaScript バンドルに含めるとサイズが大きくなりやすい点に注意してください。

本パッケージの変換処理は、microCMS から取得した HTML を表示用に加工してからページコンポーネントなどに渡す用途を想定しています。
そのため、Next.js の Server Component や Astro のフロントマター、SSG のビルド時など、サーバー側で HTML を生成するタイミングで適用するのがおすすめです。
変換後の HTML にはハイライト済みの pre / code が含まれるため、クライアント側で Shiki を動かす必要はありません。

ユースケース3:見出しから目次を生成する

本文中の見出しから目次リストを作る際も便利なものを用意しています。

microCMSのリッチエディタでは、見出し要素に id が付与されます。
そのため、そのidをページ内リンクとして使用すれば目次リストを作れます。

import {
  microCMSRichEditorHandler,
  tocExtractor,
} from 'microcms-rich-editor-handler';

const { data } = await microCMSRichEditorHandler(content, {
  extractors: {
    toc: [tocExtractor(), { phase: 'before' }],
  },
});

console.log(data.toc);

抽出した目次データ data.toc は、記事ページのサイドバーや本文上部のナビゲーションとして利用できます。

type TocItem = {
  id: string;
  text: string;
  level: number;
};

type Props = {
  toc: TocItem[];
};

export const TableOfContents = ({ toc }: Props) => {
  return (
    <nav aria-label="目次">
      <ul>
        {toc.map((item) => (
          <li key={item.id} className={`level-${item.level}`}>
            <a href={`#${item.id}`}>{item.text}</a>
          </li>
        ))}
      </ul>
    </nav>
  );
};

独自の処理を追加したい場合

リッチエディタに対して必要になる処理はプロジェクトによって異なるかと思いますが、このライブラリがすでに用意しているTransformerExtractor以外にも独自でそれらを作成して使用することができます。

ユースケース:PDF リンクを抽出する

たとえば、記事本文中に PDF へのリンクが散在しているものの、ページ下部に「関連資料」として一覧表示したい、というケースを考えてみます。

この場合、HTML 自体を書き換える必要はなく、リンク情報だけを取り出せれば十分です。
なので目次生成(tocExtractor)と同様に、Extractor として切り出します。

まずはPDF リンクを抽出する Extractor を定義します。

pdfLinkExtractor.ts
import type { Extractor } from 'microcms-rich-editor-handler';

type PdfLink = { href: string; label: string };

export const pdfLinkExtractor: Extractor<PdfLink[]> = ($) => {
  const links: PdfLink[] = [];

  $('a[href$=".pdf"]').each((_, element) => {
    const $el = $(element);
    const href = $el.attr('href');
    if (href) {
      links.push({ href, label: $el.text().trim() || href });
    }
  });

  return links;
};

この Extractor を microCMSRichEditorHandler に登録すると、目次データとあわせて PDF リンクも取得できます。

import {
  microCMSRichEditorHandler,
  responsiveImageTransformer,
  tocExtractor,
} from 'microcms-rich-editor-handler';
import { pdfLinkExtractor } from './pdfLinkExtractor';

const { html, data } = await microCMSRichEditorHandler(content, {
  transformers: [responsiveImageTransformer()],
  extractors: {
    toc: [tocExtractor(), { phase: 'before' }],
    pdfLinks: [pdfLinkExtractor],
  },
});

// html → 本文表示
// data.toc → 目次
// data.pdfLinks → 「関連資料」コンポーネントに渡す

抽出した data.pdfLinks は、記事ページのコンポーネントに渡して表示します。

RelatedDocuments.tsx
type Props = { pdfLinks: { href: string; label: string }[] };

export const RelatedDocuments = ({ pdfLinks }: Props) => {
  if (pdfLinks.length === 0) return null;

  return (
    <aside aria-label="関連資料">
      <h2>関連資料</h2>
      <ul>
        {pdfLinks.map((link) => (
          <li key={link.href}>
            <a href={link.href} target="_blank" rel="noopener noreferrer">
              {link.label}
            </a>
          </li>
        ))}
      </ul>
    </aside>
  );
};

このようにリッチエディタに関する処理をシンプルにまとめられるのも microcms-rich-editor-handler を使うメリットかなと思います。

まとめ

microCMSのリッチエディタはHTMLとしてコンテンツを取得できるためとても便利になっています。
一方で、実際のWebサイトに表示する際には、画像最適化、シンタックスハイライト、目次生成など、もう一段の後処理が必要になることがあります。

microcms-rich-editor-handler を使うと、こうしたリッチエディタの後処理を TransformerExtractor として整理できます。

リッチエディタをそのまま表示するだけでなく、サイトの要件に合わせて扱いやすくしたい場合は、
ぜひ microcms-rich-editor-handler を試してみてください。

まずは、無料で
試してみましょう。

microCMSは無料ではじめられます。
ご不明な点はお気軽にお問い合わせください。