snow

command module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2026 License: BSD-3-Clause Imports: 1 Imported by: 0

README

* Snow
  静态博客生成器

** 快速开始
*** 开始(Quickstart)
**** 创建新的站点
     #+begin_example
     ──╼ ./snow init
     Welcome to snow 0.1.0.
     > Where do you want to create your new web site? [.] mysnow
     > What will be the title of this web site? [snow]
     > Who will be the author of this web site?
     The input is required
     > Who will be the author of this web site? honmaple
     > What is your URL prefix? (no trailing slash) [http://127.0.0.1:8000]
     > Do you want to create first page? [Y/n]
     #+end_example

**** 编译和预览
     #+begin_example
     └──╼ cd mysnow
     └──╼ ../snow server -D
     DEBU Copying @theme/static/css/main.css to output/static/css/main.css
     INFO Done: Static Processed 1 static files in 588.705µs
     DEBU Writing output/categories/index.html
     DEBU Writing output/authors/index.html
     DEBU Writing output/tags/index.html
     DEBU Writing output/posts/index.html
     DEBU Writing output/authors/snow/index.html
     DEBU Writing output/tags/snow/index.html
     DEBU Writing output/categories/linux/index.html
     DEBU Writing output/tags/linux/index.html
     DEBU Writing output/tags/emacs/index.html
     DEBU Writing output/categories/linux/emacs/index.html
     INFO Done: Page Processed 1 normal pages, 0 hidden pages, 0 section pages in 10.087804ms
     INFO Done: Section Processed 1 posts in 10.1831ms
     INFO Done: Taxonomy Processed 1 authors, 3 tags, 1 categories in 10.18788ms
     #+end_example

*** 安装(Installation)
    #+begin_example
    └──╼ go install https://github.com/honmaple/snow
    #+end_example

*** 编译(Build)
    #+begin_example
    └──╼ git clone https://github.com/honmaple/snow --depth=1
    └──╼ cd snow
    └──╼ go mod tidy
    └──╼ go build .
    #+end_example

*** 命令行(Cli usage)
    #+begin_example
      └──╼ ./snow --help
      NAME:
         snow - snow is a static site generator.

      USAGE:
         snow [global options] command [command options] [arguments...]

      VERSION:
         0.1.0

      COMMANDS:
         init     init a new site
         build    build and output
         server   server local files
         help, h  Shows a list of commands or help for one command

      GLOBAL OPTIONS:
         --config FILE, -c FILE  load configuration from FILE (default: "config.yaml")
         --help, -h            show help (default: false)
         --version, -v         print the version (default: false)
    #+end_example
**** init
     #+begin_example
      └──╼ ./snow init
      └──╼ ./snow init myblog
     #+end_example
     如果不指定 *myblog* 目录,默认会在当前目录下生成一个 *config.yaml* 文件和一个 *content* 目录
**** build
     该命令会构建站点内容内写入到 *{output_dir}* 目录, 如果该目录已经有文件存在,除非制定 =-C= 参数,否则不会自动清理
     - 清理输出目录
       #+begin_example
       └──╼ ./snow build --clean
       └──╼ ./snow build -C
       #+end_example
     - 显示输出详情
       #+begin_example
       └──╼ ./snow build --debug
       └──╼ ./snow build -D
       #+end_example
     - 指定输出目录
       #+begin_example
       └──╼ ./snow build --output {output_dir}
       └──╼ ./snow build -o {output_dir}
       #+end_example
     - 指定mode
       #+begin_example
       └──╼ ./snow build --mode {mode}
       └──╼ ./snow build -m {mode}
       #+end_example
**** server
     build 支持的命令 server也同样支持, 除此之外,还有
     - 指定监听地址
       #+begin_example
       └──╼ ./snow server --listen 127.0.0.1:8088
       └──╼ ./snow server -l 127.0.0.1:8088
       #+end_example
       默认监听地址是 =site.url=
     - 监听文件修改并重新构建
       #+begin_example
       └──╼ ./snow server --autoload
       └──╼ ./snow server -r
       #+end_example
**** hooks
     显示所有hooks
     #+begin_example
     └──╼ ./snow hooks
     assets(enabled), encrypt(enabled), filter, minify, pelican(enabled), rewrite(enabled), shortcode(enabled)
     #+end_example

*** 目录结构(Driectory structure)
    #+begin_example
    .
    ├── config.yaml
    ├── content
    │   └── posts
    │       └── first-page.md
    ├── static
    ├── templates
    └── themes
    │   └── snow
    │       └── static
    │       └── templates
    #+end_example
    - *config.yaml*: 配置文件
    - *content*: 内容目录
    - *static*: 静态文件目录,该目录下的所有文件都会同步到站点的根目录
    - *templates*: 模版目录
    - *themes*: 主题目录
*** 配置文件(Configuration)
    #+begin_src yaml
    # 站点配置信息
    base_url: "http://127.0.0.1:8000"
    title: "Snow"
    description: "snow is a static site generator."
    author: "honmaple"
    language: "zh"

    # 发布时使用的配置
    modes.publish:
      base_url: "https://honmaple.me"

    # 多语言en使用的配置
    languages.en:
      base_url: "https://honmaple.me/en"

    output_dir: "output"
    content_dir: "content"

    theme: "snow"

    # 按照主题需要进行配置
    params.extra:
      menus:
        - name: "关于"
          url: "/pages/about.html"
    #+end_src
** 内容管理
   #+begin_src yaml
   # 指定内容目录
   content_dir: "content"

   # 忽略的内容,如果是目录则以 / 结尾
   ignored_content:
     - "drafts/"
   #+end_src

*** Section
    =content_dir= 目录下以 =_index.= 开头的文件都将识别为 =section= 结构,=secion= 下包括多篇文章
    #+begin_example
      content/
      ├── _index.md           // <- http://127.0.0.1:8000/index.html,包括content下所有默认语言的文章
      ├── _index.en.md        // <- http://127.0.0.1:8000/en/index.html,包括content下所有语言为en的文章
      └── posts              // no url
          ├── post1.org      // <- http://127.0.0.1:8000/posts/2022/02/post1.html
          └── subposts       //
              └── _index.org // <- http://127.0.0.1:8000/posts/subposts/index.html
              └── post2.org  // <- http://127.0.0.1:8000/posts/2023/02/post2.html
    #+end_example
**** 配置
     #+begin_src yaml
     sections:
       _default:
         # 页面默认排序, 多字段使用逗号分隔
         sort_by: "date desc"
         # 自定义某个section下的页面筛选
         filter_by: ""
         # 页面默认分页, path必须使用{number}变量, 0表示不分页
         paginate: 10
         # 分页路径
         paginate_path: "{name}{number}{extension}"
         # 分页前筛选pages
         paginate_filter: ""
         # 生成路径, 为空表示禁止生成相关页面
         path: "{section}/index.html"
         # 使用的模版
         template: "section.html"
         # section输出格式
         formats.atom:
           path: "{section:slug}/atom.xml"
       en:
         # en目录下的所有section都是en语言
         lang: "en"
     #+end_src

     *filter_by* 格式(下同):
     #+begin_example
     'emacs' in tags and not draft or weight > 1
     #+end_example
     其中 =tags=, =draft= 等都是 =FrontMatter=

**** 路径变量(*sections.xxx.path*)
     |-----------------+---------------------------------------|
     | 变量             | 描述                                   |
     |-----------------+---------------------------------------|
     | {lang}          | section所属language                    |
     | {lang:optional} | section所属language,如果是默认语言则为空 |
     | {path}          | section所属路径                         |
     | {path:slug}     | section所属路径, 转为slug               |
     | {section}       | section名称                            |
     | {section:slug}  | section slug, 中国 -> zhong-guo        |

**** 模版变量(*sections.xxx.template*)
     |-------------------+-------------------------|
     | 变量              | 描述                    |
     |-------------------+-------------------------|
     | section           |                         |
     | section.Lang | section语言           |
     | section.Slug |            |
     | section.Title     | section标题             |
     | section.Path      | section相对链接         |
     | section.Permalink | section绝对链接         |
     | section.Content   | section内容             |
     | section.RawContent | section原始内容           |
     | section.Pages     | 当前section下的页面列表 |
     | section.Children  | 子section               |
     | section.Formats | section输出的其它格式        |

*** 页面(Page)
**** 元数据
     - markdown
       #+begin_example
       ---
       title: "title"
       categories:
         - Snow/Templates
       tags:
         - linux
         - snow
       ---
       #+end_example
     - orgmode
       #+begin_example
       #+TITLE: title
       #+DATE: 2022-02-26 17:14:46
       #+CATEGORIES: Snow/Templates
       #+PROPERTY: TAGS linux,snow
       #+PROPERTY: MODIFIED 2023-02-26 14:35:37
       #+end_example
     - html
       #+begin_src html
       <head>
         <title>Project</title>
         <meta name="categories" content="Snow/Templates" />
         <meta name="tags" content="linux,snow" />
         <meta name="date" content="2015-12-22" />
       </head>
       #+end_src
**** 配置
     可以在配置文件设置页面的 =FrontMatter=,如果页面已有则忽略
     #+begin_src yaml
     pages:
       _default:
         comment: true
       posts:
         path: "/articles/{date:%Y}/{date:%m}/{slug}.html"
         template: "post.html"
         comment: true
       pages:
         hidden: true
         path: "/pages/{slug}.html"
         template: "page.html"
       drafts:
         draft: true
       en:
         lang: "en"
         path: "/en/articles/{date:%Y}/{date:%m}/{slug}.html"
         template: "post.html"
       en/pages:
         hidden: true
         path: "/en/pages/{slug}.html"
         template: "page.html"
     #+end_src
**** 路径变量(*sections.xxx.page_path*)
     |-----------------+-----------------------------------|
     | 变量             | 描述                               |
     |-----------------+-----------------------------------|
     | {lang}          | 页面语言                            |
     | {lang:optional} | 页面所属language,如果是默认语言则为空 |
     | {date:%Y}       | 创建页面的年份                      |
     | {date:%m}       | 创建页面的月份                      |
     | {date:%d}       | 创建页面的日期                      |
     | {date:%H}       | 创建页面的小时                      |
     | {path}          | 页面所属路径                        |
     | {path:slug}     | 页面所属路径, 转为slug               |
     | {slug}          | 页面标题或自定义slug                 |
     | {title} | 页面标题                 |

**** 模版变量(*sections.xxx.page_template*)
     |----------------------+----------------------|
     | 变量                 | 描述                 |
     |----------------------+----------------------|
     | page                 |                      |
     | page.Title           | 页面标题             |
     | page.Lang            | 页面语言             |
     | page.Date            | 页面创建时间         |
     | page.Modified        | 页面修改时间         |
     | page.Aliases         | 页面其它链接         |
     | page.Path            | 页面相对链接         |
     | page.Permalink       | 页面绝对链接         |
     | page.Summary         | 页面简介             |
     | page.Content         | 页面内容             |
     | page.FrontMatter.xxx        | 自定义的元数据       |

*** 分类系统(Taxonomy)
**** 配置
     #+begin_src yaml
     taxonomies:
       _default:
         # terms排序, 可选name,count
         sort_by: ""
         path: "{taxonomy}/index.html"
         template: "{taxonomy}/list.html"
         term_path: "{taxonomy}/{term:slug}/index.html"
         term_template: "{taxonomy}/single.html"
         # 页面列表筛选
         term_filter_by: ""
         # 页面列表排序
         term_sort_by: "date desc"
         # 页面列表分页
         term_paginate: 0
         term_paginate_path: ""
         term_paginate_filter: ""
       categories:
       authors:
       tags:
     #+end_src

**** 路径变量
     - *taxonomies.xxx.path*
       |-----------------+-----------------------------------|
       | 变量             | 描述                               |
       |-----------------+-----------------------------------|
       | {lang}          | 分类所属语言                        |
       | {lang:optional} | 分类所属语言,如果是默认语言则为空 |
       | {taxonomy}      | 分类系统名称                        |
     - *taxonomies.xxx.term_path*
       |-------------+------------------|
       | 变量        | 描述             |
       |-------------+------------------|
       | {lang}          | 分类所属语言                        |
       | {lang:optional} | 分类所属语言,如果是默认语言则为空 |
       | {taxonomy}  | 分类系统名称     |
       | {term}      | 分类具体名称     |
       | {term:slug} | 分类slug         |

**** 模版变量
     - *taxonomies.xxx.template*
       |----------------+------------------------------------------|
       | 变量           | 描述                                     |
       |----------------+------------------------------------------|
       | taxonomy       |                                          |
       | taxonomy.Name  | 分类系统名称, 如:categories,tags,authors |
       | taxonomy.Terms |                                          |
     - *taxonomies.xxx.term_template*
       |----------------+----------|
       | 变量           | 描述     |
       |----------------+----------|
       | term           |          |
       | term.Name      | 分类名称 |
       | term.Path      | 相对链接 |
       | term.Permalink | 绝对链接 |
       | term.List      | 页面列表 |
       | term.Children  | 子分类   |

*** 归档页(Archive)
    *snow* 中的分类系统是基于归档实现的,该功能类似 *SQL* 中的 =group by=, 所以如果要实现归档页可以有两种方式:
    1. 添加 =taxonomies.{key}=, ={key}= 可以是页面元数据里的任意字段, 比如 =categories=, =tags=, 如果需要按照时间归档, 格式为 =date:2006/01=, 其中 =2006/01= 为Go时间格式,表示按年月归档, 并生成链接 */archives/2022/10/index.html*
       #+begin_src yaml
       taxonomies:
         date:2006/01:
           path: "archives/index.html"
           template: "archives.html"
           term_path: "archives/{term}/index.html"
           term_template: "period_archives.html"
       #+end_src
    2. 在 ={content_dir}= 下添加一个 =archives.md= 的文件
       #+begin_example
       path: archives.html
       template: archives.html
       section: true
       #+end_example
       然后在模板 ={templates}/archives.html= 使用 =pages.GroupBy({key})=
       #+begin_src html
       {%- for subterm in pages.GroupBy("date:2006-01").OrderBy("name desc") %}
         {%- set date = subterm.Name | split:"-" %}
         {%- set year = date[0] %}
         {%- set month = date[1] %}
          ...
       {%- endfor %}
       #+end_src

*** 分页(Pagination)
**** 路径变量
     |--------------+-------------------|
     | 变量         | 描述              |
     |--------------+-------------------|
     | {name}       | 路径名称          |
     | {extension}  | 路径扩展          |
     | {number}     | 页码, 第一页为"1" |
     | {number:optional} | 页码, 第一页为空 |
     - 示例一:
       #+begin_src yaml
       path: "section/index.html"
       paginate_path: "{name}{number:optional}{extension}"
       #+end_src
       - 第一页: =section/index.html=
       - 第二页: =section/index2.html=
       - 第三页: =section/index3.html=
     - 示例二:
       #+begin_src yaml
       path: "section/index.html"
       paginate_path: "page/{number}{extension}"
       #+end_src
       - 第一页: =section/page/1.html=
       - 第二页: =section/page/2.html=
       - 第三页: =section/page/3.html=
**** 模版变量
     |---------------------+----------------------|
     | 变量                | 描述                 |
     |---------------------+----------------------|
     | paginator           |                      |
     | paginator.Path   | 分页链接             |
     | paginator.PageNum   | 当前页               |
     | paginator.Total     | 总页数               |
     | paginator.HasPrev() | 是否有上一页         |
     | paginator.Prev      | 上一页               |
     | paginator.Prev.URL  | 上一页链接           |
     | paginator.HasNext() | 是否有下一页         |
     | paginator.Next      | 下一页               |
     | paginator.Next.URL  | 下一页链接           |
     | paginator.All       | 所有页               |
     | paginator.List      | 当前分页下的页面列表 |

*** 草稿(Draft)
    页面中的 =FrontMatter= 中的 =draft: true= 将会识别为草稿,如果不想每一篇草稿都添加相应字段,可以添加 =pages= 配置
    #+begin_src yaml
    pages:
      drafts:
        draft: true
    #+end_src
    配置表示 ={content_dir}/drafts= 该目录下的所有页面都将被识别为草稿。

    构建时忽略草稿
    1. 忽略草稿目录
       #+begin_src yaml
       ignored_content:
         - "drafts/"
       #+end_src
    2. 使用命令行参数
       #+begin_example
       snow build --include-drafts
       #+end_example

*** 输出格式(Atom,Rss,JSON)
    可以生成 *rss* ,*atom* 或者其它任意格式(需要自定义模版)
**** 配置
     #+begin_src yaml
     # 设置rss格式的默认值
     formats.rss:
       template: "rss.xml"

     formats.atom:
       template: "atom.xml"

     sections:
       _default:
         # rss生成路径, 模版将会使用默认模版
         formats.rss.path: "{section:slug}/index.xml"
         # 为空时禁止生成
         formats.atom.path: ""

     taxonomies:
       tags:
         formats.atom:
           path: "tags/{term:slug}/index.xml"
           # 自定义模版
           template: "custom.atom.xml"
     #+end_src
**** 模版变量
     |---------+--------------------------|
     | 变量    | 描述                     |
     |---------+--------------------------|
     | section | 仅生成section 有效       |
     | term    | 仅生成taxonomy term 有效 |
     | pages   | 页面列表                 |

*** 静态文件(Static)
    静态文件分 *当前目录下静态文件* 和 *主题静态文件*
    #+begin_src yaml
    # 忽略的静态文件,如果是目录则以 / 结尾
    ignored_static:
      - "extra/"
    #+end_src

    当 =static/{filename}= 和 =themes/{theme}/static/{filename}= 同时存在时,优先当前目录下的文件

*** 多语言(Multilingual)
    需要配置 =languages=
    #+begin_src yaml
    languages.en:
      translations: "i18n/en.yaml"
      taxonomies:
        special_tags:
          path: "{taxonomy}/index.html"
    languages.fr:
      translations: "i18n/fr.yaml"
    #+end_src
    页面格式:
    - ={title}.en.md=
    - ={title}.fr.md=
    或者可以在文件头指定 =lang: en=

**** i18n
     - 模版
       #+begin_src html
       {% i18n "tags" %}
       {% T "tags %d" 12 %}
       {{ i18n("authors") }}
       {{ T("authors") }}
       {{ _("authors %f", 3.14) }}
       #+end_src
       甚至可以直接使用变量
       {{ _(term.Name) }}
     - 翻译文件
       默认会加载主题下 *i18n* 目录下的文件
       #+begin_example
       i18n
       ├── en.yaml
       └── zh.yaml
       #+end_example
       文件内容
       #+begin_src yaml
       ---
       - id: "authors"
         tr: "作者"
       - id: "tags"
         tr: "标签"
       #+end_src

       也可以自定义文件位置或翻译内容覆盖主题原有的翻译
       #+begin_src yaml
       languages.en:
         translations: "i18n/en.yaml"
       languages.zh:
         translations:
           - id: "authors"
             tr: "作者"
       #+end_src

** 模版(templates)
   [[https://github.com/flosch/pongo2]]
** 主题(theme)
*** 安装
*** 开发
**** 主题目录结构
     其中 *templates* 和 *static* 名称不可修改
     #+begin_example
       simple/
       ├── theme.yaml
       ├── templates
       │   ├── post.html
       │   ├── index.html
       │   ├── archives.html
       ├── static
       │   ├── main.css
     #+end_example
**** 配置
     #+begin_src yaml
     theme:
       # 主题名称, 未设置将使用默认主题
       name: "test-theme"
       # 默认的主题配置,该配置会自动合并,除非设置为空
       config: "theme.yaml"
       # 主题模版覆盖, 增加同名的文件到 *override* 配置的目录, snow将会优先使用该文件
       override: "layouts"
     #+end_src

** 插件(hooks)
*** rewrite
    重写文章的 =FrontMatter= 字段,不用修改原文章的内容
**** 配置插件
     #+begin_src yaml
     hooks.rewrite:
       enabled: true
     #+end_src

     配置选项,如果设置 =type= 为 =list=,将会把原字段以 =逗号= 分隔进行转换
     #+begin_src yaml
     hooks.rewrite:
       option:
         - src: "tag"
           dst: "tags"
           type: "list"
     #+end_src

*** encrypt
    文章内容加密
**** 配置插件
     #+begin_src yaml
     hooks.encrypt:
       enabled: true
     #+end_src

     配置选项
     #+begin_src yaml
     hooks.encrypt:
       option:
         password: "默认密码"
         description: "默认描述"
     #+end_src
**** 在文章中使用
     - 添加密码到 =frontmatter=
       #+begin_src markdown
       ---
       password: "123456"
       ---
       #+end_src
     - 局部加密:可以使用 =shortcodes= 中的 =encrypt= 功能
       #+begin_src markdown
       <shortcode encrypt password="123456">
       加密的内容
       </shortcode>
       #+end_src
**** 在模版中使用
     #+begin_src html
     {{ page.Content | encrypt:"123456" }}
     #+end_src

*** shortcode
    用于快速插入已有模版
**** 配置插件
     #+begin_src yaml
     hooks.shortcode:
       enabled: true
     #+end_src
**** 创建新的shortcode
     在 =templates= 目录下添加 =shortcodes/bilibili.html=
     #+begin_src html
     <div class="shortcodes-bilibili">
       <iframe
         src="https://player.bilibili.com/player.html?bvid={{ params.id }}&page={% if params.page %}{{ params.page }}{% else %}1&high_quality=1&danmaku=0&as_wide=0{% endif %}&autoplay=0"
         scrolling="no"
         border="0"
         frameborder="no"
         framespacing="0"
         allowfullscreen="true"
       >
       </iframe>
     </div>
     #+end_src

     模版内参数
     - =name=: 当前 =shortcode= 的名称
     - =params.*=: 传递的参数,比如 =params.id=
     - =body=
     - =counter=: 统计 =shortcode= 在当前文章中的使用次数
**** 使用shortcode
     #+begin_src html
     <bilibili id="BV1yB4cz8E9y" />
     #+end_src
     或者
     #+begin_src html
     <shortcode bilibili id="BV1yB4cz8E9y" />
     #+end_src

*** assets
    静态文件处理,区别于 =static= 目录, =assets= 目录支持合并,压缩等功能
    #+begin_example
    mysite/
    ├── assets
    │   ├── js
    │   │   ├── main.js
    │   │   └── theme.js
    │   ├── scss
    │   │   ├── _variables.scss
    │   │   ├── entry.scss
    │   │   ├── prose.scss
    │   │   ├── style.scss
    │   │   ├── theme.scss
    │   ├── css
    │   │   ├── custom.css
    #+end_example

**** 配置插件
     #+begin_src yaml
     hooks.assets:
       enabled: true
     #+end_src

     配置选项
     #+begin_src yaml
     hooks.assets:
       ...
       option.css:
         files:
           - "scss/style.scss"
           - "css/custom.css"
         filters:
           - "cssmin"
         output: "static/lib.min.css"
     #+end_src
     如果文件以 =.scss= 或者 =.sass=,将自动编译为 =.css=

**** 在模版中使用
     - 使用配置的名称 =css=
       #+begin_src html
       {% assets css %}
       <link rel="stylesheet" href="{{ config.base_url }}/{{ asset_url }}">
       {% endassets %}
       #+end_src

     - 在模版中调用 =assets=
       #+begin_src html
       {% assets files="css/style.scss" filters="cssmin" output="css/style.min.css" %}
       <link rel="stylesheet" href="{{ config.base_url }}/{{ asset_url }}">
       {% endassets %}
       #+end_src

*** minify
    *minify* 允许对写入的=html=、=css=、=js=文件进行压缩
**** 配置插件
     #+begin_src yaml
     hooks.minify:
       enabled: true
     #+end_src
     配置选项
     #+begin_src yaml
     hooks.minify:
       option:
         js: true
         css: true
         html: true
     #+end_src

** 本地测试和正式发布
   *snow* 提供了 *mode* 配置用于区分本地测试和正式发布
   #+begin_src yaml :noindent
   base_url: "http://127.0.0.1:8000"

   modes.publish:
     base_url: "https://example.com"

   modes.develop:
     include: "develop.yaml"
   #+end_src
   只要在构建时使用 =snow build --mode publish= 即可覆盖本地默认配置

Documentation

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL