崮生(子虚)
|
0ab51e496c
|
perf(leafer-x-webfont): 注册回调贡献者回记+静默链应用,百万节点打字场景零风暴
问题(1M Text 节点实测):
- v0 字体注册回调里全树改写 fontFamily:百万次 property.change 污染
dirty 集,打字场景退化 20s;单点改动 978ms
- 公共 setter 路径(v2):百万次完整属性变更管线 = 2.2s 风暴
方案(v4):
- 贡献者回记:commit 时合并累加每个 family 的贡献节点(不覆盖,
迟到 chunk 仍能找到贡献者),chunk 回调只把贡献者标脏——链应用
范围从全树缩小到实际用字节点,打字场景 O(1)
- 静默/公共写分流:溢出(初始全量等贡献者>512)走静默写 __ 数据层
(~50ns/次,不触发事件不污染 dirty);少量贡献者走公共 setter
(leafer 自动局部重绘该节点)
- ready() 语义闭环:字体全部落地后同步消化残留 dirtyAll/renderPending,
否则会被下一个不相关的用户操作捡走——表现为「改一个字卡 800ms」
- forceRender 收敛:仅静默写/浏览器模式标记 renderPending,flush 尾部
无 in-flight chunk 时合并成一次执行
实测(1M Text,真实 leafer + 本地后端):
- 单点改动 flush: 856ms → 0.15ms
- 随机100节点 flush: 0.9ms
- 新增 Text: 0.08ms
- 打字同步按键成本: 0.2ms/次(与无插件基线 0.012ms 同数量级)
- 拖拽等无文字变化操作: 0 请求 0 提交
|
2026-08-15 21:13:07 +08:00 |
|
崮生(子虚)
|
b385bc89bc
|
perf(leafer-x-webfont): 脏节点集增量扫描,百万节点画布可正常运行
全量 walk O(全树) 改为事件驱动增量:
- property.change 携带 target(PropertyEvent 五参构造)→ 精确记脏节点
- child.add/remove 携带 child → 整棵子树入脏集(构造期赋值不走 setAttr)
- 订阅集与 Leafer 自家 Watcher 相同(property.change + child.*),
渲染可靠 = 事件可靠;不再订阅 layout.end(每帧触发,百万级下
周期性全量 walk 是持续卡顿源)
- 脏节点 >512 退化全量(模板整体替换场景全量更省)
- 全量/增量共用 collect/walkInto/commit,指纹短路保证无变化时
update 调用归零
- 新增 provider 透传(测试/私有部署)、flushNow(跳过防抖立即提交)、
updateCalls 计数(量化指纹短路效果)
压力测试(_prof_million.entry.ts,1M Text 节点):
- 初始全量 scan: ~580ms(一次性)
- 打字稳态(emit+flush): 0.024ms/键
- 无文字变化 flush ×100: 0.16ms,update=0
- 内存: 指纹表 O(family 数),与节点数无关
真实 leafer 验证(scripts/test-leafer-incremental.mts):
初始添加/改文字/新增子树全自动捕获,拖拽 50 次 0 请求 0 提交。
附带修复 dev 后端启动:llrt_lr.ts 改动态 import + fsReady
(createRequire 与 tsx ESM loader 模块图隔离导致 implInterface
注册到孤儿实例,mkdir undefined)。
|
2026-08-15 20:19:27 +08:00 |
|
崮生(子虚)
|
c82da2f6ed
|
feat: demo 加源码/npm 链接,构建时复制进主站 dist/leafer-demo/(vite 插件 + sitemap 路由)
|
2026-08-15 16:22:17 +08:00 |
|
崮生(子虚)
|
a0c2b4aafc
|
feat: webfont-sdk Node 模式 + leafer 版基准测试(双方案并存)
- webfont-sdk: 新增 Node 模式(node-registry),GlobalFonts 注册 + 每 chunk 唯一 family + 逗号链回退
- leafer-x-webfont: fontFamily 链写回(Node 端),scan 链归一化防套娃、rewriteFamily 跳过链形态防抹回
- 修复 pnpm 双实例 bug: @napi-rs/canvas 版本对齐 1.0.6(根与 SDK 同版本共享 .pnpm 条目)
- 基准测试重构: 用例表抽取为 基准测试用例.ts 共享,SSIM 计算收敛到 scripts/ssim.ts
- 新增 基准测试_leafer.test.ts: @leafer-ui/node + Skia 渲染验证(无浏览器),ttf 输出用例 SSIM=1.0000;woff2 用例仅计时(Skia 不吃 woff2,容器验证由 puppeteer 版守护)
- Node 端集成测试 scripts/test-leafer-node.mts(插件链路 SSIM=1.0000)
|
2026-08-15 15:51:42 +08:00 |
|
崮生(子虚)
|
dc1ee66fe3
|
修复 temp-cleaner 在 LLRT 上的 unlink 兼容性问题
- 修改 interface.ts: 接受 options.unlink 和 options.rm 作为 FS 适配器的可配置方法
- 修改 llrt.ts: 使用箭头函数 (path) => fs.rm(path) 避免 this 绑定问题
- 修改 app.ts: 通过 __RUNTIME__ 条件编译,仅在 LLRT 运行时引入 llrt.ts
- 修改 tsdown.config.ts: format 从字符串数组改为字符串类型,添加 as const
- 修改 tsconfig.node.json: 添加 node 类型支持
- 新增 backend/global.d.ts: 声明 __RUNTIME__ 全局变量类型
- 修改 .gitignore: 添加 dist_backend_node 目录
- 修改 build-backend.ts: 支持 Node.js 版本构建输出到 dist_backend_node
修复问题:
- LLRT fs/promises 没有 unlink 方法,只有 rm 方法
- CJS 格式不支持 top-level await,改用 IIFE + require
- 条件编译避免 Node.js 版本包含不必要的 LLRT 适配代码
|
2026-08-15 07:02:22 +08:00 |
|
崮生(子虚)
|
5a7c6a9913
|
fix: LLRT readdir 不兼容 withFileTypes 导致临时字体清理失效
根因:LLRT 的 fs.readdir 返回字符串数组而非 Dirent 对象,
entry.isFile() 抛 TypeError 被 catch 静默吞掉,
导致 evictIfNeeded 和 temp_cleaner 从未执行(线上堆积 108 个文件 992M)。
修复:
- node.ts: readdir 改为先拿文件名再 stat 判断
- temp_cleaner.ts: catch 块加日志不再静默吞错误
同时包含:
- font-config.json homepage 链接修复(删除 3 个 404,修正 2 个)
- FontDetail 字符预览改为可实时编辑
- 添加 scripts/bench.mjs 压测脚本
|
2026-08-01 08:03:33 +08:00 |
|
崮生(子虚)
|
6421e7d059
|
fix: extractCodePoints 增加 glyph 轮廓验证 + 删除冗余正文预览卡片
- font_meta.ts: extractCodePoints 新增 createGlyphValidator,对 TrueType 字体
检查 loca 表确认 glyph 有真实轮廓数据(非空),CFF 字体保持原逻辑
- lint 同步去掉 bodyTitle/bodyText(FontDetail 已移除正文预览卡片)
- FontDetail.vue: 删除正文预览区块(与大标题预览功能重叠),移除对应 computed
- allPreviewText 只合并 previewText + charsetPreview
|
2026-07-30 23:50:27 +08:00 |
|
崮生(子虚)
|
7638ce7e2d
|
fix: 移除 FontDetail fallback 默认值 + lint 检查缺失字段 + 使用 CodeBlock 组件
- FontDetail.vue: 移除 DEFAULT_PREVIEW 等硬编码 fallback,config 缺字段时不渲染对应区块(避免显示字体不支持的字符)
- lint-font-config.ts: 新增检查 font/ 目录下所有字体是否都在 config 中有完整配置(previewText/bodyTitle/bodyText/charsetPreview 四个必填字段)
- FontDetail.vue: 使用方法代码块从 <pre><code> 改为 CodeBlock 组件(语法高亮)
|
2026-07-30 23:37:18 +08:00 |
|
崮生(子虚)
|
a095cd0590
|
feat: 详情页全面接入 font-config + 防闪烁
- font-config.json: 新增 bodyTitle/bodyText/charsetPreview 字段
为每个字体配置通过 lint 检查的专属文案
- FontDetail.vue: 正文/字符预览使用 config 字段替代写死文案
大标题/正文/字符预览加 v-if=meta 守卫,消除 hydrate 闪烁
h1 标题使用 displayName
- lint-font-config.ts: 扩展检查范围至所有文本字段
- FontUserConfig 类型同步更新(后端+前端)
|
2026-07-30 23:30:40 +08:00 |
|
崮生(子虚)
|
9397e10aad
|
feat: 字体列表/详情页接入 font-config 配置 + lint 脚本
前端:
- FontList.vue: 卡片使用 router-link 跳转;
展示 displayName/description/previewText/tags;
底部添加字体投稿联系文案
- FontDetail.vue: 预览文字使用 config.previewText 替代写死文案
工具:
- scripts/lint-font-config.ts: 检查 previewText 字符是否被字体支持
- package.json: 添加 lint:font-config 脚本
|
2026-07-30 23:23:30 +08:00 |
|
崮生(子虚)
|
8273508c79
|
feat: StatsPanel 视口内才轮询 + 底部进度条动画
- IntersectionObserver + document.visibilityState 双条件控制轮询
- 卡片底部进度条 (scaleX 动画),每次刷新数据后重启动画
- 避免不可见时浪费请求
- bump version to 1.11.1
|
2026-07-30 17:26:24 +08:00 |
|
崮生(子虚)
|
7c7db7447a
|
fix build
|
2026-04-30 21:34:48 +08:00 |
|
崮生(子虚)
|
53d170dc90
|
feat: 前端迁移至 Vue3 + TS,后端构建迁移至 tsdown
- 前端从 SolidJS 迁移到 Vue3 Composition API(<script setup lang="ts">)
- 后端构建从 tsup 迁移到 tsdown,动态 import 改为静态以支持单文件输出
- FontSelector 添加 defineProps 修复下拉无选项问题
- StatsPanel 添加"服务状态"标题
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-04-30 20:46:30 +08:00 |
|
崮生(子虚)
|
6e5b2c5fb7
|
chore: 升级至 v1.6.0,llrt 切换为 no-sdk 版本
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-04-24 13:32:07 +08:00 |
|
崮生(子虚)
|
2f9eb3fd1a
|
支持 woff2
|
2026-04-11 00:17:27 +08:00 |
|
崮生(子虚)
|
820fc71166
|
feat: 新增 woff2 输出格式支持,默认使用 woff2
- 后端支持 outType URL 参数(woff2/ttf),Node.js 默认 woff2,LLRT 默认 ttf
- woff2 wasm 延迟初始化,仅首次请求时加载(~8ms)
- SDK 三个入口函数支持 outType 选项,默认 woff2
- 前端 CSS、下载、使用说明适配 woff2
- 基准测试新增 woff2 测试(耗时、体积、压缩率)
- 构建脚本自动复制 woff2.wasm 到 dist 目录
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-04-09 11:48:07 +08:00 |
|
崮生(子虚)
|
6f0e3d8e6b
|
fix: 修复 name 表写入偏移错误导致浏览器无法渲染字体
name.js write 函数改用 view.setUint16 后未同步 writer.offset,
导致 name 字符串覆盖 header,name 表损坏。浏览器依赖 name 表
识别字体所以无法渲染,而 Node 端渲染不依赖 name 表所以基准
测试未检测到。
同时修复 cmap sizeof 动态计算记录头大小的问题。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-04-09 11:22:51 +08:00 |
|
崮生(子虚)
|
e0f34c36b6
|
修复上传功能和服务器健壮性问题
- 修复 multipart 解析器:endDelimiter 提前检查导致循环退出
- 修复 Node.js v24 兼容:改为先读取 body 再构造 Request
- 修复 HTTP keep-alive 死锁:按 Content-Length 精确读取 body
- 修复服务器崩溃:connectionHandle 加 try-catch,单连接错误不影响全局
- 修复 URL 写死:webfont.shenzilong.com 改为 localhost
- 复制按钮加"已复制/复制失败"反馈提示
- TEMP_MAX_FILES 改为环境变量可配置
- dev 环境默认启用临时上传和管理员上传
- CSS 代码默认展示,使用技巧不再折叠
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-04-08 17:11:55 +08:00 |
|
崮生(子虚)
|
7fceccfe4d
|
重构前端UI,新增字体上传/下载/模糊匹配功能
- 前端UI重构:字体选择器、文本预览、CSS输出+复制、下载字体、上传区域
- 后端新增API:/api/fonts(列出字体)、/api/config(公开配置)、/api/upload(上传字体)
- 字体查找支持模糊匹配(精确 > 前缀 > 包含)
- 上传功能分两种模式:临时上传(ENV开关,FIFO上限10个)和管理员上传(API Key认证)
- 新增multipart解析器、配置模块、文件系统抽象(writeFile/readdir/mkdir/unlink)
- 后端启动时等待运行时初始化完成,确保接口可用
- dev-all.ts后端启用tsx watch模式自动重载
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-04-08 16:18:46 +08:00 |
|
崮生(子虚)
|
1a611e7e28
|
自行下载 llrt
|
2026-04-08 15:41:39 +08:00 |
|
崮生(子虚)
|
e5b6718ad9
|
优化开发体验
|
2026-04-08 15:35:11 +08:00 |
|