投递职位需要 PDF 版简历,但内容仍希望用 Markdown 维护。这次在 Arch Linux 上搭了一套 Pandoc + XeLaTeX 流程,把中英文简历稳定导出为 PDF,并沉淀了定制 LaTeX 模板与一键脚本。本文记录选型、依赖安装、流水线、排版分工,以及模板优化上踩过的坑。

背景

源文件是 Markdown:多级标题、表格、列表、加粗混排。需要:

  • 中英文各一份 PDF,字体分别可调
  • 改 Markdown 后能一条命令重新导出
  • 排版达到简历水准(页眉、列表间距、技能表行间线等)

早期试过 cmark + Chromium headless(Markdown → HTML → 打印 PDF),能跑通,但 CSS 调版费时;最终选用 Pandoc 生成 LaTeX,再用 XeLaTeX 编译 PDF——排版可控,适合反复迭代。

工具链概览

组件 作用
LaTeX 中间排版语言(.tex);详见 LaTeX 简介
Pandoc Markdown → LaTeX(--standalone);详见 Pandoc 介绍
XeLaTeX 编译 .tex 为 PDF;详见 XeLaTeX 介绍
resume.latex 定制 Pandoc LaTeX 模板(基于默认模板,统一入口)
resume-style.tex 标题层级、列表间距、页眉样式、技能表行间线
pandoc-pdf.sh 串联上述步骤的一键脚本

整体流水线:

Resume.md
  → pandoc(--template resume.latex + resume-style.tex + 字体变量)
  → input.tex
  → xelatex × 2
  → Resume.pdf

相比早期实现,已去掉 Python 后处理:表格行间 \midrule 与标题样式一并写在 LaTeX 模板层(resume-style.tex),由 Pandoc 在生成 .tex 时注入导言区。

XeLaTeX 跑两遍,是为了稳定生成目录、交叉引用和部分书签(即使简历里用得不多,习惯上保留)。

Markdown 与细排版的分工

层级 文件 / 工具 负责什么
内容与结构 Resume_*.md 文字、标题层级、列表、表格;页眉联系行可嵌 \resumecontactline{...}
全局参数 pandoc-pdf.sh 的 -V 页边距、行距、纸张、主字体(中/英分支)
版式规则 resume-style.tex 标题字号与间距、列表、段间距、表格行间线、\resumecontactline 宏
模板骨架 resume.latex Pandoc 默认 LaTeX 结构 + 引入 resume-style.tex
结构翻译 Pandoc 内置 把 # / 列表 / 表格 转成 LaTeX 命令($body$)
编译 XeLaTeX 字体渲染、分页、输出 PDF

改内容只动 .md;改「看起来像不像简历」主要动 resume-style.tex 和脚本里的 -V。

input.tex 默认在临时目录生成,脚本结束后删除。调试时可手动:

pandoc resume.md --standalone --template=resume/templates/resume.latex \
  -V resumeStylePath=resume/templates/resume-style.tex \
  ... -o resume.debug.tex

Arch Linux 依赖安装

Arch 上 Pandoc 包名是 pandoc-cli(提供 pandoc 命令)。中文 PDF 还需要 CJK 相关 TeX 包和字体;英文简历另装 Inter。

sudo pacman -S --needed \
  pandoc-cli \
  texlive-basic texlive-latexrecommended texlive-xetex \
  texlive-fontsrecommended texlive-langcjk texlive-langchinese texlive-latexextra \
  noto-fonts-cjk inter-font
包 用途
texlive-xetex XeLaTeX 引擎
texlive-fontsrecommended 提供 lmodern.sty 等(首次英文编译常缺)
texlive-langcjk / texlive-langchinese 中文 xeCJK、ctex 宏包
texlive-latexextra titlesec(章节标题样式)
noto-fonts-cjk 中文简历字体
inter-font 英文简历字体

texlive-* 合计约 1 GB,只在需要高质量排版的机器上装即可。

一键导出

脚本放在个人配置仓库的 resume/scripts/pandoc-pdf.sh:

resume/scripts/pandoc-pdf.sh path/to/Resume_cn_example.md
resume/scripts/pandoc-pdf.sh path/to/Resume_en_example.md

输出与源文件同目录、同名 .pdf。脚本核心逻辑:

  1. 按文件名判断中/英,设置不同 mainfont
  2. pandoc 使用 --template resume.latex,经 resumeStylePath 引入 resume-style.tex
  3. 生成 input.tex(A4、页边距、行距等 -V 变量)
  4. xelatex 编译两次

Pandoc 侧关键参数示例:

pandoc resume.md \
  --standalone \
  --template=resume/templates/resume.latex \
  --pdf-engine=xelatex \
  -V resumeStylePath=resume/templates/resume-style.tex \
  -V papersize=a4 \
  -V geometry:top=1.5cm \
  -V geometry:bottom=1.5cm \
  -V geometry:left=1.8cm \
  -V geometry:right=1.8cm \
  -V linestretch=1.35 \
  -V mainfont="Noto Sans CJK SC" \
  -V CJKmainfont="Noto Sans CJK SC"

英文简历把 mainfont 换成 Inter 即可,不必设 CJKmainfont。

字体策略

版本 字体 说明
中文 Noto Sans CJK SC mainfont + CJKmainfont 均指向同一字体,避免中英文混排风格不一致
英文 Inter 无衬线,偏现代简历风格

正文里避免 Markdown 反引号行内代码(如 `kubectl`)。Pandoc 会输出 \texttt{},切换到等宽字体,与正文 sans-serif 不协调。技术名词用普通文字或加粗即可。

LaTeX 模板做了什么

resume-style.tex(由定制模板 resume.latex 引入)用 titlesec 控制标题层级,用 enumitem 拉开列表间距。要点:

  • 姓名(# → \section):左对齐 24pt
  • 联系信息:通过 \resumecontactline{...} 渲染为 10pt 灰色单行
  • ## 章节:仅加粗,不加下划线(避免和表格顶线叠成双线)
  • 正文 10.5pt(scrextend),行距 1.35
  • 技能表行间线:在 \endlastfoot 后重定义 \\,于 longtable 数据行之间自动插入 \midrule(无需 Python 后处理)

页眉示例(Markdown 内嵌 LaTeX,配合 raw_tex):

\resumecontactline{城市 · +86 1xx xxxx xxxx · \href{mailto:you@example.com}{you@example.com} · \href{https://example.com}{example.com}}

\href 需要 hyperref(Pandoc 转 PDF 时会自动加载),链接在 PDF 里可点击。

Markdown 排版约定

与 Pandoc 默认行为打交道时,总结了几条约定:

问题 处理
--- 分隔线 不要用。Pandoc 会生成居中半宽横线,简历里很突兀
「个人信息」章节 欧美简历风格:姓名 + 一行联系信息即可,不设 ## 个人信息
分组小标题 工作经历内用 #####,比加粗段落层次更清晰
过长 bullet 拆成主条 + 子列表,避免「文字墙」
技能表行间线 由 resume-style.tex 在 longtable 导言区钩子处理,不再单独跑 Python

中文简历联系行写所在城市;英文写 City, Country。

Typst 与 Quarto

选型时除了 HTML 打印路线,也看过 Typst 和 Quarto。二者定位不同:Quarto 是 Pandoc 之上的「出版框架」;Typst 是另一套排版引擎,可减轻 TeX Live 负担。当前主流程仍是 Pandoc + XeLaTeX,下表是与本文场景的对比。

三者关系(先分清层次)

                    Markdown / 类 Markdown 源稿
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
   Pandoc + XeLaTeX        Quarto              Typst
   (本文主流程)      (底层仍常走 Pandoc      (独立引擎;
                        + LaTeX 出 PDF)         也可经 Pandoc 接入)
          │                   │                   │
          ▼                   ▼                   ▼
        LaTeX              LaTeX / HTML         .typ → PDF
          │              等多格式                 (通常不经 LaTeX)
          ▼
        PDF

对比表

维度 Pandoc + XeLaTeX(当前) Quarto Typst
是什么 通用转换器 + LaTeX 引擎 基于 Pandoc 的「可重复出版」工具 新一代标记排版语言 + 编译器
源文件 .md .qmd(Markdown + YAML 元数据) .typ,或 Pandoc 从 .md 转 .typ
出 PDF 的路径 md → tex → xelatex 多数情况仍是 md → tex → xelatex md → typ → typst compile,或直接写 .typ
依赖体积 大(texlive-* 约 1 GB) 在 Pandoc/TeX 之上再加 Quarto CLI 小(typst 单包,Arch 上远小于 TeX Live)
编译速度 慢(xelatex × 2) 与底层引擎相同 快
排版控制力 很强(resume-style.tex + resume.latex) 与 Pandoc+LaTeX 同级(共用引擎) 强,语法比 LaTeX 简洁
中文 / 系统字体 成熟(XeLaTeX + fontspec / xeCJK) 同左 支持良好,需按 Typst 方式配置字体
简历场景匹配度 已验证(脚本 + 模板已落地) 功能偏多,简历只用 PDF 时收益有限 有潜力,需重写版式模板
迁移成本 — 低:把现有 md 包进 .qmd,PDF 参数基本可复用 中高:resume-style.tex 要改写成 Typst 模板或 #set 规则
多格式同源 需另配 Pandoc 参数 强项(PDF / HTML / 幻灯片等一条命令) 以 PDF 为主,其它格式非重点

Quarto:换壳不换芯

Quarto 底层依赖 Pandoc。出 PDF 时通常仍指定 --pdf-engine=xelatex,仍要装 TeX Live,版式仍由 LaTeX 模板控制——不是绕开 LaTeX,而是把配置收进 YAML 和项目结构。

适合 Quarto 的情况:

  • 同一份稿要稳定产出 PDF + 网站 + 幻灯片(技术博客、论文、讲义)
  • 需要 交叉引用、代码块执行、文献管理 等「出版级」能力
  • 团队已统一 Quarto 工作流

对只做投递简历 PDF 而言,Quarto 多一层 CLI 和 .qmd 约定,不会比现有 pandoc-pdf.sh 更简单,也不会更轻。若未来简历仓库还要附带「在线版 HTML 简历」或演讲稿,再评估 Quarto 更合适。

示意(本质与 Pandoc 命令等价):

quarto render resume.qmd --to pdf
# 内部:解析 .qmd → 调用 pandoc → xelatex

Typst:换引擎,可能更轻

Typst 是独立的排版系统,编译器直接出 PDF,不依赖 TeX Live。Arch 安装:

sudo pacman -S typst

与 Markdown 简历的衔接方式:

  1. Pandoc 中转:pandoc resume.md -o resume.typ -t typst,再 typst compile resume.typ
  2. 直接写 .typ:版式用 Typst 原生语法(#set page(...)、#text(size: 24pt)[姓名] 等)

相对当前方案的优势:

  • 安装与编译都更轻、更快
  • 表格、标题、间距用 Typst 语法表达,往往比 LaTeX 宏包组合更直观
  • 不必维护独立的后处理脚本(若版式在 Typst 模板里一次定义好)

代价与风险:

  • 现有 resume-style.tex 不能复用,要迁移为 Typst 模板或 Pandoc 的 typst 模板
  • Pandoc 的 Typst 后端与 LaTeX 后端成熟度、默认模板质量仍在演进,复杂简历需更多自测
  • 生态(简历范例、企业模板)不如 LaTeX 丰富

若主要痛点是 TeX Live 体积和编译慢,Typst 值得做一个小型 PoC;若当前 PDF 已满意,没有迫切理由立刻迁移。

怎么选(简历场景)

你的目标 建议
PDF 版式已达标,继续迭代内容 维持 Pandoc + XeLaTeX
想少装依赖、加快编译 试 Typst PoC,对比同一份简历的版式与维护成本
同时要 PDF、HTML 简历页、幻灯片 评估 Quarto
偶尔导一次、不想装 TeX 保留 HTML 打印或编辑器插件作兜底(见下节)

本次讨论结论与后续计划

围绕「简历场景下是否考虑 Typst」补充几个结论,避免后续重复调研:

结论速记

问题 结论(简历场景)
Typst 是否开源免费 是。Typst 编译器(CLI)是 Apache-2.0 开源软件,可免费商用;Web 编辑器有免费档和付费档,但本地编译不依赖它
Typst 是否有替代 XeLaTeX 潜力 有。在简历、报告、程序化 PDF 生成场景潜力明显;但在学术投稿模板与超大 LaTeX 生态方面,短期难全面替代
Typst 是否流行、社区是否活跃 增长快且活跃。开源后持续迭代,社区包和编辑器生态在增长;相对 LaTeX 仍是新生态,成熟度与覆盖面仍在追赶

为什么暂不切换主流程

  • 当前 Pandoc + XeLaTeX 已满足投递质量,且中英文版式已稳定
  • 现有 resume-style.tex、定制 Pandoc 模板可复用,迁移成本已摊薄
  • 若立即切换 Typst,需要重写模板并重新做一轮版式回归

下次可执行的 Typst PoC(记录)

目标:在不影响当前投递流程的前提下,评估 Typst 是否值得作为后续候选方案。

  1. 环境:安装 typst,保留现有 TeX 流程不动
  2. 输入:使用同一份中文简历 Resume_cn_example.md
  3. 路线 A:pandoc -t typst 生成 .typ,再 typst compile
  4. 路线 B:手写最小 Typst 模板(姓名、联系行、技能表)验证版式控制
  5. 对比项:编译耗时、依赖体积、字体效果、表格可控性、模板维护复杂度
  6. 验收:若版式达到当前 PDF 水平且维护成本更低,再评估是否引入并行脚本(如 typst-pdf.sh)

其它备选方案(未纳入主流程)

方案 特点
cmark + Chromium 无 TeX,轻量;CSS 调版成本高
npx md-to-pdf 一行命令;依赖下载慢,离线不便
VS Code 插件 Markdown PDF 适合偶尔手工导出,难脚本化

小结

对结构复杂、需要精细排版的 Markdown(简历、说明文档),Pandoc + XeLaTeX + 定制 LaTeX 模板 比 HTML 打印路线更可控。成本是 TeX 依赖体积和一点 LaTeX 学习曲线;收益是字体、间距、表格、分页都能稳定复现。

当前实现将标题样式与表格行间线收进 resume.latex + resume-style.tex,去掉了 Python 后处理,流水线更短、更易维护。

Quarto 并未替代 LaTeX,适合多格式出版,对「只出简历 PDF」偏重。Typst 是更轻的潜在替代引擎,值得在 TeX 体积成为瓶颈时再试,但需重写版式层。

更完整的 Spec、脚本与模板见个人配置仓库中的 resume/TASK-SPEC-markdown-to-pdf.md(与本文同步维护)。

维护记录