Nixtml 是一个纯 Nix 实现的静态网站生成器,利用 Nix flakes 的声明式特性,将内容、静态资源和主题组织成可重复构建的推导值(derivations)。这避免了传统 SSG 如 Hugo 或 Jekyll 中的 JS bundler 依赖,直接在 Nix 环境中生成纯静态 HTML、CSS 和 RSS,实现跨机一致的部署。核心优势在于一切均为 Nix 表达式:内容 Markdown 文件自动转换为 HTML 页面,集合支持分页和分类,主题通过模块导入覆盖,整个站点作为一个 flake 输出包,便于 nix build 和缓存。
配置 flake.nix:声明式站点定义
Nixtml 的入口是 nixtml.lib.mkWebsite,嵌入 flake outputs 中。以下是完整配置清单,按参数分类,便于落地:
基础参数(必需):
name: 站点名称,如"my-blog",用于输出目录。baseURL: 部署 URL,如"https://my-blog.com",确保相对链接正确。pkgs: 从 nixpkgs 导入的包集。
元数据(metadata):
metadata = {
lang = "en";
title = "My Blog";
description = "This is my blog";
};
这些在模板中可用,支持多语言和 SEO。
内容与静态(content.dir/static.dir):
content.dir = ./content;:遍历 Markdown 文件,content/blog/post.md→blog/post/index.html。static.dir = ./static;:符号链接整个目录到输出,无需额外处理图片 / JS/CSS。
集合(collections):用于博客分页、RSS 和分类。
collections.blog = {
path = "posts"; # content/posts/ 下文件
pagination.perPage = 5; # 每页 5 篇,推荐阈值避免长页
rss.enable = true; # 生成 /posts/index.xml
taxonomies = [ "tags" "series" ]; # 支持 tags/series 等,自动生成 /posts/tags/emacs/index.html
};
分页页码:posts/index.html、posts/page/2/index.html。Taxonomies 前置 YAML:
---
title: "My Emacs Setup"
date: 2024-07-15
tags: [ "emacs", "productivity" ]
series: [ "dotfiles" ]
---
主题导入(imports):
imports = [ ./theme.nix ];:模块化覆盖布局,如自定义website.layouts.base。
Serve 应用:
apps.serve = {
type = "app";
program = (pkgs.writeShellScript "serve" ''
${pkgs.python3}/bin/python -m http.server -d ${self.packages.${system}.blog} 8080
'').outPath;
};
运行 nix run .#serve 本地预览。
完整 flake 示例见官方仓库,确保 inputs.nixtml.url = "github:arnarg/nixtml";。
模板系统:Nix 函数式 HTML
模板定义在模块的 website.layouts 下,每个为函数返回字符串或列表。Nixtml 提供 lib.tags 如 html、head、body,及 attrs 辅助。
函数式示例(推荐,类型安全):
{lib, ...}: let
inherit (lib.tags) html head body div;
inherit (lib) attrs;
in {
website.layouts.base = { path, content, ... }@context:
"<!DOCTYPE html>\n" + html [ (attrs.lang metadata.lang) ] [
head [] [ (partials.head context) ]
body [ (attrs.classes [ "font-sans" "bg-white" ]) ] [
div [ (attrs.classes [ "container" ]) ] [ content ]
]
];
}
字符串模板备选:
<!DOCTYPE html>
<html lang="${metadata.lang}">
<head>${partials.head context}</head>
<body class="font-sans bg-white">
<div class="container">${content}</div>
</body>
</html>
标准模板:
base: 所有页骨架。home: index.md。page: 其他 Markdown。collection/taxonomy: 分页页,接收{ pageNumber, items, hasNext, ... }。partials: 共享片段。
参数化监控:模板上下文始终包含 metadata、content,集合页有 totalPages > 1 时启用分页导航。
构建、部署与可重复性
构建:nix build .#blog,输出 /result 目录纯静态文件。部署到 Netlify/Cloudflare Pages/Vercel 等,支持 GitHub Actions:
- nix build .#blog
- zip -r site.zip result/
- curl -T site.zip $DEPLOY_URL
无 JS bundler:Nix 隔离构建,确保 reproducible,无隐式依赖。
工程化参数与清单:
| 参数 | 推荐值 | 作用 |
|---|---|---|
| pagination.perPage | 5-10 | 加载速度阈值,SEO 友好 |
| rss.enable | true | 订阅源,perPage 同步 |
| taxonomies | ["tags"] | 最多 3 个,避免碎片 |
| baseURL | 精确域名 | 绝对链接,避免重定向 |
| metadata.description | <160 字 | OpenGraph/SEO |
回滚:Nix 版本固定 flake.lock,git checkout old-commit && nix build 瞬间回退。缓存:Cachix 或自建 binary cache,首次构建后秒级部署。
风险控制:Nix 学习曲线,起步用官方 examples.simple/blog 测试。规模大时,拆分 modules 避免单文件过长。
Nixtml 将静态站点构建提升到 Nix 声明式水平,内容即推导、主题即模块,完美契合 DevOps 流程。
资料来源:
- Nixtml GitHub:核心配置与模板文档。
- 示例博客:实际 flake 应用。