一、從零開始搭建自己的靜態博客 -- 基礎篇

前幾天心血來潮,想要在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,能夠讓我們快速地新建一個網站項目;

它在執行的過程中,會交互式的詢問一些配置項,如果你現在還不能確定的話,那就大膽的使用默認值吧,後面還可以在配置文件中修改;

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

<開始正文>

注意:


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代碼被展示成下面的形式,根本就不是我們想要的縮進代碼塊的效果:

screenshot_markdown_error

爲什麼會這樣呢?我們又該如何解決這個問題?

6.1. Markdown包的實現機制

pelican使用Markdown包作爲markdown文本的解釋器,這個包嚴格實現了John Gruber’s Markdown語法,並提供一些擴展;

John Grubermarkdown語法的發明者,他在2004發佈了第一個版本的markdown語法,這一版本的語法有着明顯的特點:

  • 不支持三個反引號('```')包裹代碼的寫法;
  • 不支持表格;
  • 定義了嚴格的嵌套縮進的格式,必須是4個空格;
  • ...

雖然自從發佈了第一版之後,就再也沒有更新過,但是現在流行的各種markdown語法都是基於它的擴展和補充,例如:GitHub MarkdownPHP 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. 解決問題

現在,我們來實際解決這個問題:

  1. 安裝必要的包:

    λ pipenv install pymdown-extensions
  2. 修改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);
}

最後重啓下服務,就能看到效果了:

Screenshot_full_site

注意:

這裏有個問題,如果我們重新執行構建命令,output/theme/css/main.css文件又會被覆蓋成原先的內容,我們這個效果就看不到了;

不過這並不是我們最終的方案,所以我們也不在這裏繼續深究了。

GitHub:https://github.com/luizyao/pelican-blog/tree/chapter-1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章