Releases: zycwer/hexo-theme-tranquility
Release list
v1.6.1 — 健壮性修复
修复(4 项)
- RSS 自动发现配置读取错误(功能 bug):
layout.njk中误用theme.feed判断 RSS 自动发现,但hexo-generator-feed的配置位于站点_config.yml(config.feed),导致安装了该插件的用户 RSS 自动发现分支永不触发,回退到recent_updates.rss_url分支。现已修正为读取config.feed。 - JSON-LD image 协议相对 URL 不一致:JSON-LD
Article.image只检查http开头的 URL,未处理//开头的协议相对 URL,与同文件中og:image的判断逻辑不一致。已补齐indexOf('//') == 0分支。 - 最近更新轮播箭头未做 null 检查:
recent.js中querySelector('.recent-updates__arrow--prev/next')结果直接调用addEventListener,模板渲染异常或缺元素时会抛TypeError。已提取变量并加 null 检查提前 return。 - 搜索无结果分支未提前 return:
search.js中renderSearchResult在「无结果」时设置innerHTML后未退出,继续appendChild空 fragment(逻辑冗余,无副作用但不规范)。已补return。
Full Changelog: v1.6.0...v1.6.1
v1.6.0 — 无障碍 / 性能 / 体验增强
新功能(5 项)
- 回到顶部按钮:滚动超过一屏后右下角浮现,点击平滑滚动回顶部。
requestAnimationFrame节流 scroll 监听,prefers-reduced-motion下退化为瞬时定位 - prefers-reduced-motion 无障碍降级:尊重系统「减少动态效果」偏好,全局 CSS 动画/过渡压缩为 0.01ms,HeartCurve 静态绘制一帧,back-to-top 瞬时定位
- RSS 自动发现:所有页面
<head>注入<link rel="alternate" type="application/rss+xml">,浏览器与 RSS 阅读器可自动发现订阅源 - robots.txt 自动生成:构建时生成 robots.txt,允许爬虫抓取全站、屏蔽 CSS/JS/字体目录、声明 sitemap.xml
- 字体加载优化:
font-display: swap减少 FOUT +<link rel="preload">高优先级预加载(MIME 随字体类型动态映射 woff2/woff/ttf)
移除
修复(8 项)
- HeartCurve 在
prefers-reduced-motion下完全空白(现静态绘制一帧) - back-to-top 页面刷新已滚动时不显示(补初始可见性检查)
- font.njk preload type 硬编码
font/ttf(改为动态映射) - robots.js URL 拼接可能产生双斜杠(规范化 config.url 尾斜杠)
- og:locale 直接用
config.language(zh-cn→zh_CN下划线转换) - post.njk
mermaid.run()无旧版 fallback(补mermaid.init()兼容 9.x) - theme.js localStorage 隐私模式异常兜底 +
aria-pressed - _nunjucks.js server 模式禁用缓存便于热更新
其他
- 删除未使用的 Stylus 变量与 mixin
- scripts/index.js 显式注册 stylus/lazy-img/robots 子模块
- README / README_EN 重写:新增 5 个功能文档章节,移除 Gitalk 描述,更新 Fork 说明
Full Changelog: v1.5.2...v1.6.0
v1.5.2 — 安全加固与健壮性提升
本次更新
本次版本聚焦于 安全加固(XSS 修复)、功能缺陷修复、错误处理完善 和 SEO/规范改进,共修复 16 项问题,涉及 18 个文件。
🔒 安全修复(XSS / 注入防护)
| 文件 | 问题 | 修复 |
|---|---|---|
recent-updates.njk |
RSS 外部内容(title/excerpt/date/link)未转义,存在 XSS | 对所有 RSS 字段加 | escape |
Timeline.njk |
innerHTML 拼接文章数据(title/path/date/icon),可被注入 | 改用 DOM API(createElement + textContent)构建节点 |
Timeline.njk |
{{ data | dump }} 未转义 </script>,可打断脚本上下文 |
dump 后 replace </ → <\/ |
search.js |
搜索摘要经 innerHTML 写入,内容中 < > & 被当作标签解析 |
写入前先转义 HTML,再高亮关键词 |
htmlGenerator.js |
相关文章列表动态内容(title/path/img/excerpt/date)未转义 | 新增 escapeHtml() 函数统一转义 |
🐛 功能缺陷
| 文件 | 问题 | 修复 |
|---|---|---|
category.njk |
{% set fancy %} 在 {% extends %} 外,导致 fancy 标签云从不生效 |
删除 set,直接用 theme.tagcloud.fancy |
category.njk |
tagcanvas 配置 textColour: null 重复;fadIn 拼写错误(应为 fadeIn),淡入效果失效 |
删除重复项;修正拼写 |
subpage.js |
posts.data.sort() 修改 Warehouse Query 原数组,导致后续数据污染 |
改用 toArray() 创建副本后排序 |
tagcloud.js |
直接修改传入的 config 对象,污染原始主题配置 | 使用 Object.assign() 创建副本 |
related-post.njk |
类名 realated__body 拼写错误(应为 related__body) |
修正拼写 |
🛡️ 错误处理 / 健壮性
| 文件 | 问题 | 修复 |
|---|---|---|
search.js |
fetch 无 res.ok 检查和 .catch(),网络失败时搜索静默失效 |
添加 res.ok 检查 + .catch() 错误日志 |
search.js |
正则 d 标志(hasIndices)兼容性差(Safari < 16.4 不支持),导致搜索功能完全失效 |
移除 d 标志,改用 match.index + match[0].length |
copy-code.js |
同步 try/catch 无法捕获异步 navigator.clipboard.writeText() Promise,复制失败仍显示"已复制" |
改为 async/await |
HeartCurve.njk |
构造函数抛错未捕获中断后续脚本;hover 监听器反复累积;console.log 残留 | 添加 try-catch;hoverBound 标志防重复绑定;删除 console.log |
recent.js |
全局 keydown 监听干扰输入框方向键输入 | 检查 target 是否为 INPUT/TEXTAREA/contentEditable |
font.js |
配置字段缺失时解构崩溃;getSubText 中 undefined.map 崩溃;console.log 代替 hexo.log |
添加配置校验 + 防御性 || 回退;改用 hexo.log.info |
recent.js(generator) |
fetchText 递归重定向无次数限制(循环重定向导致栈溢出);响应流缺少 error 监听 |
添加 maxRedirects 限制(默认 5)+ res.on('error') |
filters/stylus.js + lazy-img.js |
非规范注册(模块加载时立即执行,依赖全局 hexo) |
改为 module.exports = hexo => {} 规范写法 |
📈 SEO / 规范改进
| 文件 | 问题 | 修复 |
|---|---|---|
layout.njk |
缺少 <link rel="canonical">,影响搜索引擎去重 |
添加 canonical 链接 |
layout.njk |
<html lang="zh-cn"> 硬编码,多语言站点不适用 |
改为 {{ config.language or 'zh-cn' }} |
layout.njk |
mask-icon color 引用不存在的 theme.android_chrome_color,颜色恒空 |
回退到 theme.pwa.theme_color |
group-link.njk |
width="20px" / height="20px" 属性误用单位(HTML 属性应为无单位整数);浮点除法 |
去除 px;改用 round(0, 'ceil') 向上取整 |
reward.njk |
SVG width/height 属性误用 px 单位 |
去除 px |
category.njk |
window.onload = 覆盖其他 load 处理器;DEBUG 文案直接渲染给访客 |
改用 addEventListener;文案改为友好提示 |
Full Changelog: v1.5.1...v1.5.2
v1.5.1 — 性能优化与缺陷修复
概述
本次发布包含两部分:常规维护性能优化(commit 391803b)与 6 项功能缺陷修复(commit 3531436)。
建议所有 v1.5.0 用户升级。
⚡ 性能优化(commit 391803b)
运行时性能
toc.js滚动节流:scroll/resize事件改用requestAnimationFrame节流 +{ passive: true }监听器,避免每帧多次 reflow- CSS
transition: all→ 具体属性:8 处transition: all替换为background/color/transform/opacity等具体属性,避免触发非必要的 layout / paint
构建性能
- Nunjucks 模板缓存:
noCache: true→false,单次构建内模板不再重复编译(实测 51 文件构建从 533ms 降至 399ms)
资源加载
preconnect:按需为v1.hitokoto.cn/hm.baidu.com添加preconnect- SVG
width/height:补全normal.svg与 Timeline 动态图标的width/height属性,防止 CLS(Cumulative Layout Shift)
顺手修复的潜在 bug
normal.styl删除重复的@import '_variables'- 修复
$whitesoke-light→$whitesmoke-light、$blak-lighter→$black-lighter两个变量拼写错误(原变量未定义,导致表格奇行背景与 figcaption 颜色静默回退到默认值)
🐛 功能缺陷修复(commit 3531436)
1. toc.js 完全失效(严重)
现象:文章目录滚动定位从未生效。
根因:选择器 #toc / #postBody 在模板中不存在(实际是 .post-toc / .post-content__body),脚本中所有元素查找都返回 null,整个 IIFE 提前 return。同时 post.njk 从未引入 toc.js。
修复:改用类选择器 + .toc-outer 作为锚点,并在 post.njk 中按 page.toc 加载脚本。
2. HeartCurve.njk 语法错误导致整段脚本失效
现象:首页心形曲线动画不工作。
根因:mobileAdjust(window.matchMedia("(hover:none")) 括号不匹配,浏览器报语法错误,整段 <script> 失效。
修复:补全括号;同时修复 r = 2 * a * ... 隐式全局变量(严格模式下报错);addListener 废弃 API 改为 addEventListener('change', ...);添加 #wall-main 缺失时的 null 安全检查。
3. search.js 关闭逻辑与高亮 bug
closeSearchDialog中overflow = 'inherit'应为''(恢复默认)display = 'None'大小写错误,应为'none'trimeContent在forEach内对content重新赋值,下一次迭代用错内容导致多关键词高亮错乱;改为对原始子串独立替换- 用户输入含正则元字符(如
( ) *)时new RegExp报错,添加转义
4. post.njk 图片属性与链接
- 文章封面图
<img width="auto" height="auto">HTML 属性必须为数字,改为省略(由 CSS 控制),并补loading="lazy"decoding="async" - "回到顶部"
href="{{ page.link }}#"在page.link未定义时输出"#"(之前是空字符串拼接#),改为"#"
5. foot.njk 仓库链接
"致远" 链接指向已归档的原仓库 hooozen/hexo-theme-tranquility,改为 fork 仓库 zycwer/hexo-theme-tranquility。
6. category.styl .post-title-pined 深色模式不可见
硬编码颜色 rgb(75, 5, 5) 与 border: 1px solid(无颜色),深色模式下不可见;改用 var(--c-accent)。
顺手修复
reward.njk/layout.njk中<img width="100px">/<img width="60px">等 HTML 属性单位问题(HTML 属性应为纯数字像素值)
📊 验证
- 构建测试:51 文件正常生成,无警告
- 所有 JS 文件
node --check语法通过 - 生成的 HTML 中验证
toc.js已正确引入文章页 - 生成的 CSS 中验证
.post-title-pined已使用var(--c-accent) - 生成的 HTML 中验证 HeartCurve 脚本括号匹配、
addEventListener('change', ...)已替换 - 生成的 HTML 中验证页脚链接已指向 fork 仓库
🔗 完整变更
v1.5.0 — 现代化增强版
v1.5.0 — 现代化增强版
本次发布聚焦于站点基础设施与用户体验的现代化升级,新增 6 项开箱即用的功能(除文章相关功能外),无需额外依赖即可启用。
✨ 新功能
1. 深色模式(Dark Mode)
基于 CSS 变量的运行时深色模式,切换无需重建,支持四种策略:
| 模式 | 行为 |
|---|---|
light |
始终浅色(默认) |
dark |
始终深色 |
auto |
跟随浏览器 prefers-color-scheme,系统切换实时响应 |
time |
在指定时段自动切换深色(支持跨午夜,如 18:00 → 06:00) |
- 导航栏右侧 ☾/☀ 一键切换按钮,选择持久化到
localStorage - 首屏内联同步脚本在 CSS 加载前设置
data-theme,杜绝 FOUC - 用户手动覆盖优先于配置策略
- 全站适配:页面背景、页脚、搜索框、代码块、代码高亮、时间线、卡片等全部响应深色模式
- 代码高亮双主题:浅色用 GitHub Light,深色用 GitHub Dark,保证代码可读性
color_mode: auto # light | dark | auto | time
color_mode_time:
start: 18
end: 62. Open Graph & Twitter Card
自动为每个页面注入社交分享 meta 标签,在微信、Telegram、Twitter/X、Slack、Discord 等平台分享时展示标题、描述与封面图。
og:type/og:title/og:description/og:url/og:site_name/og:imagetwitter:card(有封面时为summary_large_image)- 封面图优先级:文章
cover→ 首页index.photo→logo - 自动转换为绝对 URL
3. JSON-LD 结构化数据
按页面类型自动注入 schema.org JSON-LD,帮助搜索引擎生成富媒体结果:
- 关于页 →
Person - 文章页 →
Article(含datePublished/dateModified/author/image/keywords) - 其他页面 →
WebSite - 所有字符串字段做 JSON 转义,避免标题/描述含双引号时破坏 JSON
4. 站点地图(Sitemap)
内置 sitemap.xml 生成器,构建时自动产出,可直接提交给 Google Search Console / Bing Webmaster / 百度站长。
- 首页(priority=1.0, daily)—— 使用根 URL
/,避免与/index.html重复 - 所有文章(priority=0.8, weekly, 含 lastmod)
- 所有页面(priority=0.6, monthly)
- 分类与标签归档页(priority=0.4, weekly)
sitemap:
enable: true # 默认开启5. PWA(可安装应用)
可选生成 manifest.json 与 Service Worker(sw.js),支持「添加到主屏幕」与离线访问。
manifest.json自动从favicon配置生成 icons 数组- 含 192x192 与 512x512 图标声明(满足 Chrome 安装提示要求)
- 含
maskablepurpose 图标,适配 Android 自适应图标 - Service Worker 策略:静态资源缓存优先、HTML 网络优先回退缓存
- 自动注册(仅生产环境 / HTTPS / localhost 生效)+
<meta name="theme-color">
pwa:
enable: false # 默认关闭,按需开启
name:
short_name:
display: standalone
theme_color: "#fcfcfb"
background_color: "#fcfcfb"6. 图片懒加载
after_post_render filter 自动为文章正文 <img> 注入 loading="lazy" 与 decoding="async",提升首屏性能,浏览器原生支持无需额外 JS。已含 loading 属性的图片不会被覆盖。
📦 升级方式
cd themes/tranquility
git pull
git checkout v1.5.0然后将 themes/tranquility/_config-template.yml 中的新增配置项同步到你的 _config.tranquility.yml:
color_mode/color_mode_timesitemap.enablepwa.*
📝 文档
Full Changelog: v1.4.0...v1.5.0
v1.4.0 — 个性化增强版
基于上游 1.3.6 fork,新增多项个性化功能并精简代码。本版本为 fork 后首个独立发布。
✨ 新功能
- 一言(Hitokoto)Slogan 开关:在「宁静致远」位置可启用一言 API,客户端实时拉取并附 SEO 友好的静态回退文案。配置项
slogan_hitokoto: true - 文章驱动时间线:不再在配置文件中写死事件,改用文章 front-matter
timeline: event字段驱动。首页展示事件标题,点击进入文章查看详情 - Hexo 原生关于页:通过
source/about/index.md+layout: about模板实现,不再依赖配置文件。提供 about.njk 页面模板 - 构建时 RSS 最近更新:构建期抓取外部博客 RSS 生成卡片数据,SEO 友好、国内加载稳定、无 CORS 问题
🗑 移除
- 简历(CV)功能:与关于页重复,已删除
- 时间线配置事件:
timeline.events配置项废弃,改由文章驱动
♻️ 代码精简(不影响功能)
scripts 目录从 506 行降至 389 行(-23%):
| 文件 | 变化 | 主要改动 |
|---|---|---|
| search.js | 102→41 | 提取 pluck() 公共函数 |
| recent.js | 156→109 | 合并 parseRss/parseAtom 为 parseFeed |
| subpage.js | 95→68 | 提取 sortBySticky,Set+forEach |
| font.js | 68→61 | 移除未用的 _utils 依赖 |
| htmlGenerator.js | 34→15 | 模板字符串重写 |
| tagcloud.js | 19→9 | 修复 <canvas> 闭合标签 bug |
| _timeline.js | 29→27 | 内联函数 |
| _utils.js | 删除 | getObjValues 已无调用方 |
⚠️ 破坏性变更
升级前请注意:
- 时间线事件改由文章 front-matter 驱动,原
timeline.events配置不再生效 - 关于页改用 Hexo 原生页面,原
about配置块不再使用 - 简历功能已移除
🐛 修复
- 修复最近更新卡片标题 Serif/Sans 字体交错显示问题
- 修复 tagcloud.js 中
<canvas>闭合标签错误
完整提交历史:自 fork (1.3.6) 起共 7 个提交,详见 commits