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