更新版本 hexo 2.8 to 3.1 惡夢

Parser Error

主要原因是因為 hexo 3.0 引入新的渲染引擎 mozilla/Nunjucks 的問題。

由於有 Nunjucks 的關係,有一些渲染方式要改變寫法。

Plugin Update

很多指令都模組化,所以要個別安裝需要的操作,並且插件一定要透過 npm 安裝,寫入到 blog/package.json 才會被接受。

1
2
3
$ npm install hexo-generator-sitemap --save
$ npm install hexo-generator-feed --save
$ npm install hexo-deployer-git --save

由於 mozilla/Nunjucks 的關係,改變最麻煩的是 tag plugin 的名稱,例如 rawblock -> rawmath-block -> math 的更動,因此要寫個程式進行轉換。

由於 latex 的緣故,hexo-math 這個 plugin 需要更動,以免 Nunjucks 解析時發生錯誤,強制讓 inline 的寫法有對齊,所以我把 hexo-math 做了客製化修改。

1
2
3
4
5
6
7
hexo.extend.tag.register("math", function(args, content) {
var result;
result = "<span>$" + content + "$</span><!-- Has MathJax -->";
return result;
}, {
ends: true
});

並且取消自動注入,因為目前的 hexo server 在修改文章時,效能不佳,以下代碼是 hexo-math 在用自動注入的部分呼叫函數,若使用這個函數,速度拖累很多。

1
2
3
hexo.extend.filter.register("after_render:html", function(src, data) {
return src;
}

New Feature

分頁支持

1
2
$ npm install hexo-generator-archive --save
$ npm install hexo-generator-tag --save

在這幾個地方增加分頁設計,讓一次載入大量資料的需求減少。

Browser

開啟 hexo server 時,若更動文章內容,刷新速度變得非常慢,並且會造成 nodejs 狂吃 CPU 和 memory 同時也重新渲染所有文章。

Setting

blog/__config.yml 也做了些調整,簡化不少設定檔,若不特別需要,則不會出現。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
archive_generator:
per_page: 20
yearly: true
monthly: false
category_generator:
per_page: 10
tag_generator:
per_page: 20
browser_sync:
port: 4000
browser: "google chrome"
open: false
server:
port: 4000
log: true
ip: 127.0.0.1

以及在過去版本一直被我遺忘的 highlight 設定,要把 tab 換成四個空白,有時候貼上常常會發生 tab 變成四個空白的解析,現在版本先關閉自動偵測 highlight,官方說那裏解析速度上有問題。

1
2
3
4
5
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: " "

這裡還是有個問題,highlight.js 不處理以下情況

1
<tab><space><space><space><space><tab>

最後一個 tab 將不會被轉換,也就是只有行首的 tab 會自動轉換,想必是對齊部分不容易寫。

Read More +

部落格架構更新與狀態

當前使用主題為 hexo-theme-landscape,早期使用 pacman,自己修改成 moman 一個黑色系主題,但是隨著文章數量的增加,pacman 樣板的生成速度越來越慢,更新 hexo 後,發現 landscape 的速度異常地快,於是將整個樣板配色轉移到 landscape。

想打包我嗎?直接至 morris821028/morris821028.github.io 下載即可。還是即時的版本呢,可惜地是無法再用 hexo 繼續產生文章,也就是要新增一篇文章是困難的。這裡有純草稿 morris821028/HexoBlog 提供,偶爾會更新,這偶爾想必是挺久的日子。往後要在其他主題下部屬也不是問題!

反應速度

由於 hexo 本身就是 靜態網頁 的框架,所以不會有資料庫調用問題,反應速度理所當然會快很多。為了增加網頁的反應速度,要把不少重複的框捨去,siderbar 訊息最小化!

原理就當作編寫 markdown,利用 hexo 編譯成 html 後上傳。跟一般寫 cpp 程式很像呢!

  • Tags 搬移到額外的分頁,由於每一個頁面下都會出現在 sidebar,無用訊息量太多導致載入速度拉慢,不要忽視使用者經驗 (UX)!

額外分頁的建立

/blog/source/tags/index.md
1
2
3
title: Tags
layout: tags
---

hexo 配置是採用每一個 markdown 上的參數 layout。接著只需要在主題下寫一個 /themes/landscape/layout/tags.ejs,到時候會直接經過 layout.ejs 呼叫 tags.ejs

接著就可以在 http://localhost:4000/tags/ 下看到自己想要頁面,一般而言不會有這一頁,會呈現 NOT FOUND 404 狀態。

主題設定檔

既然有用 font awesome ,覺得在默認主題下 Home 顯得不太夠力且明瞭,直接點擊 logo 也是能返回主頁。於是把設定檔案改成以下內容,搭配圖示和文字描述,希望這種方式會更脫離死板的配置。

/themes/landscape/_config.yml
1
2
3
4
5
6
7
menu:
- {name: Home, path: /, class: icon-home, layout: 1}
- {name: About, path: /about, class: icon-user, layout: 2}
- {name: Archives, path: /archives, class: icon-archive, layout: 2}
- {name: Tags, path: /tags, class: icon-tags, layout: 2}
- {name: Pictures, path: /picture, class: icon-camera, layout: 2}
- {name: Works, path: /works, class: icon-trophy, layout: 2}

接著在 header.ejs 下修改一下內容,畢竟參數上有點調整。

/themes/landscape/layout/_partial/header.ejs
1
2
3
4
5
6
7
8
9
10
<a id="main-nav-toggle" class="nav-icon"></a>
<% for (var i in theme.menu){ %>
<% if (theme.menu[i].layout && theme.menu[i].layout == 1) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i></a>
<% } else if (theme.menu[i].layout && theme.menu[i].layout == 2) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i> <%= theme.menu[i].name %></a>
<% } else { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><%= theme.menu[i].name %></a>
<% } %>
<% } %>

Ukagaka

由於 史蒂芙 任務結束,現在由 派拉斯 接管,她們的個人照片都可以在 Pictures 中見到哦!

關於 Ukagaka 的製作,目前把音樂坑解決,將可以在功能列表中看到音樂撥放功能!實作採用 HTML5 + js 的方式,並且把圖片部分全部用 font awesome 解決,功能還不夠齊全,希望已經能符合最低需求。

其實很早就用 HTML5 + js 弄過音樂撥放,但遲遲沒有嫁入到 Ukagaka 中。

音樂部份的免空是個問題,目前用容量較小的音樂檔案放置 hexo 中一起部屬。

至於 AIML 的 AI 智能對話部分,之前停留在 JAVA 那邊,暫且還不會去完成她,其一原因是必須轉成比較好跑在 server 上面的版本,並且能應付多人單一的狀態保留。如果不寫 web socket,必然要透過 ip 進行辨識,至少能記住當前使用者的名稱 (如果有教導 Ukagaka 的話)。

根據之前用 nodejs 寫 web socket 完成 chat room 的感想,有一部分是相當難理解的 js,同時存在瀏覽器要解析的 js 中,模組部分很好奇實際運作原理,詳細還沒有理解。

Read More +

製作 hexo-tag-oj

Demo UVa OJ,標製作只有自己會用的 TAG,詳細請查閱 Github。

  • 目前 javascript 存放在 Google Drive
  • 每一篇限用一個 tag,無法解決多重匯入問題。如果硬是要匯入也行,只是會重複好幾次。
  • 請確保每個頁面的 <head> 有引入 jquery 1.7.0 以上的版本。

順手測一下

GitHub jQuery Repo Widget

TEST

事實上只是將上述的 jQuery 修改而已。

Read More +

Hexo Math Plugin

展示

A hexo plugin that uses MathJax to render math equations.
Simple inline $a = b + c$.

1
Simple inline {% math %}a = b + c{% endmath %}.

This equation$\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ is inline.

1
This equation{% math %}\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 {% endmath %} is inline.
$$\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}$$ {% math %} \begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned} {% endmath %}

更多

http://catx.me/2014/03/09/hexo-mathjax-plugin/

Read More +

解決 Hexo Comment !

評論 Widget 設定

為什麼會有這篇文章

  • 你的主題可能沒有 recent_comment.ejs
  • Comment 可能是 多說Duoshuo 而你不喜歡

開始正文

使用 Disqus

  • 請到 Disqus 申請帳號,並且記住你的 shortname

    • 到本機下,修改本機目錄下的 _confid.yml 在 disqus_shortname 貼上自己的 shortname
    • 接著,就是確認運行成功。
      1
      2
      # Disqus
      disqus_shortname: morris1028
  • Widget 側欄的近期評論,當然還有熱門、聚合 … 等。請參考 這裡

    themes/xxxx/layout/_widget/recent_comment.ejs
    1
    2
    3
    4
    <div id="recentcomments" class="dsq-widget">
    <p class="asidetitle">Recent Comments</p>
    <script type="text/javascript" src="http://morris1028.disqus.com/recent_comments_widget.js?num_items=10&hide_avatars=1&avatar_size=32&excerpt_length=100&hide_mods=0"></script>
    </div>
  • 關於主題可能沒有 comment.ejs,請在目錄下增加代碼
    themes/xxxx/layout/_partial/comment.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <% if (page.comments){ %>
    <section id="comment">
    <h1 class="title"><%= __('comment') %></h1>
    <% if (theme.comment_provider == "facebook") {
    if (theme.facebook) { %>
    <%- partial('_partial/facebook_comment', {fbConfig: theme.facebook}) %>
    <% } %>
    <% } else if(config.disqus_shortname) { %>
    <div id="disqus_thread">
    <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    </div>
    <% } %>
    </section>
    <% } %>
  • 萬一還是啟動不成功,請查閱 after_footer.ejs 是否具有以下代碼
    themes/xxxx/layout/_partial/after_footer.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <% if (config.disqus_shortname){ %>
    <script type="text/javascript">
    var disqus_shortname = '<%= config.disqus_shortname %>';
    (function(){
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true;
    dsq.src = '//' + disqus_shortname + '.disqus.com/<% if (page.comments){ %>embed.js<% } else { %>count.js<% } %>';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    }());
    </script>
    <% } %>
  • 評論 CSS 設置,請到 comment.styl 查閱
    themes/xxxx/source/css/_partial/comment.styl
    1
    2
    3
    4
    5
    6
    7
    8
    #comment
    padding 20px
    background #272822
    box-shadow 1px 2px 3px #ddd
    margin-bottom 50px
    .title
    font-weight normal
    margin-bottom 15px
    • 最後再確認一下,有載入 comment 的 CSS
      theme/xxxx/source/_partial/css/style.styl
      1
      @import '_partial/comment'

更多

  • 其實差不多了,想必也能配置成功。
  • 關於近期文章 widget
    themes/xxxx/layout/_widget/recent_comment.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <% if (site.posts.length){ %>
    <div class="categorieslist">
    <p class="asidetitle">Recents</p>
    <ul>
    <% site.posts.sort('date', -1).limit(5).each(function(post){ %>
    <li>
    <a href="<%- config.root %><%- post.path %>"><%= post.title || '(no title)' %></a>
    </li>
    <% }) %>
    </ul>
    </div>
    <% } %>
  • 最後在 themes/xxxx/_config.yml 加入您的 widget
    themes/xxxx/_config.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #### Widgets
    widgets:
    - recent_posts
    - category
    - archive
    - tagcloud
    - recent_comment
    - links
    - rss

最後

非常感謝您的閱讀

Read More +

第一次來到 Hexo !

加油

失敗就是失敗

看著右上方的清單,還真有 wiki 的感覺,對於長篇大論是挺有用的,現在應該說是裝飾,接下來要描述失敗的開始。

這是一個搬運的過程,但是宣告失敗

初章

為了轉移過來,將 Morris’ blog(PChome) 文章倚靠爬蟲方式轉移過來,但是沒想到這裏要的是 markdown 檔案格式,用 Nodejs 寫了巨噁無比的代碼來專屬爬 PChome 新聞台,並且使用套件將其轉換成 markdown。

最後宣告失敗。

用了不少可以將 html to markdown 的工具,或者只是單純要 html to text,但是不管哪個產出的格式都不好,心灰意冷的情況下,開始動工修改 node_modules 資料夾下的插件代碼,track 相異插件各種作噁,最後還是沒成功。

次章

目前以玩玩的心態架設這個靜態頁面。

附上 20140411 BACKUP Morris’ blog(PChome) backup

nodejslink
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
var http = require('http'),
fs = require('fs');
var toMarkdown = require('to-markdown').toMarkdown;
var htmlToText = require('html-to-text');
/*
var text = htmlToText.fromString('<h1>Hello World</h1>', {
wordwrap: 130
});*/
// console.log(toMarkdown('<b>Hello world</b>'));
var websiteName = "zerojudge";
var websitePage = 141;
var websiteDomain = 'http://mypaper.pchome.com.tw/';
var url = websiteDomain + websiteName;
var loadprocess = 0;
clawingWebSite(url, websitePage);
function clawingWebSite(url, websitePage) {
for(var i = 0; i <= websitePage; i++) {
if(i == 0)
clawingWebPage(url);
else
clawingWebPage(url + "/P" + i);
}
}
function clawingWebPage(url) {
readWebPage(url);
}
function branchWebPage(source) {
var sourceIndex = source.indexOf('class="blog"');
while(sourceIndex >= 0) {
var pageLink = source.indexOf(websiteName + '/post', sourceIndex);
if(pageLink > 0) {
var endLink = source.indexOf('"', pageLink);
var articleLink = source.substr(pageLink, endLink - pageLink);
readWebArticleLink(websiteDomain + articleLink, articleLink);
sourceIndex = pageLink + 1;
sourceIndex = source.indexOf('title brk_h', sourceIndex);
} else {
break;
}
}
}
function parsingArticlePage(source, fileName) {
var contentBody = "";
var articleTitle = "";
var mdFormat = "";
var sourceIndex = source.indexOf('name="keywords"');
sourceIndex = source.indexOf('content="', sourceIndex);
var nextIndex = source.indexOf('"', sourceIndex + 10);
articleTitle = source.substr(sourceIndex + 9, nextIndex - (sourceIndex + 9));
sourceIndex = nextIndex;
console.log('Title = ' + articleTitle);
sourceIndex = source.indexOf('<div class="innertext brk_h"');
var endIndex = source.indexOf('<div id="ArticleMapTitle"');
contentBody = source.substr(sourceIndex, endIndex - sourceIndex - 1);
contentBody += "</div>";
var sourceBody = contentBody;
if(endIndex - sourceIndex - 1 <= 0)
return;
articleTitle = articleTitle.replace(/\[/g, "【");
articleTitle = articleTitle.replace(/\]/g, "】");
var text = htmlToText.fromString(sourceBody, {
wordwrap: 130
});
contentBody = toMarkdown(contentBody);
mdFormat += "title: " + articleTitle + "\n";
mdFormat += "date: 2014-04-10 20:10:28" + "\n";
mdFormat += "tags: " + "\n";
var tagIndex = source.indexOf('<div id="article_tag">');
if(tagIndex > 0) {
tagIndex += '<div id="article_tag">'.length + 1;
var tagTail = source.indexOf('<div id="article_author" align="right">');
var tagEndIndex;
while(true) {
var tagStartIndex = source.indexOf('search_fields=tag">', tagIndex);
tagStartIndex += 'search_fields=tag">'.length;
if(tagStartIndex < 0 || tagStartIndex > tagTail)
break;
tagEndIndex = source.indexOf('</a>', tagStartIndex);
var articleTag = source.substr(tagStartIndex, tagEndIndex - tagStartIndex);
console.log(articleTag);
mdFormat += "- " + articleTag + "\n";
tagIndex = tagEndIndex;
}
}
mdFormat += "---" + "\n\n";
text = " " + text;
text = text.replace(/\n/g, "\n ");
mdFormat += text;
loadprocess++;
fs.open('sourcePage' + loadprocess + '.html', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, source, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
fs.open('textPC' + loadprocess + '.md', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, mdFormat, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
fs.open('oldPC' + loadprocess + '.md', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, contentBody, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
}
function readWebArticleLink(url) {
http.get(url, function(res) {
var source = "";
//通过 get 请求获取网页代码 source
res.on('data', function(data) {
source += data;
});
//获取到数据 source,我们可以对数据进行操作了!
res.on('end', function() {
parsingArticlePage(source);
});
}).on('error', function() {
console.log("获取数据出现错误");
});
}
function readWebPage(url) {
http.get(url, function(res) {
var source = "";
//通过 get 请求获取网页代码 source
res.on('data', function(data) {
source += data;
});
//获取到数据 source,我们可以对数据进行操作了!
res.on('end', function() {
branchWebPage(source);
/*fs.open('hello.txt', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, source, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});*/
});
}).on('error', function() {
console.log("获取数据出现错误");
});
}
Read More +

從現在開始開始 Hexo !

用了 GitHub, 學到 Nodejs, 路過 Hexo, 到了這裡

安裝各種有趣 ?

Hexo 第一步

  • 請先把 Nodejs 和 npm 架設好
  1. 下載 Hexo
    1
    $ npm install hexo -g
  2. 安裝到你的目標目錄下
    1
    $ hexo init blog && cd blog
  3. 以下操作會將文章從 markdown 檔案產生關聯
    1
    $ hexo generate
  4. 開啟 Server, 使用於本地調效, 之後可連到 http://localhost:4000/ 查看
    1
    $ hexo server

Hexo 日常問題

  • 撰寫文章

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ hexo new [layout]
    $ hexo new "New Post"
    # => The file will be created at source/_posts/new-post.md
    $ hexo new page "New Page"
    # => The file will be created at source/new-page/index.html
    $ hexo new draft "New Draft"
    # => The file will be created at source/_drafts/new-draft.md
  • 文章標籤使用

    1
    2
    3
    4
    title: Start Hexo !
    date: 2014-04-10 19:40:22
    tags: [hexo, image]
    categories: About This Blog
  • 文章代碼高亮

    1
    2
    3
    {\% codeblock \%}
    your code here. 自行去掉反斜線
    {\% endcodeblock \%}

Hexo 個人化問題

  • 修改主題, 修改完畢後, 請進行以下操作來對 deploy 運行, style.css 才會正確, 本地查閱不影響

    1
    2
    3
    $ hexo clean
    $ hexo generate
    $ hexo deploy
  • 與 github page 連接做靜態操作

    blog_folder/_config.yml
    1
    2
    3
    4
    5
    6
    # Deployment
    ## Docs: http://zespia.tw/hexo/docs/deployment.html
    deploy:
    type: github
    repository: https://github.com/morris821028/morris821028.github.io.git
    branch: master
  • RSS 設定

    blog_folder/_config.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Plugins
    plugins:
    - hexo-generator-feed
    - hexo-generator-sitemap
    # RSS hexo-generator-feed
    feed:
    type: atom
    path: atom.xml
    limit: 20
  • BLOG 主題 pacman 配置 - 增加文章列表圖片 (詳見 http://yangjian.me/pacman/hello/introducing-pacman-theme/)

    blog_folder/theme/pacman/layout/_partial/post/article.ejs
    1
    2
    3
    <@ if(item.content.indexOf('<img src="') >= 0) { @>
    <p itemprop="description"><img style='float:left;margin:5px;height:80px;' src="<@- item.content.substring(item.content.indexOf('src="', item.content.indexOf('<img src="')) + 5, item.content.indexOf('"', item.content.indexOf('<img src="') + 11)) @>">
    <@= strip_html(item.content).replace(/^\s*/, '').replace(/\s*$/, '').substring(0, 140) @></p>
  • BLOG 主題 pacman 配置 - 色彩配置

    blog_folder/theme/pacman/css/_base/variable.styl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    color-background = #1f1f1f
    color-font = #ffffff
    color-white = #ffffff
    color-blue = #2ca6cb
    color-theme = #1f1f1f
    color-font-nav =#E9CD4C
    color-section = #272822
    color-footer = #1f1f1f
    color-gray = #CCC
    color-heading = #333333
    color-code = #eee
    color-twitter = #00aced
    color-facebook = #3b5998
    color-weibo = #eb182c
    color-google = #dd4b39
    color-qrcode= #49ae0f
    color-top = #762c54
Read More +