前幾天心血來潮,想要在
GitHub Pages
上搭建一個靜態博客;之前,我也曾基於Django
開發過自己的博客,並買了雲主機部署,但是訪問量感人,慢慢自己也不打理了,就把雲主機退訂了(去吃噸好的~~~);雖然搭建靜態博客很簡單,但是也想記錄一下,如果恰好能對你有所幫助或啟發,那我也覺的很開心了。
搭建靜態博客的工具多種多樣,即有流行的WordPress,也有GitHub Pages
官方推薦的Jekyll;其實,選用哪種工具不重要,關鍵是一步步的理解它,遇到問題、解決問題的思路和過程;
因為我本人對Python
比較熟悉,所以我選用基於Python
開發的pelican,它基本滿足我的需求:
- 支持
markdown
的格式; - 提供自動化構建;
- 足夠的主題庫和插件庫,並且支持定制化;
- ...
本文主要涉及pelican
的基本使用方法,最終在本地搭建一個簡陋的博客網站;
1. 准備環境
選定工作目錄,並使用pipenv創建一個虛擬環境:
λ mkdir pelican-blog
λ cd pelican-blog
# 創建基於 Python 3 的虛擬環境
λ pipenv install --three
# 查看虛擬環境中的 Python 版本
λ pipenv run python --version
Python 3.7.3
在虛擬環境中安裝必要的包:
λ pipenv install Markdown pelican
# 查看包之間的依賴關系
λ pipenv graph
Markdown==3.1.1
- setuptools [required: >=36, installed: 41.6.0]
pelican==4.2.0
- blinker [required: Any, installed: 1.4]
- docutils [required: Any, installed: 0.15.2]
- feedgenerator [required: >=1.9, installed: 1.9]
- pytz [required: >=0a, installed: 2019.3]
- six [required: Any, installed: 1.13.0]
- jinja2 [required: >=2.7, installed: 2.10.3]
- MarkupSafe [required: >=0.23, installed: 1.1.1]
- pygments [required: Any, installed: 2.4.2]
- python-dateutil [required: Any, installed: 2.8.1]
- six [required: >=1.5, installed: 1.13.0]
- pytz [required: >=0a, installed: 2019.3]
- six [required: >=1.4, installed: 1.13.0]
- unidecode [required: Any, installed: 1.1.1]
2. 新建項目
pelican
提供了一個命令行工具:pelican-quickstart
,能夠讓我們快速地新建一個網站項目;
它在執行的過程中,會交互式的詢問一些配置項,如果你現在還不能確定的話,那就大膽的使用默認值吧,后面還可以在配置文件中修改;
命令執行完成后,它會在我們的項目中新建如下的目錄和文件:
.
├── content # 目錄,存放原始博文和相關靜態文件
├── output # 目錄,存放構建后的網站源碼
├── Makefile
├── pelicanconf.py # 構建相關的配置文件
├── publishconf.py # 發布相關的配置文件
└── tasks.py
其中,content/
目錄存放所有的markdown
格式的文本,我們還可以再新建一個content/images/
的子目錄,用於存放所有的圖片;
注意:
在自動構建的過程中,
content/images/
中的文件會被無損地拷貝到output/images/
中,通過修改pelicanconf.py
文件中STATIC_PATHS
的配置項(默認值為['images']
)可以改變這種行為;
3. 第一篇博文
現在我們在content/
目錄下添加第一篇markdown
格式的文章,就以本文為例;
pelican
可以很“聰明”地從文章的元數據中提取需要的信息,所以我們以特定的格式編寫文章的開頭:
Title: 一、從零開始搭建自己的靜態博客 -- 基礎篇
Date: 2019-11-21 14:37
Modified: 2019-11-22 11:09
Category: 工具
Tags: pelican
Author: luizyao
Slug: pelican-blog-chapter-1
Summary: 本文簡要的介紹 pelican 的基本用法
Status: published
<開始正文>
注意:
更多元數據以參考:https://docs.getpelican.com/en/stable/content.html#file-metadata;
如果你使用
VSCode
作為你的日常開發工具,那么我建議你使用psioniq File Header插件為不同類型的文件自動生成頭信息模版;
4. 修改配置文件
在正式開始構建之前,我們需要完善一下配置文件pelicanconf.py
:
# pelicanconf.py
# 修改時區
TIMEZONE = 'Asia/Shanghai'
# 添加一個 GitHub 的“絲帶”鏈接
GITHUB_URL = 'https://github.com/luizyao'
# 修改社交賬號的展示
SOCIAL = (
('GitHub', 'https://github.com/luizyao'),
)
# 修改默認的時間格式('%a %d %B %Y')
DEFAULT_DATE_FORMAT = "%Y-%m-%d %H:%M"
# 為元數據定義默認值
DEFAULT_METADATA = {
# 默認發布的文章都是草稿,除非在文章元數據中明確指定:Status: published
'status': 'draft',
}
5. 本地構建和訪問
我們通過以下命令構建網站並自動適配文件的修改,通過http://localhost:8000訪問:
λ pipenv run pelican --autoreload --listen content/
注意:
不要忘記把文章元數據中的
Status: draft
改成Status: published
,不然我們是看不到這篇文章的;
pelican
默認使用notmyidea
這個主題來構建網站;你可以通過pelican-themes
命令查看已安裝的主題:λ pipenv run pelican-themes --list notmyidea simple
然后通過在
pelicanconf.py
中設定THEME = 'simple'
或者構建時傳入-t 'simple'
選項來使用主題simple
,實際上和純文本差不多了;
6. markdown
解析異常
-
這是一個列表:
if 1: print('這是一段python代碼')
這個時候,如果你訪問我們的網站,你會發現上面的markdown
代碼被展示成下面的形式,根本就不是我們想要的縮進代碼塊的效果:
為什么會這樣呢?我們又該如何解決這個問題?
6.1. Markdown
包的實現機制
pelican
使用Markdown包作為markdown
文本的解釋器,這個包嚴格實現了John Gruber’s Markdown語法,並提供一些擴展;
John Gruber
是markdown
語法的發明者,他在2004
發布了第一個版本的markdown
語法,這一版本的語法有着明顯的特點:
- 不支持三個反引號(
'```'
)包裹代碼的寫法; - 不支持表格;
- 定義了嚴格的嵌套縮進的格式,必須是
4
個空格; - ...
雖然自從發布了第一版之后,就再也沒有更新過,但是現在流行的各種markdown
語法都是基於它的擴展和補充,例如:GitHub Markdown、PHP Markdown等;
注意:
雖然
Markdown
包嚴格實現了John Gruber’s Markdown
語法,但是具體的實現還是有一些差別的,更多細節可以參考:https://python-markdown.github.io/#differences
6.2. pelican
默認使用的Markdown
擴展
上一節中我們提到,Markdown
包同樣提供一些擴展用於解析更多類型的語法,這些擴展又分為官方擴展和第三方擴展;
通過查閱pelican
的源碼(或官方文檔),可以看到其默認使用了以下擴展:
# pelican/settings.py
'MARKDOWN': {
'extension_configs': {
'markdown.extensions.codehilite': {'css_class': 'highlight'},
'markdown.extensions.extra': {},
'markdown.extensions.meta': {},
},
'output_format': 'html5',
},
首先,我們看一下markdown.extensions.extra擴展:
它主要實現了大多數PHP Markdown
的語法,是其它6
個擴展的合集:
擴展 | 文檔 | 描述 |
---|---|---|
Abbreviations | https://python-markdown.github.io/extensions/abbreviations/ | |
Attribute Lists | https://python-markdown.github.io/extensions/attr_list/ | |
Definition Lists | https://python-markdown.github.io/extensions/definition_lists/ | |
Fenced Code Blocks | https://python-markdown.github.io/extensions/fenced_code_blocks/ | 擴展了代碼塊的寫法 |
Footnotes | https://python-markdown.github.io/extensions/footnotes/ | |
Tables | https://python-markdown.github.io/extensions/tables/ | 支持表格 |
我們重點看一下Fenced Code Blocks
,因為它支持了我常用的三個反引號包裹代碼塊的寫法:
GitHub‘s backtick (```) syntax is also supported:
# more python code
然后,我們再看一下markdown.extensions.codehilite擴展:
它基於Pygments包為我們提供了代碼的高亮顯示,我們主要看一下它的一些可配置選項:
linenums
:如果置為True
,將會為代碼塊每行標上行號;css_class
:為<div>
標簽加上class
屬性,默認是codehilite
;在這里,pelican
使用的是highlight
;
最后,我們看一下markdown.extensions.meta:
它主要是pelican
內部使用,還記得我們每個markdown
文本的開頭都要有特定的格式嗎?就是通過這個擴展讀取的;感興趣的同學可以自己去看一下,這里我們就不多說了;
6.3. 向第三方擴展尋求幫助
看到現在,我們也沒有找到想要的解決方案:對列表里縮進嵌套反引號包裹的代碼塊,進行正確的渲染;
還好我們還有眾多的第三方擴展供我們使用:https://github.com/Python-Markdown/markdown/wiki/Third-Party-Extensions
我們找到一個pymdownx.extra的擴展貌似可以代替markdown.extensions.extra
,來一起看一下吧:
它和markdown.extensions.extra
大部分是一樣的,只是有以下不同:
- 新包含了BetterEm擴展:優化粗體和斜體的展示(不關心);
- 新包含了ExtraRawHTML擴展:增加了對原始
HTML
代碼的處理(不關心); - 使用SuperFences擴展代替
Fenced Code Blocks
:加強版的markdown
語法解析(看來正式我們想要的);
其實,看到
SuperFences
文檔的第一句話,我就知道妥了,嘻嘻;Allowing the nesting of fences under blockquotes, lists, or other block elements (see Limitations for more info).
文檔的內容很豐富,我們就不再這里一一解釋了,有興趣的同學可以自己去看一看,說不定有什么意外的收獲呢!!!
6.4. 解決問題
現在,我們來實際解決這個問題:
-
安裝必要的包:
λ pipenv install pymdown-extensions
-
修改
pelicanconf.py
文件中MARKDOWN
的默認配置:# 使用第三方擴展來增強對 markdown 語言的解析,但是首先要安裝 pymdown-extensions 模塊 MARKDOWN = { 'extension_configs': { 'markdown.extensions.codehilite': {'css_class': 'highlight'}, 'pymdownx.extra': {}, 'markdown.extensions.meta': {}, }, 'output_format': 'html5', }
7. One more thing
我在瀏覽SuperFences
文檔時,發現一個很有意思的章節:https://facelessuser.github.io/pymdown-extensions/extensions/superfences/#code-highlighting;
它推薦了pymdownx.highlight代替markdown.extensions.codehilite
,那我們就來看看這到底是個什么鬼?
在它的文檔中有一句話大概能說明兩者的關系:
The Highlight extension is inspired by CodeHilite, but differs in features. PyMdown Extensions chooses not to implement special language headers for standard Markdown code blocks like CodeHilite does; PyMdown Extensions takes the position that language headers are better suited in fenced code blocks.
更多實現上的細節,我們不再去深究,主要看看我們可以用來干什么?
比如,為代碼塊每行加上行號:
咦?markdown.extensions.codehilite
也可以啊,它不是也有一個linenums
的選項嗎?置成True
不就行了;
說的對,不過丑。
一般情況下,為代碼塊添加行號有兩種樣式:
table
:默認的樣式,創建一個表,第一列是行號;inline
:在每行代碼的開頭,但是復制代碼會把行號一起復制,不方便;
不過,pymdownx.highlight
提供了第三種樣式:pymdownx-inline
,它和inline
很像,只是復制時不會加上行號,因為實際上把行號元素渲染成下面這樣:
<span class="lineno" data-linenos="1 "></span>
然后,我們通過以下的CSS
樣式去“激活”它:
[data-linenos]:before {
content: attr(data-linenos);
}
下面,我們來將它具體的應用到我們的項目中吧:
首先,修改pelicanconf.py
文件中MARKDOWN
的默認配置:
# 使用第三方擴展來增強對 markdown 語言的解析,但是首先要安裝 pymdown-extensions 模塊
MARKDOWN = {
'extension_configs': {
'pymdownx.highlight': {
'css_class': 'highlight',
'linenums': True,
'linenums_style': 'pymdownx-inline',
},
'pymdownx.extra': {},
'markdown.extensions.meta': {},
},
'output_format': 'html5',
}
然后,在output/theme/css/main.css
文件的末尾加上下面這段代碼:
[data-linenos]:before {
content: attr(data-linenos);
}
最后重啟下服務,就能看到效果了:
注意:
這里有個問題,如果我們重新執行構建命令,
output/theme/css/main.css
文件又會被覆蓋成原先的內容,我們這個效果就看不到了;不過這並不是我們最終的方案,所以我們也不在這里繼續深究了。
GitHub:https://github.com/luizyao/pelican-blog/tree/chapter-1