NexT 主題升級折騰紀錄 (v8.18.0)

更新部落格的 NexT 主題到 v8.18 了,只能說是折騰。

升級緣由

發現自己的部落格,遇到大量圖片的時候,會有效能不佳的問題。
大量圖片最簡單的解法就是 Lazyload (當閱讀進度接近某個區塊時,才將對應圖片載入)

升級前使用的是 NexT v7.8.0,其實也不算太舊,但是 _config.yml 打開了此選項還是不成功。

我首先是思考,
是不是 "我的拿 Google Drive 當圖空" 這件事情導致如此 (怕 G 社有做預處理攔截)
於是我跑去看 NexT 所使用了第三方套件 lozad.js
clone repo 並且修改 demo file (替換圖片),其結果是運作正常。

那我也只能試著升級 NexT 看看了 🥲

踩坑 - 嘗試階段

我是這樣去嘗試的 (先看故事就好) :

  1. 更新 Hexo 到 6.3.0
  2. 把舊的 themes/NexT 資料夾重新命名成任意名字
    直接下載最新版本的 NexT 並放到 themes 之中 (名字改成 NexT)。
  3. hexo s,啟動看看。

然後就炸掉了,文章跑不出來,sidebar 也跑不出來。
打開開發人員選項,是顯示 next-boot.js 中有 function 無法正確載入。
並且 terminal 也顯示有 highlight.js 有過時的跡象。

接下來是 debug,首先更新所有套件(除了 hexo)
然後建立一個新的 hexo project,並且檔案一個個放進去,去找出 "放了哪個檔案後 crash"。
經過了血與淚,我找到了問題原因
並且很多以前做的魔改也跟著失效了,所以後面也會闡述如何將他們救回來。

正確流程

  • 更新 Hexo,我個人是只想先使用 hexo 6.3.0 就好了 (覺得最新版可能不穩,還在 rc)
    • 指令 : npm install hexo@6.3.0
  • 安裝一些新套件
1
npm i js-yaml css
  • 使用 npm outdated 來更新所有 plugin
    其中,我誠摯的推薦先更新下面三個。
1
npm update highlight.js hexo-util hexo-cli
  • 更新好這三個之後,再使用 npm outdated 來顯示哪些過時的
    並且red 一個個複製名稱 來更新 (npm update)。
    如果再次使用 npm outdated 來看仍然沒更新,有可能被 package-lock 影響了
    重複多次之後我自己是乾脆砍了然後重裝。

  • NexT 的主題更新,我一律推薦從官方最新的 repo 去下載。
    或是使用我們熟知的 git clone <git address> 也行。
    然後把你舊的 next 的資料夾改名成其他 (例如 next-old)。
    上述的下載後,他的資料夾名稱可能是 hexo-theme-next 之類的
    改成你喜歡的例如 next (對應到你 hexo config 設定的那個)

    • 這邊科普一下,NexT 會根據專案技術債去決定是否開新的 repo 來維護
      例如 8.0 版本就是直接開一個新的了,所以很多東西無法直接繼承。
      這部分可以去看 NexT Upgrade
  • 如果你在舊版有使用任何 data injection
    也就是 /hexo-root/source/_data 內有東西,推薦先將此資料夾搬走
    或是改名稱為 _x_data 之類的。因為測試 NexT 是否相容不要有太多危險因子。
    另外還有一個巨大的危險因子,就是 /hexo-root/source/js
    在我們學會 data injection 之後,以前魔改時這也是重點開發區域之一
    如果存在,建議先移動到安全位置。

  • 做完以上,可以先使用 hexo s 測試。
    如果你裝了很多 hexo plugin,可能某些文章無法正常渲染,
    也建議將它們都先搬到 /hexo-root/source/_draft

    一般來說,
    你應該會是 "沒有應用 next config 也沒有太關鍵的 data injection 狀態"
    所以很安全、至少會開啟一個很陽春的 hexo blog,文章可以正常瀏覽。

  • 那你說,"啊我的 data injection 怎辦 ? 我套用的 custom css 呢 ! config 呢 !"
    這個會在下文中一一說明。

客製化修改

關於 next 的 _config.yml

我們先複習一下以前是怎麼做的。

  • 最以前的版本 : 直接在 /hexo-root/themes/next/_config.yml 修改
  • 啟用 data injection 的版本 : 複製了一份 _config.yml,更名成 next.yml
    並且放到 /hexo-root/source/_data/next.yml,然後內部會有選項 override: true

然而,最新版本的作法是

  • /hexo-root/themes/next/_config.yml 複製到根目錄,並重新命名 :
    /hexo-root/_config.next.yml
    (希望你們能直接看懂,我這種寫法出現好幾次了,看不懂再留言給我)

當然,這邊的 next 資料夾已經是最新版本了,也就是你複製的 _config.yml 是最新版。
那我該如何整合舊版本的到新版呢 ?

  1. 先知道自己是哪個時代的
    是直接改在 /hexo-root/themes/next/_config.yml ?
    還是 /hexo-root/source/_data/next.yml 此檔案存在 ?
  2. 做一次 /hexo-root/themes/next/_config.yml 複製到根目錄,並重新命名 :
    /hexo-root/_config.next.yml
  3. 利用一些比對工具,例如 Diff checker 去比對舊版 config 和新版的差異。
    然後編輯 /hexo-root/_config.next.yml,把一些舊設定也跟著填寫上去。

這樣做的用意是新版本的 _config.yml 是有可能有新東西的,不要忽略他們。

關於 data injection: _data 篇

_data 中,用來存放一些 injection files,例如 body-end.swig, styles.styl
首先,在 NexT v8.x 版本中,已經不使用 .swig 了。全數使用 .njk
(.styl 仍然保留 !)

我看了一下我自己應用的,大多數是嵌入一些 js 或是知名的 sidebar 魔改
在簡單的應用上,語法基本沒差
所以我索性將 .swig 檔案都全複製一份,並且副檔名改掉。

但是,如果有 next.yml 存在,請另行備份,因為這個用法已經被捨棄了。

如果你想要確保這部分可以 work,首先你要確認你的 _config.next.yml

1
2
3
4
5
6
7
8
9
custom_file_path:
# 以下想要啟用的,都沒有被註解
style: source/_data/styles.styl
head: source/_data/head.njk
sidebar: source/_data/sidebar.njk
bodyEnd: source/_data/body-end.njk

# 以下不想啟用的,都有被註解
#header: source/_data/header.njk

然後我前面給的建議是先將 _data 資料夾改名成 _x_data,那現在就可以改回去了。
去測試看看吧 !

關於 data injection: js 篇

只要是放在 /hexo-root/source 中的檔案,基本上除了底線開頭有特殊用途
一般來說 ... 會全部複製一份到對應的 generated folder。(也就是 /hexo-root/public)

所以如果我在 /hexo-root/source/js 內,放了一個跟原始碼一模一樣名字的 js file
那我這邊就會覆蓋掉原始檔,是有可能讓網頁 crash 的。
所以你必須知道你放的檔案是什麼、用途又是什麼、
以及到底是不是從對應版本的對應檔案去做修改的
(你總不能拿 v7.0 的 util.js,放在 js 資料夾內,又期望它可以在 v8.10 中運作。)

所以這邊要做的事情是 :

  • 先去看你以前寫了什麼鬼東西,理解用途 (註解的重要性 🫠)
  • 複製你現在期望版本 (例如你現在 /themes/next 那個最新的版本) 裡面的檔案出來
    記得是 "複製" 到 /hexo-root/source/js,檔名不變,然後將修改放進去
    (修改要改到對的位置。建議可以從前後的 function 去推斷哪邊才是對應位置)

一般來說,只要你改的是你懂的東西,它應該會運作,除了一種可能性 :

  • 如果舊的 function 被完全棄用了 (例如 wrapImageWithFancyBox 這個 function)

在這種狀況之下,你強行去添加 js code 到新版文件之中,有可能是一種厄介行為。
那就是會吃 crash。所以請理解你修改的東西,並且找到其突破點。
關於找突破點,下面會討論 fancybox 魔改,可以參考看看。

小總結一下,如果你改的正確,那 js 除了可以成功注入,網站也不會 crash。
以上,我們已經做了 : config 繼承、_data 檔名修正並添加回來、js 更新並添加回來。
其實應該完成了大部份的修改
--- 但是還是有一些問題,例如新舊技術不同、或是 class selector 失效。

關於 nofancybox 的設置

(Tutorial: Disable fancybox for specific images.)

想要閱讀完整教學、突破點,建議查看我發在 github discussion 的討論串 (中文)
https://github.com/next-theme/hexo-theme-next/discussions/687

以下會結錄部分內容。

  • 為何需要 nofancybox

有了 fancybox,我們可以將圖片放大、在下面設置一些 caption、使用左右來瀏覽圖片。

但是,有一些圖片因為某些原因,我們就是不希望他套用。
例如這個

image

這是一個應用方法 (把自己的圖片當成 emoji,緊跟在文字尾端。)
這類的圖片就不適合被套用 fancybox。

所以,我們總要想個辦法來實現這件事情。

  • 嘗試的辦法
  • 以前怎麼做的我就怎麼做,首先使用 injection 方法,在 /hexo根目錄/source/js/ 建立 utils.js
    並且先拷貝 /next/source/js/utils.js 的全部內容,然後把 wrapImageWithFancyBox: function() {} 都貼到合理位置。
    但這並不會成功。
  • 我的想法是,可能這個 function 沒有被觸發 (搜了整個專案沒看到 wrapImageWithFancyBox 的觸發點)。
    所以看了一下,得想辦法讓他在 /next/source/js/next-boot.js 中去觸發。
    所以我添加了 CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox(); 在合理位置,畢竟以前版本也是類似這樣寫的。
    但這並不會成功。
  • 用 console.log 稍微 debug 一下,發現 CONFIG.fancyboxundefined 呀。
    自己試了老半天,明明 _config.next.yml 已經是 fancybox: true 了,怎麼還這樣。
    我自己的推斷是 CONFIG 在 assign 的過程中並沒有把 fancybox 當作 key 來讀入。
    源碼看了老半天也沒看懂在哪邊 assign 的,歡迎開發組補充解惑。
    不過讀不到,小事情,
    CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox(); 直接改成
    NexT.utils.wrapImageWithFancyBox();,我牛逼。
    但這並不會成功。 然後圖片全部都不顯示了 (等於 fancybox 套用過程中失敗)
  • 正確的作法
  1. 首先一樣要善用 injection 方法,在 /hexo根目錄/source/js/third-party/ 建立 fancybox.js
  2. /next/source/js/third-party/fancybox.js 內的東西全部複製過去。
  3. 安插一段 code 進去 (不含註解的話,三行)
1
2
3
4
5
6
7
8
9
10
11
12
// 前面省略了一些 code 
document.querySelectorAll('.post-body :not(a) > img, .post-body > img').forEach(image => {

/* Modify by MeteorV */
if (image.classList.contains('nofancybox')) {
return; // Skip elements with class "nofancybox"
}
/* ------------------ */

const imageLink = image.dataset.src || image.src;
const imageWrapLink = document.createElement('a');
// ... 下略

這樣就完成了。
不過,雖然都已經用 injection 的方式了,還是推薦像我一樣寫自己的 ID 在註解之中
這樣以後忘記自己寫了、改了什麼東西之後,就會方便一點找 ...

以上就是突破點與解決辦法,希望能提供一些啟發。

如何讓文章背景畫布變成半透明顏色

如果沒意外,目前我的部落格應該仍然是半透明的背景。(相較於 default 的純白背景)

舊版的修改方式是在 source/_data/styles.styl 中加入

1
2
3
.post-block {
background: rgba(255, 255, 255, 0.9);
}

但是新版並不 work,而且打開 F12,會發現它被槓掉了 (被呈現刪除線)。
找了老半天,總之,它是被新版的 main.css 給統一控制了顏色

我們可以觀察到他使用了 var 去控制,這就讓我想到之前看過的一些線索
於是我們去 _config.next.yml 啟用(反註解) variable: source/_data/variables.styl
並且建立一份 /hexo-root/source/_data/variables.styl,填入以下

1
$content-bg-color = rgba(255, 255, 255, 0.9);

完成 !

關於 Blog 首頁的 read more (閱讀更多) 顯示的摘要

  • 舊版 : 我們只要不啟用 auto_excerpt 之類的
    只要在文章內使用 <!-- more --> 進行分隔 (Hexo 自帶的 feature)
    就可以成功的將文章分隔的前半段顯示在首頁。
  • 新版 : 如果我們在 config 內啟用 excerpt_description: true
    那他就會使用 markdown 屬性的 description 欄位進行渲染。

這十分不人性 !
因為 markdown 的 description 欄位是為了拿來做 SEO
所以我個人極度推薦在文章內使用 <!-- more --> 進行分隔
並且把此選項變成 false,這樣就能正確的顯示摘要了。

相關的解釋在官方文檔 : https://theme-next.js.org/docs/theme-settings/posts

關於魔改 Sidebar 的 "近期文章"

這邊給一些關鍵字,因為這方法其實和其他人做法一樣
怕有人不知道,所以簡單貼一下 Code for sidebar.njk

實際上,把裡面的程式碼拿去 Google,應該就能找到其他人的介紹了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% 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('1', '6') %}
<li>
<time title="{{ __('post.created') }}" itemprop="dateCreated datePublished" datetime="{{ moment(post.date).format() }}">
{{ date(post.date, theme.mmdd_format) }}
</time>
<a href="{{ url_for(post.path) }}" title="{{ post.title }}" target="_blank">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}

關於魔改 Sidebar 的滾動條(scrollbar) CSS

如果我還是使用 Hexo + NexT,
那你可以在我的左邊查看我的個人近期新文章等等資訊。
如果文章內看不到、點了 tab 也沒找到,可以到首頁,並且往下滑動一部分
可以看到我個人介紹的部分的滾動條是一個漸層顏色 (我自己看了很開心)

然而新版本並不 work,我渾身不對勁。(預設是 html 純純的灰色超寬的那種)

這邊也不拖沓了,簡單來說以前可以使用 site-overview-wrap 去定位 css
現在必須去找 sidebar-panel-container 去定位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Next 7.8.0: use site-overview-wrap      to catch scrollbar */
/* Next 8.x.0: use sidebar-panel-container to catch scrollbar */
.sidebar-panel-container::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}

.sidebar-panel-container::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
}

.sidebar-panel-container::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-image: -webkit-gradient(linear, left bottom, left top, from(#a8edea), to(#fed6e3));
background-image: -webkit-linear-gradient(bottom, #a8edea 0%, #fed6e3 100%);
background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
}

關於 Sidebar 的友站連結

這個設定,在以前會像下方的左圖那樣顯示在 Sidebar 裡面。
(next.yml 中的 links 屬性)

現在呢,如右圖,官方把他額外做一個區域,我是覺得挺美的。
然而,他會在文章/首頁滾動到底部的時候才被加進去。
這點就有一點見仁見智了。

如果喜歡以前的做法,可以去參考 v7.8 的 sidebar.swig
並且想辦法對 sidebar.njk 進行魔改 (注入文件)

不過我覺得新版也沒特別不好,就沒去研究了。

順帶一提,即使我們在 config.links_settings.title 設定為 "友站連結",他仍然不 work。
我自己魔改了一下把這段修正

1
2
3
4
        <div class="links-of-blogroll-title">
{%- if theme.links_settings.icon %}<i class="{{ theme.links_settings.icon }} fa-fw"></i>{% endif %}
- {{ __('sidebar.links') }}
+ {{ theme.links_settings.title }}

這樣就能了。
不過我覺得這是官方疏失,找時間我再去反饋吧。

關於 hexo-tag-mmedia

作者棄坑了。然後推薦使用者們去用他另一個 plugin
我點了進去,他又說那個 plugin 他(也)棄坑了,
說可以去用這個 https://plugin-components.vuejs.press/

我還沒開始研究。
Hexo 不能使用 Aplayer 有點傷,我已經把我其中一兩篇文章的音樂連結砍了。

關於那些我還沒研究的功能

隨著 NexT 的更新,肯定有新的東西加入 (吧)
config 也多了很多我沒看懂的東西,這邊筆記一下,之後太閒可以研究一下是幹嘛用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
https://hexo.io/docs/helpers#open-graph
https://theme-next.js.org/highlight/
https://github.com/next-theme/theme-next-pdf
https://firebase.google.com/docs/firestore/ (儲存留言)
language_switcher: false
related_posts:
post_edit
body_scrollbar
tabs: sticky: false
mediumzoom
Quicklink (是一款能讓使用者覺得你網站變快的 plugin,它會趁使用者瀏覽頁面時的閒置時間,預先擷取檢視區 (Viewport) 內連結的內容,讓使用者點擊頁面中的連結,有一種一點即開的感覺。)
motion 目前使用預設的,再看看如何。
algolia_search
hexo-renderer-markdown-it-plus
https://github.com/theme-next/hexo-theme-next/issues/462#issuecomment-435429592
PDF -> {% pdf /path/to/your/file.pdf 600px %} # 可能有 CORS 問題

結語

很累。
有很多零碎改過的東西,其實不知道有沒有全都繼承 (到這篇打完都還不知道)
但至少我直覺/外觀上有想到的都解決了

也總算解決了一個逃避一陣子的事情 :
一直覺得 lazyload 沒啟用的話,會不時的導致 image loading crash (太多 request,被圖空砍)
間接的讓使用者體驗不佳,那我就會十分的傷心
(因為我放圖片一定是篩選過的,而放很多的話,那必定是希望能分享美好事物)

很多魔改都是我私人的喜好
他沒辦法被繼承到新版本的話我真的會很痛苦。

很開心解決了他們,也希望能幫助到大家 !

End

2023.08.19