D0009: Preview and HTML
Notist 的 HTML 能力分为三个层次:notist-html 将语义文档渲染为 HTML fragment,notist build 将整个 vault 构建为静态站点,notist preview 在本地持续构建并提供浏览器预览。
三者共享同一条语言管线:
.not source
-> notist-syntax
-> notist-eval lowering
-> structuring
-> StructuredDocument
-> notist-htmlHTML 层不重新解释源码。语法、函数、scope 和 reference 的语义只在 syntax、eval 与 analysis 中定义一次,preview 和 build 只是这些结果的不同消费者。
产品模型
Notist 的基本单位是 vault/module,而不是孤立文件。因此 HTML 输出也以整个 Workspace 为单位:
每个 Module 都有稳定页面。
Wiki Reference 变成模块之间的导航链接。
没有
README.not的虚拟目录模块也有索引页面。页面共享 vault 导航和静态资源。
build 与 preview 使用相同的页面结构和 URL 规则。
build 负责可部署的静态结果,preview 负责编辑期间的快速反馈。二者不应发展出两套渲染语义。
notist-html
notist-html 是纯渲染 crate。它接收 StructuredDocument,输出可嵌入页面的 semantic HTML fragment。
它负责:
渲染 Block、Content 和 Element。
转义文本、属性和 Raw 内容。
输出 source byte range metadata。
根据调用方提供的上下文生成或解析 Reference 链接。
为 Custom 和 UnresolvedCall 提供安全且可见的降级结果。
它不负责:
读取文件或扫描 Workspace。
执行 parser、lowering 或 Function。
判断某个目标 Module 是否真实存在。
生成完整页面、导航栏和站点主题。
启动 HTTP 服务或监听文件变化。
保持 fragment renderer 的边界,可以让静态构建、preview、测试以及未来的编辑器 Hover 复用同一层。
HTML 映射
核心映射为:
Block::Paragraph->pBlock::List->ul和liText-> escaped text spanStrong->strongHeading->h1到h6Quote->blockquoteinline
Raw->codeblock
Raw->pre > codeReference->a.notist-referenceunresolved Reference -> 不可点击的
spanCustom-> 带data-notist-name的span或divUnresolvedCall-> 保留函数名与 body 的降级容器
Raw Element 的文本和 Custom 内容都不是可信 HTML。插件渲染 HTML 时必须经过显式的 trusted renderer 边界,不能让 Raw 内容绕过转义。
Source Range
语义元素输出其原始 byte range:
data-notist-start="12" data-notist-end="28"这些 metadata 为未来的点击预览跳转源码、Hover fragment 和选择同步保留稳定接口。
Annotation 可能跨越多个 Element 或 block,不能总是直接映射为一个合法嵌套的 DOM 节点。Element range 可以直接进入 metadata;需要可视化 Annotation 时,通过 range events 切分 Content,再生成正确嵌套的 annotated spans。
Static Build
静态导出使用 workspace 级命令:
notist build docs -o dist构建器遍历整个 Workspace,并将 ModulePath 映射为 clean URL:
vault->index.htmlvault::grammar->grammar/index.htmlvault::designs::type system->designs/type system/index.html
URL 中的路径 segment 必须单独 percent encode。页面之间使用相对链接,使构建结果可以直接从任意静态文件服务器或子路径部署。
Wiki Reference 在构建时解析:目标存在时输出链接;目标不存在时保留可见文本和 unresolved 样式。语法、analysis 或 evaluation diagnostics 不阻止生成其他可用页面,但 notist build 应输出 diagnostics 并返回非零退出码。
站点级职责属于 CLI build 层,包括:
完整 HTML page shell。
vault 名称、当前 Module 标识和模块导航。
_notist/style.css等共享资源。虚拟目录模块页面。
ModulePath 到输出目录与相对 URL 的映射。
默认构建不清空整个输出目录,避免误删用户文件。它只创建或覆盖本次 Workspace 对应的页面和 _notist 资源;删除旧产物必须由显式 --clean 请求触发。
Local Preview
本地预览复用 static build,不维护独立的动态渲染 API:
notist preview .
notist preview . --port 3000 --no-open
notist preview . --host 0.0.0.0 --port 3000默认行为:
通过 vault::designs::D0012-daemon-and-client-interfaces 的 daemon 或 embedded service 打开 disk View。
打开根模块
vault。观察 disk View 的 snapshot publication 并 debounce。
重新构建带 live reload 资源的完整站点。
使用系统分配的空闲端口并自动打开浏览器。
analysis 和 evaluation diagnostics 输出到 CLI。
默认只监听
127.0.0.1。
Preview 结构为:
filesystem event or explicit rebuild
-> VaultEngine / Analyzer View
-> publish WorkspaceSnapshot
-> debounce snapshot generation
-> build complete staging site
-> replace served site
-> publish preview generation over SSE
-> browser reloads current clean URLHTTP 服务只需要两个表面:
GET /和各 Module clean URL:由静态目录服务返回页面。GET /_notist/events:发送当前 revision 和后续 revision 更新。
页面中的 _notist/reload.js 使用 EventSource 订阅 revision。连接建立和重连时先收到当前值,因此浏览器可以发现断线期间错过的构建。完整页面 reload 不需要 WebSocket、DOM diff 或自定义文档协议。
Atomic Rebuild
文件变化后先在 staging 目录生成完整站点,成功后再替换当前服务目录。文件读取或构建过程出现致命错误时,旧站点继续可见,并在 CLI 输出 rebuild failed。
可恢复的 syntax、analysis 和 evaluation diagnostics 不属于构建基础设施失败。页面仍可使用降级语义生成,同时 diagnostics 在终端报告。
目录替换必须保证浏览器不会读到只写了一半的页面集合。需要更严格的跨平台原子切换时,服务状态持有不可变 generation 目录,而不是让请求观察原地删除后 rename 的中间状态。
Network Boundary
Preview 会暴露用户正在编辑的文档内容,因此默认只能监听 loopback。显式使用非 loopback 地址时必须显示警告。
源码读取、编辑操作或远程共享需要随机访问 token、Origin 检查和独立授权边界。只读静态页面与 revision stream 不应被自然扩展成无认证的编辑 API。
Workspace Consistency
Parse 的 byte range、源码文本和分析结果必须来自同一个 Workspace snapshot。不能在 analysis 完成后,再由 renderer 重新读取可能已经变化的文件。
Snapshot 的构造、revision、identity 与发布规则见 vault::designs::D0011-analyzer-and-workspace-snapshot;本文只规定 build 和 preview 如何消费捕获后的 snapshot。
Analysis 提供稳定 snapshot:
Module 保存
Arc<str>或等价的不可变 source。提供按 ModulePath 查询 Module 的公开接口。
source、Parse、resolved references 和 diagnostics 属于同一 revision。
reload 完整构造新 snapshot,完成后整体替换旧 snapshot。
Preview、diagnostics、Hover 和 definition 共享同一个文档版本,而不是分别读取磁盘。