Table of Contents
上一次迁移博客系统还是在上一次。。。 哈哈,不开玩笑,上次迁移大概还是在七年前(2015.10), 不知不觉我的博客也建立快八年时间,如果算上动态博客可能都快十年了,虽然也没写多少篇(其实本地草稿都攒了快200篇了, 也没好好整理), 但好歹可以记录自己的生活和想法,之前使用的博客系统是基于
Python
的Pelican
, 此次将博客迁移至 snow —— 一个轻量,简洁的基于Go开发的静态博客生成器
迁移列表
-
[X]
内容文件(.md、.org、.html) -
[X]
静态文件(.css、.js、.scss等) -
[X]
配置文件(pelicanconf.py -> config.yaml) -
[X]
主题文件-
[X]
分类功能(子分类) -
[X]
搜索功能 -
[X]
加密功能
-
内容文件
由于 Snow
是我自己开发的, 功能上的实现本身就基于我原有的文件内容, 比如 markdown
和 orgmode
的支持,所以迁移上也很简单,有的甚至不用修改原有的内容
文件头
原来的 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: Tech #+PROPERTY: MODIFIED 2022-05-29 16:27:05 #+PROPERTY: TAGS linux,bitwarden #+PROPERTY: SLUG 私人密码库Bitwarden搭建
在 Pelican
中的 Author
和 Category
是固定字段,如果需要指定多个可以使用英文逗号分隔,而在 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_css
和 custom_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_css
和 custom_js
忽略文件
Pelican
可以单独指定 content/posts
和 content/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.ico
、robots.txt
、CNAME
这些不需要修改的文件我原来是放到 content/extra
目录,但在 Snow
中,content
目录下的所有文件都会视为页面文件或者页面的资源文件, 所以需要把extra目录下的文件移动到static目录下,并设置
statics: static: ignore_files: # 排除所有static下的文件,不包括子目录的文件 - "^[^/]+$" - "^images/" static/CNAME: path: "CNAME" static/robots.txt: path: "robots.txt" static/favicon.ico: path: "favicon.ico" static/README.md: path: "README.md" content/pages/css: path: "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/Flask
和 Python/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>