Hugo中优雅地使用数学公式
Hugo中优雅地使用数学公式
2024.2 更新:hugo已在v0.122.0正式支持公式语法
参考hugo官方文档Mathematics in markdown,原理是通过识别公式块符号,然后将其内容直接传递到Html而不渲染。配置如下:
|
|
可以配置自己喜欢的直通块符号。注意['$', '$']
内联符号使用时要额外处理数学环境外的转义问题
上面的配置、JavaScript 和示例使用
\(...\)
分隔符对来表示内联方程。$...$
分隔符对是一种常见的替代方案,但如果您在数学上下文之外使用$
符号,则使用它可能会导致意外的格式设置。如果将
$...$
分隔符对添加到配置和 JavaScript,则在数学上下文之外时必须对$
进行双重转义,无论页面上是否启用了数学渲染。例如:
1
A \\$5 bill _saved_ is a \\$5 bill _earned_.
以下内容已过时,仅作存档
hugo中的数学渲染问题
hugo内置的goldmark渲染器并不能识别直接识别$[行内公式]$
和$$[公式块]$$
语法的数学公式,所以在遇到公式时会将其中\\、\_
之类的符号仍然按照markdown的的转义语法渲染,导致\\
在输出中变为\
。当用户或者主题需要渲染公式而引入mathjax或者katex等库时,会因此无法正确识别换行等语法导致公式排版混乱,或者直接报错。
在历史上,hugo使用的内置markdown渲染器经历了mmark、blackfriday、goldmark的变化。其中只有mmark支持直接识别公式,但目前hugo官方只支持goldmark渲染器(另外还有pandoc,这个后续会提到),前两种都已经被弃用。
自mmark被弃用起,公式渲染这一问题已经在hugo的社区和issue中讨论了很长时间,但目前hugo官方并没有解决的打算。一个原因是Hugo 的贡献要求中具有一条 “no cgo rule”, 而实现数学功能的goldmark插件大多都依赖cgo特性来调用其他JS引擎,如 goldmark-qjs-katex。
- Add KaTeX server side math rendering support - PR #6842
- How to render math equations properly with KaTeX - support - HUGO
- MathJax and KaTeX support - support - HUGO
- Consider markdown extensions for math typesetting in Hugo · Issue #6544 · gohugoio/hugo
- MathJax issue in hugo · Issue #6344 · gohugoio/hugo
- Expect to be able to solve the problem of mathematical formula · Issue #8133 · gohugoio/hugo
- Add MathJax build support – post-hugo processing · Issue #6694 · gohugoio/hugo
经过一番查阅与尝试,目前想要在hugo中正确渲染数学公式,有如下几种解决方案:
方法 | 效果 | 侵入性 | 优雅程度 | 配置复杂性 |
---|---|---|---|---|
shortcode | 好 | 需要修改md源文件 | 麻烦 | 简单 |
pandoc | 可能影响主题 | 无 | 一般 | 一般 |
自编译hugo | 好 | 无 | 方便 | 折腾 |
其中shortcode需要修改每个markdown文件,不够优雅;pandoc兼容性较差,无法同时使用完整的主题功能。而自编译hugo的方式在折腾编译时可能较为麻烦,但编译完成之后就可以直接支持数学公式。对于其他使用者,也能下载编译好的支持数学公式的程序直接使用。
方法一:使用shortcode
部分主题提供了能够保持内容不受转义的shortcode,例如LoveIt/FitIt提供的的
shortcode,将公式块包围在这个shortcode之间就可以避免被渲染器转义。
如果主题并没有提供类似的shortcode,可以自己创建。参考hugo关于创建shortcode的文档,创建layouts/shortcodes/keepit.html
并写入如下内容:
|
|
然后可以在markdown中将公式使用上述shortcode包围:
|
|
这样公式就不会被转义,能够正常被mathjax/katex解析。
使用shortcode也是目前最方便,应用最广的方法。
但是这种方法在markdown源文件中额外引入了shortcode这一非原生语法,在使用typora等其他markdown编辑器查看和编辑时视觉体验较差。
方法二:使用pandoc作为md渲染器
根据hugo的内容格式文档,当源文件扩展名为.pdc时,hugo会直接调用pandoc进行解析和渲染。但通过一些配置也可以使用pandoc直接渲染md文件。
配置hugo使用pandoc
要使用pandoc,首先请安装pandoc。由于hugo的安全设计,安装pandoc之后还要在配置中将pandoc加入允许执行的外部程序白名单(前面几项是hugo的默认值):
|
|
接下来有两种方式可以使用pandoc。
第一种:在markdown文件的yaml front matter添加markup: pdc
,或者将xxx.md重命名为xxx.pdc。这样hugo就会单独使用pandoc渲染这一篇文章。但这种方式需要修改md源文件,因此如果只有少量文章需要使用数学公式,可以使用这一方法。
第二种:将pandoc作为默认markdown渲染器。在配置中添加:
|
|
这样hugo就会调用pandoc作为默认markdown渲染器。而pandoc本身就可以识别数学公式,因此输出时不会存在goldmark的转义问题。
pandoc输出的兼容性问题
pandoc输出的HTML页面中元素的组织结构和属性与goldmark不同。
由于hugo使用goldmark已经有很长一段时间,许多主题利用仅受goldmark支持的hugo render hook来实现某些效果,或是在theme.js中有许多操作依赖goldmark生成的HTML元素属性。
这就造成使用pandoc生成的页面中,**部分主题的某些效果和组件可能会失效。**其中较为常见的是输出的代码块无法高亮,或者目录消失等。
方法三、自编译支持数学插件的hugo
开箱即用
在介绍手动修改步骤前,我将修改过程编写为了自动化脚本上传到了github,并且配置了github action以在hugo发布新版本时自动编译生成支持数学公式的构建版本。
因此如果你只需要一个Hugo的数学公式解决方案,可以在此处直接下载现成的hugo_katex可执行文件,并跳转使用方式章节。
goldmark的数学插件
实际上,goldmark只是本体不支持识别数学公式,其本身支持插件系统。在goldmark的github仓库页面,可以找到如下能够提供数学功能的插件:
然而hugo使用的goldmark是作为go模块静态编译到hugo内,只包含本体不能增加插件。hugo官方由于“no cgo rule”,也没有将数学支持插件一同打包的打算。
幸运的是,hugo是开源的,我们可以自己编译一份加入了goldmark数学插件的hugo版本。在hugo的PR/fork中,已经有用户进行了相关尝试:
经过测试,上述fork维护时间已经较为久远,已经behind官方repo很多个commit。为方便起见我们可以按相同方式自己修改并编译一份。
手动修改步骤
下面是修改过程记录。
由于我完全不会go语言,所以记录得详细一点。下面的内容以引入goldmark-qjs-katex为例。
参考hugo的contributing.md,可以按如下步骤进行(操作环境为linux但理论上通用):
首先安装golang开发环境。
找一个干净的文件夹,clone hugo的仓库。
1
git clone https://github.com/gohugoio/hugo
然后安装mage,这个命令会把mage安装到
~/go/bin/mage
。1
go install github.com/magefile/mage
cd到hugo的仓库里,切换到stable分支。这是由于master分支还有很多不稳定的feature。当然,你也可以选择一个release tag。
1 2
cd hugo git checkout stable
添加goldmark-qjs-katex依赖:
1
go get github.com/graemephi/goldmark-qjs-katex
这个命令会更新go.mod和go.sum
添加执行代码,找到
markup/goldmark/convert.go
,首先在开头的import添加导入:1 2 3 4 5 6 7 8 9 10
package goldmark import ( "bytes" ……//此处省略多行 "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/text" //添加下面这行 qjskatex "github.com/graemephi/goldmark-qjs-katex" )
然后在中间的代码中(约134行)将qjskatex添加到插件列表:
1 2 3 4 5 6 7 8 9 10 11
if cfg.Extensions.Footnote { extensions = append(extensions, extension.Footnote) } //下面的是插入内容 if cfg.Extensions.KaTeX { extensions = append(extensions, &qjskatex.Extension{}) } //插入内容结束 if cfg.Parser.AutoHeadingID { parserOptions = append(parserOptions, parser.WithAutoHeadingID()) }
增加一个hugo配置项,找到
markup/goldmark/goldmark_config/config.go
,在第33行左右的Default Config中添加一个用于启用katex支持的布尔键。注意末尾的逗号不能省略;以及在第46行的Extensions定义中同样增加一行。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
var Default = Config{ Extensions: Extensions{ Typographer: true, Footnote: true, DefinitionList: true, Table: true, Strikethrough: true, Linkify: true, LinkifyProtocol: "https", TaskList: true, KaTeX: false,//添加了这一行 }, …… type Extensions struct { Typographer Typographer Footnote bool DefinitionList bool // GitHub flavored markdown Table bool Strikethrough bool Linkify bool LinkifyProtocol string TaskList bool KaTeX bool//添加了这一行 }
最后构建。这里的环境变量是启用extended特性,如果不需要相关特性可以不设置。
1
HUGO_BUILD_TAGS=extended ~/go/bin/mage hugo
此时会在当前目录编译生成一份hugo可执行文件。
使用方式
将前述编译的hugo程序复制到博客所在目录,为便于区分,可以重命名为hugok或者hugo-katex等名字。当然你也可以添加到环境变量以在任何地方使用,这样你也可以卸载默认的hugo并将编译的hugo作为替代。
在博客的config.toml中,添加站点配置启用katex功能。
1 2
[markup.goldmark.extensions] katex = true
按katex样式表章节内容,开启主题自带katex支持,或手动引入css
最后如果是复制到博客目录,可以用如下方式启动演示服务器或者生成。其他参数等与原版hugo完全相同。
1 2
./hugok serve # 演示服务器 ./hugok # 生成
katex样式表
goldmark-qjs-katex默认只处理数学公式并输出,不包含katex对应的css,会导致直接使用时页面展示的公式排版较为奇怪。
使用主题提供的katex库(如果有)
如果在使用自行编译的hugo之前,所使用的主题已经支持通过shortcode编写数学公式并使用katex渲染,那么此时只需要在主题配置中启用对应的数学配置即可。
例如,在LoveIt主题中,可设置:
|
|
需要说明的是,由于我们编译的hugo直接支持数学公式,无需使用主题提供的shortcode,这里启用该选项是为了让hugo在生成时引入主题已经包含的katex相关库文件和样式。
自行引入css
如果使用的主题本身不包括katex支持,需要自行在页面中引入katex样式表。可以使用cdn的链接,例如https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css。
大部分主题都提供了引入自定义css的方式,请自行查看主题提供的配置项。
如果主题连添加自定义css的功能都没提供,可以查看这两个教程手动编写模板添加css: