Reading view

There are new articles available, click to refresh the page.

使用 TikZ 在 Hexo 博客中愉快地画图

一转眼就到 2024 年了!大家新年快乐!

前段时间在写文章时,需要一些配图,于是就使用了 TikZ 来绘制。TikZ 是一个强大的 宏包,可以使用代码的形式绘制出各种各样精美的矢量图。

如果你的阅读器看不到上面的 SVG 格式图片,可以点这里查看 PNG 格式。example-tikz-graph

上面的图对应的 TikZ 代码可以在这里找到。然而画是画爽了,想把它贴到博客里时却犯了难——目前竟然没有什么好办法可以直接在博客里使用 TikZ!

TL;DR

咱们废话不多说,直接上结果:我写了一个 Hexo 插件,可以直接把 Markdown 源码里的 TikZ 代码渲染成 SVG 矢量图,然后在博客构建时嵌入到页面 HTML 中,用起来就和 MathJax 写数学公式一样简单。

而且最重要的是渲染完全在构建时完成,浏览器上无需运行任何 JavaScript。同时构建机上也无需安装 环境,因为其底层运行的是 WebAssembly。

👉 prinsss/hexo-filter-tikzjax: Server side PGF/TikZ renderer plugin for Hexo.

npm install hexo-filter-tikzjax

注意:插件安装成功后,需要运行 hexo clean 清除已有的缓存。

安装插件后,只需要在博客文章中添加 TikZ 代码块:

---title: '使用 TikZ 在 Hexo 博客中愉快地画图'tikzjax: true---Markdown text here...```​​tikz\begin{document}  \begin{tikzpicture}    % Your TikZ code here...    % The graph below is from https://tikz.dev/library-3d  \end{tikzpicture}\end{document}```

插件就会自动把代码渲染成对应的图片,非常方便:

TikZ 教程

不做过多介绍。贴几个链接,有兴趣的可以学学:

比如这就是我在写文章时画的图,全部用 TikZ 代码生成,画起来改起来都很方便。

原理

在本插件之前,主流的在网页上渲染 TikZ 绘图的方式是使用 TikZJax。TikZJax 有点类似 MathJax,都是通过 JavaScript 去渲染 语法。

<link rel="stylesheet" type="text/css" href="https://tikzjax.com/v1/fonts.css"><script src="https://tikzjax.com/v1/tikzjax.js"></script><script type="text/tikz">  \begin{tikzpicture}    \draw (0,0) circle (1in);  \end{tikzpicture}</script>

然而这样做的问题是,太重了。在网页上动态加载 TikZJax,需要加载 955KB 的 JavaScript + 454KB 的 WebAssembly + 1.1MB 的内存数据,如果再另外安装一些宏包,最终打包产物大小甚至可以达到 5MB+。

对于一些有加载性能要求的网站,这显然是难以接受的。

那怎么办呢?答案就是 SSR / SSG,把渲染过程搬到服务端/构建时去做。这很适合博客这样的场景,尤其是静态博客,只需要构建时渲染一下,把生成的图片塞到 HTML 里就完事了,完全不需要客户端 JavaScript 参与,加载速度大幅提升。

因为 TikZJax 底层跑的是 WebAssembly,而 Node.js 也支持运行 WebAssembly,所以很自然地我就想,能不能把它的渲染流程直接搬到 Node.js 里面去做?

说干就干。于是就有了 node-tikzjax,一个 TikZJax 的移植版,可以在纯 Node.js 环境下运行,无需安装第三方依赖或者 环境。轻量化的特性很适合拿来做服务端渲染,也支持在 Cloudflare Worker 等 Runtime 上运行,非常好用。

hexo-filter-tikzjax 则是 node-tikzjax 的一个上层封装,主要就是在渲染 Hexo 博客文章时提取 Markdown 源码中的 TikZ 代码,交给 node-tikzjax 执行并渲染出 SVG 图片,然后将其内联插入到最终的 HTML 文件中。

如果是其他博客框架,也可以用类似的原理实现 TikZ 静态渲染的接入。

局限性

因为 node-tikzjax 并不是完整的 环境,所以不是所有宏包都可以使用。目前支持在 \usepackage{} 中直接使用的宏包有:

  • chemfig
  • tikz-cd
  • circuitikz
  • pgfplots
  • array
  • amsmath
  • amstext
  • amsfonts
  • amssymb
  • tikz-3dplot

如果希望添加其他宏包,可以参考 extractTexFilesToMemory 这里的代码添加。

如果在使用插件的过程中 TikZ 代码编译失败了,可以通过 hexo s --debug 或者 hexo g --debug 开启调试模式,查看 引擎的输出排查问题:

This is e-TeX, Version 3.14159265-2.6 (preloaded format=latex 2022.5.1)**entering extended mode(input.texLaTeX2e <2020-02-02> patch level 2("tikz-cd.sty" (tikzlibrarycd.code.tex (tikzlibrarymatrix.code.tex)(tikzlibraryquotes.code.tex) (pgflibraryarrows.meta.code.tex)))No file input.aux.ABD: EveryShipout initializing macros [1] [2] (input.aux) )Output written on input.dvi (2 pages, 25300 bytes).Transcript written on input.log.

或者也可以在这个 Live Demo 中输入你的 TikZ 代码,提交后可在控制台查看报错。

致谢

首先要感谢 @kisonecat 开发的 web2js 项目,这是一个 Pascal 到 WebAssembly 的编译器,使我们可以在 JavaScript 中运行 引擎,也是下面所有项目的基石。

这里有作者关于构建基于 Web 的 引擎的一篇文章,可以拜读一下:Both TEX and DVI viewers inside the web browser

感谢 @drgrice1 对 TikZJax 和 dvi2html 的修改,TA 的 fork 中包含了很多有用的新功能,并且修复了一些原始代码中的问题。

感谢 @artisticat1 对 TikZJax 的修改,这是基于上述 @drgrice1 的 fork 的又一个 fork,也添加了一些有用的功能。本插件依赖的 node-tikzjax,其底层使用的 WebAssembly 二进制和其他文件就是从这个仓库中获取的。

感谢 @artisticat1 开发的 obsidian-tikzjax 插件,这是本项目的灵感来源。本项目和该插件底层共享同一套 引擎,使用语法也很类似,基本可以在 Obsidian 和 Hexo 之间无缝切换(实际上也是我开发这个的原因 😹)。

如有任何问题,请在 GitHub 上提交 issue。祝使用愉快!

使用 GitHub Actions 自动部署 Hexo 博客

联动三年前的文章:使用 Travis CI 自动部署 Hexo 博客

今天更新了一下博客,寻思着好歹也改一下页脚的 Copyright 年份,改完 push 上去以后却发现 GitHub Pages 迟迟没有更新。进去 Travis CI 一看,发现任务一直处于 Queued 状态,半小时了都没开始构建。

查了一下,并不是只有我遇到了类似情况(似乎是因为 Travis CI 正在将 travis-ci.org 迁移至 travis-ci.com):

看了一圈感觉有点悬,干脆换成 GitHub Actions 吧。

我的博客完全托管在 GitHub 上:prinsss.github.io,其中 source 分支放的是源码,master 分支(即 GitHub Pages)是 Hexo 生成的静态博客页面。

要做的也和之前 Travis CI 差不多,当 source 分支有更新时,自动使用 Hexo 构建新页面并更新 GitHub Pages 就可以了。

配置部署密钥

生成一个新的 SSH 密钥,用于 push 至 GitHub Pages 所在的 repo:

ssh-keygen -f hexo-deploy-key -C "prinsss.github.io"

将公钥 hexo-deploy-key.pub 设置为仓库的部署密钥(Settings > Deploy keys):

add-deploy-key

然后在 Settings > Secrets 中新增一个 secret,命名为 DEPLOY_KEY,把私钥 hexo-deploy-key 的内容复制进去,供后续使用。

编写 Workflow

Workflow 就是 GitHub Actions 的配置文件,类似于 .travis.yml

首先新建文件:

mkdir -p .github/workflowstouch .github/workflows/deploy.yml

编辑 deploy.yml

name: Hexo Deploy# 只监听 source 分支的改动on:  push:    branches:      - source# 自定义环境变量env:  POST_ASSET_IMAGE_CDN: truejobs:  build-and-deploy:    runs-on: ubuntu-latest    steps:      # 获取博客源码和主题      - name: Checkout        uses: actions/checkout@v2      - name: Checkout theme repo        uses: actions/checkout@v2        with:          repository: prinsss/hexo-theme-murasaki          ref: master          path: themes/murasaki      # 这里用的是 Node.js 14.x      - name: Set up Node.js        uses: actions/setup-node@v1        with:          node-version: '14'      # 设置 yarn 缓存,npm 的话可以看 actions/cache@v2 的文档示例      - name: Get yarn cache directory path        id: yarn-cache-dir-path        run: echo "::set-output name=dir::$(yarn cache dir)"      - name: Use yarn cache        uses: actions/cache@v2        id: yarn-cache        with:          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}          restore-keys: |            ${{ runner.os }}-yarn-      # 安装依赖      - name: Install dependencies        run: |          yarn install --prefer-offline --frozen-lockfile      # 从之前设置的 secret 获取部署私钥      - name: Set up environment        env:          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}        run: |          sudo timedatectl set-timezone "Asia/Shanghai"          mkdir -p ~/.ssh          echo "$DEPLOY_KEY" > ~/.ssh/id_rsa          chmod 600 ~/.ssh/id_rsa          ssh-keyscan github.com >> ~/.ssh/known_hosts      # 生成并部署      - name: Deploy        run: |          npx hexo deploy --generate

当然,具体步骤还是得根据自己的需求进行相应的修改。

GitHub Pages 相关的具体配置放在了 Hexo 的 _config.yml 里:

deploy:  type: git  repo: git@github.com:prinsss/prinsss.github.io.git  branch: master  name: prinsss  email: prinsss@gmail.com

部署结果

更新 source 分支,push 后 GitHub Actions 就会自动执行。

deploy-result

不到半分钟就 build 完了,只能说微软爸爸还是牛逼。

参考链接

博客由Typecho迁移至Hexo

因为前一段时间发现Typecho的安全性不佳,所以我就投入了静态博客的怀抱。趁着自己心血来潮,就想着赶紧把博客数据啥的全部迁移到Hexo去。不然过段时间我又懒得迁移了。而且我Typecho的主题原本就是从Hexo移植过来的,这样也省去了主题移植所花费的时间。

前几天就开始了我的博客迁移,迁移过程中我就直接把域名解析直接暂停了,如果这段时间有人访问我的博客的话,估计会发现上不去。然后我来介绍一下我其中遇到的坑。

文章永久链接

博客用Typecho的时候,链接是https://qiuri.org/xxx.html这样的形式,但是在Hexo中你要设置成这样的话,会很麻烦,而且我也不太想再沿用这个链接形式。

如果放弃原有的方式的话,就要考虑网站收录的问题,那么就得把原有的链接301重定向到新链接,这样才能让搜索引擎知道你更换了链接。不过对于我这种懒人来说,网站收录排名什么的都是不存在的,所以这只是算一个小坑。

评论

评论在我思索片刻后选择了disqus。因为周围人都是用这个的,而且我一直对这个评论框架抱有好感。

Typecho可以直接调用别人造好的轮子直接导出,然后导入disqus就好了。然后导入之后就遇到很多问题了。

国内用户访问问题(墙)

本来想着不搞的,因为无论什么方法,实现起来都会有一些不足的地方,想着直接调用就完事了。不过后来觉得不是每个人都会翻,或者说需要翻,所以就采用了周围博友都用的方式,就是disqus-php-api这个方式。这个也应该是我能找到最好的方式了。

我把这个程序的后端部署在了香港的腾讯云上面。这样的话速度稍微会快一点,采用的模式是同时加载两个评论框(国内简易版和国外完整版),如果能加载到国外被墙版本的话,就显示完整的国外版,否则显示简易版。我看了下周围人的博客,发现@小F实现的非常好,用了按钮来区分,不过我这种前端渣渣兼懒人就用最简单的模式了。

导入后的评论文章链接对应问题

disqus的评论是用文章链接来对应每个文章评论的,迁移前后文章链接不对应,这就导致了无法在新的博客系统中加载旧的评论,解决方法十分暴力,直接对照者新博客网站改链接就好了。

当然disqus还有不少坑

  • 无法删除某篇文章的评论(discussion),只能合并到另一个discussion里面
  • 有时候本地开启Hexo测试的时候会不经意间自动创建discussion
  • 评论邮件通知回复还没有测试,希望这个不要又来坑

图片存放问题

我之前博客的图片都是放在又拍云里面的,Hexo的话我不太熟悉它的运行模式,毕竟还没用多久,图片的具体存放格式我还没想好,只是心里面想着先用日期区分。

博客备份

Hexo的源文件都在本地,而且Hexo最好的备份方式就是备份源文件,而源文件的备份用Git备份比较友好,所以我在Github上创建了一个仓库来专门存放源文件,这样就算换了电脑也可以轻松部署回去。

如果是多平台写作的话,我推荐再用Dropbox同步文章的markdown源文件,这样多平台写作也非常的有效率

主题

之前说了,我原本主题就是从Hexo这个开源主题过来的。但是因为对Hexo的这套系统语法不是特别熟悉,也就稍微看了下文档这个样子,暂时还没去深入了解,主题方面和以前相比做了一些小调整,包括但不限于字体,首页文章背景等,总体来说相对以前来说,变得好看了一些。

建立长久博客的一点心得

谨慎选择插件和博客所依赖的服务

换过博客系统的人就很容易知道,原先博客为了显示的更加漂亮直观或者为了提供更多的功能,会安装很多插件,这些插件在系统变迁的时候不能好好的迁移过去,就导致很多功能的缺失。这样处理起来的话,是非常繁琐的。

举个例子

  • 调用了第三方网易云音乐播放器插件
  • 评论调用了第三方表情
  • 使用了第三方播放器插件

以上这些在迁移博客的时候,或者在文章发布时间过了很长的时候,就会让原本想呈现给别人的文章变了原有的样子。所以,在选择每一个插件的时候尽量谨慎小心,因为你选择了这个插件并用上了,那么你的博客的一部分功能就得依赖这个插件。换言之我们所依赖的服务能少就少。比如我选择了disqus是因为它在评论框架里面是相对最稳定的(不容易跑路)。

编辑器的选择

每个博客都会有很多编辑器,有很多编辑器集成了很多功能,比如可以添加表情,做表单之类。市面上的编辑器数不胜数。其实我个人倾向于选择一个好的,更加现代化的方式,就是运用标记语言来书写自己的博客文章,这样某个博客系统支持这个语法的解析,那么就能长久的保持使用下去。其实说了那么多我就是想推荐Markdown来写博客。好处就是因为是近几年才流行起来的,不至于这么容易淘汰,而且用了之后你就发现比那些HTML语言实现的编辑器不知道高到哪里去。

文件备份及管理

图片和文章的存放位置及最好做到心中有数(建议有一定规律的去存放),定时备份博客的重要数据和文件这个就不必多说了,如果使用了图床,七牛,又拍云等等的加速,文章里面所含有的图片链接形式要搞清楚,以防止到时候不用这些服务的时候图片,文件链接转换不回去。

其实大概也就是随便扯扯一些个人的经验,只是凭感觉写的,非常随意,如果有什么地方写错了或者写的不妥当你就当随意看看就好。

我个人是比较喜欢简单,清新的博客的,让别人看起来非常舒服的博客。说到最后,其实还是你有没有这个心,或者说喜不喜欢这样子去搞下去,如果喜欢的话那么大概率是可以坚持下去的。

最后,我这个人最喜欢在重要的时候折腾一些有的没的的事情,比如在考试周疯狂折腾博客。

英文

今年因为自动忽略了报名时间而错过了四六级报名考试。不过话说回来,我最近突然不知怎么的开始重视起了英文,不仅开了一个破博客(XD.CI)还下载了扇贝+百词斩来提高英文水平。总是觉得学了这么多年的英文,到用的时候却总是发现没有什么句子能够熟练的运用上来。就是感觉白学了。

目前计划大概是这样的,破博客用来实践,扇贝来提升听力,句子理解和造句;百词斩来提升词汇。不知道能够坚持多久,毕竟我是三分钟热度的人。有经验的朋友可以和我分享一下。

破博客(XD.CI)

早就想用Hexo来建一个博客了,上个礼拜又在一个地方看到一个设计很棒的主题。原本以为是免费的。后来看了下,要9美元,不过风格刚好符合自己的口味,忍痛也就买了。

原本打算放在腾讯云香港上的。因为考虑到国内访客,想着国内解析到腾讯云香港,国外解析到cloudflare。不过这台只有2Mbps的带宽。而我又打算在破博客上放点高清的图片(不想用七牛,图床等各类服务)。后来我又觉得破博客应该没人看,只有我自己意淫而已,就直接全局走cloudflare的cdn了。

然而我又想了想,源站带宽太小,就算cdn缓存再久,速度也是会受一点影响,于是,在腾讯云放了几天之后迁移到了BandwagonHost的QN机房。大致原因如下:

  • cloudflare 官网虽然显示有香港数据中心,但是貌似免费套餐并不会给你分配。而且香港节点除了对移动好之外,其他(电信,联通)都直接绕道美国去了。
  • 源站带宽太小,只有2Mbps。
  • QN机房貌似有cloudflare的节点,我在服务器上Ping只有0.3ms左右。

所以就这样,破博客就建立好了。

备份

我这个博客其实很少备份,主要是我非常相信腾讯云的稳定程度。不过最近又是突发奇想,想着要把数据备份一下。看了这么多家网盘,我自始自终还是比较相信Dropbox的,索性就将数据定时备份到了这上面。

❌