1. 程式人生 > >一、從零開始搭建自己的靜態部落格 -- 基礎篇

一、從零開始搭建自己的靜態部落格 -- 基礎篇

目錄

  • 1. 準備環境
  • 2. 新建專案
  • 3. 第一篇博文
  • 4. 修改配置檔案
  • 5. 本地構建和訪問
  • 6. markdown解析異常
    • 6.1. Markdown包的實現機制
    • 6.2. pelican預設使用的Markdown擴充套件
    • 6.3. 向第三方擴充套件尋求幫助
    • 6.4. 解決問題
  • 7. One more thing

前幾天心血來潮,想要在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 Grubermarkdown語法的發明者,他在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. 解決問題

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

  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);
}

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

注意:

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

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

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