Nixtml:用 Nix 编写的静态网站和博客生成器
Nixtml: Static website and blog generator written in Nix

原始链接: https://github.com/arnarg/nixtml

## Nixtml:一个基于 Nix 的静态网站生成器 Nixtml 是一个使用 Nix 构建的静态网站生成器,灵感来自 Hugo。它允许你使用 Nix 表达式声明式地定义网站的结构和内容。 主要特性包括:Markdown 内容处理、基于目录的内容组织以及可定制的模板,这些模板定义为返回 HTML 字符串的函数。Nixtml 支持集合,用于分组和分页内容(如博客文章),以及分类法,用于使用标签或系列对内容进行分类。 配置通过 `flake.nix` 文件完成,你可以在其中定义元数据、内容目录、集合和模板导入。模板是模块化的,可以通过片段重用。Nixtml 会自动生成集合和分类法的列表页,包括 RSS 订阅源。 内置开发服务器 (`nix run .#serve`) 简化了测试。示例提供了基本用法和博客设置的演示,可通过 `nix build .#examples.simple` 和 `nix build .#examples.blog` 访问。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 Nixtml: 用 Nix 编写的静态网站和博客生成器 (github.com/arnarg) 21 分,by todsacerdoti 1 小时前 | 隐藏 | 过去 | 收藏 | 1 评论 JoelMcCracken 25 分钟前 [–] 不错!我一直在将我的网站迁移到大量使用 emacs/org 作为编写格式,并使用 nix 作为工具基础设施。我会记住这个工具,看看是否能帮到我;我还不确定我还需要做什么,而这些事情可能无法轻松地用 emacs 完成。回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

nixtml logo

A static website generator written in nix. Inspired by hugo.

{
  description = "My website generated using nixtml.";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    nixtml.url = "github:arnarg/nixtml";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
      nixtml,
    }:
    (flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs { inherit system; };
      in
      {
        packages.blog = nixtml.lib.mkWebsite {
          inherit pkgs;

          name = "my-blog";
          baseURL = "https://my-blog.com";

          # Arbitrary metdata to be used in
          # templates.
          metadata = {
            lang = "en";
            title = "My Blog";
            description = "This is my blog";
          };

          # Walk a directory of markdown files
          # and create a page for each of them.
          content.dir = ./content; 

          # Copy an entire directory and symlink
          # in the final website derivation.
          static.dir = ./static;

          # Collections are for paginating content
          # and generating RSS feeds.
          collections.blog = {
            path = "posts";

            # Posts in the collection should be
            # grouped by optional tags in posts'
            # frontmatter.
            taxonomies = [ "tags" ];
          };

          # Import any nixtml modules (good for
          # "themes").
          imports = [ ./theme.nix ];
        };

        # Quickly build and serve website with
        # `nix run .#serve`.
        apps.serve = {
          type = "app";
          program =
            (pkgs.writeShellScript "serve-blog" ''
              ${pkgs.python3}/bin/python -m http.server -d ${self.packages.${system}.blog} 8080
            '').outPath;
        };
      }
    ));
}

Templates should be defined in modules under website.layouts. All templates should be a function to a string (or list of strings, that is automatically coerced to a string).

In nixtml's lib there are functions for most commonly used HTML tags which can be used like this:

{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 ]
              )
            ]
          )
        ];
}

The above is equivalent to defining the markup using strings in nix:

{lib, ...}: {
  website.layouts.base =
    { path, content, ... }@context: ''
      <!DOCTYPE html>
      <html lang="${metadata.lang}">
        <head>
          ${partials.head context}
        </head>
        <body class="font-sant bg-white">
          <div class="container">
            ${content}
          </div>
        </body>
      </html>
    '';
}

Each template in website.layouts has a specific purpose.

  • website.layouts.base: Used for the skeleton of each HTML file for the website. It gets passed the result of other rendered templates.
  • website.layouts.hom: Used for ./index.md, if found in website.content.dir. It gets passed the metadata in the markdown frontmatter as well as the HTML content generated from markdown.
  • website.layouts.page: Used for any other markdown file found in website.content.dir. It gets passed the metadata in the markdown frontmatter as well as the HTML content generated from markdown.
  • website.layouts.collection: Used for pagination pages for collections.
  • website.layouts.taxonomy: Used for pagination pages for taxonomies in collections.
  • website.layouts.partials: An attribute set of templates (functions to string or list of strings) that can be used to reduce repitition in the other standard templates.

By setting website.content.dir nixtml will traverse that directory, transform any markdown file it finds and output an HTML file in the final website derivation with the same path. For example, ${content.dir}/about.md becomes about/index.html in the final website derivation.

Collections allow you to group, paginate and list related content such as blog posts or portfolio pieces.

Create a collection under website.collections.<name> and point it to a folder inside website.content.dir.

website.collections.blog = {
  path = "blog/posts";     # ./content/blog/posts/
  pagination.perPage = 5;  # Number of items each listing page shows
  rss.enable = true;       # Generate /blog/index.xml
};

nixtml automatically produces listing pages hosting pagination.perPage items per page (blog/index.html, blog/page/2/index.html, …) rendered with the collection layout template.

You may want to allow readers to explore entries by common key–words such as tags, categories or authors. Activate any number of taxonomies with the list key taxonomies:

website.collections.blog = {
  path = "blog/posts";
  taxonomies = [ "tags" "series" ];
};

In every markdown file inside that collection you can now list these terms in the YAML frontmatter:

---
title: "My Emacs Setup"
date: 2024-07-15
tags:
  - emacs
  - productivity
series:
  - dotfiles
---
Post body…

nixtml will then create pages such as /blog/tags/emacs/index.html, /blog/tags/emacs/page/2/index.html and so on using the taxonomy layout template.

Inside collection or taxonomy templates you always receive the same context attribute set:

{
  # --- collection & taxonomy -------------
  pageNumber,     # Current page number
  totalPages,     # Total amount of pages
  items,          # List of posts in this page
  hasNext,        # A next page exists (bool)
  hasPrev,        # A previous page exists (bool)
  nextPageURL,    # URL to next page
  prevPageURL,    # URL to previous page
  # --- only taxonomy --------------------
  title,          # The tag or term being shown
}

Look at the examples directory to see how to work with nixtml. They can be built with nix build .#examples.simple and nix build .#examples.blog.

联系我们 contact @ memedata.com