在 Astro 中显示数学公式
发布于
精简步骤
在这个时间点(2023 年 10 月),你大概率会遇到多行公式渲染报错的 bug,可见 remark-math
throws an error on multiline math。你可以在这个 issue 中找到解决方案,也可以翻到这篇文章的最后。
现在(2023 年 12 月),Astro 4.0
已经发布,上述 bug 已经被修复,你可以直接使用最新版本的 remark-math
和 rehype-katex
。
安装依赖
npm install remark-math rehype-katex katex
编辑配置
---
...
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
...
---
export default defineConfig({
...
markdown: {
remarkPlugins: ["remarkMath"],
rehypePlugins: ["rehypeKatex"]
},
...
});
编辑模板
---
import "/node_modules/katex/dist/katex.min.css";
---
如果你已经看懂了,那你可以关闭这个网页了;如果你没看懂,请你继续往下看,大致原理和详细步骤。
大致原理
Astro 处理 Markdown 的程序
我并不了解 Astro 的工作过程,那就问问 ChatGPT 吧(以下回答由 ChatGPT 3.5 生成,经过我修饰):
Astro 使用 remark
和 rehype
来将 Markdown 文件转换为 HTML。这两个工具协同工作,处理和转换文档内容。以下是一个 Markdown 文件转换为 HTML 时经历的主要步骤:
- 解析 Markdown:
- 当 Astro 遇到一个 Markdown 文件时,它首先使用
remark
来解析这个文件。 remark
将 Markdown 文本转换为一个叫做 “mdast”(Markdown Abstract Syntax Tree)的结构。这是一个树状的数据结构,表示了 Markdown 文件的内容和结构。
- 操作抽象语法树:
- 在此阶段,你可以使用各种
remark
插件来操作 mdast。例如,你可以使用插件来处理链接、添加脚注、转换数学公式等。 - 插件可以读取、修改、添加或删除 mdast 中的任何部分。
- 转换为 HTML 抽象语法树:
- 完成 mdast 的所有处理和操作后,下一步是使用
remark-rehype
将它转换为一个名为 “hast”(HTML Abstract Syntax Tree)的结构。
- 操作 HTML 抽象语法树:
- 与 mdast 类似,你也可以使用
rehype
插件来操作 hast。这允许你在生成 HTML 之前执行各种任务和转换,例如,优化图片、添加 CSS 类名、内联样式等。
- 生成 HTML:
- 最后,一旦 hast 被所有所需的插件处理并准备好了,
rehype
会将其转换为最终的 HTML 字符串。 - 之后这个 HTML 可以被 Astro 用来渲染页面或组件。
显示数学公式的原理
为了在 Astro 中显示数学公式,我们会使用 remark-math
将 Markdown 中的数学公式转换为一个中间结构,再使用 rehype-katex
将中间结构转换为 HTML。
详细步骤
我们都用 Astro 这样新的框架了,那么就不用纠结 MathJax 与 KaTeX 了——肯定不会考虑 MathJax 这种老东西。
安装相关依赖
这一步没什么好说的,直接在命令行中运行这一行命令,安装 remark-math
rehype-katex
katex
即可。
npm install remark-math rehype-katex katex
编辑 Astro 配置
现在,插件已经安装好了,但是 Astro 并不会去用它们。编辑 Astro 的配置文件 astro.config.mjs
,告诉 Astro 应该使用这些插件,两个省略号之间的是要添加的内容:
---
...
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
...
---
export default defineConfig({
...
markdown: {
remarkPlugins: ["remarkMath"],
rehypePlugins: ["rehypeKatex"]
},
...
});
也许你的 Astro 文件并不是 astro.config.mjs
,而是 astro.config.js
,那么只需要这样添加:
---
...
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
...
---
module.exports = {
...
markdown: {
remarkPlugins: ["remarkMath"],
rehypePlugins: ["rehypeKatex"]
},
};
...
astro.config.ts
:
---
...
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
...
---
export default {
...
markdown: {
remarkPlugins: ["remarkMath"],
rehypePlugins: ["rehypeKatex"]
},
...
};
astro.config.json
:
{
...
"markdown": {
"remarkPlugins": ["remark-math"],
"rehypePlugins": ["rehype-katex"]
},
...
}
在完成以上步骤后,你可以运行 npm run dev
来看看现在是什么样的。在你的网站中找一篇带有数学公式的网页,你会发现公式看起来很奇怪;查看页面源代码。你会发现数学公式都被 <span>
包裹了起来。这说明 Astro 已经能够正确处理数学公式了,但是浏览器并没有内置 KaTeX,它只能和渲染正常的字符一样渲染处理过后的数学公式。
编辑页面模板
为了告诉浏览器如何该如何渲染数学公式,我们需要引入 katex.css
或 katex.min.css
,这里以 katex.min.css
为例,不过使用 katex.css
也是没有问题的,因为 Astro 会自动压缩 CSS(仅限于本地托管,不适用于 jsDelivr 第三方托管的方法)。
本地托管
如果你和我一样使用了 Astro 的 Blog 模板,那你可以在打开 src/components/BaseHead.astro
,在 Frontmatter(也就是文件顶部用“---”包裹起来的部分)中添加一行:
---
...
import "/node_modules/katex/dist/katex.min.css";
...
---
这行代码不一定要添加到 BaseHead.astro
的 Frontmatter 中,理论上任意一个 .astro
文件都行,只要这个 .astro
文件参与到了含有数学公式的网页的生成即可。例如 src/layouts/BlogPost.astro
等。这种方法是最简便的,Astro 会自动处理 CSS 和字体文件。
还有一种方式也可以在本地托管 KaTeX:
<link rel="stylesheet" href="/node_modules/katex/dist/katex.min.css">
Astro 同样会自动处理 CSS 和字体文件。不过这种方式意义不大,不如第一种方便,就不详细讲了,步骤和下面 👇 使用 jdDelivr 的那个方法一样,有需要的可以参考。
当然还有一种更加鸡肋的本地托管方法,大致就是将 CSS 和字体文件都复制到 public
文件夹下,然后手动引入 katex.min.css
。这种方法默认情况下会找不到字体,还要手动修改 katex.min.css
中的字体链接。由于实在鸡肋,就不展开了。有需要的可以自己去试试。
第三方(jdDelivr)托管
如果你不希望自己托管 CSS 和字体文件,也可以使用 jdDelivr。只需要将以下代码复制到负责生成 <head>
部分的 .astro
文件中,例如 BaseHead.astro
。注意这段代码应复制到正文部分,而不是 Frontmatter。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous">
完成!
使用 npm run dev
命令运行本地服务器,然后在浏览器中打开 localhost:4321
。使用你喜欢的编辑器打开你的一篇博客,然后添加以下内容:
$$E = MC^2$$
回到浏览器,你就可以看到
了!
也许你遇到了一些小问题…
现在(2023 年 12 月),这个问题已经被修复,你可以忽略以下的步骤。
你可能习惯在公式块中换行:
$$
E = MC^2
$$
保存之后回到浏览器,就会发现 报!错!啦! 满屏密密麻麻的文字,头都要大了!
总之,如果你安装了最新的 remark-math
和 rehype-katex
,并且在 $$ … $$
中使用了换行,就会报错。似乎官方人员对于这个 bug 也做不了什么,直接把相关的 issue 给 close 了。
但是,要(暂时)解决这个问题也很简单!打开 package.json
,找到:
{
"rehype-katex": "^7.0.0",
"remark-math": "^6.0.0"
}
把它修改成:
{
"rehype-katex": "^6.0.3",
"remark-math": "^5.1.1"
}
然后运行一下 npm install
,就好了!这个问题困扰了我很久,希望它没有对你造成什么麻烦~