在Hakyll 4中配置Pandoc 3实现Markdown转HTML并兼容KaTeX
1. 如何正确理解Hakyll的Item类型?
Item的核心作用是把内容和它的资源标识绑定,Identifier本质是Hakyll用来追踪资源来源、管理缓存和依赖的标记(比如对应源文件的路径),和内容里的元数据(比如author、title)完全是两个独立的东西。
你完全不用把Identifier当成元数据的键——元数据存在Item的metadata字段里,比如要获取author字段,直接用itemMetadata item拿到元数据集合,再用lookupString "author"提取即可。Identifier只是Hakyll内部管理资源用的,和内容的业务元数据无关。
2. 能否获取Pandoc命令行的默认Context?
其实不用刻意“获取”,因为Pandoc命令行的--standalone效果是靠自身的模板和内置元数据处理逻辑实现的,Hakyll可以通过配置Pandoc的WriterOptions直接复用这套逻辑:
- 先导出Pandoc的默认HTML模板:执行
pandoc -D html > templates/default.html5,把模板放到Hakyll的templates目录下 - 配置WriterOptions时开启
writerStandalone = True,并指定模板路径,Pandoc会自动用内置的逻辑处理元数据(比如title、author、abstract这些),生成规范的标签,不需要你手动写Hakyll Context。
另外,metadataField是Hakyll模板用来读取元数据的工具,但如果你用Pandoc自带的模板,Pandoc会直接处理元数据,不需要依赖Hakyll的Context。
3. 当前实现是否正确?有没有更简便的复刻命令行效果的方法?
你当前的实现只生成了HTML主体,因为默认Hakyll的Pandoc编译器是生成片段,没有启用standalone模式。更简便的方式是让Pandoc直接生成完整的HTML文档,和命令行效果完全一致,步骤如下:
步骤1:导出Pandoc默认模板
执行命令导出模板到Hakyll的templates目录:
pandoc -D html > templates/default.html5
步骤2:编写完整的katexCompiler
import Hakyll import Text.Pandoc.Options import Text.Pandoc.Filter (applyFilters, JSONFilter(..)) import Text.Pandoc.Error (runIOorExplode) import Hakyll.Core.Compiler (recompilingUnsafeCompiler) import Data.Char (isSpace) import System.Process (readProcess) -- 辅助函数:去除字符串首尾空格 trim :: String -> String trim = f . f where f = reverse . dropWhile isSpace katexCompiler :: Compiler (Item String) katexCompiler = do -- 获取pandoc-katex对应的KaTeX版本,构造正确的CSS链接 katexVersion <- unsafeCompiler $ trim <$> readProcess "pandoc-katex" ["--katex-version"] "" let katexCss = "https://cdn.jsdelivr.net/npm/katex@" ++ katexVersion ++ "/dist/katex.min.css" pandocCss = "https://pandoc.org/demo/pandoc.css" -- 配置Pandoc Writer选项:启用standalone、指定模板、添加CSS链接 writerOpts = defaultHakyllWriterOptions { writerStandalone = True , writerTemplate = Just "templates/default.html5" , writerCSS = [katexCss, pandocCss] } -- 应用pandoc-katex滤镜 katexFilter doc = recompilingUnsafeCompiler $ runIOorExplode $ applyFilters noEngine def [JSONFilter "pandoc-katex"] [] doc -- 使用带滤镜和配置的Pandoc编译器 pandocCompilerWithTransformM defaultHakyllReaderOptions writerOpts katexFilter
步骤3:在站点规则中使用
比如处理markdown文件:
main :: IO () main = hakyll $ do match "posts/*.md" $ do route $ setExtension "html" compile katexCompiler
这样实现后,生成的HTML和你命令行执行的效果完全一致:包含Pandoc标准模板、加载指定的两个CSS、正确处理LaTeX公式、自动解析Markdown元数据生成对应标签。
内容的提问来源于stack exchange,提问作者user11718766

