博客系统从Pelican迁移至Snow


上一次迁移博客系统还是在上一次。。。 哈哈,不开玩笑,上次迁移大概还是在七年前(2015.10), 不知不觉我的博客也建立快八年时间,如果算上动态博客可能都快十年了,虽然也没写多少篇(其实本地草稿都攒了快200篇了, 也没好好整理), 但好歹可以记录自己的生活和想法,之前使用的博客系统是基于 PythonPelican, 此次将博客迁移至 snow —— 一个轻量,简洁的基于Go开发的静态博客生成器

迁移列表

  • [X] 内容文件(.md、.org、.html)

  • [X] 静态文件(.css、.js、.scss等)

  • [X] 配置文件(pelicanconf.py -> config.yaml)

  • [X] 主题文件

    • [X] 分类功能(子分类)

    • [X] 搜索功能

    • [X] 加密功能

内容文件

由于 Snow 是我自己开发的, 功能上的实现本身就基于我原有的文件内容, 比如 markdownorgmode 的支持,所以迁移上也很简单,有的甚至不用修改原有的内容

文件头

原来的 Pelican 使用三种文件头形式:

.md.org

  • .md

    Title: 使用pelican搭建个人博客
    Author: honmaple
    Date: 2015-12-22
    Category: Python
    Tags: python,pelican
    Slug: 使用pelican搭建个人博客
    
    ## pelican介绍
  • .org

    #+TITLE: 私人密码库Bitwarden搭建
    #+AUTHOR: honmaple
    #+DATE: 2022-05-29 16:21:15
    #+CATEGORY: Linux
    #+PROPERTY: MODIFIED 2022-05-29 16:27:05
    #+PROPERTY: TAGS linux,bitwarden
    #+PROPERTY: SLUG 私人密码库Bitwarden搭建

Pelican 中的 AuthorCategory 是固定字段,如果需要指定多个可以使用英文逗号分隔,而在 Snow 中这两个字段是可选或者说是可配置的,无法知道指定的字段是一个列表还是一个完整的单词,所以这里需要修改为

- Category: Linux
+ categories: [Linux]

或者

- #+PROPERTY: TAGS linux,bitwarden
+ #+PROPERTY: TAGS [linux,bitwarden]

而在 markdown 中,因为 Snow 支持类似 Hugo 的文件头,如果想要一次性修改好,可以直接改成 yaml 或者 toml 格式

  • yaml

    ---
    categories:
      - Linux
    ...
    ---
  • toml

    +++
    categories = ["Linux"]
    ...
    +++

除了修改原来的文件外,我还在 Snow 中内置了一个 pelican 插件,只要在配置里添加

hooks:
  - pelican
...

就能将 Category 字段转成 categories 列表, Author 转成 authors 列表, Tags 转成 tags 列表, 这样就不用修改原来的文件

.html

<html>
  <head>
    <title>Project</title>
    <meta name="tags" content="随意写写" />
    <meta name="date" content="2015-12-22" />
    <meta name="category" content="Life" />
    <meta name="authors" content="honmaple" />
    <meta name="slug" content="project" />
    <meta name="custom_css" content="/static/css/project.css" />
    <meta name="custom_js" content="https://cdn.bootcss.com/geopattern/1.2.3/js/geopattern.min.js" />
    <meta name="custom_js" content="/static/js/project.js" />
  </head>
  <body>
    ...
  </body>
</html>

html 文件中,原来的 custom_csscustom_js 两个字段主要用于自定义css和js,也是利用我开发的一个pelican插件,把多条记录合并成一个列表,在 Snow 中,不用开发新的插件,但需要修改原来的内容

- <meta name="custom_css" content="/static/css/project.css" />
- <meta name="custom_js" content="https://cdn.bootcss.com/geopattern/1.2.3/js/geopattern.min.js" />
- <meta name="custom_js" content="/static/js/project.js" />
+ <link type="text/css" href="/static/css/project.css" rel="stylesheet"/>
+ <script type="text/javascript" src="https://cdn.bootcss.com/geopattern/1.2.3/js/geopattern.min.js"></script>
+ <script type="text/javascript" src="/static/js/project.js"></script>

这样就能得到两个类型为列表的变量 custom_csscustom_js

忽略文件

Pelican 可以单独指定 content/postscontent/pages, 而在 Snow 中 无法指定 content 目录下的部分目录,但可以设置忽略文件, 这有两种方式

  • 在需要忽略的目录下新建一个 _index.md, 并指定 ingore_files 字段

    ---
    # 忽略整个目录
    ignore_files: ["*"]
    # 忽略目录下的README.md和所有js文件
    ignore_files:
      - README.md
      - *.js
    ---
  • 在配置里设置 sections.{目录名}.ignore_files

    sections:
      drafts:
        # 忽略{content_dir}/drafts目录
        ignore_files: ["*"]

静态文件

favicon.ico

Pelican 中,类似 favicon.icorobots.txtCNAME 这些不需要修改的文件我原来是放到 content/extra 目录,但在 Snow 中,content 目录下的所有文件都会视为页面文件或者页面的资源文件, 所以需要把extra目录下的文件移动到static目录下,并设置

static_dirs:
  - "static/favicon.ico"
  - "static/CNAME"
  - "static/README.md"
  - "static/robots.txt"
  - "content/pages/css"
static_paths:
  "static": "/"
  "content/pages/css": "static/css/"

scss/css/js

在 Python 中有一个专门处理静态文件的 webassets,在 Pelican 中也有一个插件https://github.com/pelican-plugins/webassets, 而在 Snow 中同样支持静态文件的处理, 比如编译并压缩scss文件

params.assets.css:
  files:
    - "@theme/static/scss/common.scss"
    - "@theme/static/scss/entry.scss"
    - "@theme/static/scss/entry-tree.scss"
  filters:
    - libscss:
        path: ["themes/snow/static/scss/"]
    - cssmin:
  output: "static/lib/css/style.min.css"

其中 filters 支持 libscss,cssmin,jsmin(js处理有些问题,不要使用)

然后就可以在模版里使用

{%- assets "css" %}
<link href="{{ config.site.url }}/{{ asset_url }}" rel="stylesheet">
{%- endassets %}

配置文件

Pelican 使用 pelicanconf.py, 而 Snow 使用 config.yaml

site:
  url: "http://127.0.0.1:8000"
  title: "紅楓吟"
  subtitle: "风落花语风落天,花落风雨花落田."
  language: "zh"
  author: "honmaple"
  logo_name: "楓"

mode.publish:
  site:
    url: "https://honmaple.me"

主题文件

Snow 的模版系统使用的是 https://github.com/flosch/pongo2, 从 Pelican 使用的 jinja2 迁移到 pongo2 除了相关变量的修改和各种大写外,还有部分区别

  • loop: pongo2 使用的是 forloop, 计数使用的 forloop.Counter, 从1开始

  • marco: pongo2 想要加载并调用文件内的函数,需要添加 export

    {%- macro archive_list(pages) export %}
    ...
  • super: pongo2 使用的是 block.Super

分类功能

Pelican 中,可以使用 page.tags[0].url 获取标签路径,而在 Snow 中想要获取标签路径, 需要使用 get_taxonomy_url

{%- for name in page.Meta.Get("tags") %}
<a href="{{ get_taxonomy_url("tags", name) }}">{{ name }}</a>
{%- endfor %}

子分类功能

原来的子分类是用我写的一个插件实现的,使用的是 . 作为分隔,如 Category: Life.Coding, 在 Snow 中原生支持子分类, 只需要把 . 改成 /, 比如 Python/FlaskPython/Ansible/Jinja2 会创建如下分类系统

- Categories
  - Python
    - Flask
    - Ansible
      - Jinja2

我的博客导航栏的实现就是基于该功能

{%- set categories = get_taxonomy("categories") %}
{%- if categories %}
  {%- for term in categories.Terms %}
    {%- if term.Children %}
      <li class="dropdown">
        <a href="{{ term.Permalink }}">{{ _(term.Name) }}</a>
        <ul class="dropdown-menu">
          {%- for child in term.Children %}
            <li><a href="{{ child.Permalink }}">{{ _(child.Name) }}</a></li>
          {%- endfor %}
        </ul>
      </li>
    {%- else %}
      <li><a href="{{ term.Permalink }}">{{ _(term.Name) }}</a></li>
    {%- endif %}
  {%- endfor %}
{%- endif %}

搜索功能

Snow 本身没有自带搜索,但可以输出 json 文件

  • search.md 首先在 {content_dir} 目录下新建 search.md 文件

    ---
    title: Search
    path: search.html
    template: search.html
    filter: type="posts"
    paginate: 0
    section: true
    formats:
      json:
        path: "index.json"
        template: "search.json"
    ---

    然后在字段 formats 指定格式,路径和模版

  • search.json{theme}/templates 目录下或者 templates (配置文件同级目录下) 建立

    {{- scratch.Set("newjson", slice()) | slient }}
    {%- for page in pages %}
    {{- scratch.Add("newjson", dict("index", forloop.Counter - 1, "permalink", page.Permalink, "summary", page.Summary, "title", page.Title, "content", page.Content | striptags)) | slient }}
    {%- endfor %}
    {{- scratch.JSON("newjson") | safe }}

    当写入到 /index.json 后就可以利用其它的搜索库比如 lunr 来进行搜索

加密功能

文章加密也是我不用 Hugo 的一个重要原因,我不希望使用 snow build 之前还需要使用另外的程序对内容进行一个预处理,所以在 Snow 中,我内置了一个名为 encrypt 的插件

hooks:
  - encrypt
...

注册插件后就可以在内容文件里使用 encrypt 的 shortcode代码,或者在模版里使用 encrypt 函数

  • 全局加密: 只要在文件头添加 passowd: xxx,hello world, 其中 xxx 是输入的密码,hello world 是显示的描述信息

  • 局部加密: 使用 shortcode 进行加密

    <shortcode _name="encrypt" password="xxx" description="hello world">
    ...
    </shortcode>
  • 模版加密:

    <div>
      {{ page.Content | encrypt:"xxx" }}
    </div>

示例:为pelican添加文章加密功能

作者: honmaple
链接: https://honmaple.me/articles/2023/02/博客系统从Pelican迁移至Snow.html
版权: 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat