NexT 主題升級折騰紀錄 (v7.8.0)

之前逛別人文章時,說到了 Next 主題平滑更新的好
卻因為我們修改源碼而導致各種不便
為了能夠自由的更新主題,也為了更好的部落格品質,開始了一段折騰之路 ...。

e x T

升級原由

當時我正在看該作者的其他 plugin 功能,偶然看到了這段 :

當時選擇 NexT 主題就是看中它的維護者多、用戶量大,基本一個月左右的時間就會有一個版本更新,直接跟著官方就可以用到最新的特性。
但由於我之前對 NexT 主題做了不少自定義修改,這也使得更新主題變得比較麻煩,沒有辦法通過 git pull 平滑更新,這也違背了我選擇 NexT 主題的初衷。
同時,現在可以通過數據文件(Data File)將配置與主題分離,同時也可以把自定義佈局、樣式放到數據文件中,不用再修改主題源碼,便於後續主題更新。

其實,我當初選擇 NexT 只是因為外觀主題我喜歡而已 XD
但有些細節仍然無法靠官方 config 去設定,這時就只能去改源碼。

正常的 NexT 更新,是 git pull,然後就會發生各種 merge 錯誤(
merge 的時候每個在那邊看實在頭很痛,誰記得我那時候改了哪些東西。

文件分離真的是個好設計 (透過載入放在主題外部的文件,蓋掉某些內置設定)
於是開始更新報錯之路 ... 。

升級步驟

預設你的部落格資料夾叫做 hexo
原主題文件夾是 hexo/themes/next

我先寫我整個流程,有些可能是冤枉路或是你沒遇到的問題,那就可以跳過
所以請看完再決定流程。

git clone 最新版

git clone https://github.com/theme-next/hexo-theme-next themes/next-reloaded

  • 請在部落格根目錄做
  • clone 下來的資料夾叫做 next-reloaded,不會直接把你原本(next)的蓋掉。

更改 theme

hexo/_config.yml 內的 theme: 設置改掉。

hexo/_config.yml
1
2
-theme: next
+theme: next-reloaded

這麼做的好處是舊資料可以先保留,確認新版本完全可以用
再將資料夾名稱 next-reloaded 改回 next 就好。

試試看能不能跑

hexo clean && hexo g,然後享受報錯

  • 如果你之前沒有對 NexT 資料夾內 config 以外的東西做更改,那應該沒差。
  • 如果出 error,可以往下看有沒有相關的。

試做資料分離

我其實沒有直接去跑 hexo g,因為我要延用我的 next config 我必須先搬舊設定。
於是這時候我要來做資料分離 (前面提到的,load 外置檔案)

  • 參考 : NexT 文件: DATA-FILES
    • 方式有 <Hexo 方式> 和 <NexT 方式>,就是寫 config 的位置不同。
      我自己不太想全部擠在 /_config.yml 裡面,所以選擇了 <NexT 方式>。
    • 實際做起來流程 : 先建 /source/_data/next.yml
      (結構 : hexo/source/_data/next.yml)
      然後直接把新 NexT repo 內的 _config.yml 全部內容複製到 next.yml
      看一下 next.yml 內,前面部分就會有個選項叫 override,改成 true

遇到 Cannot read property 'active' of undefined

我自己改完之後,想要 hexo clean && hexo g 卻出現
Cannot read property 'active' of undefined

  • 原因在於我以為我改了,結果我卻是拿舊版本的 _config.yml 的內容去改。
    • 這邊我踩了 Sublime 的一個大坑,有個 plugin 可以讓我做文件 Compare 而且可以編輯
      結果按了儲存,卻其實沒有儲存 (有點難解釋),做了第三次以後才發現
      所以那個 next.yml 我就這樣來來回回做了四次,改到我選項都背起來了 ...
    • 結論 : 確認自己是拿最新的 _config.yml 去複製來改。

遇到 Unhandled rejection Template render error

改完再試試 hexo clean && hexo g
卻產生: Unhandled rejection Template render error

  • 特點 : 常常會有不同 swig 編譯失敗 ...

  • 有些說雙大括號 {{ }} 造成的問題,但我文章壓根沒動過,沒道理因為升級就變這樣。跳過。

  • 這種 render 失敗,有可能是你裝了一些 plugin
    要靠放 custom.js 等等檔案才能用的,你卻沒放好導致他們無法正常運作
    所以無法解析某些 tag,如下方
    ``{% some_function %}`

  • 花了很大一段時間,發現自己放錯地方 (我有裝個需要自己放 custom.js 的插件)

  • 註 : 同類型 error : TypeError: Cannot read property 'replace' of null

    • replace 問題有可能是 tag 產生的問題或者是 config 沒完全。
    • 我在建立新的測試用 blog 有遇到這個問題,後來整個 blog 又再刪掉重建一次就好了 ...
  • 或是 : hexo 插件過舊,需要用 npm 更新。

npm 插件更新

在找上述問題的過程中,也把 npm 插件全更新了。

  • 說實話我很不會用 npm。npm install 打了好幾次就是不更新。
  • 原來這和根目錄的 /package.json 有關,你要把想要的版本寫上去,他才會更新。
    (或是寫 "latest" 也會直接幫你弄到最新。)
1
2
3
4
// 舉例
"hexo": {
"version": "^4.2.1" // 你原本在 3.x,改成這樣,再 npm install。
}
  • 這個步驟有個技巧,你可以用 npm outdated 檢查。
    • 更新的話可以裝 npm-check 這個程式,或是手動改 /package.json

過了這邊,其實該處理的都差不多了,剩下 :

  • 你可能裝了一些 plugin 但是過舊,作者也沒推出更新。
  • 以前有改過 NexT 主題的源碼,

如果有裝 hexo-tag-aplayer

後面 render 跑出了一些和 hexo-tag-aplayer 這個 plugin 有關的 error。
簡單來說,這是一個小型網頁音樂撥放器,我以前文章有用到。

這部份我也是繞了超久 ...
可能會遇到的問題 :

重複載入 Aplayer.js 資源腳本問題

  • hexo server 後,瀏覽器開 console 發現某某文件突然多了些奇怪的文字。
    • <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script>
    • 多了這段,除了懷疑 hexo-tag-aplayer 之外還有誰呢 ...。
    • 相關症狀與討論 : issues#44
    • 開發者的解釋 : Readme CN

解決 :

  1. 在 hexo config 那邊,如同 readme 所寫,新增 asset_inject 這個選項。

    1
    2
    3
    aplayer:
    + asset_inject: false
    // 記得前面是兩個空白
  2. 再來我們必須自己引入 js 和 css 等檔案。
    我原本在 hexo 3.x 版本 配上 next 7.1.1 版本 ,自動注入就能 work 了
    現在升級了才發生這個問題,但是相對的,override 的功能也做得更完善。
    以下方式是適用 "如果可以使用 override" 的場合 :

  3. 建立 blog資料夾/source/_data/head.swig
    _data 這個資料夾預設沒有,自己創。

  4. /source/_data/next.yml
    搜尋 head: source/_data/head.swig 將他取消註釋。
    (註 : next.yml 這個配置在上方章節有提到)

  5. head.swig 內放入以下內容

    1
    2
    3
    4
    5
    <!-- require APlayer -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">
    <script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
    <!-- require MetingJS -->
    <script src="https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>

如果你說,步驟 2 後面的東西都看不懂怎麼辦,或是不想搞/不能搞 Override 怎辦。
那也可以直接做 file inject,就是直接修改源碼
在 next 主題資料夾內,找 layout/_partials/head/head.swig
最後面加入上面那份引入的區塊就可以了。

Unrecognized tag argument(3): loop:one at throwError

抱歉,這個問題我不知道怎麼解決。
其實我以前曾經去改過 hexo-tag-aplayer 的 plugin 源碼
但我也重新裝了,理論上也無關才是
後來看看,這個 repo 最後更新已經是兩年前了
故我決定去找找有沒有新的取代 plugin 可以用。

我找到了 hexo-tag-mmedia

hexo-tag-mmedia

這是一個也是基於 aplayer 做的插件,而且作者看起來有在更新的樣子
但是畢竟是個人做的,使用者也少,所以 bug 和功能還不算完善。
下面會提及我遇到的問題。

Repo 連結
使用說明

ReferenceError: value is not defined

hexo g 後產生這段。
直接上結論 : 我使用了 {% aplayerlrc %} 的這個 tag
但是作者說這部分功能還不完善,拿掉這個 tag 的播放器 code 就沒事了。

#issue 5

無法同個文章放置多個播放器

我自己有一篇文章放了兩首歌,用兩個播放器
但是不知道為何總是只出現一個
後來看了一下 render 後的 js,是用 getElementById ...
這樣當然會只渲染同個 DOM ...
順帶一提,外部 JS 庫也會被重複 loading。

回報後作者說下個版本改進。

#issue 6

width 失效

舉例 :
{% aplayer "晴天と喪失" "RADWIMPS" "xxx.mp3" "width:30%" %}

然後 width 都會失效。

原因 : 源碼疏失

/util/tag/aplayer.js
1
2
3
Line 50
-<div id="aplayer" style="margin-bottom: 20px;${width}"></div>
+<div id="aplayer" style="margin-bottom: 20px; width: ${width}"></div>

不過我不太想直接改,先等看看作者會不會修吧,issue 已提。

目前不支援 loop:none

說實話這是個很常用的功能,mutex 也是
但是作者預設的選項並沒有提供可以設定的地方
看作者會不會增加囉,或是哪天我太閒 clone 過來看 ...

語言界面

以前在 /_config.yml 是這樣寫的

1
2
3
language: 
- zh-tw
- en

更新後就突然變成英文了。
原因應該是讀取參數的名稱改了
改成以下

1
2
3
language: 
- zh-TW
- en

順利解決。

一些 CSS 調整

字體大小

    • 升級後,部落格預設文字大小變成 1em,在我的環境差不多是 16px
      這點我十分頭痛 ... 但 next.yml 理論上可以設定。

側邊欄 部落格簡介排版跑掉

  • sidebar 上方會顯示部落格的 description,padding 也被調整過了。
    如果因為字體跑掉而導致排版和以前不一樣,可以考慮調整以下
styles.styl
1
2
3
4
5
/* 2020/05/20 sidebar description 在最新 next 變瘦了,是因為這邊 */
.site-brand-container {
padding: 0 0px;
/*原本: 0 10px;*/
}
  • 注意,要啟用 styles.styl 的話需要做幾件事情 :
    • /source/_data/ 裡面建立 styles.styl 這個檔案
      (跟 next.yml 同個位置)
    • next.yml 裡面,把 custom_file_path
      裡面的 style: source/_data/styles.styl 取消註釋
  • 如果不使用上述 data 分離方式,想直接改主題源碼
    可以到 /themes/next/source/css/_customcustom.styl 這個檔案
    效果是一樣的。

取消文章貼齊頂端

  • 在我以前部落格配置中,首頁文章是沒有貼齊頂端的
    我不是很喜歡貼齊的那種感覺 ... 也可以說我已經習慣有距離的感覺了
    但是把舊的 CSS 套用了之後,新版 NexT 卻還是一樣貼齊。
    (主要是透過調整 .post 的 margin 和 padding 來讓他不貼齊)
    看了一下架構
1
2
3
4
5
6
7
8
9
10
11
以前首頁 : 

<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal">
<div class="post-block" >

現在

<div class="content index posts-expand" >
<article class="post-block" lang="zh-tw">

所以 #post#content 已失效;
原本 .post.post-block 外面,現在也直接省略 .post
解決方式 : 在 <div class="content index posts-expand" > 加個 .post

加入方式一樣有兩種

  • 用 data 分離方式 :
    • /source/_data/ 裡面建立 body-end.swig 這個檔案
      (跟 next.yml 同個位置)
    • next.yml 裡面,把 custom_file_path
      裡面的 bodyEnd: source/_data/body-end.swig 取消註釋
    • body-end.swig 內寫以下 code
      • 使用 body-end.swig 來進行啟用不確定是不是最好的方法。
        有更好的使用方式歡迎留言跟我說。
1
2
3
<script>
document.getElementsByClassName('content')[0].classList.add('post')
</script>
  • 透過改主題源碼方式 :
    • 我沒實際做過,單純看看源碼推測,可以試試。
    • /themes/next/layout/index.swig,修改其中一行
      • 只改 index.swig 的,因為點進去後的文章和以前的架構差不多,首頁改掉了而已
1
2
3
我這邊是 Line 6
-{% block class %}index posts-expand{% endblock %}
+{% block class %}index posts-expand post{% endblock %}

Fancybox 特定圖片不套用

以前看別人教學,就是在特定 js 裡面,阻止特定 class 渲染 :

/theme/next/source/js/src/utils.js
1
2
3
4
var $image = $(this);
+if ($(this).hasClass('nofancybox')) return;
var imageTitle = $image.attr('title') || $image.attr('alt');
var $imageWrapLink = $image.parent('a');

然後在你不想套用 fancybox 的圖片,加上 class="nofancybox" 就好。

... 可是 !
今天如果我想要在不動 NexT 源碼的情況呢 ?

我嘗試了在 body-end.swig 放一些 js code
(像是拿掉 fancybox class、或是拿掉 <a> tag )
但是因為 fancybox js 渲染時機問題,總之無效。

其實之前一直沒嘗試所謂的 Hexo Data File 特性,只知道好像可以新增一些檔案
後來嘗試在 /source 裡面建立 /js/utils.js
看能不能覆蓋 ... 於是就成功了。

步驟大概是 :

  1. /source 裡面建立 js 資料夾
  2. 複製 /theme/next/source/js/src/utils.js,貼過去 /source/js
  3. 修改 /source/js/utils.js
/source/js/utils.js
1
2
3
4
5
// v7.8.0 的跟以前有一點點不一樣
var $image = $(element);
+if ($(element).hasClass('nofancybox')) return;
var imageLink = $image.attr('data-src') || $image.attr('src');
var $imageWrapLink = $image.wrap(`<a class="fancybox fancybox.image"...

添加自己的頭像和背景圖片

以前總是自己手動丟到 /public/images 資料夾。
但是缺點是 : 每次 hexo clean 都會頭很痛,又要重放。

後來發現,有一部分圖片是從 next/source/images 當作來源
所以就把他放到該資料夾去了。

由於發現了 Hexo Data File 特性,於是
建立 /source/images 然後放入想要放的圖片,愉快解決。

近期文章區塊

參考: Hexo博客:九、添加近期文章板块 Hexo-NexT 版本更新记

針對 Hexo Data File 特性加上一點點個人化,我這樣做 :

  1. next.yml 中添加

    1
    2
    3
    recent_posts_title: 近期文章
    recent_posts_layout: block
    recent_posts: true
  2. /source/_data/sidebar.swig 放以下 code
    注 : 中間我是寫 posts.slice('1', '5'),因為我有置頂文章

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {% if theme.recent_posts %}
    <div class="links-of-blogroll motion-element {{ "links-of-blogroll-" + theme.recent_posts_layout }}">
    <div class="links-of-blogroll-title">
    <!-- modify icon to fire by szw -->
    <i class="fa fa-history fa-{{ theme.recent_posts_icon | lower }}" aria-hidden="true"></i>
    {{ theme.recent_posts_title }}
    </div>
    <ul class="links-of-blogroll-list">
    {% set posts = site.posts.sort('-date').toArray() %}
    {% for post in posts.slice('0', '5') %}
    <li>
    <a href="{{ url_for(post.path) }}" title="{{ post.title }}" target="_blank">{{ post.title }}</a>
    </li>
    {% endfor %}
    </ul>
    </div>
    {% endif %}
  3. next.yml 中取消 sidebar.swig 的註釋:

    1
    2
    3
    4
    custom_file_path:

    - #sidebar: source/_data/sidebar.swig
    + sidebar: source/_data/sidebar.swig

如何查看 Hexo 和 Next 的版本 ?

預設 config 設置中,底下會有 Powered by Hexo, Powered by Next 的文字。
這部分在更新之後,原本可以顯示版本的,但後來被簡化掉了。
看了一下,有在這份 PR 提及

簡化掉了,如果自己又想看怎麼辦 ?
(就像我當初想要升級卻不知道當前版本 ...)

以下提供簡單的方式 (要用 F12 看)

1
2
Get Hexo version: <meta name="generator"> in <head>
Get NexT version: console.log(CONFIG.version)

大概是這樣。

End
-----------------------------------

2020.05.23