Typsite二三想
Typsite二三想
1 从何处开始?
一款良好的 General Static Site Generator (GSSG),应当是一个 Content Compiler (CC):
- 输入: 内容、模板、配置、资源
- 中间过程: 解析、建模、路由、聚合、渲染
- 输出: 编译为输出目标
我们当然可以顺理成章地对这一层层结构做抽象,就像这样:
- 输入: (typst), (markdown), (html), (txt), etc.
- 中间过程: 统一的, 语义足够丰富的中间表示
- 输出: 可部署的完整静态网站, pdf, etc.
那么,基于 Why Concrete Syntax Doesnt Matte 文章中所提的观点,我们设计GSSG的重中之重应当是先设计一套良好的中间表示(Interprete Representation).
2 良好的中间表示?
我通常习惯于“Define it by what it does”, 首先,我们应当至少有两层IR:
- 文章层 Slug -> Metadata@(Relations, etc.)
- 内容层 Slug -> Content@(Plain Text, Cite, Embed, etc.)
并且为了性能考虑,它们都应当是被Flatten的.
考虑到
Embed
Embed
的存在,在渲染管线(Rendering Pipeline)中,应当单独生成一层记录了完整依赖信息与内容的渲染节点
- 渲染层 Slug -> Pending@(Plain Text, Cite Content(&Metadata.title), Embed Content(&Pending) etc.)
3 本地编译缓存?
为了加快编译,所有IR层都应当被完全缓存,当某个文章内容变动时则单独重新生成此文章的IR,由于在渲染层中我们所保存的依赖状态均为引用,所以其它所有本身内容未变动的文章不再任何重新编译,我们已经在渲染层记录过文章间的依赖关系,于是我们只用通过查询依赖关系重新将受影响的文章重新渲染到HTML便可
4 实时热更新预览!
实时热更新预览可以极大地提高用户体验,只要依赖信息足够,我们完全可以做到非常丝滑的热增量更新!
5 对于 typsite
既然要做typst这样一种给予用户极大操作能力的可编程标记语言的SSG,就需要在一致性 (Consistency) 与 通用性 (Generality) 之间做妥协了
5.1 typst + markdown ?
一款基于 Typst 的 SSG 不支持 Markdown, 并不必然是缺陷; 相反, 这恰恰可能是一种对系统一致性的坚持。
首先, 若系统的核心渲染模型, 语义表达, 排版能力, 宏系统乃至扩展机制都建立在 Typst 之上, 那么继续额外接纳 Markdown, 实际上就是在同一个系统内部并置两套不同的书写逻辑。表面上看, 这像是在“兼容更多用户习惯”; 但在结构上, 它意味着同一篇内容可以有两种语法, 两种抽象层次, 两种能力边界, 两种预期行为。于是问题便立刻出现: 究竟谁才是系统真正的“母语”?
一旦 Markdown 被纳入, 系统便不得不面对一种持续的分裂: 哪些功能是两者共有的, 哪些是 Typst 独有的, 哪些写法在一种语法中合法却在另一种中失效, 哪些组件可以跨语法复用, 哪些宏只能停留在 Typst 世界之内。开发者不得不不断解释“这里为什么 Markdown 不行”“那里为什么转换后结果不同”“这个特性为什么只支持 Typst”。这种解释成本, 本质上正是系统一致性已经被破坏的证明。
更重要的是, Typst 并不只是另一种标记语法; 它本身就是一套更完整的内容表达与排版语言。若一个 SSG 以 Typst 为根基, 那么内容, 结构, 组件, 模板, 样式, 本应共享同一种语法与同一种思维方式。作者写正文时使用 Typst, 定义组件时使用 Typst, 组织页面时使用 Typst, 扩展功能时仍使用 Typst; 这才构成一个真正内聚的系统。若在入口处放进 Markdown, 便等于承认最核心的写作层不属于这套语言自身, 而只是借道进入。如此一来, Typst 就不再是系统的基础, 而只是渲染终点; 系统内部也因此失去了“从书写到生成都说同一种语言”的完整性。
从一致性的角度看, 拒绝 Markdown, 其实是在拒绝一种常见却懒惰的折中: 为了降低迁移门槛, 而牺牲语言边界; 为了照顾旧习惯, 而削弱系统自身的清晰性。一个真正围绕 Typst 构建的 SSG, 理应让用户明确知道: 这里的内容不是“先随便写成别的, 再被翻译过来”, 而是从一开始就直接存在于 Typst 的世界里。只有这样, 语法, 语义, 能力与实现才能彼此对齐, 形成统一的心智模型。
因此, 基于 Typst 的 SSG 不支持 Markdown, 并不是“不够友好”, 而是拒绝让系统沦为多套语法拼接而成的折衷产物。它所维护的, 不只是实现上的简洁, 更是语言上的主权, 结构上的纯度, 以及整个生成流程自始至终的统一性。
简言之:既然选择了 Typst 作为根语言,就不应再让 Markdown 以“兼容性”之名,在入口处重新分裂系统。
5.2 为什么typsite不接入 vue/vite | react 等框架?
一句话就是对于typst来说完全没必要
5.2.1 Vue/Vite | React 能提供什么?
- 可复用性的组件(Components are great for reusable UI)
- 可交互式的内容(Contents are interactive)
- 庞大的社区
5.2.1.1 可复用组件?
对于typsite, 去做typst的组件化处理完全是天经地义的,甚至就typst本身来说————通过声明一些函数就能很好的完成组件化任务;不过,typsite要提供的是自动style/scripts导入与去重。
5.2.1.2 可交互内容?
对于一款 SSG 来说,我们真的有必要加入可交互的内容吗?甚至不惜引入一个臃肿的运行时来增大包体积? , SSG 的首要职责,从来不是在浏览器里再造一个小型应用程序,而是把内容尽可能直接,尽可能稳定地交付给用户。文章, 文档, 笔记, 索引页,这些页面的核心价值在于“阅读”与“检索”,而不是在客户端重新执行一整套组件树, 状态系统与 hydration 过程。若一个页面百分之九十的区域只是静态文本与链接,却仍要求用户为那极少数交互承担整套运行时的下载, 解析与执行成本,这本身就是一种本末倒置
更严重的是,一旦引入 React / Vite 这一类面向前端应用开发的体系,SSG 的重心便会悄然偏移:原本应当围绕“内容组织, 生成速度, 输出体积, 可移植性, 长期稳定性”展开的设计,开始被“组件拆分, 客户端状态, 路由水合, 构建链兼容性, 依赖升级”所支配。最后你得到的往往不再是一个纯粹的静态站点生成器,而是一个假装自己是 SSG 的前端工程脚手架
所谓“可交互内容”也常常被夸大。绝大多数站点真正需要的交互,无非是目录展开, 主题切换, 站内搜索, 代码块复制, 局部注释, 少量筛选。这些功能完全可以通过原生 JavaScript, 渐进增强,或极小规模的局部脚本实现;它们并不天然要求引入一个完整的虚拟 DOM, 组件运行时与 hydration 机制。若为了一个深色模式按钮而让整站背上框架负担,那不是工程上的进步,而是对复杂性的屈服
而且,SSG 的意义本就包含一种明确的技术立场:预先生成,提前完成;
- 能在构建期解决的问题,就不要留到运行期;
- 能输出为纯 HTML/CSS 的内容,就不要强行包装成客户端组件
因此,真正合理的原则应当是:交互应当是局部的、可选的、后附的增强;而不是整个 SSG 架构的出发点。
5.2.1.3 庞大的社区?
我们typst-universe的生态可是勃勃生机,万物竞发!