steemblog: Steem时光机 | Steem Time Machine

steemblog: Steem时光机 | Steem Time Machine

本文我们将介绍 steemblog 的最新的进展。‌

‌Image Source: Pixabay

#1 回顾

‌steemblog 是一项 Steem 文章镜像服务。‌

如果你还不了解这个服务,或许你可以通过访问:https://steemblog.github.io/@team-cn/ 作为一个案例体验一下。‌

在文章《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中,我们提到过创建steemblog 服务的缘由,主要是为了更好的查看历史文章。‌

现在来看,它主要带来了以下几点助益:‌

  1. 首先,steemblog 作为一份档案和历史记录,将 steem 数据以便于阅读和查询的方式保存;虽然区块链技术被认为具有数据不可毁灭的潜力,但有一份额外的备份也存在价值;
  2. 其次,它提供了更好的用户体验访问速度,对于查询、搜索、整合个人或组织的文章,效率更高、更有愉悦感;
  3. 再次,它目前每日更新,虽然是存档,但基本可以保持是近实时的,多于过去几日的文章,也可以一并处理。

根据上一篇文章和微信群中的留言,我们已经帮以下12个账号部署了每日更新的博客镜像服务:‌

  1. @robertyan
  2. @andrewma
  3. @ericet
  4. @julian2013
  5. @annepink
  6. @bring
  7. @sunai
  8. @nostalgic1212
  9. @m18207319997
  10. @iguazi123
  11. @team-cn
  12. @lemooljiang

‌每日北京时间凌晨0点,steemblog 会自动同步镜像一次。‌

总体而言,对我来说 steemblog 是一个还比较好用的时光机(Time Machine),可以更好地学习和了解 steem 上各种有趣的事情。

下面举几个例子来看看吧:‌

#2 场景

‌以下是steemblog的几个有意思的应用场景。

(1)新手村访谈

初入CN区或者新手村的新人,想要了解一下社区内的朋友,其实没有看上去那么容易。去逐个翻看各个用户的历史文章,效率很低。‌

但新手村访谈部分解决了这个问题,我们只要看 #cn-interview 这个标签下的文章就行,但由于steemit / busy 查看标签历史或多或少都有点问题,所以也很难流畅地阅读。在以前,大概有2种方式:‌

  1. 看新手村的索引贴,例如2018版的:https://busy.org/@team-cn/2018-x61niax2i4/
  2. 阅读《Steem指南》的新手村计划部分:https://steem-guides.github.io/steemh/fl.html#section-17.3

但这两种方法更新可能不太及时,最近的访谈没有录入,而 steemblog 是及时更新的。 steemblog 的搜索功能也更快速和有针对性。‌

通过链接:https://steemblog.github.io/@team-cn/tags/cn-interview/,我们可以看到新手村历史上所有的访谈的记录:‌

最新的访谈:

最初的访谈:

按村名搜索:

screenshots from steemblog: https://steemblog.github.io/@team-cn/tags/cn-interview/

想要了解新手村 @team-cn 里的各位朋友,用 steemblog 看一看就一目了然了,确实很有趣。 这对新人也很有帮助,建议你们来看看。‌

(2)社区名人录

‌Steem是个社区,社区是由人组成的,其中有些人由于各种原因成为舆论的焦点或实际的掌权派,总是在历史上不断发生的事情。‌

—-‌

最近 #sct 标签称霸舆论,对于创始人之一的 Jack @jack8831 也接受到了大量的八卦和追捧。但要看家里有矿的男神的生辰八字,也不是这么容易的事啊。‌

steemblog 可以帮你解决这个问题。昨天服务器花了6分钟备份了 Jack @jack8831 的历史文章:https://steemblog.github.io/@jack8831/

然后,要阅读 Jack 的最新动态、历史观点、常用的标签,就容易多了。

不过韩文/朝鲜语我不懂,所以读起来还是需要借助机器翻译的力量。但不可思议的是,下面早期文章的图中的“基本英语”我居然看懂了!!

Jack 好像曾经喜欢给韩国朋友们分享英文,标题中也有“鲑鱼”(연어)的前缀:https://steemblog.github.io/@jack8831/tags/englishforkorean/

所以 steemcoinpan 上鲑鱼泛滥,似乎也在情理之中了。

‌screenshots from steemblog: https://steemblog.github.io/@jack8831/

Jack和团队做的 steemcoinpan 风头正劲,要向韩国朋友们学习,也不妨了解下他们的过往~‌

—-‌

回到CN区。‌

我之前读过《Steem指南》中的 《Steem 十讲》,觉得 刘美女 @deanliu 的观点和文章很独到,所以特地同步了刘美女的文章到 steemblog (服务器时间 18 分钟,刘美女的文章和标签都很多,同步较慢):https://steemblog.github.io/@deanliu/

刘美女已经写了 1400+ 文章,可谓笔耕不辍、涉猎广泛。

最常用的首标签(类别):除了CN区话题,摄影、旅游、美食、讨论 steem / blockchain、以及聊娃(TT)是日常。

最初的文章都是英文,拓荒时期CN区还没有形成规模吧:

老道茶馆的一些过往:https://steemblog.github.io/@deanliu/tags/laodr-teahouse/

‌screenshots from steemblog: https://steemblog.github.io/@deanliu/

不过其实之前 大鹏 @dapeng 也曾经帮助 刘美女 @deanliu 备份过文章( GitHub上的 文章 Markdown 源码 / Netlify 备份站点 ),只是并没有设置成自动更新、以及网站模板较简单罢了。从备份的角度,steemblog 也只是另一种工具和服务而已,并不新奇,但希望它也有所帮助。‌

—‌

我不是很喜欢八卦,所以八卦社区名人和豪杰们的任务,就交给大家自己去完成了。不过想要用 steemblog 来八卦哪些名人倒是可以给我提供一个名单,我可以帮助备份到 steemblog。‌

(3)活动的回顾

‌活动一般以标签的形式进行推广,所以与上面看到的以个人账户为主的文章展示方式并不相同。对于标签文章的备份,steemblog 也可以支持,但目前并没有部署单独对标签进行备份的案例,而且需要对界面做少量修改。‌

这里展示一下 我 @robertyan 主办的对联活动如何查看。‌

以 https://steemblog.github.io/@{username}/tags/{tag}/ 的格式,就能查看标签下的文章。由于对联活动的文章都是我发表的,所以可以这样查看:https://steemblog.github.io/@robertyan/tags/cn-couplet/

‌screenshot from steemblog: https://steemblog.github.io/@robertyan/tags/cn-couplet/

已经办到第四期了,欢迎对语言和文化有兴趣的朋友参与。这期的题目是给刚刚升级到50/60/70级的朋友们写寿联https://busy.org/@robertyan/qs55nyh8x9

(4)奇文共欣赏

‌第四种用途对我还是挺有帮助的:Steem上有一些极度认真的作者,对于喜欢看好文章用户,现在的steemit/busy/steempeak等界面都满足不了需求。‌

上面提到过我推崇 刘美女 @deanliu 的文章并在昨天同步到了 steemblog。其实更早之前,我还同步了 维参 @crowflew 的文章,是我之前在 steem 看到的最有意思的文章系列之一吧:https://steemblog.github.io/@crowflew/

对于阅读博客,steemblog 会显示目录方便作者通览全文和跳转到章节:

可以方便的跳转到前后文章、找到 steem的原文,以及回到顶部等:

‌screenshots from steemblog: https://steemblog.github.io/@crowflew/or-or-or-or/

当然,steem 上的奇文还有很多,如果你有觉得仔细希望阅读的作者,也不妨把他的账户分享给我,一起欣赏一下。‌

(5)揭秘黑历史

‌steemblog 不但能让有用的信息能够被快速查询到,还能让罪行无处遁形。是不是听着挺像一位侦探的?‌

好吧,下面我们来看看 机机 @julian2013 和 村长 @ericet 是如何互黑的。(其实你们是不是更愿意看 软哥 @softmetal 和 小P @pgr 互黑的桥段?)‌

到 steemblog 页面上,点击右上角的搜索进行“侦查”。‌

—-‌

机机谈论村长:

‌screenshots from https://steemblog.github.io/@julian2013/

—-‌

村长评价机机:

‌screenshots from https://steemblog.github.io/@ericet/

—-‌

看上去机机从来没说过村长“坏”话,而村长可不是这样。真的是这样吗?

那么到底究竟说了什么呢?还是要各位自己去看才行。真相永远只有一个,看了以后不妨告诉我。‌

(6)组织的起源

‌其实相比查看人的文章,我更感兴趣组织的发展历史和起源,以及它们的生长过程,比如 @team-cn、@steemstem、@utopian-io,这里也为他们备份了镜像以便于追根溯源、温故知新:‌

@team-cn

‌screenshot from https://steemblog.github.io/@team-cn/page/45/

—-‌

@steemstem

‌screenshot from https://steemblog.github.io/@steemstem/page/28/

—-‌

@utopian-io

‌screenshot from https://steemblog.github.io/@utopian-io/page/33/

希望这些团队不忘初心,破除艰险、勇往直前。‌

—-‌

以上这些例子,不知对你来说是不是也同样有趣或有帮助。‌

如果需要帮你镜像博客,可以在文章后面留言,本次提供5个免费服务名额,先到先得~‌

#3 进展

‌相比于《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中的描述,steemblog 最近也有一些功能和性能更新,这里简要介绍:‌

  1. 编译性能优化:编译速度提高了大约有20~100倍。
  2. 多平台部署:支持备份镜像到Netlify等平台。
  3. 渲染优化:由于采用了组件,进行了优化以保证用户体验
  4. 问题修复:比如类别(category)显示顺序、编译内存溢出等

(1)编译性能优化

‌其实 steemblog 的功能实现是相对比较简单的(可以参考上一篇文章)。但真正有困难的是在 hexo 的编译速度。‌

hexo 虽然号称速度极快,但实际编译的时候简直是灾难。当然,原因不能完全归罪与 hexo 框架本身,更多是 hexo theme的问题。‌

例如,以下是几个账户一开始的编译所有文章花费的时间:

@andrewma: 400+ posts, 80+ tags, ~20 mins

@ericet: 630+ posts, 260+ tags, > 60 mins

很多人的文章数量都接近这个量级,如果要全都同步的话,时间耗费还是很大的,每天更新就要消耗很多资源。‌

除了优化编译方式,另一种是采用增量更新(即只编译新增加的文章), hexo 虽然自称是支持增量更新的,但实际情况是基本不支持、且有很多潜在的问题。‌

—-‌

(a) 优化编译过程

其实原先我只打算做一个简单的服务,不想在主题(theme)优化上花太多功夫,但真正用起来才发现开源世界并不是那么美好 :) ‌

为了完成给大家的每天更新的承诺,以下是优化的方案。‌

  1. 修改主题:由于我们采用的主题(https://github.com/ppoffice/hexo-theme-icarus)较多的使用了各种控件和大量使用了标签和分类等,使得功能较为强大,但带来的问题是编译成静态页面时的成本也很高,为了修复这个主题的问题,我们fork原来的项目,采用了修改后的主题:https://github.com/steemblog/hexo-theme-icarus
  2. 大量使用缓存(cache):hexo 自带有fragment_cache和partial方法,以方便缓存重复使用的组件(如head, footer, sidebar等),但 theme 的作者有时候不清楚可以这样使用,所以我们需要修改。
  3. 控件页面分离:除了使用cache,像很多组件是可以通过 iframe 或者 ajax 异步加载的形式来展示的,这样可以在实现静态页面的时候减少很多冗余的 控件的 html,减少文件大小、提高效率。
  4. 采用时间线布局:原来的 index、tag、archive等页面,都采用了直接展示文章内容的布局,其实不是很有必要,不方便阅读而且使得静态 html 页面变得很庞大。所以我们改成了 timeline 的 layout。
  5. 增加每页文章数量:默认的分页是 6 篇文章一页,对于时间线模式是太少了,所以改成了 20 篇文章一页。编译的速度受页面数量影响很大,而一页展示的文章多了,html 页面总数自然就少了、速度会有明显提高。

策略1:修改主题:

.gitmodules

1
[submodule "theme"] path = themes/icarus url = https://github.com/steemblog/hexo-theme-icarus.git

‌‌code from https://github.com/steemblog/blog | MIT License

策略2:大量使用缓存(cache)

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<% if (page.__widget) { %>
<%- body %>
<% } else { %>
<!DOCTYPE html>
<html <%- has_config('language') ? ' lang="' + get_config('language').substring(0, 2) + '"' : '' %>>
<head>
<%- partial('common/head', {}, {cache: false}) %>
</head>
<body class="is-<%= column_count() %>-column">
<%- partial('common/navbar', { page }) %>
<% function main_column_class() {
switch (column_count()) {
case 1:
return 'is-12';
case 2:
return 'is-8-tablet is-8-desktop is-8-widescreen';
case 3:
return 'is-8-tablet is-8-desktop is-6-widescreen'
}
return '';
} %>
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>
<%- partial('common/footer', {}, {cache: true}) %>
<%- partial('common/scripts', {}, {cache: true}) %>

<% if (has_config('search.type')) { %>
<%- partial('search/' + get_config('search.type'), {}, {cache: true}) %>
<% } %>
</body>
</html>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

对于重复的模块,使用 partial(‘component’, {param}, {cache: true}) 来替换原来的实现‌

策略3:控件页面分离

将原来的 profile, recent_posts, category, tag, tagcloud, archive 等组件,生成独立的 html 页面,减少冗余的 html。此外,组件采用独立的页面也是实现增量编译所必须完成的,所以这一步必须要做。‌

themes/icarus/layout/layout.ejs 需要修改 generators,生成新的 widgets 页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Widget page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('widget', function (locals) {
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
const component_widgets = widgets.filter((w) => (w.component))

return component_widgets.map(function(widget){
return {
path: `widgets/${widget.type}.html`,
layout: 'component/pjax_widget_src',
data: {
widget: widget,
__widget: true
}
};
});
});
}

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_ref.ejs 将原来的组件用对页面的引用替换。

1
2
3
4
5
<div class="card widget">
<div class="card-content">
<div id="widget-<%= widget.type %>" data-pjax="<%= `${get_config("root")}widgets/${widget.type}` %>.html" style="position: relative; width: 100%; display: block;"></div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_src.ejs 对不同的组件,获取对应的内容

1
<%- partial(`widget/content/${page.widget.type}`, {widget: page.widget}) %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/source/js/pjax_widget.js 在页面加载时通过 ajax 来通过url获取组件的 html,替换控件的内容为实际内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (typeof(jQuery) !== 'undefined') {
(function($){
function load_pjax(element) {
// $.pjax({url: element.attr("data-pjax"), container: "#"+element.attr("id")})
$.get(element.attr("data-pjax"), function(data) {
element.html(data);
});
}
$("div[data-pjax]").each(function(){
load_pjax($(this));

})
})(jQuery);
} else {
(function(){
window.$ = document.querySelectorAll.bind(document);
function load_pjax(element) {
const url = element.getAttribute("data-pjax")
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
element.innerHTML = xhr.responseText;
};
xhr.send();
}
for (const e of $("div[data-pjax]")) {
load_pjax(e);
}
})();
}

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/common/widget.ejs 对控件,也要添加 cache 模式,减少冗余。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<% function render_widget(widget) {
const component = widget.component || false;
const cache = widget.cache || false;
if (component) {
const cahced_prefix = cache ? 'cached_' : '';
const template = `component/${cahced_prefix}pjax_widget_ref`;
return partial(template, { widget })
} else {
return partial('widget/' + widget.type, { widget, post: page }, {cache: cache});
}
} %>
<div class="column <%= side_column_class() %> <%= visibility_class() %> <%= order_class() %> column-<%= position %> <%= sticky_class(position) %>">
<% get_widgets(position).forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
<% if (position === 'left') { %>
<div class="column-right-shadow is-hidden-widescreen <%= sticky_class('right') %>">
<% get_widgets('right').forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
</div>
<% } %>
</div>
<% } %>

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

此外,每个组件都要重构将内容独立出来,这里不详细解释了。‌

策略4:采用时间线布局

将categories和tags页面的布局都显示为时间线模式,更容易浏览,且页面所占空间更小。‌

以 category 为例,展示为时间线 + 分页:‌

themes/icarus/layout/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="<%- url_for('/categories') %>"><%= _p('common.category', Infinity) %></a></li>
<% page.parents.forEach(category => { %>
<li><a href="<%- url_for(category.path) %>"><%= category.name %></a></li>
<% }) %>
<li class="is-active"><a href="#" aria-current="page"><%= page.category %></a></li>
</ul>
</nav>
</div>
</div>
<%- partial("component/timeline", {posts: page.posts}) %>
<% if (page.total > 1) { %>
<%- partial('common/paginator') %>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

采用时间线以后,同时也会每个展示的 item 添加 cache:‌

themes/icarus/layout/component/timeline.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="card widget">
<div class="card-content">
<% if (typeof(head) !== 'undefined' &amp;&amp; head) { %>
<h3 class="tag is-link">
<%= head %>
</h3>
<% } %>
<div class="timeline">
<% posts.each(post => { %>
<%- partial("component/cached_item", {post}) %>
<% }) %>
</div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

策略5:增加每页的文章数量

可以有效减少页面总数,减少编译的负担。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Pagination
## Set per_page to 0 to disable pagination
per_page: 6
pagination_dir: page

index_generator:
per_page: 6

archive_generator:
per_page: 20
yearly: true
monthly: true

category_generator:
per_page: 20

tag_generator:
per_page: 20

code from https://github.com/steemblog/blog | MIT License

经过以上各类方案,编译所有文章的速度已经得到的极大的提高,大约已经提到了10~50倍了。

@andrewma: 400+ posts, 80+ tags, 1~2 mins

@ericet: 630+ posts, 260+ tags, 1~2 mins

(b) 实现增量编译

但我们的目标是增量更新,为了实现这个目的,我们需要做两方面修改:‌

  1. 增量生成markdown:无须每次都从 steem 获取 posts 并生成 markdown;
  2. 只编译受影响的 html 文件:修改 hexo 的 tag, category, archive, 和 post的generators,只在 html 受影响时生成。

步骤1:增量生成 markdown

为了不重复生成过去的posts的 markdown 文件,我们用 git repo 来管理过去已经生成的 markdown 文件,并只更新最近1天左右的文章。‌

同时,我们需要和之前的 source 对比,从而知道哪些文章需要更新。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def setup_source_repo(self):
git_clone_cmd = "git clone --depth 1 --branch {} --single-branch https://{}github.com/{}.git {}".format(SOURCE_BRANCH, self._get_github_pat(), self._get_repo(prefix=False), SOURCE_REPO_FOLDER)
os.system(git_clone_cmd)
# on `source` branch after clone
logger.info("Cloned source repo into workspace: {}".format(SOURCE_REPO_FOLDER))

def _commit_source(self):
os.chdir(SOURCE_REPO_FOLDER)
# commit the files into source repo
os.system("git add --all *")
res = os.system('git commit -m "Source updated: {}"'.format(get_uct_time_str()))
os.chdir("..")

if res == 0:
logger.info("Commited source into [{}] folder".format(SOURCE_REPO_FOLDER))
return True
else:
logger.info("Failed to add new source into [{}] folder".format(SOURCE_REPO_FOLDER))
return False

def _diff_files(self):
os.chdir(SOURCE_REPO_FOLDER)
res = subprocess.run(['git', 'diff', 'HEAD', 'HEAD~1', '--name-only'], stdout=subprocess.PIPE).stdout.decode('utf-8')
os.chdir("..")
files = [f for f in res.split("\n") if len(f) > 0]
logger.info("{} different files:\n{}".format(len(files), res))
return files

code from https://github.com/steemblog/blog | MIT License

为了保证每个用户运行时,文章的内容不会混乱,需要多source的workspace也做一些管理,这里不详细叙述了。‌

步骤2:只编译受影响的 html 文件

在用主题进行编译时,也需要知道哪些 markdown 文件需要更新,以及由此判断更新哪些 html。‌

themes/icarus/includes/helpers/diff.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
hexo.extend.helper.register('list_updated_posts', function (link) {
if (_posts.length == 0) {
process.chdir("source")
const res = execSync("git diff --name-only --cached").toString('utf8');
process.chdir("..")

const paths = res.split("\n").filter((p)=>(p.length > 0))
_posts = paths
}
return _posts
});

hexo.extend.helper.register('list_updated_categories', function (link) {
if (_categoreis.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_categories(post.categories);
}
}
}
}
return _categoreis
});

hexo.extend.helper.register('list_updated_tags', function (link) {
if (_tags.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_tags(post.tags);
}
}
}
}
return _tags
});

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

在 generators 中,只考虑那些受影响的文件。以category 为例:‌

themes/icarus/includes/generators/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function needs_update(category) {
if (config.incremental) {
// in incremental mode, update the affected category pages only
const updated_categories = list_updated_categories();
if (updated_categories &amp;&amp; updated_categories.length > 0 &amp;&amp;
updated_categories.indexOf(category['name']) != -1) {
return true;
}
return false;
}
return true;
}

return locals.categories.reduce(function(result, category){
if (! needs_update(category)) {
return result;
}

const posts = category.posts.sort('-date');
const data = pagination(category.path, posts, {
perPage: perPage,
layout: ['category', 'archive', 'index'],
format: paginationDir + '/%d/',
data: {
category: category.name,
parents: findParent(category)
}
});

return result.concat(data);
}, []);

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

需要注意的是,这里需要找到 hexo 对应的几个 generator 的源码,并将其进行替换,例如 hexo-generator-tag、hexo-generator-category、hexo-generator-archive ‌

—‌

实现增量编译以后,经过测试,大概每天更新时,每个账户消耗的时间大约在几秒钟 到1分钟之间。12个账户更新时,总的耗时大约在2分钟至10分钟左右,包括环境部署的时间。

@andrewma: 400+ posts, 80+ tags, ~17s

@ericet: 630+ posts, 260+ tags, < 1min

—-‌

至此,编译性能优化的工作告一段落,可以支持更多账户的镜像同步了。‌

(2)多平台部署

‌除了 GitHub pages,现在常用的静态网站部署方式还有Netlify等。只需要按照Netlify的界面上步骤操作即可,或者参考 hexo deployment 一节的描述。‌

作为结果,我们可以将页面部署到不同环境:‌

‌注意:Netlify上目前只部署了 @robertyan 的文章,但也可以支持其他账户。‌

(3)渲染优化

‌由于采用了组件化的 html 页面内,在上文提到过需要动态加载 widget 的页面,由于页面加载资源的阻塞等问题,我们需要对页面做一些优化才能保证 widget 的渲染不被图片等资源影响太大。‌

这里主要是在 widget 的占位符组件被渲染以后,立即调用 ajax 加载组件的代码,以尽早显示这些 widgets;否则,首页打开时的卡顿还是挺明显的。‌

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

主要需要优化的渲染过程就是组件的渲染,其余目前并未做更多测试。‌

(4)问题修复

‌除了以上提到的问题,由于在编译或展示时还需要一些别的问题,也一同修复了。‌

  1. @andrewma 想可以将 category 和 tag 等按使用频率从大到小排序;
  2. 编译 @lemooljiang 的博客时,产生 node / v8 的内存溢出问题,编译失败。

这些问题较容易修改:前者只需渲染前进行排序;后者需要对node运行的参数进行配置,改上限为8GB。后者的修改在:‌

blog/command.py

1
2
3
def configure():
settings.set_env_var("NODE_OPTIONS", "--max-old-space-size=8192")
os.system("cp -f _config.theme.yml themes/icarus/_config.yml")

#4 未来

‌steemblog 实现时 只是为了满足更好的阅读、搜索文章的需要。简言之,它是一个更好的博客“阅读器”(当然也是一个有趣的“时光机”),并不具有写的功能。‌

这是它想要解决的问题决定的,但它的未来可以有着有趣的发展方向,我们从小和大两个方面来讲。‌

—-‌

:从steemblog的角度来讲,我们可以做各类改进,包括功能、性能、运营等。‌

  • 功能:支持语言切换、主题切换、留言(原来就有,为了性能隐藏了)、图片本地保存等
  • 性能:hexo 模板的渲染速度可进一步优化
  • 运营:可以扩展现有系统以支持更多用户、可以考虑付费模式以满足更多需求(费用可能是一次性 10 STEEM 之类的)
  • 扩展:用户可以借助此框架和其他建站服务,快速构建基于 steem 数据的各种网站,包括博客、简历、图库等,以及各种基于 steem 数据的展示组件、基于 steem-js 的写操作 等等;

‌—-

:steemblog 展示了一种基于blockchain 的 app 的更多的可能性。为什么这么说呢?主要原因如下:‌

  • 一份数据、多种展示:与传统数据库相比,blockchain 数据库的公开性和可访问性使得它可以被方便用于基于同一份数据构建多种应用。这也是dApp有趣的方面。steemblog 通过 将 steem blockchain 的数据,进行二次加工,形成了不同的展示方式,这体现了一份数据、多种应用场景的特点。 steemblog 的意图和 steemit 等客户端不完全相同。这里强调的展示有更多 “数据应用”(data apps)的意味,并不全然是 web app 或者 mobile app的视角。
  • 分久必合、强调综合:steem 等区块链平台,现在流行的 dApp 以web app的思维,不断产生新的应用和平台,使得数据不断分化、分裂,到了一定复杂度后,需要一个可以集中管理各类数据与事务的调度中心,steemblog 对于历史的总览体现了这一种思想的一个方面。
  • 数据基础的改进方向:steem 类应用的用户体验的局限性一部分在于其数据基础设施的不灵活与低效,steemblog 通过分离数据读和写,改进了用户体验,但这只是一个方向。blockchain 数据基础设施有着更多的发展的可能性。
  • 社会:生产还是消费?:steemblog 把 steem 数据展现出的一个用户的能力、经验、历史等方面,更有效的展现出来,这是一个更具有生产、企业或产业角度的意义的展示。 steemblog 可以让我们更清楚地看到一个用户的时间是如何被应用与转化的。这种方式对于大规模协作的价值大于娱乐消费型 app 的需要。

这只是一个大致的方向,或许随着思考的深入我们可以把它演变成新的应用。‌

但有三点应该是对的:(1)你在 steem 的历史不会消失;(2)更好的时光机将会不断被发明出来;(3)未来必定会来到。‌

基于这些前提,我们或许能不断看到更多有趣的应用吧。‌

—-‌

昨天 @holger80 在 discord 和我聊到了关于 hexo theme 的问题,同时创建了 steemsites 这个项目(https://github.com/holgern/steemsites),可能也有通过 steem 构建站点,或者其他方面的考虑。‌

对于 steemblog 和相关的项目,我们在之后会进一步思考和探索。如有任何建议请随时留言讨论~‌

参考文献

  1. Hexo博客框架:https://hexo.io
  2. Hexo icaru 主题:
    1. 修改后:https://github.com/steemblog/hexo-theme-icarus
    2. 原作者:https://github.com/ppoffice/hexo-theme-icarus
  3. steemblog 博客镜像服务:https://steemblog.github.io/ (源码:https://github.com/steemblog/blog | MIT License)


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/steemblog-steem%e6%97%b6%e5%85%89%e6%9c%ba-steem-time-machine


This page is synchronized from the post: steemblog: Steem时光机 | Steem Time Machine

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×