diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec3ca6d23a8..406a5cc50ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,17 +29,17 @@ jobs: run: | hugo --cleanDestinationDir --forceSyncStatic --gc --ignoreCache --minify --enableGitInfo --templateMetrics --templateMetricsHints - # - name: Setup Node LTS - # uses: actions/setup-node@v4 - # with: - # node-version: 20.x - # cache: yarn + - 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 syntax || true + - name: Install and run Shiki + run: | + export NODE_OPTIONS="--max_old_space_size=7168" + npm install + npm run shiki || true # - name: Deploy to GitHub Pages # uses: peaceiris/actions-gh-pages@v4 diff --git a/.gitignore b/.gitignore index 763891d5846..d41bf974ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ static/node_modules bun.lockb package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/config/_default/markup.toml b/config/_default/markup.toml index 7658d04ce98..d740d0b7be4 100644 --- a/config/_default/markup.toml +++ b/config/_default/markup.toml @@ -5,9 +5,11 @@ [goldmark.renderer] unsafe = true hardWraps = true +[goldmark.parser.attribute] + block = true [highlight] - codeFences = true + codeFences = false guessSyntax = true lineNos = false lineNumbersInTable = true diff --git a/content/blog/code/hugo-syntax-highlight-shiki/background.jpg b/content/blog/code/hugo-syntax-highlight-shiki/background.jpg new file mode 100644 index 00000000000..2a1b779a413 Binary files /dev/null and b/content/blog/code/hugo-syntax-highlight-shiki/background.jpg differ diff --git a/content/blog/code/hugo-syntax-highlight-shiki/featured.png b/content/blog/code/hugo-syntax-highlight-shiki/featured.png new file mode 100644 index 00000000000..ea104a811a6 Binary files /dev/null and b/content/blog/code/hugo-syntax-highlight-shiki/featured.png differ diff --git a/content/blog/code/hugo-syntax-highlight-shiki/index.md b/content/blog/code/hugo-syntax-highlight-shiki/index.md new file mode 100644 index 00000000000..71ed1b58d04 --- /dev/null +++ b/content/blog/code/hugo-syntax-highlight-shiki/index.md @@ -0,0 +1,188 @@ +--- +title: "在 Hugo 中使用 Shiki" +authors: ["eallion"] +categories: ["代码"] +tags: + - Hugo + - Highlight + - Shiki + - 高亮 +slug: "hugo-syntax-highlight-shiki" +summary: "本文介绍了如何在 Hugo 中使用 Shiki 代码语法高亮器。Shiki 是一款美观而强大的代码语法高亮器,基于 TextMate 的语法和主题,并能为几乎所有主流编程语言提供准确且快速的语法高亮。与其他代码语法高亮器不同,Shiki 是纯静态的,无需引入庞大的 JS 资源。文章详细介绍了在 Hugo 项目中安装和配置 Shiki 的步骤,包括安装相关插件、设置 Hugo 配置文件以及创建.rehyperc 文件来配置高亮主题等。此外,还提供了适配暗黑模式和生成 Shiki 所需命令行操作等内容。最后还介绍了如何在 GitHub Actions 中使用 Shiki 进行部署,并给出了相应的工作流程示例。" +draft: false +date: 2024-08-15T22:42:21+08:00 +# images: ["/assets/images/og/在-hugo-中使用-shiki-代码语法高亮器.png"] # Delete this line +--- + +### 官方简介 + +[Shiki](https://github.com/shikijs/shiki)(式,一个日语词汇,意为 “样式”) 是一款美观而强大的代码语法高亮器,它与 VS Code 的语法高亮引擎一样,基于 TextMate 的语法及主题。Shiki 能为几乎所有主流编程语言提供非常准确且快速的语法高亮。 + +你不需要维护自定义的正则表达式,不需要维护自定义的 CSS,也不需要维护自定义的 HTML;因为你在 VS Code 中使用的颜色主题一样可以用在 Shiki 上。 + +### 优势 + +只需几分钟即可在 Hugo 配置好 Shiki 代码语法高亮器。 + +我最喜欢它的一点是,它不像其他代码语法高亮器需要引入体积庞大的 JS 资源,Shiki 是写入 HTML 文件的,是纯静态的。Hugo 博客项目可以利用 [@shikijs/rehype](https://github.com/rehypejs/rehype) 插件实现 Shiki 代码语法高亮,在本地或 GitHub Actions 等构建平台都能轻松部署交付。 + +### 安装 Shiki + +进入到 Hugo 博客的项目目录,安装: + +- [`shiki`](https://github.com/shikijs/shiki) +- [`@shikijs/rehype`](https://github.com/rehypejs/rehype) +- [`rehype-cli`](https://github.com/rehypejs/rehype/tree/main/packages/rehype-cli) + +前提是需要安装 `Node.js` 和 `Yarn` 。选择 `Yarn` 是它的 GitHub Actions 缓存友好。 + +```bash +# cd my-hugo-project + +npm install shiki +npm install @shikijs/rehype +npm install rehype-cli +``` + +### 配置 Hugo + +在 Hugo 的 config 中必须将 [`codeFences`](https://gohugo.io/getting-started/configuration-markup/#highlight) 设置为:`false` + +```toml +[markup] + [markup.highlight] + codeFences = false +``` + +### 创建 `.rehyperc` + +在 Hugo 目录中创建 `.rehyperc` 文件,我的配置内容如下: + +```txt +{ + "plugins": [ + [ + "@shikijs/rehype", + { + "themes": { + "light": "github-light", + "dark": "github-dark-dimmed" + } + } + ] + ] +} +``` + +Rehype 有很多 [插件](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) ,但我只配置了高亮主题,`light` 模式用的是 `github-light`,`dark` 模式用的是 `github-dark-dimmed` ,GitHub 的主题永远值得相信。 + +主题列表在这里: [https://shiki.tmrs.site/themes](https://shiki.tmrs.site/themes) + +让暗黑模式生效,可能需要在原来的 Hugo 的 CSS 中适配一下,比如我的博客用的是 `` 的方式来切换暗黑主题的,只需要在 [custom.css](https://github.com/eallion/eallion.com/blob/4776202069b6a1c570bf00bd697a367502f95c41/assets/css/custom.css#L11-L19) 中加入主题颜色变量即可: + +```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` 的方式切换暗黑模式,简单适配一下这几个变量即可: + +```css +.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`](https://github.com/rehypejs/rehype/tree/main/packages/rehype-cli) 生成 Shiki : + +```bash +# cd my-hugo-project + +npx rehype-cli public -o +``` + +运行此命令可能会导致内存报错: + +> FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory + +需要限制一下内存使用: + +```bash +export NODE_OPTIONS="--max_old_space_size=7168" +``` + +> 7168 ≈ 7G,可以根据自己的电脑配置调整,但 GitHub Actions 免费 Runner 最高是 7G + +### 在 GitHub Actions 中使用 Shiki + +在 Hugo 目录 [`package.json`](https://github.com/eallion/eallion.com/blob/4776202069b6a1c570bf00bd697a367502f95c41/package.json#L15) 的 `scripts` 中加入: + +```json + "scripts": { + "shiki": "npx rehype-cli public -o" + }, +``` + +GitHub Actions Workflow: + +```bash +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 || true + + - name: Keep going + # 后续流程 +``` + +为了预防 Shiki 报错而中断 Hugo 部署流程,可以加入 `|| true`,即使出错也会继续执行部署流程。常见的报错是以前的博文可能使用了不支持的代码名称。 + +在 Cloudflare Pages 或者 Vercel 中部署的 Hugo,可以使用 `hugo && yarn run shiki` 这个命令。 diff --git a/content/blog/code/s3-sync/index.md b/content/blog/code/s3-sync/index.md index 1bc68282892..fd184affb8f 100644 --- a/content/blog/code/s3-sync/index.md +++ b/content/blog/code/s3-sync/index.md @@ -46,7 +46,7 @@ Rclone 生成 Config 很简单,输入 `rclone config` 基本上就是一路选 最终会得到一份这样的 Config 文件: -```config +``` [B2] ... diff --git a/content/blog/daily/explain/index.md b/content/blog/daily/explain/index.md index da21aaa1d01..4300f985aff 100644 --- a/content/blog/daily/explain/index.md +++ b/content/blog/daily/explain/index.md @@ -34,7 +34,8 @@ win 2003 的系统虽然没有原来用的那几个 linux 主机用着那么方 随便贴一下我现在用的这个伪静态 url rewrite rules 的完整 httpd.ini 文件内容。 -```[ISAPI_Rewrite] +``` +[ISAPI_Rewrite] # Defend your computer from some worm attacks #RewriteRule .*(?:global.asa|default\.ida|root\.exe|\.\.).* . [F,I,O] @@ -54,7 +55,7 @@ win 2003 的系统虽然没有原来用的那几个 linux 主机用着那么方 # For normal WordPress content, via index.php RewriteRule ^/$ /index.php [L] RewriteRule /(.*) /index.php/$1 [L] - ``` +``` 伪静态效果为 “域名 +postname” 即为本文地址栏里面的样式。 diff --git a/example/blog/ai-summary/background.jpg b/example/blog/ai-summary/background.jpg deleted file mode 100644 index 15d13f0d97c..00000000000 Binary files a/example/blog/ai-summary/background.jpg and /dev/null differ diff --git a/example/blog/ai-summary/featured.png b/example/blog/ai-summary/featured.png deleted file mode 100644 index 823a93ab877..00000000000 Binary files a/example/blog/ai-summary/featured.png and /dev/null differ diff --git a/example/blog/ai-summary/index.md b/example/blog/ai-summary/index.md deleted file mode 100644 index 168167cac3a..00000000000 --- a/example/blog/ai-summary/index.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -title: "博客 AI 摘要及优化" -authors: ["eallion"] -categories: ["代码"] -tags: - - hugo - - blog - - ai - - summary -slug: "ai-summary" -summary: "这篇文章介绍了作者如何使用 AI 摘要插件来优化博客阅读体验。他通过多种方式获取 AI 摘要,并将其保存在本地的 JSON 文件中。然后,他修改了博客模板文件,将 AI 摘要渲染到每篇文章的开头。最后,他还添加了打字机效果和样式来增强显示效果。通过这些优化措施,作者提高了博客阅读的效率和质量。" -draft: false -date: 2023-07-18T11:45:26+08:00 ---- - -### 为何需要 AI 摘要 - -记不太清了,印象中在中学时代学过一篇课文,是讲如何读报纸的。 -我在阅读时一直保持了当时文中介绍的习惯。 -对于不需要精读的内容可以跳读。 -现在 ChatGPT 爆火后出现了大量的应用,其中 AI 摘要插件对我的帮忙很大。 -信息过剩后,我们被很多低价值的信息轰炸,这类插件可以让我快速的辨别一篇文章是否值得细读。 -通过多方对比后,我选择了「[ChatGPT 总结助手 - Chrome 应用商店](https://chrome.google.com/webstore/detail/chatgpt-summary-assistant/nnjcoododbeemlmmhbfmmkbneniepaog)」作为我浏览网页时的首选插件。 -它的使用效果如图: - -![](/assets/images/posts/2023/07/chatgpt_summary.gif) - -### 必须要 AI 摘要吗 - -不必要! - -我集成 AI 摘要只是为了方便跟我有一样阅读习惯的人。 -我的个人博客在于记录生活和写一些备忘录,对于别人来说全是一些低价值的数据。 - -我现在在博客上集成了 AI 摘要功能,是因为我使用了 [TianliGPT](https://tianli-blog.club/tianligpt/)。 -我当时因为出于“支持独立开发者”的情结,购买了 TianliGPT 的服务。 -发现购买的 Key 很快就消耗完了,又买了一个 Key,发现还是不够,再买了一个 Key。 -即便如此,我的博客中也只有不到三分之二的文章有 AI 摘要。 -这样下去,感觉像个无底洞。 -这个时候的 AI 摘要功能就变成了一个历史包袱。 -如果取消 AI 摘要功能,那前面花的那些小钱就变成了沉没成本了。 - -有情怀不代表需要妥协 Geek 精神。 -所以决定自己动手改造一下 AI 摘要。 -这也符合当初换到 Hugo 静态博客的初衷,尽量把数据都静态化。 -尽量让页面数据 SSG(Static-Site Generation)/ SSR(Server-Side Rendering)。 - -### 怎么优化 AI 摘要 - -> 推荐:https://github.com/Moraxyc/ai-summary-hugo 辅助生成 summary.json 的 Python 脚本 - -##### 1. 方式 - -把 AI 摘要放在本地有 2 个思路: - -1. 在 `data` 目录下用 `.json` 文件保存数据 - -![](/assets/images/posts/2023/07/data_summary_json.png) - -2. 把摘要结果放在文章 `.md` 文件的 Front Matter 里 - -![](/assets/images/posts/2023/07/summary_frontmatter.png) - -##### 2. 数据格式 - -我选择的是方式 1 ,把所有 AI 摘要放在 `.json` 文件中,这样方便后期维护,也不破坏现有文章。 -数据来源: - -- TianliGPT 已经生成的摘要 -- 通过脚本从 ChatGPT 和 Claude2 获取的摘要 - -我现在用了好几个脚本来获取摘要,没有一个完美的脚本能胜任这一工作,所以就不贴脚本了。 -TianliGPT 的摘要,可以在网页上按 F12 打开 DevTools 找到: - -![](/assets/images/posts/2023/07/tianligpt_response.png) - -把多种方式获取到的 AI 摘要集中起来后,生成一个 `summary.json` 文件。 -在 `data` 目录新建 [data/summary/summary.json](https://github.com/eallion/eallion.com/blob/240215451d1aa3133c929428e6efb238c0baa908/data/summary/summary.json) 文件, 所有数据复制到其中,数据格式: - -```json -{ - "summaries": [ - { - "title": "2010 年 12 月 15 日 雪景", - "slug": "snows", - "generated": true, - "summary": "文章描述了作者在 2010 年 12 月 15 日所经历的雪景。作者提到,下雪之前天空只有几点零星的白天,没人预料到会下这么大的雪。作者认为家乡可能下得更大。文章还提到了关于地址设定和程序错误的问题,并以数字花园用爱发电作为结尾。" - }, - { - "title": "2011 向左,2010 向右", - "slug": "goodbye2010", - "generated": true, - "summary": "文章讲述了作者对 2010 年的回顾和对 2011 年的期望。他认为自己在过去一年中太过于为别人而活,失去了自我。他希望新的一年能更加积极阳光,并将经历和感悟当成财富。最后,他表示不再傻逼地诉说苦难,祝大家新年快乐。" - } - ] -} -``` - -其中 `generated` 是我自用的一个判断词,可有可无,`title` 和 `slug` 是用于对应文章的锚点。 - -##### 3. 渲染 AI 摘要 - -把 `summary.json` 文件中的 AI 摘要渲染到每篇文章的开头,修改一下 Hugo 文章的模板文件即可。 -不同主题的模板文件可能不太一样,不过也差不离。 -一般名叫 `single.html` ,位于主题的 `layouts` 或 Hugo 根目录的 `layouts` 下。 -比如 DoIt 的模板位于 `themes/DoIt/layouts/posts/single.html` 。 -我把它复制到根目录 [layouts/posts/single.html](https://github.com/eallion/eallion.com/blob/240215451d1aa3133c929428e6efb238c0baa908/layouts/posts/single.html) 了,[同名模板优先渲染根目录](https://gohugo.io/templates/lookup-order/#hugo-layouts-lookup-rules-with-theme)。 -在文章模板 `single.html` 的 `{{ .Content }}` 之前,插入以下代码: - -```html - - - -{{ $summary := getJSON "data/summary/summary.json" }} - - -{{ $currentSlug := .Params.slug }} -{{ $matchingSummary := index (where $summary.summaries "slug" $currentSlug) 0 }} - -