- Published on
2026-第三十七周
- Authors

- Name
- AgedCoffee
- @__middle__child
该周报主要为各个地方内容的汇总整理
技术
Half Past Fetch
这篇文章的核心是:await fetch(url) 只等到 HTTP 响应头,而不是整个响应。promise 在最后一个响应头字节到达时即刻 settle,此时 body 仍是一个正在接收数据的活跃 ReadableStream。这个看似微小的间隙带来一连串后果——连接被占用、clone() 只是对活跃流做 tee、abort 在 promise resolve 后仍然生效、基于 race 的超时只覆盖头部阶段——文章用 Node 与浏览器实验逐一验证,并指出正是这个特性让流式进度等能力成为可能。
- 🔍 await fetch 只等到了一半:promise 在响应头完成时 settle,body 仍在传输,所以通常需要 await 两次
- 📜 规范层面:HTTP-network fetch 在最后一个 header 字节处退出循环,挂上新的 ReadableStream;processResponse 被排为任务,规范明确注明 body 的流此后仍在被 enqueue
- 🧪 实测差距:httpbin drip 示例中 headers 在 250ms 可读,body 在 3445ms 才结束;普通端点上两者只差不到 1ms,因此极易被忽视
- 🚫 例外情况:HEAD 请求与 null body 状态码(101、103、204、205、304)的 body 为 null,没有后续传输
- 🔌 连接仍归你所有:状态码不合意就提前返回而不读 body,HTTP/1.1 下连接无法交回连接池,只能被关闭
- 📊 Node 基准:16KB 以下响应已被完全缓冲,读不读都一样;16KB 以上每忽略一次就多耗一条连接(10 个请求用 10 条而非 2 条)
- 🌐 运行时差异:Chrome 可容忍 512KB 乃至更大的未读 body,比 Node 的边界高两个数量级,两边都依赖底层缓冲区大小,不能作为可靠保证
- 🚫 cancel() 换不回连接:显式取消流与直接无视 body 的计数完全相同,只有读到末尾才能把连接还给连接池
- 📈 失败是渐进的:不会卡死或报错,只是连接数增长、文件描述符堆积,客户端池随压力涨落,因此可在生产环境潜伏很久
- 💧 根因是背压:网络层填满内部缓冲后停止从 socket 拉取,等待一个永远不会到来的读者
- 👥 clone() 什么都不复制:规范定义就是"tee body's stream",相当于在仍在运行的管道上分叉,两个分支被绑在一起
- 💾 代价是内存:60MB 响应下,放弃一个分支约多占 55MB(116.1MB → 169.3MB),与响应体大小相当
- 📦 数据被保留而非重取:读完第一分支、等 500ms 后再读被弃分支,仍在 32.5ms 内拿到完整 60MB
- ⏱️ 顺序规则:必须在任何 pull 之前调用 clone(),读取后再 clone 会抛 "Body has already been consumed";bodyUsed 按对象区分
- ⚠️ 取消克隆的陷阱:await copy.body.cancel() 会死锁,它要等另一分支读完;不 await 也要等原分支结束才 settle
- 🛑 Abort 比 promise 活得久:resolve 后 abort 仍会在下一次 body 读取时抛 AbortError,已到手的 chunk 依然有效;写入端会收到 aborted,是真正的断连
- 🧩 便捷方法无法给出部分结果:arrayBuffer/json/text 被 abort 就直接 reject,想保留已收数据必须用 getReader()
- ✅ 读取完成后 abort() 是空操作:不抛错,可安全放在清理路径,但调用成功并不代表真的取消了什么
- ⏰ Promise.race 超时只覆盖头部阶段:慢 body 场景下 race 在 59.7ms 结束,请求却在 1251ms 才真正完成,200ms 预算在关键部分开始前就用尽了
- ⏳ AbortSignal.timeout 覆盖全程:作为请求信号传入并附着到 body,在哪个阶段超时就在哪个阶段生效,慢 body 与慢 headers 都在约 200ms 被切断
- 🖥️ Chrome 后台标签页陷阱:后台标签的 setTimeout 被钳制到约 1 秒,200ms 预算要 800ms 后才触发,正确行为看起来像坏了
- 🔗 组合信号:用 AbortSignal.any 合并调用方信号、转换器信号、超时信号与内部控制器信号,任一方触发都会中止请求
- 🔄 读取 body 才是真正的工作:也是这一切的正面价值——仍是活跃流才能被 pipeThrough 观察进度,示例中 promise 在 52ms settle,25%/50%/75%/100% 分布在随后的 1257ms 里
- 📐 包装很重要:pipeThrough 返回的是流,需用原 status 与 headers 重建 Response,下游调用方对此毫无感知(ffetch 的 download-progress 插件即此思路)
- 🧭 结论:await fetch(url) 应读作"头部已完成、body 即将开始"的那一刻;连接、内存、取消与超时都属于它之后的部分,之后写的代码才决定这一部分如何收场
在 Next.js 应用中根据自定义指标构建仪表盘和告警
本文介绍如何在 Next.js 应用中通过 Sentry 从自定义指标出发,快速搭建仪表盘与告警。只需从 Server Action 中发出一个自定义指标,就能把它变成可视化仪表盘组件,并配置阈值或异常检测告警;所有数据都与追踪关联,指标异常时一键跳转到对应的请求。教程约需 20-25 分钟,共 6 个步骤,适合具备 Next.js Route Handlers 或 Server Actions 基础的开发者。
- 🚀 前提条件:需要一个 Next.js 应用(推荐 v13+ 的 App Router)、
@sentry/nextjs10.25.0 或更高版本(该版本起指标默认开启),以及 Sentry 账号和项目;使用异常检测告警需 Trial、Business 或 Enterprise 套餐 - 🛠️ 第一步:安装 SDK:在项目根目录运行
npx @sentry/wizard@latest -i nextjs,向导会自动配置 instrumentation 文件,指标默认开启,如需关闭可设置enableMetrics: false - 📊 第二步:发出自定义指标:用
Sentry.metrics.count()统计计数类事件,用Sentry.metrics.distribution()记录需要百分位的数值;示例中每次用户增删演讲都会统计schedule.event,并附带action和result属性 - 🔍 第三步:在指标浏览器中查看:触发几次代码路径后打开 Metrics explorer,选择
schedule.event,按result属性分组查看成功、重复和失败情况;Samples 标签页可查看单个指标事件并直接跳转到对应追踪 - 📈 第四步:搭建仪表盘:从浏览器中点击 Save As 将查询固定为仪表盘组件,再加入第二个相关指标(如
ai.tokens.total的 p95 或page.view吞吐量)并排展示 - 🚨 第五步:添加阈值告警:通过 Save As 菜单将其转为 Monitor,选择 Threshold 检测方式并设置明确的数值(如每小时 token 费用上限),通知可发送至 Slack、PagerDuty 或邮件
- 🤖 第六步:改用异常检测:当尚不清楚"正常"基线时,创建第二个告警并选择 Anomaly 检测方式,Sentry 会学习指标的季节性和日/周规律,只需调整灵敏度滑块,适合流量自然起伏的指标
- 💡 命名建议:使用一致的点分命名约定(如
schedule.event、ai.tokens.total),便于团队查找和分组 - 💡 善用属性:把业务上下文(action、result、套餐等级)放入 attributes 而非指标名称中,高基数事件的属性不额外收费,且能提供更多切分和告警维度
- 💡 百分位用分布:需要 p95 或 p99 时应使用分布而非 gauge,因为 gauge 只保留最新快照
- ⚠️ 常见误区:不要把维度写进指标名(如
schedule.event.success),否则会爆炸基数导致无法分组;不要指望从 counter 或 gauge 中得到百分位;不要在强季节性指标上使用静态阈值;SDK 版本低于 10.25.0 会静默忽略指标调用 - ❓ 常见问题:指标无需额外配置;count 用于计数、gauge 用于即时值、distribution 用于百分位;静态阈值适合已知危险数值,异常检测适合无基线或强季节性场景;指标按量计费,免费套餐足够入门;阈值和异常告警均可通知 Slack、PagerDuty 或邮件
- 🔗 后续方向:可进一步探索 Tracing(分布式追踪)、Logs(结构化日志),并查看本教程基于的 Sentry 工作坊示例应用源码
面向比人类审查速度更快的 frontend 项目的 10 个反 AI 垃圾内容举措
本文面向 TypeScript/React 与 AI agent 开发,提出 10 项对抗 AI 生成“看似可用实则难查”代码的工程措施。作者把检查分成三类:避免多余代码被写出、找出已被写出的问题、通过 CI 强制落地,并讨论了成本、渐进式推行顺序,以及自动化无法取代的人类判断。
- 🧾 OpenAPI 契约先行:前后端共用权威 API 规范,自动生成类型、客户端与 Zod schema;AI 猜错字段(如
user.fullName)会直接编译失败,审查重点回到小得多的契约本身。 - 🔒 开启严格 TypeScript:
strict: true并加上noUncheckedIndexedAccess、exactOptionalPropertyTypes,强制处理“值可能不存在”的情况,减少 AI 代码里常见的乐观假设。 - 🧼 把 linter 当作行为过滤器:sonarjs 查复杂度/重复逻辑;
react-you-might-not-need-an-effect拦多余 effect;Vitest/Playwright 插件抓无断言测试和.only;jsx-a11y 查无障碍;再禁用any、非空断言等捷径。 - 🧱 用依赖边界保护架构:通过 eslint-plugin-boundaries 或 dependency-cruiser 声明组件/服务/工具/设计系统间的依赖方向,阻止 AI 每轮会话都“向 GitHub 平均架构漂移”。
- 🛠️ 把踩过的坑写成自定义 lint 规则:AI 让自定义规则十分钟内可完成,规则应源于真实事故,例如“service 返回前禁止
Math.round/toFixed”,避免二次舍入 bug。 - 📏 把规则前置到模型生成阶段:把规则写进项目规则文件或 skill,让 agent 边写边看到指引;但这类预防只是概率性降低风险,不能替代事后检测。
- 🧬 用变异测试检验测试是否真的有效:Stryker 故意改动代码,找出没有任何测试会发现的变化;存活变异往往指向只执行不验证、快照未核实、断言 mock 而非代码的测试。
- 🪤 用 Knip 与自定义脚本清除死代码:Knip 找无人引用的文件/导出/依赖;自定义脚本可遍历入口图找不可达代码,或检查过期的
vi.mock(),把“不知道有多少问题”变成可度量的数量。 - 📑 用 jscpd 抓重复代码:AI 倾向新写一个实现而不是搜索已有实现;jscpd 按不同阈值检测文本重复,JSX 可宽松、业务逻辑应严格。
- 🚥 让每项检查都在 CI 中成为门禁:format/lint/tsc/unit/mutation/build 各自独立运行,分支不过就不能部署;唯一不可跳过的检查才真正有效。
- 💸 注意成本并渐进式落地:误报、过期规则、运行时间和新人理解成本都真实存在;应先以 warning 建立基线并只扫改动文件,再逐条提升为 error,最后才上 CI 门禁。
- 🧠 自动化不能替代人的理解:十项全绿只代表没有触发已知问题;功能对错、抽象时机、架构品味和产品判断仍需人工负责,这套机制是用来减少人工审查范围,而不是取消审查。
工具
serve-sim
- 🚀 serve-sim 被称为 Apple Simulator 的
npx serve,可把已启动的模拟器托管给 Codex、Cursor、Claude Desktop 等 Agent 工具,支持本地、局域网、远程 Mac 与隧道访问。 - 🎥 它通过 Swift 助手用
simctl io捕获模拟器帧缓冲,提供 MJPEG 流、WebSocket 控制通道和 React 预览 UI,无需 Xcode 插件或 App 埋点。 - 🕹️ 支持浏览器中 60 FPS 视频流、底部上滑回主屏、Option 键捏合缩放、键盘与热键转发、拖放图片/视频、日志转发和事件面板,并支持 iOS、iPad、Apple Watch。
- 🧪 主要用于先本地测试托管基础设施,远程托管时隧道化 URL;工具与 React Native 无关,作者来自 Expo。
- ⚙️ 环境要求:macOS、Xcode 命令行工具(
xcrun simctl)、Node 20+ LTS;运行 CLI 不需要 bun;相机注入助手需 macOS 14+;仅支持 Apple Silicon arm64,不支持 Intel。 - ⌨️ Xcode 27 键盘输入需 Device Hub 运行且目标模拟器窗口可见并前台,可能还需辅助功能权限;可设
SERVE_SIM_DISABLE_DEVICE_HUB_KEYBOARD=1禁用桥接。 - 🖥️ 核心命令包括
serve-sim [device...]启动默认localhost:3200预览,--no-preview仅前台流,以及gesture、button、type、rotate、ca-debug、memory-warning、event-log等。 - 🎛️ 常用选项有
-p/--port、-d/--detach、-q/--quiet、--panes、--fit、--theme、--codec、--list、--kill;可指定多个模拟器,或留空附加全部已启动模拟器。 - 📷 相机注入:
serve-sim camera <bundle-id>可替换单个 App 的相机源,支持 placeholder、file、webcam,并可通过camera switch、camera mirror、camera status等热切换而无需重启 App。 - 🧠 相机注入原理:主机侧助手把 BGRA 帧写入 POSIX 共享内存,注入 dylib 通过
DYLD_INSERT_LIBRARIESswizzle AVFoundation;每设备一个助手,可被同一模拟器多个 App 共享。 - 🤖 Agent Skill 位于
skills/serve-sim,可教 Claude Code、Cursor、Codex CLI、Gemini CLI 等通过 CLI 驱动模拟器;可用bunx add-skill EvanBacon/serve-sim添加。 - 🧩 集成方式:Claude Code Desktop 可通过
.claude/launch.json配置;Expo 可在metro.config.js挂载simMiddleware,访问http://localhost:8081/.sim。 - 🔌 可嵌入开发服务器:
serve-sim/middleware是 Connect 风格中间件,适用于 Metro、Vite、Next、Express;单端口/远程代理用proxyHelpers: true,并需把upgrade事件交给handleUpgrade,TLS 反代转发X-Forwarded-Proto。 - 🏗️ 工作原理:iOS Simulator →
simctl io→serve-sim-bin(Swift)→ MJPEG/WS → 浏览器;状态文件在$TMPDIR/serve-sim/;Swift 助手独立运行,CLI 通过bun build --compile嵌入,npm 安装即可。 - 📦 开发与许可:使用
bun install、build、build:swift、dev;许可证为 Apache-2.0;仓库约 2.8k stars、148 forks、161 commits。
fast-check
fast-check 是由 dubzzz 创建并用 TypeScript 编写的 JavaScript/TypeScript 基于属性测试框架,类似 QuickCheck。它通过随机生成输入来验证代码属性,并在失败时自动收缩到最小反例,适合单元测试、模糊测试、模型测试与竞态检测。
- 🧪 核心定位:用于 JavaScript/TypeScript 的属性测试框架,验证“对所有满足前置条件的输入,断言都应成立”。
- 📦 安装方式:支持 pnpm、yarn、npm,例如
pnpm add -D fast-check。 - 🔌 测试集成:可配合 AVA、Jasmine、Jest、Mocha、Tape 等测试框架使用,并附有 Mocha 示例。
- 🐞 失败诊断:属性失败时会报告种子、路径、收缩次数等信息,帮助快速定位实现问题。
- 🧠 核心优势:强类型、TypeScript 友好,提供
map、chain、fc.pre(...)、fc.gen()等扩展能力。 - 🧩 智能生成与收缩:默认偏向同时生成小值和大值,支持
fc.oneof收缩,更易找到反例。 - 🛠️ 调试能力:支持 verbose 模式、最小反例重放、自定义样例、
fc.context日志记录。 - 🏗️ 高级测试:支持模型测试,可用于测试 UI、API、状态机,并检测异步代码中的竞态条件。
- ✅ 广泛信任:被 Jest、Jasmine、fp-ts、io-ts、Ramda、js-yaml、query-string 等项目使用,并帮助发现过开源项目 bug。
- 📊 仓库数据:约 5.1k stars、212 forks、58 issues、14 PR、6,814 commits,采用 MIT 许可证。
- 🧾 兼容性:4.x 需要 Node ≥12.17.0、ES2020、TypeScript ≥5.0;旧版本支持更低环境。
- 🤝 社区贡献:拥有大量贡献者,遵循 all-contributors 规范,欢迎各种形式的贡献。
- 💸 赞助支持:可通过 GitHub Sponsors 或 OpenCollective 赞助项目。
- 📚 文档资源:提供入门教程、内置/自定义 arbitraries、属性运行器、API 参考和示例。
react-devtools-cdt-mcp
这是 React 仓库中 react-devtools-cdt-mcp 包的说明,属于实验性浏览器库,用于把 React 检查与性能分析工具注册到 chrome-devtools-mcp,本身不是 MCP 服务器,需在页面中于 React 之前导入,并依赖实验性第三方工具支持。
- 🧪 实验性库:基于
chrome-devtools-mcp的实验性第三方开发者工具 API,用于向 MCP 客户端暴露 React 检查与性能分析能力。 - 🌐 浏览器库定位:需在受测页面中导入,
chrome-devtools-mcp会从页面发现 React 工具;它不是 MCP 服务器,不应放入 MCP 客户端配置。 - 📦 安装方式:
npm install react-devtools-cdt-mcp。 - ⚙️ 使用要求:在 React 之前导入
react-devtools-cdt-mcp/register,以确保 DevTools hook 先于 React 初始化安装;该入口在非浏览器环境会抛错。 - 🔌 自定义目标:包根无副作用,并导出
register、buildToolGroup等底层 API。 - 🛠️ MCP 配置:需在 MCP 客户端配置中加入
--categoryExperimentalThirdParty=true,并要求chrome-devtools-mcp 1.3.0+。 - 🔍 工具调用:React 工具会出现在
list_3p_developer_tools中,可通过execute_3p_developer_tool({toolName, params})或evaluate_script(window.__dtmcp.executeTool(toolName, params))调用。 - 🔐 隐私提示:这些工具可能向 MCP 客户端暴露组件 props 和 hook 值,仅建议在本地或可信调试会话中使用。
- 🆔 UID 约定:组件以稳定 uid(如
r5)标识,跨工具和重渲染保持一致,但页面重载后失效。 - 📤 输出约定:工具返回普通 JavaScript 值;失败时返回
{error: string}。 - ⏱️ 时长约定:性能分析时长单位为毫秒;若构建未收集性能计时则返回
null。 - 🌳
react_get_component_tree:获取组件树快照,支持depth和rootUid,返回节点数组。 - 🔎
react_get_component_by_uid:获取单个组件详情,可选includeHooks;检查 hooks 会重新渲染组件渲染函数,但不运行 effects。 - 🧩
react_get_component_by_dom_element:根据页面 DOM 元素引用获取对应 React host 组件详情。 - 🔤
react_find_components:按名称子串不区分大小写查找组件,支持分页和限定子树。 - 📍
react_get_component_source:获取组件定义源码位置;host 组件或生产构建可能返回null。 - 🧵
react_get_owner_stack_trace:获取原始 owner 栈追踪,仅 DEV 环境有值。 - 🪜
react_get_parent_stack:获取已渲染父级列表,从直接父级到根,包含 host DOM 组件。 - 🧭
react_get_owner_stack:获取结构化 owner 列表,表示通过 JSX 创建该元素的组件链;仅 DEV 可用,owner 不等于结构父级。 - 🟢
react_start_profiling:启动性能分析会话,记录每次提交的渲染耗时,可选traceName。 - 🔴
react_stop_profiling:停止当前性能分析会话,返回 trace 名称和提交次数。 - 📊
react_get_trace_overview:获取某次 trace 的逐提交概览,包括渲染、布局、被动耗时和变更组件数。 - 📈
react_get_commit_report:获取单次提交的详细报告,组件按actualDuration降序排列。
memlab
memlab 是一个用于检测和调试内存泄漏的工具,支持浏览器、Node.js 和 CI 环境,提供自动化泄漏检测、堆分析、可视化调试及 AI 集成等功能,工作原理是通过定义场景、运行测试并追踪引用链来定位泄漏。
- 🔍 浏览器泄漏检测:通过 Puppeteer 驱动应用,自动对比堆快照并聚类真正的泄漏对象。
- 🧩 堆遍历 API:提供面向对象的快照访问接口,支持 Chromium、Node.js 等,可构建自定义泄漏检测器。
- 🛠️ 内存 CLI 工具箱:内置重复字符串、超大对象和无限增长等分析,帮助发现优化机会。
- 🖥️ MemLens 调试:在浏览器页面内直接可视化并交互式调试泄漏,无需离开测试页面。
- ✅ Node.js 断言:单元测试可捕获自身堆快照并断言对象已释放,在 CI 中提前发现回归。
- 🤖 MCP 服务器集成:可将堆快照交给 Claude Code 或 Cursor 等 AI 代理,用自然语言调查内存问题。
- 📝 三步工作流程:编写测试场景(如点击操作)、运行 memlab CLI、通过引用链报告泄漏位置。
- 🔗 引用链追踪:从 GC 根节点到泄漏对象完整展示引用关系,聚合相似泄漏,减少修复数量。
- ⚡ 快速上手:使用
npm install -g memlab安装即可开始泄漏检测。
更新
发布 pnpm 12.4 · pnpm/pnpm · GitHub
pnpm v12.4.0 发布,重点支持在同一工作区管理 npm、Python 与 Cargo 依赖,新增 pnpm pipeline 任务编排,并带来大量锁文件、注册表、Windows 和跨平台修复。
- 🐍 支持 Python 依赖:启用
python.enabled,用pnpm add pypi:<package>安装,支持pyproject.toml、pylock.toml、托管.venv及冻结/离线安装。 - 🦀 支持 Cargo 依赖:启用
cargo.enabled,用pnpm add crate:<package>安装,支持 crates.io、自定义 sparse registry 和凭据认证。 - ⚙️ Python 与 Cargo 均可通过
pnprServer加速解析,不支持时回退本地解析。 - 🧩 新增
pnpm pipeline [name]:安装冻结依赖并运行pipelines中声明的任务图,任务失败后仍继续执行。 - 👀
pnpm pipeline --dry-run可预览任务图,不安装配置依赖或运行 workspace hooks。 - 💻 新增平台支持:Android arm64/x64、FreeBSD x64、Linux ppc64le、s390x、RISC-V。
- 🧹 新增
trustPolicyExcludePrune,可在add/update/remove时自动清理未使用的trustPolicyExclude,默认关闭。 - ✅ 新增
pnpm change check,用于 CI 校验包版本是否符合versioning.epics和versioning.fixed分组。 - 🔐 注册表元数据按 URL 路径与协议隔离,避免混用不同 registry 的版本、tarball 或 HTTP/HTTPS 元数据。
- 🧾
pnpm cache view现在显示完整 registry URL,相关解析脚本需要更新。 - 🛠️ 新增构建脚本或
binding.gyp的补丁会触发构建审批;支持--allow-build=!<pkg>和approve-builds保存决定。 - 🌐
.npmrc中的 registry 优先于pnpm login保存的全局配置,修复登录后使用错误 registry。 - ⏱️
fetch-timeout改为限制无进展时间,慢速大文件下载不再超时。 - 🚀 提升大型工作区安装、
pnpm deploy、warm global virtual store 等场景性能,并修复相关锁文件错误。 - 📦 修复
pnpm add --workspace <pkg>,支持workspace:协议;add/install接受jsr:、npm:、workspace:等协议前缀。 - 🔁 布尔标志支持显式值,如
--prod=false;pnpm install <pkg>支持--offline与--prefer-offline。 - 🧷 修复
frozen-lockfile、符号链接锁文件、lockfileDir版本固定、pnpm import、patch-commit、版本范围上界等问题。 - 🪟 修复 Windows 下
pnpm setup、命令 shim 重试、shellEmulator参数转发、store 路径反斜杠等兼容问题。 - 🔍 其他改进:
audit汇总排除忽略项、pack --json错误 JSON、outdated -r表格换行、shell 补全支持pn别名、pnpm version -m短别名。
React DevTools 8.0.0
React DevTools 8.0.0 于 2026 年 9 月 8 日发布,重点是将 Suspense 标签页默认开启、移除 Timeline Profiler 并转向浏览器 Performance 面板,同时让 Elements 面板能显示对应 React 组件。本次更新还包含大量功能改进与错误修复,涉及 Profiler、Suspense、搜索导航、连接、过滤器、CSP 兼容性等。
- 🧩 Suspense 标签页默认开启,可直接检查组件挂起原因,无需额外开启。
- ⏱️ 移除 Timeline Profiler 标签页及相关代码;React 性能分析改用浏览器 Performance 面板中的 React 轨道。
- 🔍 在浏览器 Elements 面板检查 DOM 节点时,可看到匹配的 React 组件,并新增 React Element 窗格。
- 📊 Profiler 空状态围绕主操作重新设计;新增提交视图组件搜索、开始/停止分析快捷键、提交导航快捷键、父级堆栈工具。
- 🧵 Suspense 标签页支持列出命名 Activity、按结束时间排序时间线、与主文档同步滚动;Activity 子树在隐藏模式下显示并变暗。
- 🛠️ 新增组件搜索结果直接导航、忽略列表堆栈帧披露、显示 React.optimisticKey、允许重命名 Host Component props。
- 🌐 支持 React DevTools 客户端连接自定义 host/port/path;在 sandbox CSP 页面中提供最小支持;在 React 检测前创建扩展面板。
- 🔄 初始加载即应用组件过滤器,并在过滤器变化时更新检查元素;改进 changed hooks 检测;禁用 Strict Mode 日志变暗设置。
- 🐛 修复 fallback Fiber 内容协调、嵌套 HOC 名称提取、prerender 时连接/重连、WhatChanged 滚出视图、控制台占位符与转义、独立错误 HTML 注入等问题。
- 🐛 修复 -Infinity 保留、鼠标离开 DevTools 清除高亮、空 Suspended By 区块、旧 React 页面忽略新生产 renderer、类组件错误模拟崩溃、ContextMenu 空列表崩溃、AMD 模块、hoistables 内存泄漏。
- 🐛 修复性能分析相关问题:断开子树时长、过滤 Activity 子节点崩溃、过滤节点误报重渲染、初始操作提交树构建、切换 profiler 根时提交索引重置、console 链接、useSyncExternalStore hook 索引、Activity slice 解码等。
Vitest 5.0
Vitest 5 正式发布,这次大版本以性能为核心,带来了全链路的速度优化和多项新功能,如 Trace View、嵌套项目继承、vi.when 条件 Mocking、全新的 Benchmarking API 等,同时收紧了默认行为和断言检查,并引入了一些破坏性变更(要求 Vite ≥6.4 与 Node ≥22.12)。
- 🚀 性能提升显著:基于多套基准应用测量,vm 池、Browser Mode 和大型隔离套件速度提升明显,如 deps-heavy 提升 53%,大型 monolith 提升 19%。
- ⚡ 内联项目如果没有修改 Vite 配置,会复用声明它的 Vite server,共享文件只转换一次。
- 💾 文件系统模块缓存(fsModuleCache)已稳定,可在多次运行和不同 Vitest 进程间复用转换后的模块。
- 🔄 主进程与 worker 之间减少往返通信,预热模块一次即可送达 worker。
- 🧪 vmThreads/vmForks 重写:跨上下文复用编译代码、预预热模块图,并支持 require(esm)。
- 🌐 Browser Mode 更快:预打包自身运行时、启动 Vite 时预热浏览器、自适应打开浏览器会话,并减少每文件往返。
- 📦 安装体积更小:Vitest 现在打包自己的依赖,减少了 node_modules 数量和解析时间。
- 📊 覆盖率更快:v8 provider 有界内存合并与预编译 glob,istanbul 迁移到维护的 @vitest/istanbuljs 包。
- 🕵️ 新增 Trace View(Browser Mode):记录每个交互、断言和 page.mark 的 DOM 快照,可在 UI/HTML 报告中逐步回放调试。
- 📂 嵌套项目与继承增强:内联项目默认继承根配置,被引用的配置可作为容器定义自己的 projects,--project 支持 -p 简写。
- 🎭 新增 vi.when API:按参数(深比较 + asymmetric matchers)为 spy 定义不同返回值或拒绝行为,并支持 thenReturnOnce/times 限制。
- ⏱️ Benchmarking 重写:bench 作为 test-context 夹具,可在普通 test() 内使用并参与 fixture/断言;支持 writeResult、bench.from() 基线对比和自定义 provider。
- 🌳 Locator 找不到元素时显示 ARIA 树,方便调试;locators 默认真实匹配(exact: true),避免 getByText('Item') 误匹配 "Item 1"。
- 🕰️ Fake timers 现在会同时模拟 Temporal API(基于 @sinonjs/fake-timers v15.4),并可通过 toNotFake 关闭。
- ⚠️ 异步断言(resolves、rejects、toMatchFileSnapshot)未 await 时直接失败;expect.poll 超时会 reject,并提供 AbortSignal。
- 📝 断言与类型系统强化:Matchers 接口引入返回类型和接收类型参数,自定义 matcher 可精确匹配期望参数类型。
- 🧹 clearMocks 默认启用:每个测试前自动 vi.clearAllMocks(),避免调用历史跨测试污染;可用 clearMocks: false 恢复旧行为。
- 📁 报告器与附件统一输出到根目录下的 .vitest 目录,HTML reporter 新增 singleFile 选项生成单文件报告,方便上传 CI 产物。
- 🔁 CLI 新增 --repeats 循环运行所有测试,用于定位 flaky;还提供 vitest doctor 自动推荐加速配置。
- 🔻 其他改进:新增 injectCjsGlobals 开关、coverage 支持子进程/worker 跟踪、junit 命名兼容选项、test.for 支持非 ASCII 等。
- 🔨 破坏性变更:要求 Vite >=6.4.0、Node.js >=22.12.0;建议升级前阅读详细迁移指南。
Motion 是你本不会注意到的部分
动效是用户界面里“不应该被注意到”的关键细节——它让人明白刚刚发生了什么,让操作连贯流畅。作者将自己的博客比作一块好却煎坏的牛排,并围绕六个细节进行动效打磨,让网站从“能用”变成“真正有质感”。
- 💡 动效的本质:它的存在是引导用户感知界面变化,而不是为了炫技;缺少动效时,每个操作都会变成生硬跳变,像一台“没有上油的生锈机器”。
- 🧾 列表入场改为整体级联:文章列表不再由每一行各自淡入,而是作为单一整体交错进入,行间间隔约 50ms,约 0.5 秒内完成。父组件控制间隔,子组件只描述自己的动画,因此即使列表被过滤或重排也不会错位。
- 🔍 搜索对话框加入过渡:打开时从 96% 缩放淡入,背景稍快变暗以将视线引向面板;关闭动画更短促。借助
AnimatePresence让退出动画成为可能,同时修复了点击外部无法关闭、以及焦点未正确落入输入框的问题。 - 📉 头部导航向下收缩让开:向下滚动时头部缩小约 6% 并略微上提,回滚时恢复。通过滚动位置驱动 MotionValue 而不是 React state,避免每次滚动都触发重渲染;并且用迟滞区间避免在临界点反复切换,且只是视觉缩放,不改变实际布局。
- 📊 文章阅读进度条:页面顶部新增一条 2px 细线,表示阅读进度。使用
useScroll指定文章容器为测量目标,而非整个页面,并附加弹簧平滑处理;不显示百分比数字,避免干扰阅读,同时保证文章结束时进度条准确停在满格。 - 🖱️ 统一所有卡片的悬停反馈:之前每种卡片都有不同缩放和速度,作者将效果统一为“卡片上移 2px+ 图片放大到 1.03”,使用纯 CSS 实现。并通过
@media (hover:hover)限制为真正的鼠标设备,避免触屏卡死在悬停态;同时让:focus-visible获得完全一致的视觉反馈,确保键盘导航也不被忽略。 - 🖼️ 页面之间加入视图转场:点击文章卡片时,旧的索引页和新的文章页会交叉淡化,且被点击的卡片图片会通过 View Transitions API 中相同的
view-transition-name被浏览器识别,从而平滑移动到文章顶部图位置。等待新页面渲染完成后再启动捕获,否则转场会失效;不支持该 API 或开启减少动效时会自动回退为瞬时导航。 - ✨ 真正的价值并不在单个功能中:这些改动不会有人专门感谢,也看起来“像浪费一个晚上”,但配合在一起,就构成了普通网站与“有人认真思考过每一个细节”之间的差别。写作、布局、颜色都没变,仍是同一块牛排,只是现在被恰当地烹饪,能尝到鲜甜的肉汁。
其他
科学分成两种。"科学 1"是一种理想化的追求真理,"科学 2"是实际的科学实践,更多是一种社交活动,要考虑社会和政治现实。
如果你是一个博士生,你必须知道,你主要从事科学 2,而不是科学 1。
-- 《博士生不要试图改革科学》
关于向上管理以及如何做
向上管理不是讨好上级,而是从领导视角出发,主动沟通、协同和支持,确保双方共同成功。它是区分同水平人才成长速度的关键能力,核心在于弥合自己意图与他人感知之间的差距,并通过预期管理建立信任。
- 🧭 先理解上级视角:思考“什么样的下属会让领导放心又欣赏”,以此指导自己的行为。
- 🤝 管理上级的实质:不是控制或迎合,而是看到领导看不到的团队实情,同时理解领导的处境与目标。
- 🎯 胜任本职是第一前提:明确领导的期望,确保自己的优先级与团队方向一致,并努力把该做的事做好。
- 🛡️ 成为可靠的人:主动汇报进度,不等催促;让领导能把任务交给你后不用再担心。
- 📢 宁可多沟通,也不要制造“惊喜”:无论事情好坏都提前同步,问题出现时带着缓解方案汇报,避免因隐瞒失去信任。
- 💡 带着方案说问题:说出风险的同时也要给出解决思路、所需支持,而不是只抛困难。
- 🔁 用“复盘”替自己加分:下次见面先回顾上次达成的共识、各自承诺和进展,既体现负责,也促使对方履行承诺。
- 🧾 把“自我品牌”当动作来经营:别人如何感知你的“做了什么、怎么做、为何做”比你自己怎么看更重要。
- 🚫 别怕被当成“拍马屁”:管理上级是正当的专业技能;你的经理无论如何都会影响你,主动经营这段关系才最有益。