eallion

大大的小蜗牛

机会总是垂青于有准备的人!
mastodon
github
twitter
steam
telegram
keybase
email

Hugo で Shiki を使用する

Hugo 以外の Hexo などの他の静的ブログでもこの方法を使用できます。

公式紹介#

Shiki(式、意味は「スタイル」)は、美しく強力なコードシンタックスハイライターで、VS Code のシンタックスハイライトエンジンと同様に、TextMate のシンタックスとテーマに基づいています。Shiki は、ほぼすべての主要なプログラミング言語に対して非常に正確かつ迅速なシンタックスハイライトを提供します。

カスタムの正規表現を維持する必要も、カスタムの CSS を維持する必要も、カスタムの HTML を維持する必要もありません。なぜなら、VS Code で使用しているカラーテーマを Shiki でも使用できるからです。

利点#

Hugo で Shiki コードシンタックスハイライターを設定するのに数分しかかかりません。

私が最も気に入っている点は、他のコードシンタックスハイライターのように大規模な JS リソースを導入する必要がなく、Shiki は HTML ファイルに書き込まれ、純静的です。Hugo ブログプロジェクトは、@shikijs/rehypeプラグインを利用して Shiki コードシンタックスハイライトを実現でき、ローカルまたは GitHub Actions などのビルドプラットフォームで簡単にデプロイできます。

Shiki のインストール#

Hugo ブログのプロジェクトディレクトリに移動し、次のものをインストールします:

前提条件として、Node.jsYarnをインストールする必要があります。Yarnを選択するのは、GitHub Actions のキャッシュに優しいからです。

# cd my-hugo-project

npm install shiki
npm install @shikijs/rehype
npm install rehype-cli

Hugo の設定#

Hugo の config で、codeFencesfalseに設定する必要があります。

[markup]
  [markup.highlight]
    codeFences = false

.rehypercの作成#

Hugo ディレクトリに.rehypercファイルを作成し、私の設定内容は以下の通りです:

{
  "plugins": [
    [
      "@shikijs/rehype",
      {
        "themes": {
          "light": "github-light",
          "dark": "github-dark-dimmed"
        }
      }
    ]
  ]
}

Rehype には多くのプラグインがありますが、私はハイライトテーマだけを設定しました。lightモードにはgithub-lightを、darkモードにはgithub-dark-dimmedを使用しています。GitHub のテーマは常に信頼できます。

テーマリストはこちら: https://shiki.tmrs.site/themes

ダークモードを有効にするには、元の Hugo の CSS を適応させる必要があるかもしれません。例えば、私のブログでは<html class="dark">の方法でダークテーマを切り替えていますので、custom.cssにテーマカラー変数を追加するだけで済みます:

html.dark .shiki,
html.dark .shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* オプション、フォントスタイルを定義するため */
    /* font-style: var(--shiki-dark-font-style) !important; */
    /* font-weight: var(--shiki-dark-font-weight) !important; */
    /* text-decoration: var(--shiki-dark-text-decoration) !important; */
}

prefers-color-scheme: darkの方法でダークモードを切り替える場合は、これらの変数を簡単に適応させるだけで済みます:

.shiki,
.shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* オプション、フォントスタイルを定義するため */
    /* font-style: var(--shiki-dark-font-style) !important; */
    /* font-weight: var(--shiki-dark-font-weight) !important; */
    /* text-decoration: var(--shiki-dark-text-decoration) !important; */
}

Shiki の生成#

まず、hugoコマンドを実行して Hugo を構築します。構築された成果物がpublic/ディレクトリにあると仮定し、次にrehype-cliを使用して Shiki を生成します:

# cd my-hugo-project

npx rehype-cli public -o

このコマンドを実行すると、メモリエラーが発生する可能性があります:

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

メモリ使用量を制限する必要があります:

export NODE_OPTIONS="--max_old_space_size=7168"

7168 ≈ 7G、コンピュータの構成に応じて調整できますが、GitHub Actions の無料ランナーは最大 7G です。

GitHub Actions で Shiki を使用する#

Hugo ディレクトリのpackage.jsonscriptsに次のように追加します:

  "scripts": {
    "shiki": "npx rehype-cli public -o"
  },

GitHub Actions ワークフロー:

name: Build Hugo and Deploy With Shiki

on:
  workflow_dispatch:

jobs:
  build-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'
          extended: true

      - name: Build Hugo
        run: |
          hugo -gc --minify

      - name: Setup Node LTS
        uses: actions/setup-node@v4
        with:
          node-version: 20.x
          cache: yarn

      - name: Install and run Shiki
        run: |
          export NODE_OPTIONS="--max_old_space_size=7168"
          yarn install
          yarn run shiki || true
          # または 👇
          # npx rehype-cli public -o --silent || true

      - name: Keep going
        # 後続のプロセス

Shiki のエラーによって Hugo のデプロイプロセスが中断されるのを防ぐために、|| trueを追加することができます。エラーが発生してもデプロイプロセスは続行されます。一般的なエラーは、以前のブログ記事がサポートされていないコード名を使用している場合です。

Cloudflare Pages ではメモリ制限を設定できないため、cloudflare/wrangler-actionという Actions を使用できます:

      - name: Publish to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          quiet: true
          command: pages deploy public --project-name=${{ secrets.CLOUDFLARE_PROJECT_NAME }} --commit-dirty=true
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。