eallion

大大的小蜗牛

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

Using Shiki in Hugo

This method can also be used in other static blogs like Hexo.

Official Introduction#

Shiki (式,a Japanese word meaning "style") is a beautiful and powerful code syntax highlighter that, like the syntax highlighting engine of VS Code, is based on TextMate's syntax and themes. Shiki provides very accurate and fast syntax highlighting for almost all mainstream programming languages.

You do not need to maintain custom regular expressions, custom CSS, or custom HTML; because the color themes you use in VS Code can also be used in Shiki.

Advantages#

You can configure the Shiki code syntax highlighter in Hugo in just a few minutes.

What I like most about it is that, unlike other code syntax highlighters that require large JS resources, Shiki is written directly into the HTML file and is purely static. Hugo blog projects can utilize the @shikijs/rehype plugin to implement Shiki code syntax highlighting, making it easy to deploy on local or build platforms like GitHub Actions.

Installing Shiki#

Navigate to the Hugo blog project directory and install:

You need to have Node.js and Yarn installed. Choosing Yarn is friendly for its GitHub Actions cache.

# cd my-hugo-project

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

Configuring Hugo#

In the Hugo config, you must set codeFences to: false

[markup]
  [markup.highlight]
    codeFences = false

Creating .rehyperc#

Create a .rehyperc file in the Hugo directory. My configuration content is as follows:

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

Rehype has many plugins, but I only configured the highlight themes, using github-light for light mode and github-dark-dimmed for dark mode. GitHub's themes are always reliable.

The theme list is here: https://shiki.tmrs.site/themes

To enable dark mode, you may need to adapt your original Hugo CSS a bit. For example, my blog uses <html class="dark"> to switch to dark mode, so I just need to add theme color variables in custom.css:

html.dark .shiki,
html.dark .shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* Optional, for defining font styles */
    /* font-style: var(--shiki-dark-font-style) !important; */
    /* font-weight: var(--shiki-dark-font-weight) !important; */
    /* text-decoration: var(--shiki-dark-text-decoration) !important; */
}

If you switch to dark mode using prefers-color-scheme: dark, you can simply adapt these variables:

.shiki,
.shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* Optional, for defining font styles */
    /* font-style: var(--shiki-dark-font-style) !important; */
    /* font-weight: var(--shiki-dark-font-weight) !important; */
    /* text-decoration: var(--shiki-dark-text-decoration) !important; */
}

Generating Shiki#

First, run the hugo command to build Hugo, assuming the build output is in the public/ directory, then use rehype-cli to generate Shiki:

# cd my-hugo-project

npx rehype-cli public -o

Running this command may lead to memory errors:

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

You need to limit memory usage:

export NODE_OPTIONS="--max_old_space_size=7168"

7168 ≈ 7G, you can adjust according to your computer's configuration, but the maximum for GitHub Actions free runners is 7G.

Using Shiki in GitHub Actions#

In the Hugo directory, add to the package.json scripts:

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

GitHub Actions Workflow:

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
          # or 👇
          # npx rehype-cli public -o --silent || true

      - name: Keep going
        # Subsequent processes

To prevent Shiki errors from interrupting the Hugo deployment process, you can add || true, so that even if an error occurs, the deployment process will continue. Common errors may arise from previous blog posts that might have used unsupported code names.

Currently, Cloudflare Pages cannot configure memory limits, but you can use the cloudflare/wrangler-action action:

      - 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
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.