用html制作编写静态日志,[译] 编写一个小型静态网站生成器

大概有数百个 Python 编写的静态网站生成器(更多的其他语言编写的)。

我决定写一个自己的。为什么呢?当我决定把我的博客从Ghost搬迁到别的博客系统,我想找一个最小的。我决定使用 Github Pages 去部署,它要支持给自定义域名提供 SSL 支持。

渲染内容

每一个静态网站生成器都需要把某种格式(如Markdown 或者 RestructredText)转换成HTMl。既然是从 Ghost 迁移,我决定继续使用 Markdown。

由于我最近将 Github-flavored Markdown集成到了 Warehouse,我决定使用我为它编写的库 - cmarkgfm。使用 cmarkgfm 渲染 Markdown 到 HTML 看起来如下:

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...] 扩展。当我想在文章中嵌入代码时,我不太想要这个特性。所以创建渲染器时,我通过代码选择自己想使用的特性。

扫描源文件

我们已经可以渲染 Markdown 了,接下来我们需要遍历我们要渲染的源文件。我决定把他们都放到 .src 目录。我们可以使用 pathlib 库来遍历它们:

import pathlib

from typing import Iterator

def get_sources() -> Iterator[pathlib.Path]:

return pathlib.Path('.').glob('srcs/*.md')

Frontmatter

许多静态站点生成器都有 frontmatter 这个概念,这是一组元数据,在每个文件开头都有。我决定支持frontmatter 用来设置日志的标题和日期。如下所示:

---

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 内容可以使用操作字典的方式进行获取。

生成日志

现在我们有了日志内容和元信息解析,我们可以生成日志了。我决定使用 jinja2 将 cmarkgfm 生成的内容和元信息组合进一个HTML 模板。

模板内容:

{{post.title}}

{{post.title}}

Posted on {{post.date.strftime('%B %d, %Y')}}

{{content}}

调用的 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 返回的内容嵌进去。

代码:

My blog posts

{% for post in posts %}

{{post.title}}

{% endfor %}

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/...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值