原文连接: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
用来设置日志的标题和日期。以下所示: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
内容可使用操做字典的方式进行获取。日志
如今咱们有了日志内容和元信息解析,咱们能够生成日志了。我决定使用 jinja2 将 cmarkgfm
生成的内容和元信息组合进一个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 查看本文所讲内容的完整代码,包括语法高亮支持:https://github.com/theacodes/...