从 Cargo examples 生成站点(Experimental)
本例让 Notist SSG 在构建时读取 Cargo.toml 的 [[example]] 和 Rust 源文件,为每个 example 生成一个页面及模板数据。增减 Cargo targets 后重新构建即可,无须为每项维护独立的文档与 data 目录中的 TOML 文件。
本例使用 SSG 的 beforecompile 生成源码,在同一进程中保留元信息,随后在 beforetemplate 生成模板数据。协议见 SSG 站点扩展。
文件布局
project/
Cargo.toml
examples/
hello/main.rs
website/
Notist.toml
content/index.not
scripts/examples.py
templates/page.tera
准备一个最小 Cargo.toml:
[]
= "demo"
= "0.1.0"
= "2024"
[[]]
= "hello"
= "examples/hello/main.rs"
examples/hello/main.rs:
配置扩展
website/Notist.toml:
[]
= "example-site"
[]
= "Rust examples"
= "content"
= "public"
[]
= ["python3", "scripts/examples.py", "../Cargo.toml"]
= ["scripts", "../Cargo.toml", "../examples"]
脚本在 website 目录运行,因此 ../Cargo.toml 指向项目清单。watch 中的路径也相对于 website:清单和 Rust 源码位于站点根之外,需要显式声明才能触发预览重建。依赖目录递归监听,新增 example 目录也会触发重建。脚本需要 Python 3.11+,使用标准库中的 tomllib 解析 TOML。
website/content/index.not 是唯一需要手写的内容页:
= Rust examples
[浏览 example 目录](examples/index.md)。
链接目标稍后由扩展创建,可以在构建中正常解析。
实现事件处理
将下面代码保存到 website/scripts/examples.py:
=
=
# 本扩展管理 examples/ 页面和 site.data.examples。
del
=
=
=
=
=
=
=
= +
return ,
=
=
=
, =
=
=
=
=
documents 的键相对于 content:examples/hello.md 生成 examples/hello.html。根注解将 example 名称提供给模板中的 page.attrs.example。
本扩展重新生成 examples/ 下的页面与 site.data.examples,保留其他内容。请将手写页面放在 examples/ 以外,避免被覆盖。
页面模板
website/templates/page.tera:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{{page.title}} · {{site.title}}</title>
<link rel="stylesheet" href="{{assets.highlight}}">
</head>
<body>
<nav><a href="{{url(path='index.html')}}">Home</a></nav>
<main>
{{page.html | safe}}
</main>
{% if assets.components %}
<script type="module" src="{{assets.components}}"></script>
{% endif %}
</body>
</html>
模板通过 page.html 放置生成的正文,包括 Rust 代码高亮。还可以通过 site.data.examples 访问脚本生成的数据,见 模板。
构建与检查
从 project 目录执行:
输出结构为:
website/public/
index.html
examples/
index.html
hello.html
content 中仍只有手写的 index.not,data 目录不需要创建。添加新的 Cargo example target 及源码后,预览会生成相应页面;删除 target 后,再次成功构建会清理旧输出。
调试脚本时,日志写到 stderr,例如 print("loading manifest", file=sys.stderr)。stdout 只能返回协议响应。清单缺失或无法解析时,本例返回 errors,构建失败,CLI 保留已有输出;修复被 watch 观察的文件后,预览会重新构建。
单独执行 notist check website/content/index.not 只检查现有单文档,不执行站点扩展,因此应通过 build 检查生成页面之间的链接和完整站点。
仓库还提供 examples/ssg-extensions,包含分组目录、相邻 scenes.rs 源码读取,以及保留现有媒体数据的生成版本。从 Notist 仓库根目录可直接执行:
该示例使用 ranim 的 example 目录布局。它是 Notist 仓库 workspace 的成员,通过 -p 按包名选择,默认输出到仓库根的 notist-output/ssg-extensions/。上面的 website/public/ 则来自教程清单中显式配置的 output = "public"。