思源笔记 v2.9.5 深度解析:面包屑交互重构、.sy 文件单行 JSON 存储与属性视图「表格化」
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
本篇文章基于思源笔记(Siyuan)v2.9.5 的官方发布说明(繁体中文版,另有简体中文版与英文版),结合仓库当前源码,对这一版本在面包屑组件、编辑器细节、.sy存储格式、属性视图(Attribute View)与内核网络 API 等方面的变化做逐项展开。读完你将理解:为什么该版本值得升级、云同步为何在 v2.9.4 处设下"版本门槛"、.sy单行 JSON 配置项在前后端的完整生效链路,以及插件开发者可用的新事件总线与/api/network/forwardProxy内核 API 的调用方式。
版本概览:细节打磨 + 数据格式兼容的一版
官方概述将其定位为"改进了面包屑和一些细节"的版本,同时明确了两点升级诉求:
- 修复了工作空间文件夹名称含非 ASCII 字符时无法导出 Data 的问题,涉及所有使用非英文/非纯 ASCII 目录名的用户,例如中文用户名路径下的工作空间;
- 云同步兼容门槛收紧:由于旧版本存在可能导致云端数据损坏的问题,v2.9.5 发布之后,官方数据同步不再支持 v2.9.4 之前的旧版本。使用官方数据同步的用户必须升级到 v2.9.4 及以后版本。
这一"数据安全红线"式声明属于服务端兼容策略的常见做法——客户端版本过旧时会与新版服务端协议不兼容,强行同步可能引入脏数据,因此上游以版本下限作为兜底保护。
除上述两点外,本版本变更集中在三块:功能改进 15 项、缺陷修复 5 项、开发者能力 12 项,其中开发者侧的重头戏是属性视图(Attribute View)在 v2.9.5 首次支持"表格"形态及其配套列类型。下文按此脉络逐一展开。
面包屑(Breadcrumb)组件体验重塑
v2.9.5 的多项改动围绕"面包屑"展开,说明该版本在文档导航细节上做了集中打磨:
- 改进移动端面包屑(issue #8623):针对窄屏下的面包屑交互与布局进行了适配优化;
- 在面包屑右侧增加文档块标(issue #8654):用户可以直接从面包屑最右侧唤出文档级菜单,进而对整篇文档执行只读/全宽等属性操作,不必再回到文档树或编辑器顶部图标;
- 改进面包屑转义文本(issue #8679):处理了特殊字符(如
<、>、引号等)在面包屑中显示被错误转义的问题; - 动态计算面包屑高度(issue #8674):面包屑高度不再依赖固定值,而是随内容动态测量,避免文档标题过长时挤压/溢出编辑器区域。
从当前源码看,面包屑"更多菜单"的弹出逻辑集中在 app/src/protyle/breadcrumb/index.ts:点击文档块标后会先通过fetchPost拉取文档统计信息(response.data.stat中包含runeCount、wordCount、linkCount、imageCount、refCount、blockCount等),随后追加只读的文档统计菜单项,并向插件系统发出open-menu-breadcrumbmore事件(详见后文"开发者能力"章节)。这说明 v2.9.5 的面包屑并不是单纯的展示栏,而是文档级操作与插件扩展的入口。
编辑器与移动端的交互细节优化
除面包屑外,功能改进清单还覆盖了导出预览、移动端生命周期、集市、同步与关系图等模块:
| 变更点 | issue | 说明 |
|---|---|---|
| 导出预览模式下页签切换,大纲跟随切换 | #8669 | 导出预览中切换页签时,右侧大纲不再滞留旧页签内容,而是跟随当前预览文档联动 |
| 移动端「退出应用」时保存文档浏览状态 | #8670 | 记录退出前正在浏览的文档,下次启动恢复浏览位置 |
| 改进集市界面布局对齐 | #8671 | 集市(Marketplace)卡片/列表的对齐细节修正 |
| 改进云端数据同步报错文案 | #8675 | 同步失败时的提示信息更明确,便于判断是网络、账号还是版本原因 |
| 改进「关系图」设置界面 | #8676 | 关系图(Graph View)的设置项布局与文案调整 |
| 停用账号前需输入用户名和密码进行校验 | #8680 | 账号停用属于高风险操作,强制二次身份确认,防止误操作或越权 |
| 改进设置界面 | #8685 | 通用设置界面布局细节优化 |
| 反链链接面板颜色不再受提及折叠状态影响 | #8688 | 反链面板(Backlink)中链接高亮颜色与"提及/折叠"状态解耦,避免状态切换导致颜色跳变 |
| 更新移动端缩进/反向缩进图标 | #8698 | 工具栏图标样式刷新 |
| 改进桌面端创建工作空间交互 | #8700 | 首次启动/切换工作空间的创建流程更顺畅 |
其中"关系图"与"反链"分别对应内核中的 kernel/model/graph.go 与 kernel/model/backlink.go 数据服务,这类纯前端 UI 改动在桌面端与移动端代码中各自维护实现,属于典型的"端侧体验收敛"型发布。
.sy文件单行 JSON 存储
.sy是思源文档在磁盘上的持久化格式,本质是一个 JSON 结构的文档树。历史上思源默认将其格式化(多行缩进)存储,便于人工阅读排查。v2.9.5 新增能力(issue #8712):支持以单行 JSON 格式保存.sy文件,同时覆盖属性视图的.json文件。这是文件系统层面的一个可配置行为,而非强制切换。
配置项与前后端生效链路
- 前端设置项位于「设置 → 文件树」中,开关绑定的配置键为
fileTree.useSingleLineSave,见 app/src/config/tabs/fileTab.ts; - 该键的类型声明在 app/src/types/config.d.ts,注释明确写着"Whether to save the content of the .sy file as a single-line JSON object";
- 内核侧配置结构体字段定义于 kernel/conf/filetree.go,JSON 键同样为
useSingleLineSave("使用单行保存文档 .sy 和属性视图 .json"); - 配置读取时,kernel/model/conf.go 会把该值同步到全局变量
util.UseSingleLineSave;用户在设置界面保存配置后,kernel/api/setting.go 同样会刷新该全局变量,保证无需重启立即生效; - 实际写入时,kernel/model/export.go(文档树渲染落盘)与 kernel/model/import.go(导入/转存)都会判断
util.UseSingleLineSave:为false时对渲染结果做缩进美化,为true时直接以紧凑的单行 JSON 落盘。
关于.sy的文件级格式约定,可进一步参考仓库中的 SY-FORMAT 说明(中文见 SY-FORMAT.zh-CN.md)。
单行格式的价值与取舍
从工程角度看,单行 JSON 存储主要有三类收益:
- 显著减小文件体积:去掉换行与缩进空格后,包含大量子块的文档磁盘占用明显下降,云同步与本地备份的数据量随之减少;
- 利于版本控制与差异对比:单行格式下每个文档对应一条紧凑记录,配合 Git 等工具做内容级 diff 时更稳定,不会因缩进变动产生大量噪声差异;
- 便于脚本与程序化处理:对 JSON 解析器更友好,适合二次开发工具批量读取。
代价是人类直接阅读与手改.sy文件的体验下降。因此思源将其做成一个可开关的配置项而不是默认强制。若更看重可读性与调试便利,保持默认的多行缩进格式即可。顺带一提,与该配置相邻的largeFileWarningSize(大文件警告阈值,默认 8MB,见 kernel/conf/filetree.go)用于在编辑超大文档/超大属性视图时给出性能提示,两者共同服务于大规模文档场景的存储与编辑体验。
行级元素合并策略调整
issue #8713 描述了一项编辑器底层行为变更:"不再自动合并相邻换行的行级元素"。
在思源的块级编辑器(基于 Protyle/WYSIWYG)中,同一段落内换行产生的相邻行级元素(行内节点)过去会被编辑器自动合并;v2.9.5 起这一自动合并被移除。其意义在于:当两行各自带有不同的行级属性(例如字体、颜色、行内公式/代码标记),或者用户通过换行有意分隔渲染内容时,编辑器将保留这两行元素的独立性,不再静默改写结构,从而保证复制、导出与排版结果符合用户原始输入。这属于"少干预、保原样"的编辑器策略调整,对追求精确排版的长文档用户更为友好。
缺陷修复盘点与实现位置
v2.9.5 修复的 5 个缺陷覆盖了导出、表格、复制与排版四大场景:
| 修复项 | issue | 影响面 |
|---|---|---|
| 工作空间文件夹名含非 ASCII 字符时无法导出 Data | #8678 | 中文/日文等多字节路径下的「导出 Data」失败 |
| 表格单元格内三击全选后无法修改字体外观 | #8703 | 表格中三击选中整格文本后,字号/字体颜色等外观修改失效 |
| HTML 块相关复制问题 | #8706 | HTML 块在复制/粘贴场景下的内容异常 |
| 列表项带特定自定义属性值时复制内容不正确 | #8707 | 列表项携带特定custom-*属性时复制结果错乱 |
| 标题块父级构造列表项后「优化排版」解析异常 | #8709 | 将标题块转换为列表子项后执行"优化排版"出现解析错误 |
其中#8678 是本次最重要的缺陷修复:导出 Data 的入口是内核 API/api/export/exportData(路由注册见 kernel/api/router.go,处理函数位于 kernel/api/export.go),该功能会把整个工作空间打包为数据备份。当工作空间绝对路径中混入非 ASCII 字符(如用户名含中文)时,打包/解包环节存在路径处理缺陷导致失败。该问题修复意味着以中文等非英文目录名创建工作空间的用户在 v2.9.5 之后可以正常执行「设置 → 导出 → 导出 Data」的完整数据备份流程。其余复制类缺陷集中在剪贴板与块属性序列化逻辑(内核侧可参考 kernel/util/clipboard.go 与块属性处理模块 kernel/treenode),"优化排版"则与 kernel/model/format.go 的排版重排逻辑相关。
开发者能力(一):属性视图(Attribute View)迈向表格化
v2.9.5 的开发者清单几乎全部围绕属性视图展开,标志着这一面向"结构化知识管理"的能力开始成熟:
- 编辑器支持属性视图 - 表格(issue #7536):编辑器内首次原生支持以"表格"形态渲染属性视图;
- 属性视图列排序(issue #8663):支持对列做自定义排序;
- 属性视图添加数字类型列(issue #8690):新增
number列类型,可存储并参与排序/计算; - 属性视图添加文本类型列(issue #8693):新增
text列类型; - 属性视图添加选择类型列(issue #8694):新增
select列类型,配合下拉选项完成枚举值录入; - 属性视图支持过滤、属性和排序面板中的项目排序(issue #8691):三个配置面板中的项目排列顺序可调;
- 块数据同步至属性视图(issue #8696):块内容/块引用可向属性视图行同步,为"块 ↔ 数据库行"联动打下基础。
"块数据同步至属性视图"意味着属性视图不只是独立的二维表,它能够感知文档树中的真实块(block)——这是属性视图与普通表格的本质差异,也为后续基于属性视图构建看板、画廊等视图形态埋下伏笔。从仓库现状看,属性视图相关的内核实现非常庞大:数据层与表格/画廊/看板各视图布局实现在 kernel/av(如 av.go、layout_table.go、layout_gallery.go、layout_kanban.go),模型层在 kernel/model/attribute_view.go 及同目录attribute_view_*.go系列,SQL 查询/缓存层在 kernel/sql 下的av*.go文件,内核 API 入口则在 kernel/api/av.go。可以说 v2.9.5 的表格列类型与排序只是起点,如今已成长为支持数字/文本/选择/日期/资源等多种列类型、多视图形态的大型子系统。
开发者能力(二):插件事件总线新增open-menu-breadcrumbmore
插件系统在本版本获得了一个新事件类型:open-menu-breadcrumbmore(issue #8666)。事件类型名收录在事件总线类型联合中,见 app/src/types/index.d.ts。实际触发位置在面包屑"更多菜单"弹出处(app/src/protyle/breadcrumb/index.ts):
if (protyle?.app?.plugins) { emitOpenMenu({ plugins: protyle.app.plugins, type: "open-menu-breadcrumbmore", detail: { protyle, data: response.data.stat, // 文档统计:字数、块数、引用数等 }, separatorPosition: "top", }); }插件监听该事件后,即可在面包屑右侧的文档菜单中注入自己的菜单项,detail.data携带了当前文档的统计信息(runeCount、wordCount、blockCount、linkCount等),detail.protyle则给出编辑器实例上下文。这使得插件无需再通过 DOM hack 就能扩展"文档级操作"入口。
同批还补充了bind this事件总线示例(issue #8668):当插件回调中需要访问插件实例(如调用this.log、this.loadData)时,事件监听函数应使用箭头函数或显式绑定this,避免在事件回调的独立作用域中丢失插件上下文——这属于典型的 JSthis绑定陷阱,官方通过示例帮助插件作者规避。
开发者能力(三):内核 API/api/network/forwardProxy
本版本新增了一个面向管理员的服务端网络转发 API:POST /api/network/forwardProxy(issue #8724)。路由注册于 kernel/api/router.go,并挂载了CheckAuth(登录校验)与CheckAdminRole(管理员角色校验),实现位于 kernel/api/network.go 起的forwardProxy函数。
请求参数
| 参数 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
url | 是 | 无 | 目标地址,仅允许http/https协议,非法地址返回错误码 1 |
method | 否 | POST | HTTP 方法,服务端会转为大写 |
timeout | 否 | 7000(毫秒) | 请求超时,小于 1 时回退到默认 7000ms |
redirect | 否 | true | 是否跟随重定向,传false时使用不跟随重定向策略 |
headers | 否 | 无 | 请求头,数组元素为键值对对象,逐项设置 |
contentType | 否 | application/json | 请求Content-Type |
payloadEncoding | 否 | json | 载荷编码:json、base64/base64-std、base64-url、base32/base32-std、base32-hex、hex、text |
payload | 按需 | 无 | 请求体;二进制类编码(如base64)会先解码再发送 |
responseEncoding | 否 | text | 响应体编码,取值同上,用于将响应内容回传为文本 |
实现细节(kernel/api/network.go):函数先解析并校验url,scheme非http/https时直接返回错误码 2;随后按method、timeout、redirect构建带超时与重定向策略的客户端,根据payloadEncoding对载荷做对应解码(错误码 3~7 分别对应 base64-std、base64-url、base32-std、base32-hex、hex 解码失败),text以外的编码分支通过request.SetBody写入解码后的二进制内容,最后request.Send(method, destURL)发起请求;请求失败返回错误码 8,读取响应失败返回错误码 9。responseEncoding用于把响应字节编码回文本(含各 base32/base64/hex 变体),便于上层拿到可直接落库或展示的结果。
与其他代理 API 的定位差异
仓库中已存在POST /api/network/proxy(HTTP 代理)与GET /ws/network/proxy(WebSocket 代理,见 kernel/api/router.go)。相比之下,forwardProxy是一次性的服务端请求转发:它不建立长连接,而是让内核作为一个受控 HTTP 客户端代为向第三方 URL 发请求并把响应回传。对于桌面端渲染进程或浏览器中受同源策略限制、需要绕过跨域约束的场景,插件与前端可以借助该 API 经由本地内核完成对第三方服务的调用。因为该接口需要管理员角色,实践中应仅将其暴露给可信调用方。
升级建议与延伸阅读
- 务必升级:如果正在使用官方数据同步,请至少升级到 v2.9.4(含)以上版本,否则将因版本兼容策略无法继续同步;
- 注意工作空间路径:如果你的数据目录/工作空间路径含中文等多字节字符,且此前导出 Data 失败,v2.9.5 已修复该问题,建议升级后完整执行一次「导出 Data」验证数据备份能力;
- 关注
.sy存储格式:启用"单行保存 .sy"后磁盘占用与同步体积会下降,但文件可读性降低,按需开启即可;该配置保存在设置中的"文件树"分组下(配置键fileTree.useSingleLineSave)。
本版本三种语言的完整发布说明均可直接查阅:v2.9.5.md(英文)、v2.9.5_zh_CN.md(简体中文)、v2.9.5_zh_CHT.md(繁体中文);仓库根目录的 CHANGELOG.md 汇总了全部历史版本记录。若希望深入了解内核与编辑器实现,可从 AGENTS.md 入手概览工程结构,再按上文给出的文件路径逐模块深入。
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考