PlainSite: A Simple but Truly Hackable Static Site Generator https://github.com/CJex/PlainSite
这个项目其实是去年做的,当时没时间推广。之前看到某 Python 静态站点生成器还特地强调不仅是生成博客而是 Site ,我就低调不下去了。 PlainSite 虽然功能简单,但却具有无限的扩展性,理论上可以生成分类任意复杂的静态站点(只要你会写 Ruby)。没人用太可惜。
下载运行也和 Jekyll 差不多,gem install PlainSite
,plainsite init
,plainsite build
。支持 Markdown,也用了 FrontMatter 格式。
我先列举下它的亮点:
git status
读取哪些文件被修改过,只生成修改过的 Post 相关的 HTML 页面,不会每次都重新生成整个站点。(plainsite build -a
可以重新生成整个)plainsite build -l
就生成一个 local 站点,直接在文件管理器中打开就能浏览。当然 PlainSite 也内置了一个实时预览用的 WebServer,修改文件不需要重启。_src/assets
下面,这样它就可以自动删除孤立的文章页面。你删除了某文章,生成的页面也能自动清理。好了,上面的亮点其实是次要的。最主要的是,PlainSite 是一个 Framework,提供了一套 API,而且这套 API 和 MVC 框架很相近。首先是数据管理,在站点_src/data
目录下,相当一个文件数据库,一个目录表示一个 Category,类似于数据库中的 Table,一个 Markdown 或 HTML 文件表示一个 Post,相应于数据库中一条记录。
如何查询呢?Ruby DSL 的强大体现出来了。
读取 news 目录下的所有 Post,相当于 SQL:SELECT * FROM news
$site.data / :news / '*' # 返回PlainSite::Data::PostList 对象
你要文章置顶功能?
($site.data / :news / '*' ).order_by &:top
对应在_src/data/news/
目录下的 Post 文件中就写:
---
title: Today Top News-Wall down
top: true
---
这里是正文内容
你要分页?好,按每页 5 条分页
$site.data / :news / '*' / 5 # 返回 [PlainSite::Data::PostListPage]
可这数据拿出来又怎么使用呢?对应于 MVC 中的 URL Router,在_src/data/routes.rb
:
$site.route(
url_pattern: "/{date}-top-news-{title}.html",
data: $site.data / :news / '*' ,
template: 'news-list.html'
)
上面的代码其实就相当于以 PostList 中每篇 Post 为 Context 去 Render news-list.html
这个模板,URL 模式中用 Post 的属性值去替换。
那接下来就是模板,PlainSite 使用 ERB,扩展支持 include 和 layout,例如:
---
layout: base.html # 相对于当前模板文件的路径
---
<% content_for :page_title do %>
<%=title%> - <%=site.name %>
<% end %>
<% content_for :page_content do %>
<h1><%=title%></h1>
<p>Date:<%=date%></p>
<%=content%>
<hr />
Use site.url_for to get url,so it can be affected by 'plainsite build --local',results in relative url.
<%=site.url_for 'essays/hello' %>
Also support includes.
<%=include 'footer.html' %>
<% end %>
base.html 文件内容:
<html>
<head>
<title><%=yield :page_title%></title>
</head>
<body>
<%=yield :page_content%>
</body>
</html>
好了,MVC 齐全了。但强大在什么地方呢?强大的不是 PlainSite 而是你会 Ruby!因为routes.rb
就是一个 Ruby Script。所以:
# 给每个分类都生成一个列表页面
# $site.data.subs 是子目录,返回 Category[]
$site.data.subs.each do |category|
$site.route(
url_pattern: "#{category.name}/{slug}.html",
# category.posts/5 means category.posts.paginate(page_size:5)
# return PostListPage[]
data: category.posts/5, # category.posts is same as category / '*' .
template: 'list.html'
)
end
# 要RSS?
$site.route(
url_pattern: 'rss.xml',
data: { posts: $site.data/'**' }, # RubyChina代码高亮补丁:/
template: 'rss.erb' # rss.erb在PlainSite中已经内置,`plainsite init`会自动生成这个文件
)
#你要给每个分类单独生成一个RSS?
$site.data.subs.each do |category|
$site.route(
url_pattern: "#{category.name}/{slug}-rss.xml",
data:category,
template: 'category-rss.html'
)
end
而且模板是 ERB,你想怎么搞就怎么搞:
# routes.rb 中写
$site.route(
url_pattern:'jobs',
data: {jobs:($site.data / :jobs / '*').order_by &:pay_money }, #按付的钱排序
template: 'jobs.html'
)
然后jobs.html
:
<%jobs.each do |job|%>
<li><%=job.title%></li>
<%end%>
好了,明白了吧,意思就是只要你会写代码,那它扩展性是无限的。 Who choosed PlainSite?好吧,其实只有我自己一个人在用:https://jex.im/
另外我告诉你们一个网站:https://staticsitegenerators.net/ ,想用哪个随便挑