typst编写博客

Written by: algebnaly

Date: 2026-03-29T16:45:12.000Z

简介

尽管有astro-typst这样的 astro集成可以直接在astro中使用typst渲染博客页面。但是它基于主线typst release版本, 而截至这篇博客编写的时候 mkorje的mathml分支 还没有被合并进主线, 但是我已经按耐不住想用typst编写数学博客的心情, 开始着手实现使用mkorje的mathml分支渲染typst博客页面。

实现细节

基本上代码全是gemini写的, 基本的做法就是通过vite plugin把typst文件编译成html, 然后使用正则表达式取出<style>和<body> 合并成一个html片段字符串, 然后使用typst query 命令取出frontmatter的内容。然后把这两个部分作为js模块的两个导出变量。

return {
code: `
export const frontmatter = ${JSON.stringify(frontmatter)};
export const html = ${JSON.stringify(finalHtml)};
export default html;
`,
map: null
};

接着就是使用astro提供的[…slug].astro生成动态路由, 把那两个导出的变量填进astro页面的模板中, 就能访问typst生成的博客页面了。

也就是说vite插件实际上是把typst的渲染结果(html)作为js变量导入到astro中。

构建环境

我使用cloudflare pages托管我的博客, 由于我使用的是自己编译的特定版本的typst, 构建环境并不能直接获取这个特殊版本的typst可执行文件, 我编译了一个musl静态链接的typst可执行文件(至于为什么要使用musl, 那就是另一个故事了), 并上传到cloudflare R2上, 然后在vite插件中下载该typst可执行文件, 这样就搞定了!

成果展示

基本的数学公式:
$ e^(pi i) + 1 = 0 $
𝑒 𝜋 𝑖 + 1 = 0
矩阵:
$ mat(1,2,3 ; 4,5,6; 7,8,9) $
( 1 2 3 4 5 6 7 8 9 )
Variants

下面的几种字体都是typst官网的例子:

sans:

$ sans(A B C) $
𝘈 𝘉 𝘊

frak:

$ frak(P) $
𝔓

mono:

$ mono(x + y = z) $
𝚡 + 𝚢 = 𝚣

bb:

$ bb(b) $
$ bb(N) = NN $
$ f: NN -> RR $
𝕓 = 𝑓 :

cal:

Let $cal(P)$ be the set of ...

Let 𝒫︀ be the set of …

scr:

$scr(L)$ is not the set of linear maps $cal(L)$.

ℒ︁ is not the set of linear maps ℒ︀ .

看起来Script font还是有点问题。不过我已经很满意了。