tsrs: 在 ENX 项目里试用 Rust 版 TypeScript 类型检查器

起因 先是在微信公众号上看到一篇介绍 tsrs 的文章,又读了 Cloudflare 的公告 Porting TypeScript to Rust。tsrs 在 Oxc 项目下孵化,Oxc 属于尤雨溪的 VoidZero。我一直关注尤雨溪的动向,早年也用过 Vue,对他团队出的东西比较信任,所以想在自己的项目 ENX 上试一下。 ENX 有两个 TypeScript 前端:enx-ui(Next.js)和 enx-chrome(Chrome 扩展,Vite 构建)。两边现在都用 TypeScript 6.0.3。 tsrs 是什么 把 TypeScript 7 的 Go 版编译器(tsgo)逐个函数移植到 Rust,命令行用法和 tsc 一样,许可证是 Apache-2.0。 由 Owner.com 的 Max Schwenk 发起,Cloudflare 和 VoidZero 参与,和 TypeScript 团队有合作。它不是 fork,语言方向仍由 TypeScript 团队决定。 对齐的是 TypeScript 7.1 开发版(microsoft/TypeScript@b85298b6a81f)。官方一致性测试的 13,462 条错误基线通过了 13,458 条,作者说剩下 4 条是测试工具本身的问题。 Cloudflare 的数据:同样数量的检查线程下,tsrs 比 TypeScript 7.0 快最多 8 倍,内存少约 70%。 仓库 2026-10-01 才建,到我试的时候已经发到 0.18.0。仓库不接受 PR。不支持 --init 和 --showConfig,没有 Intel Mac 二进制,Windows 包还没发布。 试用过程 为了不动项目依赖,我把 tsrs 装在一个临时目录里,再用它的二进制去检查两个前端: ...

Created 21216-10-21 · Updated 21216-10-21 · 2 min · 263 words · -

ENX Mark Known: 从等待接口改为乐观更新

背景 enX 的 Chrome 扩展会给查过的生词画下划线。主窗口点一个词会弹出浮层,浮层里有 Mark Known(标为已认识)按钮,点了之后这个词的下划线消失。 后来侧边栏的整句翻译也加上了同样的下划线(ADR-053),于是有了一个新问题:在主窗口标为已认识之后,侧边栏里这个词的下划线也应该一起消失。 原来的做法 content script → background → POST /api/mark → enx-api 写库 ↓ 成功 content script 收到回复 → 去掉主窗口下划线 主窗口要等接口成功才去掉下划线,侧边栏完全不知道这件事。 改成什么样 content script:先去掉主窗口下划线 └─ runtime.sendMessage({ type: 'markAcquainted', word }) ├─ 侧边栏:收到后立即去掉下划线,不回复 └─ background:调 enx-api,完成后回复 content script 两点变化: 主窗口先改界面,再让 background 在后台调接口,也就是常说的乐观更新(optimistic update),和它相对的是原来那种等服务端确认再改界面的做法。 侧边栏不需要新的通道。chrome.runtime.sendMessage 从 content script 发出时,会投递给扩展里所有监听 runtime.onMessage 的页面,background 和侧边栏都能收到。侧边栏只需要多注册一个监听。 为什么可以先改界面 标为已认识失败的代价很低:服务端没记上,用户下次读别的文章时这个词还会带下划线,再标一次就行。为了这个小概率的失败让用户每次都等一个网络往返,不划算。 如果改成「background 调接口成功后再通知侧边栏」,状态会更严格一致,但侧边栏要多等一个接口的时间。对这个操作来说,一致性没有那么重要。 多个接收方只能有一个回复 runtime.sendMessage 允许多个页面监听,但发送方只会收到第一个调用 sendResponse 的回复,其余的被忽略。侧边栏如果也回复,会抢在 background 前面,content script 就看不到接口的真实结果了。 ...

Created 12126-10-12 · Updated 12126-10-12 · 1 min · 95 words · -

Chrome Side Panel 侧边栏

Side Panel 是什么 Chrome 窗口右侧可以展开的一栏,和当前网页并排显示。Google 的说法是「a new companion surface that allows users to use tools alongside the content they are browsing」:一个伴随页面的界面,让用户一边看网页一边用工具。 它分两层: 浏览器自带的侧边栏:书签、阅读清单等 Chrome 自己的功能。 扩展的侧边栏:扩展通过 Side Panel API(chrome.sidePanel)在这一栏里显示自己的页面。 时间线 时间 版本 变化 2022-03 Chrome 99 稳定版出现侧边栏,内容是书签和阅读清单(9to5Google 报道;Google 自己的博客写的是 2022 年 5 月加入) 2023-05 Chrome 114 扩展可用 Side Panel API,只支持 Manifest V3,需要 sidePanel 权限 2023-08 Chrome 116 新增 sidePanel.open(),可以由扩展主动打开,但必须在用户操作(点击、快捷键、右键菜单等)里调用 为什么要有 Side Panel API API 出现之前,扩展想做侧边栏,只能用 content script 往每个网页里注入一个 <div>。Google 在发布 API 时给的理由: ...

Created 12126-10-12 · Updated 12126-10-12 · 1 min · 131 words · -

Chrome Extension 开发笔记

chrome extension content script, 只能访问 dom, 不能访问页面 js 变量和函数 Injected Script, 被插入到页面里的 js 代码 chrome://extensions puzzle button: chrome extension 图标后面的拼图按钮 develop chrome extension doc https://developer.chrome.com/docs/extensions/mv3/ javascript web api: https://developer.mozilla.org/en-US/docs/Web/API chrome api: https://developer.mozilla.org/en-US/docs/Web/API html: https://web.dev/learn/html/ css: https://web.dev/learn/css/ javascript: https://developer.mozilla.org/en-US/docs/Learn/JavaScript chrome extension development overview: https://developer.chrome.com/docs/extensions/mv3/devguide/ chrome extension 的构成 The manifest, manifest.json, 唯一一个必须要存在于 extension 根目录的文件 The service worker, service worker 监听 chrome 的各种事件, 可以调用 Chrome api, 但是不能直接操作页面内容 Content scripts: content script 可以直接在页面中执行 js 代码, 可以直接操作 DOM, 还可以跟 service worker 通信 The popup and other pages content script 与 service worker 的分工和通信 各自负责什么 对比项 content script service worker(background) 运行位置 注入到网页里,每个匹配的 tab(以及 all_frames 打开时的每个 frame)各一份 整个扩展只有一个,运行在扩展自己的后台 DOM 能读写所在页面的 DOM 没有 DOM,也没有 window、document、localStorage 页面的 JS 变量 访问不到,运行在 isolated world 访问不到 可用的 chrome API 只有一小部分:chrome.runtime(发消息、getURL 等)、chrome.storage、chrome.i18n 按 manifest 里申请的 permissions 全部可用:tabs、scripting、cookies、alarms、contextMenus 等 网络请求 fetch() 按所在页面的 origin 处理,受页面 CORS 限制 对 host_permissions 里的域名 fetch() 不受 CORS 限制 生命周期 跟着页面走,页面刷新或关闭就没了 事件驱动,空闲约 30 秒被回收,有事件再拉起(见下一节) 一句话概括:content script 负责“页面里看得见的部分”,比如读取用户选中的文字、在页面上插入按钮或浮层;service worker 负责“页面之外的部分”,比如调用后端 API、保存登录 token、管理 tab、响应扩展图标点击和右键菜单。两边都做不了对方的事,所以绝大多数扩展功能都是两者配合完成的。 ...

Created 21216-04-21 · Updated 4046-10-04 · 4 min · 801 words · -

2026 W37

这周主要在给 enx 取名字。另外 enx 接了 DeepSeek,HomeLab 的 CI/CD 加了缓存,在 YouTube 上新建了一个产品频道。 enx:取名字 enx 一直是开发代号,要做成产品发布,得有一个正式的名字。取名字是最不重要、也最纠结的一件事。 这一周一直在纠结叫什么。想了好多名字,一个个去查域名和商标,大部分都和现有的软件或者商标冲突:有的域名已经被人注册了,有的已经注册了商标,用了会有法律风险。 最后在仅有的几个不冲突的名字里来回纠结,周六选了一个,注册了域名。 enx:开发 新功能不多:Reader 页面,可以把一段英文粘贴进来阅读、查词;从浏览器扩展里发起登录,登录完会自动回到原来的页面。 另外还做了一些细节上的小调整和优化。 UI 和 API 的提示文案全部改成了英文。用这个工具的人本来就在学英文,UI 上简单的英文应该不是问题; MiniMax 的订阅过期了,DeepSeek 的账户里还有余额,所以给 enx 加了一个 DeepSeek 的 provider,HomeLab 上切到了 DeepSeek。HomeLab 是测试用的,对后端用哪个模型不是特别敏感。 HomeLab:CI/CD 提速 最近一直在测 enx,频繁调细节,也频繁往 HomeLab 上部署,CI/CD 跑的时间就成了一个比较明显的问题。 这周优化了一下:加了缓存,加了 Nexus 私有仓库。npm 和 Go 的依赖走 Nexus 代理,镜像构建的缓存也放在 Nexus 里,依赖没变的时候可以跳过安装依赖那一步。 YouTube:两个频道 打算拍一些东西放到 YouTube 上,比如 enx 的安装/使用演示, 宣传视频, 这周在准备拍摄方案,周六在自己的 YouTube 账号下新建了一个产品频道。 注册 YouTube 账号之后本来就会有一个默认的频道,每个注册用户都有,只是大多数人没有往里面发过视频。我的默认频道就当个人频道用。同一个账号下面还可以再新建别的频道,这一点我也是这周才知道的,算是一个新发现。 这样一个账号下面就有了两个频道。个人频道放我自己的内容,比如 HomeLab 的改造、有可能的未来的房车旅行,也许会有美食类的视频,主要是个人记录。产品频道只发产品相关的内容。个人频道是全集,跟 enx 相关的视频会同时发到两个频道。 ...

Created 14146-09-14 · Updated 14146-09-14 · 1 min · 90 words · -

2026 W36

enx:认证从 Cognito 换成了 Clerk,单词高亮换成了浏览器原生的 Highlight API。 enx:认证从 Cognito 换到 Clerk 当初选 Cognito 的原因是,那会儿在聊一个职位,对方公司用 Java 技术栈,也用 AWS。我想让自己更熟悉 AWS 和 Java 一些,所以 enx 选型的时候选了 Cognito,还给 enx 加了一个 Java 后端。 那个职位后来没有 Offer,见 W33。 这周把认证换成了 Clerk。换的原因是 Clerk 和 Google 登录集成得更好一些,另外它同时支持 Google 和 GitHub 两种登录。网页端和扩展的会话也能同步。两端手写的 OAuth 客户端一起下线,Cognito 那套基础设施也删掉了。 enx:单词高亮换成浏览器原生的 Highlight API 有天晚上碰到思科的前同事 Roc,聊了一会儿,发现自己的前端知识实在太匮乏了。页面上点一下要查的词,其实可以用鼠标的坐标反查到点中的是哪个词,不需要像之前那样预先改 DOM、把所有词都拆开包起来,也不用挂那么多 onClick。 以前的做法就是把匹配到的单词用元素包起来,再给这个元素加样式。这样会改动页面的 DOM,在结构复杂或者会自己重绘的页面上容易出问题。 这周换成了 CSS Custom Highlight API:高亮范围用 Range 描述,交给浏览器渲染,不再往页面里插元素。点击查词改成在容器上做事件委托,用 caretPositionFromPoint 定位点到的是哪个词。 顺带把两件事拆开了:「阅读时高亮生词」和「点击查词」现在是两个独立的开关,可以只启用其中一个。X 上切换推文时正文是原地替换的,加了自动重建。Playwright 的用例按新的实现重写了一遍。 周六:大黑石 周六老婆公司团建,在大黑石的海边烧烤,她带着女儿去了。女儿下午有英语课,我中午开车去大黑石的沙滩接她们。 据说,小朋友到了沙滩就想去海边,饭都不吃了。一开始还在岸边挖沙子,后来看妈妈下水游泳,她也要下水。下水之后就不想走了,用老婆的话说是 “血脉觉醒”。 上次带她去海边是在广鹿岛,那时候她还只是在浅水里捡海星和贝壳。 路边为啥要栽这么多树… 开车去大黑石的路上,偶尔过桥的时候能看到远处的山,景色还不错。其余大部分时间视线都被路两边的树挡着,开多久,窗外都是一样的树。 ...

Created 7076-09-07 · Updated 7076-09-07 · 1 min · 82 words · -

2026 W35

这周主要是 enx 的开发:接入 Stripe,以及上线前的一些细节调整。 enx:接入 Stripe 订阅加积分这套方案是上周那份规划里定下来的,这周把它落进代码。 周三一天,enx 里多出了一整套计费:积分账本、Stripe 的 webhook、配额、结账和账单管理入口,网页端加了定价页和账单页,扩展这边加了积分不足和需要升级的提示。方案之前讨论过,这次是把方案细化,然后由 AI 生成代码。 同一批改动里还补了一组单元测试,账本、webhook、配额、结账处理各有一份。补测试的原因是接入 Stripe 之后要开始新一轮测试,而现有代码的单元测试覆盖太小,先把底子补上。 接下来是测试。 订阅之外加了一次性充值包 周四改了一次访问规则。 前一天定的是:AI 翻译必须有订阅才能用,不能靠单独充值绕过。第二天推翻了,改成账户里有积分就能用,不限来源,订阅发放的积分和一次性购买的积分包都算。 改的原因是有了一个新想法,可以开放一次性购买的充值包。按月订阅并不是所有人都愿意,月费也不好定太高,一次性的充值包是个补充。 代价是前一天已经写进代码的那条校验现在是错的,得删掉。项目还在开发中,随时都会有变化,这些变化都是正常的。 内网域名换成 wiloon.lab wiloon.com 是公网域名,homelab 内部之前也用它,只是在内网解析。但 DNS 分流上遇到了问题,所以内网改用 wiloon.lab,专门给 homelab 用。 这周把 enx 的内网访问切了过去。 公司账本:把方法固化成一个仓库 上周写过决定自己记账,用 beancount,AI 出数、人工复核。这周把它做成了一个仓库。 促成这件事的还有几点。找代账公司有沟通成本;在 twitter 上看到有人用 AI 处理公司的账目,我也想试试;另外公司现在没有业务,都是零申报,应该不复杂。有代账公司打电话过来,我跟他们说的也是自己先试试,实在不行再找专业人士。 仓库里放的是科目表模板、余额断言、季度增值税和年终结账两份 SOP,以及法定报表的字段映射。另外把几个常用动作做成了 Claude Code 的 skill:开票申请、季度报税、出报表、报税准备。 上周是决定自己记账,这周是把记账做成一套可以重复执行的流程。 homelab 杂项 kubectl 的 logs 和 exec 一度用不了,加了一个 ClusterRoleBinding 修回来,交给 ArgoCD 管理。 路由器那边把 IPv6 的 WAN 口改成了静态接口,之前记录过的前缀委派丢失问题走到了这一步。 监控补了一批采集配置。 blog 这周写了三篇:mktemp、DuckDB,以及微信扫码查看与下载 PDF。另外给 SQLite 那篇做了修订。 ...

Created 30306-08-30 · Updated 30306-08-30 · 1 min · 83 words · -

2026 W34

这一周几乎没碰键盘。带娃在老家待了五天,只有她午睡和晚上睡了之后,才有一点时间做自己的事。 从鞍山到老四平 上周从大连出发,在鞍山住了一晚,周一走下半程。 去程走的是国道,这天改走高速。四岁的娃也感觉出来国道太慢了,是她要求走高速的,条件是全程系安全带,她答应了。 到老四平已经是下午,太阳落了山。她还是要去菜园子,非开着手电筒去摘菜。 奶奶家在一个小镇上,房子前后都有菜园子,房子后面是一条铁路,经常有火车轰隆隆地开过去。从小在城市里长大的娃,对这里的一切都新奇。 周二天一亮她又冲进菜园子,拉着奶奶东看西看,摘各种蔬菜,收获满满。 小公园 周三去了老家附近的一个小公园。 爷爷奶奶本来打算当个景点看一眼就回家,中午外面太热。没想到娃对什么都新奇,跟小树小草玩起来就不肯走了。有荷花池,有草地,有树林。 亲戚家的动物 周四去亲戚家看小动物。 老姨家养了羊,还有鸡、鹅和鸽子。娃见了鸽子,就掏出车上的玉米去喂。家里养的鸽子和城市里的广场鸽不一样,星海公园的鸽子只要见了玉米就成群结队地下来吃,家里的鸽子完全没有这个概念。据说每天下午五点才是它们觅食的时间。 又去了二舅家,二舅妈刚卖菜回来。他们也有菜园子,平时吃不掉的菜拿到市场上卖。暖棚里有葡萄,也有各种菜。临走时二舅从鸡窝里掏了一些鸡蛋,给我们带上。 娃拿到鸡蛋,第一个问题是:这个鸡蛋能孵小鸡吗? 我们解释了好一会儿,得有鸡爸爸和鸡妈妈,蛋才能孵出小鸡。她大概是因为亲眼看见鸡蛋是从鸡窝里掏出来的,才会觉得它能孵小鸡。平时从市场买回来的鸡蛋,看不到母鸡的影子,也就不会有这样的联想。 早上跑步 我每天早上跑步。老家在内陆,中午三十几度,早晚凉快,跑步只能放在早上。 小镇上很少有人把跑步当成锻炼。老年人有打太极的,有做操的,有跳广场舞的,跑步的很少。所以 Keep 的地图上,老四平一条跑步路线都没有。上次回来我开发了一条 2 公里的,这次又开发了一条 4 公里的。路上车不多,早上跑起来很舒服。 不方便的是跑完一身汗,洗澡不方便。家里没有独立的卫生间,厕所是旱厕,只能用湿毛巾擦一擦。 回大连 周五开车带娃和奶奶一起回大连。 在大连是姥姥姥爷和爷爷奶奶轮班过来帮忙带娃,这次刚好赶上换班的周期,带娃回老家,顺便把奶奶接过来。 她自己编的一个故事 周六上完英语课,我们坐在外面的长凳上休息,娃自己编了一个故事。 有一只小象,在大森林里走着走着,遇到一张蜘蛛网。网上有两只蜘蛛,一只蜘蛛国王,一只蜘蛛王后。蜘蛛王后会变成老奶奶的模样,骗小象进蜘蛛网,没有成功。后来小象打败了蜘蛛国王和蜘蛛王后,把它们装进了垃圾袋。 正讲到这里,飞过来一只麻雀,落在附近的地上。她接着说:后来来了一只鸟,把垃圾袋叼走了,用嘴啄那个蜘蛛国王和王后。 这个故事的来源能对上。上周回老四平,路上无聊的时候给她讲过孙悟空三打白骨精,白骨精先变成一个姑娘,再变成老奶奶,最后变成老爷爷。另外最近买了 Switch 2 上的《世界游戏大全 51》,和她玩过里面的国际象棋,国际象棋有国王和王后。她把三打白骨精的情节、国际象棋的棋子,还有当时飞过来的那只鸟,编进了同一个故事。 我帮她把这个故事做成了连环画,下次再找时间生成一个动画片。 还是要多带她去看不同的东西,接触各种各样的事物。她会把见过的、经历过的重新排列组合,变成自己的认知。 项目 这周项目上基本没有进展,只有她午睡和晚上睡了之后才有一点点时间。 在老家这几天不碰键盘,倒是想清楚了一件事。enx 这个项目我断断续续做了很久,一直是自己在用。做了这么久,如果最后没有真正上线,我会有遗憾。所以暂时不找工作,接下来一段时间集中精力把它部署上线。 2026 W34,老四平 — 大连。

Created 30306-08-30 · Updated 30306-08-30 · 1 min · 48 words · -

2026 W33

面试结果 上周那场第二轮面试,周二有了结果:职位不匹配。 从 4 月离职到现在同事/朋友帮推过三家公司。一家给了 offer,薪资太低,拒了;一家没有下文;这一家前后聊了四个月,两个岗位都进了二面,都没有 offer. 这一家前后接触了一位 HR 和八位面试官。感觉得出来,有的是希望我加入的,也有的对我有疑虑。anyway,最终的结论是职位不匹配。 接下来先测试 enx 独立商业化的可行性:把功能做完、部署到 AWS、接上 Stripe 订阅,先在 YouTube 和 X 上推(因为只做了 google 账号登录),看能不能有几个付费订阅用户;跑不通的话就再找工作。 enx: 划词翻译 之前选中一个短语会走词典查询,而后端判定"包含空格就是句子",直接返回一句"句子翻译功能暂未开放",短语永远拿不到释义。现在改成:选中的如果是句子中间的几个词,侧边栏显示这个短语在整句里的含义。像 “hunt down emails”,三个词单看都认识,放进上下文里是什么意思才是要查的。 另外给三个翻译 provider 各补了单测。 enx:上线还差什么 周三花了一天,把 enx 距离上线还差哪些事情列了一遍,写成两份文档,一份是商业化设计,一份是任务清单。 先定义什么叫"上线":在生产环境上,真实用户可以注册、登录、订阅、使用 AI 翻译、被限流、退订,这条链路全部跑通,才谈得上开始推广。 顺序定成三步。先在现在这套 homelab 环境里把订阅功能做完、测通,不用等基础设施迁移——然后把跑通的功能迁到 AWS。最后在生产环境完整跑一遍端到端冒烟测试,作为发布门禁。 几条已经定下来的: 计算平台继续用 EC2,不上 ECS 或 EKS。EKS 控制面每月的固定成本,在验证付费意愿这个阶段不划算 上线时数据库继续用 SQLite,先不迁 PostgreSQL。现有链路已经跑过,上线门槛越低越好,数据库迁移不是订阅功能的前置依赖 域名不换。Cognito 的 callback、CORS、证书、扩展权限都已经围绕现在这个域名配好了 全部开源,包括计费规则,继续用 AGPL-3.0 最后一条想得比较久。最初担心闭源可以防止别人用 AI 抄产品,后来推翻了:闭源只能防直接复制代码,防不了照着功能用 AI 重写一遍,而后者才是真正的风险,源码可不可见对它基本无效。定价和免费额度这些数字,用户用一遍产品就能观察到,藏代码也藏不住。真正让我决定开源的是另一件事——找工作这条退路还在,一个有真实用户、有测试和 ADR 的开源项目本身就是求职作品集,这个价值闭源换不来,而闭源换来的那点"防护"本来就是假的。 局域网域名的一秒延迟 周五在准备 enx 的测试环境,发现局域网里的域名访问都带着一段很规律的延迟。查下来是 IPv6 的 DNS 问题。 ...

Created 16166-08-16 · Updated 16166-08-16 · 1 min · 176 words · -

2026 W32

广鹿岛:彩虹滩赶海 上周末坐船去了广鹿岛。 周一换了个海滩,去彩虹滩赶海。这次出来玩时间赶得不错,退潮都在傍晚 6 点左右,太阳快落山,正好是一天里凉快下来的时候。海滩很浅,可以往前走很远,靠岸这一段脚下都是细沙,沙滩上有很多海葵,寄居蟹更是数不过来。再往深处走,细沙变成礁石,海草也多起来,水到膝盖左右。 四岁的女儿一路捡,寄居蟹、螃蟹、各种贝壳,把整个桶底铺满了。后来我们在海草附近捡到一只海星,她立刻把桶里的螃蟹和寄居蟹全倒回海里,整个桶只装这一只海星。 海星带回了民宿。到晚上它大概是缺氧,开始往桶外爬。我们商量了一下,还是放回去吧,不然会死掉。于是又把海星送到离住处最近的海里。 赶海的时候一边拍照一边让 AI 识别,认识了海葵和鱿鱼的卵鞘。海葵挺有意思,拿铲子碰一下,它整个身体缩进沙子里,同时喷出一股海水。鱿鱼的卵鞘在滩上到处都是,半透明、软软的、圆圆的一团。 周三从广鹿岛回大连。在杏树港下船之后是我开车,女儿自己坐安全座椅,全程走国道没上高速——小朋友随时可能需要我,国道方便停车。过几周我要单独带她去爷爷奶奶家,这次算是一次 dry run。 enx:遮阳伞下的 side panel 周二在岛上找了家有泳池的酒店,女儿和妈妈在泳池里泡了一下午。我没带泳衣,就在遮阳伞下写码。 这周 enx 主要在开发句子翻译的 side panel。 后端给三个翻译 provider 都加上了「按句子上下文翻译单词」的能力,配了对应的 handler 和路由,每个 provider 补了单测。前端这边,侧边栏里点击单词后的展示从单行文字改成了卡片。 卡片这块反复改了几版。一开始词、音标、上下文含义、查询次数分四行堆着,太占纵向空间,改成一行内排列、放不下才折行;有道词典的外链也删掉了,侧边栏就这么宽;「Query Count」几个字重复出现太啰嗦,换成一个放大镜图标,原文字挪到 title 属性里做悬浮提示。 加载方式也调了。以前是词典查询和 AI 上下文翻译两个请求都回来才一起渲染,现在点击的时候就先插入一张骨架卡片,两个请求各自返回后只更新自己那部分。词典那边通常更快,音标和释义会先显示出来。列表按点击时间倒序排,重复点同一个词不再发请求,只把已有的卡片挪到最前面。 第二轮面试 周三从广鹿岛回来,在杏树港排队驶出停车场的时候接到了 HR 的电话。是第二轮面试的邀请,安排在周五下午,30 分钟,听起来会是全英文。 当天下午要带娃上课,距离面试还有一天多准备时间。上一次面试因为一直在看 Spring 的资料,没准备自我介绍,英文的自我介绍讲得不太好,这次得准备一下;剩下的主要是怎么用英语把简历上的经历说清楚。周四一整天和面试当天的白天,基本都在准备这些。 周五当天出了个小插曲。我之前很少用 zoom,16:20 就打开了,输会议号、输密码、调整摄像头和麦克风,然后等面试官上线。等到 16:27 还没看见人,才注意到窗口右下角有一个 join 按钮——原来我一直在会议外面 -_- 赶紧点了 join,发现两位面试官已经在线了。 面试过程还算顺利。我的英文不是特别好,中间有问题没听清楚就麻烦面试官再讲一遍,对方会很友好地放慢语速重复。有些问题答得还好,也有因为准备不够没能表达清楚的。面试官也问到了个人项目,我讲了 enx,说计划部署到 AWS 上,或许能帮到其他人。 快结束的时候我还纠结了一下,要不要解释一句我其实一直在会议外面等着。但这么复杂的句子,我的英文暂时还撑不住,就直接 say goodbye 了。

Created 9096-08-09 · Updated 9096-08-09 · 1 min · 62 words · -

2026 W30-W31

这两周的周记合成一篇。 enx:先把功能做完,上线再说 enx 是我自己的项目,一个查词加翻译的 Chrome 扩展。这两周它是主线。 前一周主要在部署链路上:调查词性能(SQLite 相关的调整、给 words 表加索引的 migration),构建时把 version 注入镜像,Go API、Java API 和 UI 三条镜像链路陆续跑通,部署到 homelab。 后一周是功能推进: 合入本地 ECDICT 词典,查词路径不再依赖外部接口 单词弹窗迁到 React + Shadow DOM,样式不会再被宿主页面污染 加了句子翻译的 Side Panel,翻译后端做成多 provider(MiniMax、Bedrock、Kimi),用 factory 加 handler 分派 修扩展的 session 超时问题,Cognito 那边改成手写刷新逻辑 周六在岛上想清楚一件事:微信登录先不做了。现在已经有 Google 登录,把 Stripe 接上就可以上线部署。把基本功能做完先上线,不需要等到完美。 一个朋友的文档校验工具 之前写过的、给一位朋友做的文档校验工具,这两周继续往前走。 前一周主要是仓库骨架落地:架构 ADR、几个模块的 Spec、测试,周末开始写 Web UI 的 SDD 和 lint 配置。后一周把它部署进了测试环境。 另外这个项目按正常的需求分析、报价流程走一遍。因为如果以后真的在线接单,报价是绕不开的问题,正好拿它测试一下。 starlabrys 官网 公司官网这两周加了历史项目展示页,还有一个 Site Advisor 的雏形,包括意图识别、知识库、tools 和对话几个部分。ew8 帮我改的那部分周五合并进来了。 w_dashboard:一个玩具级的仓库看板 周末起了个新项目 w_dashboard,Linux 端用 Rust 加 Slint,macOS 端用 Swift 加 SwiftUI,两端各写了一版初版。 ...

Created 2026-08-02 · Updated 2026-08-02 · 1 min · 130 words · -

2026 W26

enx 加 Java 后端 最近投了 Java 方向的职位,这段时间在回忆和熟悉 Java/Spring,也在整理 blog 里之前攒下的资料。但只看文档、不动手,理解很有限。过去做 Java 项目时训练过的"生物神经网络"痕迹应该还在,细节被修剪掉了,主要的连接还在,得花点时间把细节重新接上。 enx 是我写的一个英文学习工具,也是技术栈的 playground。这周给 enx 加了一个 Spring Boot 后端,把一个简单的 API 迁了过去,依赖走 Homelab 里的 Nexus Maven 私服,构建和部署接到现有的 Tekton + k8s 流水线上:推代码后 Tekton 自动打镜像、更新到集群。这样一个最小闭环先跑起来,后面再慢慢补。 梳理 Java/Spring 文档 接着 W25 的节奏,继续整理 blog 里的 Java 文档,这周重心移到 Spring 和 JVM 周边。大脑像是索引和内存,blog 像是外部存储;脑子里的东西大概是 blog 内容的一个子集加上索引,有交叉,但也不是所有东西都写进了 blog。整理的过程就像是顺着索引把外存里的细节重新梳理一下。 这几个文档是本周动过的,方便以后自己回溯:classloader、Spring IoC 与 Spring Boot、graalvm native image、HotSpot,以及顺手补的 SPI / ServiceLoader 和 YAGNI。 公司:领照、刻章、开户 W24 注册了公司,这周把领营业执照、刻章办了,银行开户排到了下周。本来 6 月 24 日计划去领照,车启动打开导航才发现当天大连有达沃斯论坛限行,只好折回,在家准备面试和注册材料。第二天才正式跑完一圈。 ...

Created 28286-06-28 · Updated 30306-06-30 · 1 min · 150 words · -

2026 W25

本周一(6 月 16 日)补写了 2026 W24 周记。下面记 W25 自己的事。 投递邀请与简历准备 6 月 15 日收到一份投递简历的邀请。这周主要修改简历和可能的面试准备,homelab 改造、公司刻章之类都先往后放。 写简历时沿用平时写代码、写 blog 用的 SDD 思路:先和 AI 写一份 spec,对照旧简历与新职位描述列出差异;再按差异到个人 profile 里挖过往项目的故事;回到 spec 标注每条差异可以引用哪些素材;最后让 AI 根据 spec 生成新一版简历。因为此前投过类似方向的岗位,很多段落可以复用,这个流程既有结构又省时间。6 月 17 日跟前同事聊 AI 用法时,才突然意识到 SDD 不只适用于代码和文章——简历同样适用。 挖素材的过程中,我把一些早年做过但没在简历里展开的项目重新整理成文,例如 车联网平台第三方数据推送集成。有些事只是做过、学过,和跟别人讲过一次之后,大脑里留下的关联是不一样的;输出过一遍,需要的时候更容易想起来。 PDF 导出是另一条线。以前用 VS Code / Cursor 的 Preview 在浏览器里打开再打印 PDF,软件更新后这条路走不通了。跟 AI 聊了几轮,第一次正经用排版工具链:Markdown 经 Pandoc + XeLaTeX 出 PDF,定制了 LaTeX 模板和一键脚本。流程稳定后另写了一篇技术记录:Markdown to PDF: Pandoc + XeLaTeX 简历导出实践。 看职位描述时还记下一个概念 Speed over Perfection,顺手写进了 agile 笔记。 梳理 Java 文档 简历主体定稿后,重心转到 blog 里攒了很久的 Java 笔记。这次投的是 Java 方向,正好借机把零散文章理顺:拆大篇、补版本脉络、把 JVM 和 HotSpot 分开写。日历上这几天和简历收尾有重叠,但主线已经换成「整理文档」。 ...

Created 21216-06-21 · Updated 23236-06-23 · 1 min · 149 words · -

enx-api 在 Homelab 的构建与部署

这篇文档讲什么 Homelab 里跑 enx-api 时,从本机一条 Taskfile 命令到 Pod 滚动更新,中间经过 Tekton 构建镜像、Nexus 存镜像、GitOps 改 manifest、Argo CD 同步集群。本文按实际配置把这条链路拆开说明。 Tekton、Kaniko、Argo CD 各自的概念见 Tekton 与 Kaniko 和 Argo CD 与 GitOps 持续部署;这里只写 enx-api 这条线的落地细节。 涉及的两个仓库 仓库 作用 enx 应用源码、enx-api/Containerfile、根目录 Taskfile w10n-config(私有仓库) K8s manifest、Tekton Pipeline/PipelineRun、Argo CD Application CI 在集群里 clone 的是 GitHub 上的 enx,不是本机工作区;CD 改的是 GitHub 上的 w10n-config(私有仓库,不对外公开),再由 Argo CD 拉到集群。文中出现的 manifest、Pipeline 路径均指该仓库内的 infra/homelab/k8s/ 目录。 整体流程 flowchart LR A[本机 task tekton:build:api] --> B[创建 PipelineRun] B --> C[git-clone-ssh拉 enx 源码] C --> D[kaniko-build构建并推送镜像] D --> E[update-gitops-repo改 deployment.yaml] E --> F[Argo CD 自动 sync] F --> G[enx namespace Pod 更新] 一次完整发布可以概括成四步: ...

Created 21216-06-21 · Updated 21216-06-21 · 4 min · 717 words · -