# 背景說明
Shoka 主題已經停止更新許久,但內部有許多寫死的邏輯,特別是圖片處理部分。原本的設計是使用新浪圖床(Sina Image Server),但隨著時間推移,我們可能想要:
- 使用自己的 CDN 服務(如 Cloudflare R2)來托管隨機背景圖
- 保留某些本地資源(如 favicon、avatar 等)在網站本地
# 問題分析
# 原本的限制
- 寫死的新浪圖床邏輯:在
themes/shoka/scripts/helpers/engine.js中,parseImage函數會自動將圖片路徑轉換為新浪圖床格式 - 無法區分本地與遠端資源:所有非完整 URL 的圖片都會被當作新浪圖床處理
- 配置不靈活:
_config.shoka.yml中的images設定無法同時支援 CDN 和本地資源
# 解決方案
# 核心概念
通過修改圖片處理邏輯,實現:
- 本地資源(
images/路徑)→ 使用網站本地路徑 - CDN 資源(數字檔名)→ 使用自訂 CDN(如 R2)
- 完整 URL → 直接使用原始 URL
# 修改步驟
# 1. 修改配置檔 _config.shoka.yml
# 第 14 行:將 images 改為你的 CDN URL | |
images: https://pub-da440be71028438aa9683b63bef5ccf1.r2.dev | |
# 第 18 行:本地資源使用 images/ 前綴 | |
favicon: | |
apple_touch_icon: images/apple-touch-icon.png | |
# 第 86 行:頭像也使用 images/ 前綴 | |
sidebar: | |
avatar: images/avatar.jpg | |
# 第 107-109 行:支付二維碼也使用 images/ 前綴 | |
reward: | |
account: | |
wechatpay: images/wechatpay.png | |
alipay: images/alipay.png | |
paypal: images/paypal.png |
關鍵邏輯:
- 包含
images/的路徑 = 本地資源 - 不包含
images/的路徑 = CDN 資源
# 2. 修改圖片列表 themes/shoka/_images.yml
將原本複雜的新浪圖床檔名(如 6833939bly1giciryrr3rj20zk0m8nhk.jpg )改為簡單的數字編號:
- 1.jpg | |
- 2.jpg | |
- 3.jpg | |
# ... | |
- 100.jpg |
注意:這些檔案需要上傳到你的 CDN(R2)根目錄,檔名必須與列表一致。
# 3. 修改 themes/shoka/scripts/helpers/engine.js
# 修改 1: parseImage 函數(第 27-41 行)
var parseImage = function(img, size) { | |
if (img.startsWith('//') || img.startsWith('http')) { | |
return img; | |
} | |
// 新增這一段:如果路徑包含 images/,代表它是本地 source 裡的靜態資源 | |
else if (img.startsWith('images/') || img.startsWith('/images/')) { | |
const { statics } = hexo.theme.config; | |
return (statics || '/') + img; | |
} | |
else { | |
const config = hexo.theme.config; | |
const baseUrl = config.images.endsWith('/') ? config.images : config.images + '/'; | |
return baseUrl + img; | |
} | |
} |
說明:
- 第 1 個
if:完整 URL 直接返回 - 第 2 個
else if:包含images/的路徑,使用本地statics路徑 - 第 3 個
else:其他路徑(如1.jpg),使用 CDN 路徑
# 修改 2: _image_url helper(第 118-140 行)
hexo.extend.helper.register('_image_url', function(img, path = '') { | |
if (!img) return ''; | |
const config = hexo.theme.config; | |
// 1. 如果已經是完整網址,直接返回 | |
if (img.startsWith('//') || img.startsWith('http')) { | |
return img; | |
} | |
// 2. 處理本地資源 (頭像、favicon 等) | |
// 如果路徑包含 images/ 且不是純數字 ID,我們直接返回本地路徑,不經過 url_for | |
if (img.includes('images/')) { | |
// 確保路徑是以 / 開頭的絕對路徑,例如 /images/avatar.jpg | |
return img.startsWith('/') ? img : '/' + img; | |
} | |
// 3. 處理 R2 隨機封面圖 | |
// 確保 baseUrl 最後有斜線,且不讓 Hexo 自動處理它 | |
const baseUrl = config.images.endsWith('/') ? config.images : config.images + '/'; | |
return baseUrl + img; | |
}); |
重要:
- 本地資源返回
/images/xxx.jpg格式 - CDN 資源返回
https://your-cdn.com/xxx.jpg格式 - 不使用
url_for(),避免 Hexo 自動處理路徑
# 4. 修改模板 themes/shoka/layout/_partials/sidebar/overview.njk
<!-- 第 2 行:使用 _image_url() 函數處理頭像 -->
<img class="image" itemprop="image" alt="{{ author }}"
data-src="{{ _image_url(theme.sidebar.avatar) }}">
說明:原本直接拼接 URL,現在統一使用 _image_url() 函數處理,確保邏輯一致。
# 文件結構
修改完成後,你的文件結構應該如下:
Blog/
├── _config.shoka.yml # 主配置檔
├── themes/shoka/
│ ├── _images.yml # 隨機圖片列表(1.jpg ~ 100.jpg)
│ ├── source/images/ # 本地圖片資源
│ │ ├── avatar.jpg # 頭像
│ │ ├── favicon.ico # 網站圖標
│ │ ├── apple-touch-icon.png
│ │ ├── wechatpay.png # 支付二維碼(如需要)
│ │ └── alipay.png
│ ├── scripts/helpers/
│ │ └── engine.js # 圖片處理邏輯
│ └── layout/_partials/sidebar/
│ └── overview.njk # 側邊欄模板
# CDN 端設置
如果使用 Cloudflare R2,需要:
- 上傳隨機背景圖:將
1.jpg~100.jpg上傳到 R2 bucket 根目錄 - 設置 Public Access:確保這些圖片可以公開訪問
- 設置 Custom Domain(可選):綁定自訂域名,如
https://images.yourdomain.com
# 測試驗證
# 1. 檢查本地資源
打開瀏覽器開發者工具,檢查以下元素的圖片路徑:
<!-- 頭像應該是本地路徑 --> | |
<img data-src="/images/avatar.jpg"> | |
<!-- Favicon 應該是本地路徑 --> | |
<link rel="icon" href="/images/favicon.ico"> |
# 2. 檢查 CDN 資源
檢查文章封面圖或隨機背景圖:
<!-- 隨機背景圖應該是 CDN 路徑 --> | |
<div style="background-image: url('https://pub-xxx.r2.dev/42.jpg')"> |
# 3. 清除快取
hexo clean | |
hexo generate | |
hexo server |
# 常見問題
# Q1: 為什麼頭像還是顯示舊的路徑?
A: 檢查以下幾點:
_config.shoka.yml中sidebar.avatar是否有images/前綴- 確認
themes/shoka/source/images/avatar.jpg檔案存在 - 執行
hexo clean清除快取
# Q2: 隨機背景圖無法載入?
A: 檢查:
- R2 bucket 中的圖片檔名是否與
_images.yml一致 - R2 bucket 是否設置為 Public Access
_config.shoka.yml中的 CDN URL 是否正確(結尾不需要斜線)
# Q3: 如何新增更多隨機背景圖?
A:
- 將新圖片上傳到 R2(如
101.jpg) - 在
_images.yml中新增- 101.jpg - 重新生成網站
hexo clean && hexo g
# 總結
這次修改的核心是區分本地資源和 CDN 資源:
| 資源類型 | 路徑格式 | 最終輸出 |
|---|---|---|
| 本地資源 | images/avatar.jpg |
/images/avatar.jpg |
| CDN 資源 | 42.jpg |
https://cdn.com/42.jpg |
| 完整 URL | https://example.com/pic.jpg |
https://example.com/pic.jpg |
關鍵文件:
_config.shoka.yml- 配置 CDN URL 和本地資源路徑engine.js- 實現圖片路徑處理邏輯_images.yml- 管理隨機背景圖列表
下次遇到類似問題,只需要:
- 修改
_config.shoka.yml的images設定 - 確保
engine.js中的parseImage和_image_url邏輯正確 - 區分本地資源(加
images/前綴)和 CDN 資源(不加前綴)