🌸

microCMSのコードブロックをShikiで彩る

2025/01/25に公開

はじめに

最近自分のブログサイトにコードハイライターのShikiを導入したので、microCMSで入稿したコンテンツをShikiで彩ったときにやったことを書いていこうと思います
Shiki Transformer Copy Buttonを使ってコピーボタンも追加します

前提

今回使ったフレームワーク、ライブラリは以下です

  • Astro 5.1.1
  • Cheerio 1.0.0
  • Shiki 1.26.2
  • Shiki Copy Button 0.0.3

彩っていく

それでは彩っていきます
ShikiはAstroにデフォルトで組み込まれていますが、今回は事前にShikiでハイライトしたものを表示側に渡すため別でインストールしておきます
上記の対応をするのでAstro以外のフレームワークでもおそらくそのまま使えると思います(使えなかったらすみません)

事前準備

cheerioとShikiとShiki Copy Buttonを追加します

pnpm i cheerio
pnpm i -D shiki shiki-transformer-copy-button

CheerioとShikiで彩る

CheerioでmicroCMSから渡されるコンテンツをHTMLにし、その後Shikiでハイライトしてもらい、元のコードブロックを置き換えたら表示側に渡します
microCMSのエディタで選択できる言語はcodeタグのクラス名として渡されるので、クラス名から抜き出してShikiに渡します
microCMSから渡されるリッチエディタのコンテンツは post.content に入っていますが、ご自身の環境に合わせて変えてください

const { post } = Astro.props

const promise: any = []
const $ = load(post.content)
$("pre").each(function (this: cheerio.Element) {
    const element = $(this)
    // 言語名を取得
    const lang = element.find("code")?.attr("class")?.replace("language-", "")

    // preタグをShikiに渡してハイライトしてもらう
    const code = codeToHtml(element.text(), {
        lang: lang ?? "plaintext", // 言語名
        theme: "dark-plus", // Shikiのテーマ
        transformers: [addCopyButton({ toggle: 3000 })], // コピーボタンを付与
    }).then((highlight) => {
        // 元のpreタグを置き換える
        element.replaceWith(highlight)
    })
    promise.push(code)
})
await Promise.all(promise)

// 表示側に渡すための整形済みコンテンツ
const formattedContent = $.html()

これでコードがハイライトされたHTMLが生成されました

あとは表示させたい場所に生成したHTMLを埋め込みます

<div class="contents" set:html={formattedContent} />

コピーボタンのスタイリング

このままでは追加したコピーボタンが何も表示されないので、コピーボタンのスタイリングをしていきます
コピーボタンのアイコンは https://www.svgrepo.com/ から頂戴したものを public/icons 配下に置いています

pre {
    position relative;
}

.copy {
    position: absolute;
    right: 16px;
    top: 16px;
    height: 28px;
    width: 28px;
    padding: 0;
    display: flex;

    & span {
        width: 100%;
        aspect-ratio: 1 / 1;
        background-repeat: no-repeat;
        background-position: center;
        background-size: cover;
    }

    & .ready {
        background-image: url(/icons/copy.svg);
        opacity: 0.4;
        transition: 0.1s;

        &:hover {
            opacity: 1;
        }
    }

    & .success {
        display: none;
        background-image: url(/icons/success.svg);
    }

    &.copied {
        & .success {
            display: block;
        }

        & .ready {
            display: none;
        }
    }
}

完成

実際にブログを表示してみると、以下のように彩られたコードブロックが表示され、右上にコピーボタンも表示されているかと思います

コードブロック

おわりに

今回のコードの全体像は以下から確認できます

https://github.com/shibaTT/astro-microcms-netlify-blog/blob/main/src/pages/[category]/[post].astro

ブログの方ではファイル名も表示する処理を入れているため、ちょっとだけコードが違っていますので、もしファイル名を表示する処理も参考にしたい方がいたら全体のコードを見ていただけるとよいかと思います

microCMS以外の記事ももっと書きたいけどネタがないですね~

Discussion