[譯] 編寫一個小型靜態網站生成器

原文連接:https://blog.thea.codes/a-small-static-site-generator/html

大概有數百個 Python 編寫的靜態網站生成器(更多的其餘語言編寫的)。python

我決定寫一個本身的。爲何呢?當我決定把個人博客從Ghost搬遷到別的博客系統,我想找一個最小的。我決定使用 Github Pages 去部署,它要支持給自定義域名提供 SSL 支持。git

渲染內容

每個靜態網站生成器都須要把某種格式(如Markdown 或者 RestructredText)轉換成HTMl。既然是從 Ghost 遷移,我決定繼續使用 Markdown。github

因爲我最近將 Github-flavored Markdown集成到了 Warehouse,我決定使用我爲它編寫的庫 - cmarkgfm。使用 cmarkgfm 渲染 Markdown 到 HTML 看起來以下:markdown

import cmarkgfm


def render_markdown(content: str) -> str:
    content = cmarkgfm.markdown_to_html_with_extensions(
        content,
        extensions=['table', 'autolink', 'strikethrough'])
    return content

cmarkgfm 提供一個便利的方法 github_flavored_markdown_to_html,但它使用的是 Github 的 (tagfilter)[https://github.github.com/gfm...] 擴展。當我想在文章中嵌入代碼時,我不太想要這個特性。因此建立渲染器時,我經過代碼選擇本身想使用的特性。app

掃描源文件

咱們已經能夠渲染 Markdown 了,接下來咱們須要遍歷咱們要渲染的源文件。我決定把他們都放到 .src 目錄。咱們可使用 pathlib 庫來遍歷它們:函數

import pathlib
from typing import Iterator


def get_sources() -> Iterator[pathlib.Path]:
    return pathlib.Path('.').glob('srcs/*.md')

Frontmatter

許多靜態站點生成器都有 frontmatter 這個概念,這是一組元數據,在每一個文件開頭都有。我決定支持frontmatter 用來設置日誌的標題和日期。以下所示:post

---
title: Post time
date: 2018-05-11
---

# Markdown content here.

使用 python-frontmatter 實現這個功能很容易。我可使用它獲取元數據和日誌內容:網站

import frontmatter


def parse_source(source: pathlib.Path) -> frontmatter.Post:
    post = frontmatter.load(str(source))
    return post

這段代碼返回的 post 對象包含的 .content 屬性是日誌內容,其餘的 frontmatter 內容可使用操做字典的方式進行獲取。日誌

生成日誌

如今咱們有了日誌內容和元信息解析,咱們能夠生成日誌了。我決定使用 jinja2cmarkgfm 生成的內容和元信息組合進一個HTML 模板。

模板內容:

<!doctype html>
<html>
<head><title>{{post.title}}</title></head>
<body>
  <h1>{{post.title}}</h1>
  <em>Posted on {{post.date.strftime('%B %d, %Y')}}</em>
  <article>
    {{content}}
  </article>
</body>
</html>

調用的 Python 代碼:

import jinja2

jinja_env = jinja2.Environment(
    loader=jinja2.FileSystemLoader('templates'),
)


def write_post(post: frontmatter.Post, content: str):
    path = pathlib.Path("./docs/{}.html".format(post['stem']))

    template = jinja_env.get_template('post.html')
    rendered = template.render(post=post, content=content)
    path.write_text(rendered)

能夠注意到,咱們存儲生成後的 HTML 文件在 .docs 目錄。着是由於我配置的 Github Pages 的發佈目錄

如今咱們已經成功生成一個日誌文件了。咱們能夠對 get_sources 的返回結果作一個遍歷:

from typing import Sequence


def write_posts() -> Sequence[frontmatter.Post]:
    posts = []
    sources = get_sources()

    for source in sources:
        # Get the Markdown and frontmatter.
        post = parse_source(source)
        # Render the markdown to HTML.
        content = render_markdown(post.content)
        # Write the post content and metadata to the final HTML file.
        post['stem'] = source.stem
        write_post(post, content)

        posts.append(post)

    return posts

索引

咱們如今能夠渲染日誌了,可是咱們還須要一個 index.html 索引這些內容。咱們使用另外一個 jinja2 模板將 write_posts 返回的內容嵌進去。

代碼:

<!doctype html>
<html>
<body>
  <h1>My blog posts</h1>
  <ol>
    {% for post in posts %}
    <li>
      <a href="/{{post.stem}}">{{post.title}}</a>
    <li>
    {% endfor %}
  </ol>
</body>
</html>

Python 代碼:

def write_index(posts: Sequence[frontmatter.Post]):
    # Sort the posts from newest to oldest.
    posts = sorted(posts, key=lambda post: post['date'], reverse=True)
    path = pathlib.Path("./docs/index.html")
    template = jinja_env.get_template('index.html')
    rendered = template.render(posts=posts)
    path.write_text(rendered)

結尾

如今在主函數中加個調用,將這些代碼串起來。

def main():
    posts = write_posts()
    write_index(posts)


if __name__ == '__main__':
    main()

在 Github 中訪問

本頁面即爲你讀到的代碼渲染而成(並非)!你能夠在 Github 查看本文所講內容的完整代碼,包括語法高亮支持:https://github.com/theacodes/...

相關文章
相關標籤/搜索