2026-10-15 · 原文发布日
把LaTeX存进网址:可分享的在线渲染器
Simon Willison受Tiny Little Office启发,用Claude Code做了一个纯网页LaTeX渲染器:粘贴或从URL、Gist载入源码,编辑器与渲染视图可切换,单条公式走MathJax、整篇文档走faster-latex。所有内容编码进URL的#fragment,渲染结果本身就是可收藏、可分享的链接,文中还附了他逐条提需求的完整提示词和iframe沙箱防XSS思路。
原文要点
Simon Willison受Tiny Little Office启发,用Claude Code做了一个纯网页LaTeX渲染器:源码既可粘贴输入也可从URL或Gist载入,编辑/渲染视图可切换;单条公式用MathJax排版,整篇文档用faster-latex。所有内容编码进URL的#fragment,渲染页本身就是可分享链接;支持自定义压缩字典(Pako)缩短链接,并借鉴其SVG工具的iframe sandbox机制防XSS。文中列出依赖版本:Pako 2.1.0、MathJax 4.1.3、faster-latex 0.3.1、DOMPurify 3.4.16。
这次做成什么
照着做一个最小可用的单文件LaTeX渲染页:粘贴LaTeX→即时渲染→生成含源码的可分享URL;并给出一段可直接喂给AI编程助手的完整提示词,复刻原作者的提需求方式。
准备什么
- 一个纯文本编辑器(如VS Code)和现代浏览器
- 能访问CDN加载MathJax、Pako、DOMPurify(离线需自备库文件)
- 本地静态服务器(如python -m http.server),避免file://下fetch受限
具体怎么做
新建单文件页面骨架
创建latex-share.html,写编辑器textarea与渲染div两个区域,加一个“编辑/渲染”切换按钮;在head里用script标签从CDN引入MathJax、Pako、DOMPurify三个库。
实现源码进URL
点“渲染”时取textarea内容,用pako.deflate压缩后经btoa转base64,拼成location.hash='#p:'+base64;页面加载时若hash以#p:开头则解压还原源码,若以#开头则按encodeURIComponent解码,再写入编辑器并触发渲染。
渲染并消毒
把LaTeX源码交给MathJax排版(MathJax.typesetPromise),输出HTML先经DOMPurify.sanitize再写入渲染区,防止源码中夹带<script>之类的注入。
加iframe沙箱(可选加固)
若想彻底隔离,可把渲染页放进<iframe sandbox="allow-scripts">,父页只通过postMessage传源码,仿照原文借用的SVG工具防护思路。
验证分享链路
输入一段公式,点渲染,复制地址栏完整URL发给另一浏览器窗口打开,确认无需任何服务器存储即可还原同样渲染结果。
可直接复制的材料
最小可运行单文件latex-share.html
本站独立编写的精简示例,仅覆盖hash存取+MathJax+DOMPurify主链路;faster-latex整文档模式与自定义压缩字典未实现,如需请按原思路扩展。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>LaTeX分享渲染器</title>
<script src="https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.4.16/dist/purify.min.js"></script>
<script>
window.MathJax={tex:{inlineMath:[['$','$'],['\\(','\\)']]},svg:{fontCache:'global'}};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@4.1.3/es5/tex-svg.js"></script>
</head>
<body>
<button id="toggle">切换渲染</button>
<textarea id="src" rows="8" cols="60" placeholder="粘贴LaTeX源码"></textarea>
<div id="out"></div>
<script>
const src=document.getElementById('src'),out=document.getElementById('out'),tg=document.getElementById('toggle');
function toHash(t){const c=pako.deflate(t);const b=btoa(String.fromCharCode(...c));location.hash='p:'+b;}
function fromHash(){const h=location.hash.slice(1);if(h.startsWith('p:')){const bin=atob(h.slice(2));const arr=Uint8Array.from(bin,c=>c.charCodeAt(0));return new TextDecoder().decode(pako.inflate(arr));}return decodeURIComponent(h);}
async function render(){toHash(src.value);const html=DOMPurify.sanitize(src.value);out.innerHTML=html;src.style.display='none';out.style.display='block';await MathJax.typesetPromise([out]);tg.textContent='编辑源码';}
tg.onclick=()=>{if(src.style.display==='none'){src.style.display='block';out.style.display='none';tg.textContent='切换渲染';}else{render();}};
if(location.hash.length>1){src.value=fromHash();render();}
</script>
</body>
</html>给AI编程助手的复刻提示词
本站按原文公开的需求顺序改写的中文提示词,可直接粘贴给Claude Code等助手,逐条对应原文列出的几轮需求。
我要一个纯前端工具:可以用#片段链接(#后面接LaTeX代码)直接渲染该代码,排版效果要好;还要支持一个p:前缀,表示LaTeX先经deflate压缩再base64编码,以缩短链接。从CDN引入最合适的LaTeX渲染库(单条公式用MathJax,整篇文档可考虑WebAssembly方案)。无hash加载时显示编辑器,可粘贴LaTeX并切换到“渲染”视图,渲染视图本身要可收藏分享;从#片段链接打开时也要能切回编辑源码。渲染输出必须先经DOMPurify消毒;为防XSS,渲染区可放进iframe沙箱,参考既有SVG渲染项目的做法。再加一个从URL或GitHub Gist载入LaTeX源码的选项。输入与输出示例
本站虚构演示,hash值为示意,未实际运行;实际base64取决于压缩结果。
输入
在编辑器粘贴:欧拉恒等式 $e^{i\pi}+1=0$ 被称为最美的公式。对应输出
点“切换渲染”后地址栏变为 latex-share.html#p:eJxLTS5JLU5RyM...(示意base64),页面显示排版后的公式“e^{iπ}+1=0”与中文句子同行;把完整URL发到新窗口打开,无需服务器即还原同一渲染。做完检查这些
- 新开浏览器窗口粘贴分享链接,能直接看到渲染结果而不是编辑器空白页
- 源码中含<script>alert(1)</script>时渲染页不弹窗,说明消毒生效
- 无hash打开页面时出现编辑器且可正常切换到渲染视图
- 地址栏hash以p:开头且长度明显短于encodeURIComponent直编码版本
容易卡住的地方
- file://协议直接打开时部分浏览器限制CDN脚本或fetch,建议用本地静态服务器
- MathJax排版是异步的,写入DOM后必须等typesetPromise完成再算渲染完成
- base64含+/=字符,放hash前最好换成URL安全字符或在解码端兼容处理
- 整篇LaTeX文档(含\documentclass)MathJax排不了,需引入faster-latex之类方案
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- LaTeX renderer
- 原作者
- Simon Willison
- 原始发布日期
- 2026-10-15
- 来源
- https://simonwillison.net/2026/Oct/15/latex/