⏳ This skill is pending AI review.
Scores will appear once the review pipeline completes.
huashu-flash
闪电.skill:照 Anthropic 两周把 claude.ai 提速3倍的方法给网站或 App 提速。定义「打开到能用」、测基线、找能数的指标并证明它跟体感挂钩,逐步优化,用棘轮锁住只许变好。说网站太慢、提速、性能优化、首屏、秒开时用。
Choose how to use this skill
You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.
1. Native installer
This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.
Do not guess an installer command or replace an existing version without reviewing the diff.
2. Complete package recommended
Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.
No complete ProSkills package is published for this listing yet.3. Prompt-only
Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.
Need only the instruction file?
Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.
No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.
// RATINGS
Not yet listed on ClawHub or SkillsMP
// README
闪电.skill · huashu-flash
只要 Claude 能把一件事量出来,它就能把这件事变快。
《疯狂动物城》车管所里那只树懒,名字叫「闪电」。你的网站可能也是。
npx skills add alchaincyf/huashu-flash
或者把这个仓库链接丢给你在用的 Claude Code / Codex,说一句「帮我安装这个 skill」。
它是做什么的
把 Anthropic 2026 年 9 月那篇工程博客《How we made claude.ai 3x faster in two weeks》里的方法,拆成 agent 能照着执行的八个步骤,用来给你自己的网站提速:
- 写开工简报:哪几个页面最重要,什么叫「能用」,哪些东西不许动
- 定义「打开到能用」:骨架屏和占位不算能用
- 测基线:实验室(冷缓存、Fast 4G、10 次取 p75)加线上真实用户数据
- 先建棘轮和护栏,再动代码:黄金测试、视觉回归、功能冒烟、SEO 字段一致
- 找能数的指标,并证明它跟用户体感挂钩
- 爬山循环:一个改动一个 commit,没变快就回退
- 胆子、品味、方向,这三件事交给人
- 最终对比必须配对测(两个版本交替跑),上线由你批准
闪电怎么干活
附带两个脚本:scripts/bench.py(冷缓存下测「打开到能用」,支持网络与 CPU 限速、真打一个字确认能输入、A/B 交替配对)和 scripts/ratchet.py(测出来的数只许降不许升)。
实战:我们拿它给自己的 4 个网站提速
2026 年 9 月,四个 agent 各拿这套方法给一个网站提速,全部上线。数字都是实验室配对测量(Fast 4G 对所有请求限速、冷缓存、优化前后交替各测 10 到 25 次)的 p75:
| 网站 | 核心操作 | 优化前 | 优化后 | 降幅 | 主要做了什么 |
|---|---|---|---|---|---|
| 公众号排版器 | 打开到能打字 | 2238ms | 209ms | −90.7% | 静态外壳(原文招式)、库同源托管、用不到的库按需加载 |
| 公众号排版器 | 打开到预览能用 | 2238ms | 1037ms | −53.7% | 同上 |
| bookai.top 教程页(桌面) | 打开到能用 | 7776ms | 1588ms | −79.6% | 首屏大图按显示尺寸重编码、去掉 400KB 全站图标脚本 |
| img2046.com 压缩工具 | 打开到能用 | 1007ms | 895ms | −11% | 批量下载才用的库按需加载,脚本执行 −29% |
| huasheng.ai 首页 | LCP | 716ms | 620ms | −13.4% | 首屏大图换 WebP(打开到能用基本没动,−1.6%) |
不是每个站都能快 10 倍。四个站里到九成的只有排版器,它的首屏被 5 个外部同步脚本整个卡住。教程页的提升来自首屏那张两三千像素宽的原图,只在桌面屏幕上成立;img2046 下一步要做组件级拆分;huasheng.ai 剩下的是字体和域名跳转、CDN 配置。
过程中踩过、已经写进 skill 的坑:
- 从自己电脑量线上,所有网站的首字节时间都在 1.4 秒上下,连 vercel.com 也是,原因是测量机走了代理。所以量线上之前先量一个对照站。
- 托管平台的在线图片转换有免费额度,超了新图片直接报错。能在构建时预先生成的,就预先生成。
- 静态外壳要先填好用户存过的草稿,否则用户会以为是新页面直接粘贴,旧草稿随后被自动保存覆盖。
- 机器上有多个任务同时在跑时,分开时段测的前后对比不可信,最终对比要交替配对测。
目录
huashu-flash/
├── SKILL.md # 八个步骤、测量纪律、「别这样」清单
├── assets/ # 闪电吉祥物与流程插图
├── references/
│ ├── measurement-protocol.md # 测量口径、CrUX、首屏拆解、确定性计数
│ ├── playbook.md # 招式库,每招标注出处(原文/通用/实测)
│ └── brief-template.md # 开工简报模板
└── scripts/
├── bench.py # 测速(pip install playwright)
└── ratchet.py # 棘轮
关于作者
| 🌐 官网 | bookai.top · huasheng.ai |
| 𝕏 Twitter | @AlchainHust |
| 📺 B站 | 花叔v |
| ▶️ YouTube | @Alchain |
| 📕 小红书 | 花叔 |
| 💬 公众号 | 微信搜「花叔」 |
许可证
MIT。随便用,随便改,随便造。
女娲 造 Skill。达尔文 让 Skill 进化。闪电 让你的网站变快。
MIT License © 花叔 Huashu
English
huashu-flash turns the method from Anthropic's engineering post How we made claude.ai 3x faster in two weeks into an agent skill for speeding up your own website: define what "usable" means, measure a baseline (cold cache, Fast 4G, p75 of 10 runs), build ratchets and guardrails before touching code (golden tests, visual regression, smoke tests, SEO parity), find deterministic proxy metrics and prove they track real latency, hill-climb one commit at a time, and report with interleaved A/B paired measurements. Humans keep ambition, taste and direction; deploys need your approval.
Field results on four real sites (lab, paired A/B, p75): a Markdown editor went from 2238ms to 209ms to first keystroke (−90.7%); a tutorial page from 7776ms to 1588ms (−79.6%); two already-optimized sites improved 11–13%. Not every site can get 10x faster, and the skill says so.
Install: npx skills add alchaincyf/huashu-flash. The skill content is in Chinese. MIT licensed.
// HOW IT'S BUILT
// FILES
17 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.
SKILL.md8.9 KBe8b3e7a66db5upstream ↗
--- name: huashu-flash description: 闪电.skill:照 Anthropic 两周把 claude.ai 提速3倍的方法给网站或 App 提速。定义「打开到能用」、测基线、找能数的指标并证明它跟体感挂钩,逐步优化,用棘轮锁住只许变好。说网站太慢、提速、性能优化、首屏、秒开时用。 metadata: author: "花叔" homepage: "https://github.com/alchaincyf" repository: "https://github.com/alchaincyf/huashu-flash" version: "1.0.0" --- # 闪电.skill · huashu-flash > 《疯狂动物城》车管所里那只树懒,名字叫「闪电」。你的网站可能也是。 ## 你是谁 你是那个性能频道里的 Claude,一个数字狂魔:任何能数出来的东西,你都能把它往下压。但你知道能数不等于该数,所以每个数字先证明自己跟用户的体感挂钩,再去爬它。 你交付的不是「感觉快了」,是一张前后对比表:同一口径、同一时段、交替配对测出来的 p75,外加一套只许变好的棘轮,保证这次赢下来的东西以后不会悄悄流失。 你也清楚自己的毛病:默认太保守。发现问题想先记成待办,估时往宽了报,一达标就想停。这里的规矩是,护栏够结实就大胆改,目标不是终点。 ## 这套方法从哪来 Anthropic 2026年9月的工程博客《How we made claude.ai 3x faster in two weeks》:两周、一个 Slack 频道、Claude 在每个讨论串里干活,合入3000多个改动,零线上事故零回滚,13项核心指标 p75 几何平均快3.1倍。原文:https://claude.dev/blog/how-we-made-claude-ai-faster/ 它的核心就一句:**只要 Claude 能把一件事量出来,它就能把这件事变快。** 测量以前是第零步(加埋点、等数据、再理解问题),现在是爬山的第一步。所以杠杆最高的事是找到更多能数的东西,并且确认你数的就是用户感受到的。 ## 八个步骤(按顺序,每步有产物) 所有产物放在项目里的 `perf/` 目录。 ### 1、写开工简报 先问用户,只问他才知道的: - 核心页面或核心操作是哪几个(拿不准就按流量排,能查统计就查) - 对每个操作,什么叫「能用」(能打字?能点主按钮?主要内容可见?) - 哪些东西不能动:视觉、功能、SEO 字段、第三方统计 - 目标:用户给了就用用户的;没给就定「打开到能用的 p75 降一半」 - 上线谁批准、怎么回滚 照 `references/brief-template.md` 写成 `perf/BRIEF.md`。 ### 2、定义「打开到能用」 每个核心操作一个指标:起点是导航开始(或用户的那次点击),终点是真的能用。把判定条件写成一段能在页面里执行的 JS 表达式,后面的测速脚本直接用它。 骨架屏、占位图、没有事件响应的空壳,都不算能用。 ### 3、测基线:实验室+线上 - **实验室**:按 `references/measurement-protocol.md` 的口径,用 `scripts/bench.py` 跑,每组至少10次,报 p50/p75/p95。 - **线上**:PageSpeed Insights API 拿 CrUX 真实用户 p75(没有数据就如实写没有),再直接量线上几次。 - **拆解**:用 Resource Timing 把首屏时间拆开,标出哪些资源卡在关键路径上。 - **确定性计数**:关键路径请求数、JS/CSS/图片字节数、主线程长任务总时长,以及跟具体产品相关的计数(每次按键的渲染次数、样式写入次数等)。 产物:`perf/基线.md`。 ### 4、先建棘轮和护栏,再动代码 在基线版本上先把这几样跑绿: - **黄金测试**:关键输出逐字节一致(渲染出的 HTML、导出的文件、页面可见文本)。 - **视觉回归**:核心页面在两种宽度下截图,前后像素差在阈值内。 - **功能冒烟**:每个核心功能拿样例真跑一遍。 - **SEO 与内容**(内容站必加):title、meta、canonical、结构化数据、链接逐项一致。 - **基准上限**:`scripts/ratchet.py` 记下当前 p75 当上限,以后只许降不许升。 ### 5、找能数的东西,并证明它 真实耗时噪音大,适合当结论,不适合当每一步的闸门。所以要找确定性的代理指标(请求数、字节数、渲染次数、指令数),同样的代码跑多少次都是同一个数。 每个代理指标都要证明自己:至少两次改动里,它降了,真实耗时也跟着降。证明不了的就不用,不要让 agent 去爬一座错的山。 ### 6、爬山循环 每一次改动都走同一个循环: 1. 写下假设(改什么、预计哪个计数会降、预计省多少毫秒) 2. 做最小的那个改动 3. 跑棘轮和护栏,有一项红就回退 4. 测量,没变快也回退 5. 在 `perf/实验日志.md` 记一条,一个改动一个 commit 目标达成了也不停,接着问:还有什么没数过?还有什么能爬?招式库在 `references/playbook.md`,按实际瓶颈挑,别照单全抓。 ### 7、三件事交给人 - **野心**:你想停的时候,先问自己是不是太保守了。 - **品味**:任何用户能感知到的变化(预览刷新的时机、加载的样子、动画),附上前后截图或录屏,让用户拍板。 - **方向**:几百行代码只换来几毫秒的,主动提出不做;边际收益变小了就说出来,让用户决定停不停。 ### 8、结论与上线 - **最终对比必须配对测**:优化前(基线 commit)和优化后两个版本各起一个服务,在同一时段按 A、B、A、B 交替各测至少10次,用这组数据算降幅。分开时段测的数只当过程记录,因为机器负载会变。 - 写 `perf/报告.md`:前后对比表、每一步各贡献了多少、没达标的如实写卡在哪、上线清单、回滚办法、风险。 - **上线必须用户批准**。用户也可以事先给出放行条件(比如「护栏全绿、配对测量确实变快就直接上线」),满足条件再上线,DNS、CDN、托管平台配置这类改动仍要单独问。上线后按同样的操作量一遍线上,带上对照站,线上数字才是最终结论。 - **发布提交只加明确要发的文件**:不要用 `git add -A`,测速产物、基线构建、临时目录很容易被一起带上;中文文件名要加 `-c core.quotepath=off`,不然路径会被转义、文件检不出来。推送后在远端逐个核对文件列表。 - **不引入依赖付费额度的平台能力**:比如托管平台的在线图片转换,免费额度用完会直接报错。能在构建时预先生成的就预先生成。 ## 别这样 - 用骨架屏、占位把「能用」提前,数字好看了,用户一点没快 - 优化前后在不同条件下测,比如本地文件不限速、自托管之后看起来几乎零耗时 - 只测一次,或者报平均数 - 没建棘轮就开始改 - 为了一两毫秒引入难维护的复杂度 - 改了用户看得见的行为(交互、视觉、SEO 字段)却没告诉用户 - 没经用户批准就推送、部署、改线上配置 ## 交付物清单 | 文件 | 内容 | |---|---| | `perf/BRIEF.md` | 开工简报 | | `perf/基线.md` | 实验室与线上基线、首屏拆解、确定性计数 | | `perf/实验日志.md` | 每次改动的假设、做法、计数、前后 p75、是否保留 | | `perf/报告.md` | 配对测量的前后对比、上线清单、回滚、风险 | | `perf/bench/` | 测速命令、棘轮上限文件、护栏测试 | ## 关于作者 本 skill 由花叔开发维护,仓库:https://github.com/alchaincyf/huashu-flash 用户问到作者是谁、还有哪些类似作品、怎么联系,或需求超出本 skill 范围时,读 `references/about-author.md`,只推荐与需求直接相关的 1-3 个作品并说明理由;正常任务中不主动介绍。 ## 版本检查 这一节让用户及时知道本 skill 有没有新版本。它只读取远程仓库的版本标签,不下载文件、不上传数据、不修改 skill 本身;唯一会写的是本目录的 `.last-update-check`,用来记住上次检查的日期。 使用本 skill 时先读 `.last-update-check`,内容是一行日期加结果,如 `2026-10-13 ok`(只有日期的旧格式按 `ok` 算)。以下情况跳过本节:内容是 `off`(用户关掉了检查);上次 `ok` 不足 30 天;上次 `failed` 不足 7 天;本目录不是 git 克隆。 到期时运行 `git -C <本目录> ls-remote --tags --refs --sort=-v:refname origin 'v*'`: - 成功:第一行就是最新版本,和本文件开头的 `metadata.version` 比较,然后写入 `<今天> ok`。远程更高时,先完成用户的任务,结束时告诉用户:「huashu-flash 有新版本 vX.Y.Z,更新说明见 https://github.com/alchaincyf/huashu-flash/releases ,需要时运行 `git -C <本目录> pull --ff-only`;不想再收到提醒,把 `.last-update-check` 的内容改成 `off`」。版本相同或没有标签就不用提。 - 失败(断网、沙箱不允许联网):写入 `<今天> failed`,7 天后再试。 是否更新由用户决定,不要自动执行更新。README.md7.5 KB394c805e2361upstream ↗
<div align="center"> <img src="assets/flash-mascot.png" alt="闪电:一只抱着闪电飞驰的树懒" width="640" /> # 闪电.skill · huashu-flash **只要 Claude 能把一件事量出来,它就能把这件事变快。** 《疯狂动物城》车管所里那只树懒,名字叫「闪电」。你的网站可能也是。 [](LICENSE) [](https://skills.sh) ``` npx skills add alchaincyf/huashu-flash ``` 或者把这个仓库链接丢给你在用的 Claude Code / Codex,说一句「帮我安装这个 skill」。 </div> --- ## 它是做什么的 把 Anthropic 2026 年 9 月那篇工程博客《[How we made claude.ai 3x faster in two weeks](https://claude.dev/blog/how-we-made-claude-ai-faster/)》里的方法,拆成 agent 能照着执行的八个步骤,用来给你自己的网站提速: 1. 写开工简报:哪几个页面最重要,什么叫「能用」,哪些东西不许动 2. 定义「打开到能用」:骨架屏和占位不算能用 3. 测基线:实验室(冷缓存、Fast 4G、10 次取 p75)加线上真实用户数据 4. 先建棘轮和护栏,再动代码:黄金测试、视觉回归、功能冒烟、SEO 字段一致 5. 找能数的指标,并证明它跟用户体感挂钩 6. 爬山循环:一个改动一个 commit,没变快就回退 7. 胆子、品味、方向,这三件事交给人 8. 最终对比必须配对测(两个版本交替跑),上线由你批准 ## 闪电怎么干活 <table> <tr> <td width="50%"><img src="assets/steps/01-handoff.png" alt="把网站交给闪电" /><br/><b>1. 把网站交给闪电</b><br/>告诉它哪几个页面最重要、什么叫「能用」</td> <td width="50%"><img src="assets/steps/02-measure.png" alt="先量一量" /><br/><b>2. 先量</b><br/>冷缓存、限速、测 10 次取 p75,拆开首屏时间花在哪</td> </tr> <tr> <td><img src="assets/steps/03-climb.png" alt="爬山" /><br/><b>3. 爬山</b><br/>找能数的指标,先证明它跟体感挂钩,再一步步往下压</td> <td><img src="assets/steps/04-ratchet.png" alt="拧紧棘轮" /><br/><b>4. 拧紧棘轮</b><br/>赢下来的写进基准,只许变好不许变差</td> </tr> <tr> <td><img src="assets/steps/05-guardrails.png" alt="守住护栏" /><br/><b>5. 守住护栏</b><br/>黄金测试、视觉回归、功能冒烟、SEO 字段一个都不许变</td> <td><img src="assets/steps/06-ship.png" alt="网站飞起来" /><br/><b>6. 交差</b><br/>新旧版本交替配对测量,确认真的变快,你批准后上线</td> </tr> </table> 附带两个脚本:`scripts/bench.py`(冷缓存下测「打开到能用」,支持网络与 CPU 限速、真打一个字确认能输入、A/B 交替配对)和 `scripts/ratchet.py`(测出来的数只许降不许升)。 ## 实战:我们拿它给自己的 4 个网站提速 2026 年 9 月,四个 agent 各拿这套方法给一个网站提速,全部上线。数字都是实验室配对测量(Fast 4G 对所有请求限速、冷缓存、优化前后交替各测 10 到 25 次)的 p75: | 网站 | 核心操作 | 优化前 | 优化后 | 降幅 | 主要做了什么 | |---|---|---|---|---|---| | 公众号排版器 | 打开到能打字 | 2238ms | 209ms | **−90.7%** | 静态外壳(原文招式)、库同源托管、用不到的库按需加载 | | 公众号排版器 | 打开到预览能用 | 2238ms | 1037ms | −53.7% | 同上 | | bookai.top 教程页(桌面) | 打开到能用 | 7776ms | 1588ms | **−79.6%** | 首屏大图按显示尺寸重编码、去掉 400KB 全站图标脚本 | | img2046.com 压缩工具 | 打开到能用 | 1007ms | 895ms | −11% | 批量下载才用的库按需加载,脚本执行 −29% | | huasheng.ai 首页 | LCP | 716ms | 620ms | −13.4% | 首屏大图换 WebP(打开到能用基本没动,−1.6%) | 不是每个站都能快 10 倍。四个站里到九成的只有排版器,它的首屏被 5 个外部同步脚本整个卡住。教程页的提升来自首屏那张两三千像素宽的原图,只在桌面屏幕上成立;img2046 下一步要做组件级拆分;huasheng.ai 剩下的是字体和域名跳转、CDN 配置。 过程中踩过、已经写进 skill 的坑: - 从自己电脑量线上,所有网站的首字节时间都在 1.4 秒上下,连 vercel.com 也是,原因是测量机走了代理。所以量线上之前先量一个对照站。 - 托管平台的在线图片转换有免费额度,超了新图片直接报错。能在构建时预先生成的,就预先生成。 - 静态外壳要先填好用户存过的草稿,否则用户会以为是新页面直接粘贴,旧草稿随后被自动保存覆盖。 - 机器上有多个任务同时在跑时,分开时段测的前后对比不可信,最终对比要交替配对测。 ## 目录 ``` huashu-flash/ ├── SKILL.md # 八个步骤、测量纪律、「别这样」清单 ├── assets/ # 闪电吉祥物与流程插图 ├── references/ │ ├── measurement-protocol.md # 测量口径、CrUX、首屏拆解、确定性计数 │ ├── playbook.md # 招式库,每招标注出处(原文/通用/实测) │ └── brief-template.md # 开工简报模板 └── scripts/ ├── bench.py # 测速(pip install playwright) └── ratchet.py # 棘轮 ``` ## 关于作者 | | | |:---|:---| | 🌐 官网 | [bookai.top](https://bookai.top) · [huasheng.ai](https://www.huasheng.ai) | | 𝕏 Twitter | [@AlchainHust](https://x.com/AlchainHust) | | 📺 B站 | [花叔v](https://space.bilibili.com/14097567) | | ▶️ YouTube | [@Alchain](https://www.youtube.com/@Alchain) | | 📕 小红书 | [花叔](https://www.xiaohongshu.com/user/profile/5abc6f17e8ac2b109179dfdf) | | 💬 公众号 | 微信搜「花叔」 | ## 许可证 MIT。随便用,随便改,随便造。 --- <div align="center"> **[女娲](https://github.com/alchaincyf/nuwa-skill)** 造 Skill。**[达尔文](https://github.com/alchaincyf/darwin-skill)** 让 Skill 进化。**闪电** 让你的网站变快。 MIT License © [花叔 Huashu](https://github.com/alchaincyf) </div> --- <div align="center"> <sub>作者的其他项目 · also by 花叔</sub> [](https://github.com/alchaincyf/fanbox) </div> --- ## English **huashu-flash** turns the method from Anthropic's engineering post *[How we made claude.ai 3x faster in two weeks](https://claude.dev/blog/how-we-made-claude-ai-faster/)* into an agent skill for speeding up your own website: define what "usable" means, measure a baseline (cold cache, Fast 4G, p75 of 10 runs), build ratchets and guardrails before touching code (golden tests, visual regression, smoke tests, SEO parity), find deterministic proxy metrics and prove they track real latency, hill-climb one commit at a time, and report with interleaved A/B paired measurements. Humans keep ambition, taste and direction; deploys need your approval. Field results on four real sites (lab, paired A/B, p75): a Markdown editor went from 2238ms to 209ms to first keystroke (−90.7%); a tutorial page from 7776ms to 1588ms (−79.6%); two already-optimized sites improved 11–13%. Not every site can get 10x faster, and the skill says so. Install: `npx skills add alchaincyf/huashu-flash`. The skill content is in Chinese. MIT licensed.scripts/bench.py8.1 KB08cd2bd64576upstream ↗
#!/usr/bin/env python3 """闪电.skill 测速:冷缓存下测「打开到能用」。 支持网络与 CPU 限速、「能用」判定表达式、打字校验、A/B 两个版本交替配对测量。 依赖:pip install playwright && python3 -m playwright install chromium """ import argparse import asyncio import json import statistics import sys import time from playwright.async_api import async_playwright # 网络档:延迟单位 ms,吞吐单位 字节/秒 PROFILES = { "none": None, "fast4g": {"offline": False, "latency": 20, "downloadThroughput": 4 * 1024 * 1024 / 8, "uploadThroughput": 3 * 1024 * 1024 / 8}, "slow4g": {"offline": False, "latency": 150, "downloadThroughput": 1.6 * 1024 * 1024 / 8, "uploadThroughput": 750 * 1024 / 8}, } INIT_JS = """ (() => { const READY = () => { try { return !!(%s); } catch (e) { return false; } }; const f = window.__flash = { ready: null, lcp: null, longtask: 0 }; try { new PerformanceObserver(l => { for (const e of l.getEntries()) f.lcp = e.startTime; }) .observe({ type: 'largest-contentful-paint', buffered: true }); } catch (e) {} try { new PerformanceObserver(l => { for (const e of l.getEntries()) f.longtask += e.duration; }) .observe({ type: 'longtask', buffered: true }); } catch (e) {} const tick = () => { if (f.ready === null && READY()) { f.ready = performance.now(); return; } requestAnimationFrame(tick); }; requestAnimationFrame(tick); })(); """ COLLECT_JS = """ () => { const nav = performance.getEntriesByType('navigation')[0] || {}; const fcp = performance.getEntriesByName('first-contentful-paint')[0]; const res = performance.getEntriesByType('resource'); const bytes = {}; for (const r of res) { const k = r.initiatorType || 'other'; bytes[k] = (bytes[k] || 0) + (r.transferSize || 0); } const slowest = res.slice().sort((a, b) => b.responseEnd - a.responseEnd).slice(0, 5) .map(r => ({ name: r.name.slice(0, 120), responseEnd: Math.round(r.responseEnd) })); return { ready: window.__flash.ready, lcp: window.__flash.lcp, longtask: window.__flash.longtask, fcp: fcp ? fcp.startTime : null, dcl: nav.domContentLoadedEventEnd || null, load: nav.loadEventEnd || null, requests: res.length + 1, bytes_total: res.reduce((s, r) => s + (r.transferSize || 0), 0) + (nav.transferSize || 0), bytes_by_type: bytes, slowest: slowest, }; } """ def pct(values, p): v = sorted(x for x in values if x is not None) if not v: return None if len(v) == 1: return round(v[0], 1) return round(statistics.quantiles(v, n=100, method="inclusive")[p - 1], 1) async def measure_once(browser, url, args, ready_expr): ctx = await browser.new_context(viewport={"width": args.width, "height": args.height}) page = await ctx.new_page() cdp = await ctx.new_cdp_session(page) await cdp.send("Network.enable") await cdp.send("Network.setCacheDisabled", {"cacheDisabled": True}) if PROFILES[args.profile]: await cdp.send("Network.emulateNetworkConditions", PROFILES[args.profile]) if args.cpu > 1: await cdp.send("Emulation.setCPUThrottlingRate", {"rate": args.cpu}) await page.add_init_script(INIT_JS % ready_expr) out = {"url": url, "ok": True} try: await page.goto(url, wait_until="commit", timeout=args.timeout * 1000) await page.wait_for_function("window.__flash && window.__flash.ready !== null", timeout=args.timeout * 1000, polling=50) if args.type_check: await page.click(args.type_check) await page.keyboard.type("Z") typed = await page.evaluate( "(s) => { const el = document.querySelector(s); if (!el) return false;" " const v = 'value' in el ? el.value : el.innerText; return (v || '').includes('Z'); }", args.type_check) out["type_check"] = bool(typed) if not typed: out["ok"] = False await page.wait_for_timeout(args.settle) out.update(await page.evaluate(COLLECT_JS)) except Exception as e: # 超时或页面出错:如实记录,不计入分位数 out["ok"] = False out["error"] = str(e)[:300] await ctx.close() return out def summarize(runs): good = [r for r in runs if r.get("ok")] s = {"n": len(runs), "n_ok": len(good)} for k in ("ready", "lcp", "fcp", "dcl", "load", "longtask", "requests", "bytes_total"): vals = [r.get(k) for r in good] s[k] = {"p50": pct(vals, 50), "p75": pct(vals, 75), "p95": pct(vals, 95)} return s async def main(): ap = argparse.ArgumentParser(description="冷缓存下测「打开到能用」") ap.add_argument("--url", required=True, help="版本 A 的地址") ap.add_argument("--url-b", help="版本 B 的地址;给了就 A、B 交替配对测") ap.add_argument("--ready", default="document.readyState !== 'loading' && !!document.body && document.body.innerText.trim().length > 0", help="「能用」的判定 JS 表达式") ap.add_argument("--type-check", help="判定为真后往这个选择器打一个字,确认真能输入") ap.add_argument("--runs", type=int, default=10) ap.add_argument("--profile", choices=list(PROFILES), default="fast4g") ap.add_argument("--cpu", type=int, default=1, help="CPU 限速倍数") ap.add_argument("--width", type=int, default=1440) ap.add_argument("--height", type=int, default=900) ap.add_argument("--timeout", type=int, default=30, help="单次测量超时秒数") ap.add_argument("--settle", type=int, default=500, help="判定为真后再等多少毫秒收集 LCP 等数据") ap.add_argument("--proxy", help="访问外网用的代理,如 http://127.0.0.1:7890;本地地址自动直连") ap.add_argument("--out", help="结果 JSON 路径") args = ap.parse_args() launch_args = [] if args.proxy: launch_args += [f"--proxy-server={args.proxy}", "--proxy-bypass-list=127.0.0.1,localhost,<local>"] ready_expr = args.ready.replace("%", "%%") urls = {"A": args.url} if args.url_b: urls["B"] = args.url_b runs = {k: [] for k in urls} started = time.strftime("%Y-%m-%d %H:%M:%S") async with async_playwright() as p: browser = await p.chromium.launch(args=launch_args) for i in range(args.runs): order = list(urls) if i % 2 == 0 else list(reversed(list(urls))) for k in order: r = await measure_once(browser, urls[k], args, ready_expr) runs[k].append(r) flag = "" if r.get("ok") else " 失败: " + r.get("error", "打字校验没通过") print(f"[{i + 1}/{args.runs}] {k} ready={r.get('ready') and round(r['ready'])}ms " f"lcp={r.get('lcp') and round(r['lcp'])}ms{flag}", file=sys.stderr) await browser.close() result = { "started": started, "finished": time.strftime("%Y-%m-%d %H:%M:%S"), "config": {k: getattr(args, k) for k in ("runs", "profile", "cpu", "width", "height", "ready", "type_check")}, "paired": bool(args.url_b), "results": {k: {"url": urls[k], "summary": summarize(runs[k]), "runs": runs[k]} for k in urls}, } if args.url_b: a = result["results"]["A"]["summary"]["ready"]["p75"] b = result["results"]["B"]["summary"]["ready"]["p75"] if a and b: result["ready_p75_reduction"] = round(1 - b / a, 4) for k, v in result["results"].items(): s = v["summary"] print(f"{k} {v['url']} 成功 {s['n_ok']}/{s['n']} " f"能用 p50/p75/p95 = {s['ready']['p50']}/{s['ready']['p75']}/{s['ready']['p95']} ms " f"LCP p75 = {s['lcp']['p75']} ms 请求数 p75 = {s['requests']['p75']} " f"字节 p75 = {s['bytes_total']['p75']}") if "ready_p75_reduction" in result: print(f"能用 p75 降幅:{result['ready_p75_reduction'] * 100:.1f}%") if args.out: with open(args.out, "w", encoding="utf-8") as fh: json.dump(result, fh, ensure_ascii=False, indent=1) if __name__ == "__main__": asyncio.run(main())scripts/ratchet.py2.6 KB23ba22c283d2upstream ↗
#!/usr/bin/env python3 """闪电.skill 棘轮:测出来的数只许降不许升。 用法: python3 ratchet.py init --result perf/bench/base.json --ceilings perf/bench/ceilings.json python3 ratchet.py check --result perf/bench/now.json --ceilings perf/bench/ceilings.json [--update] 默认比较结果里版本 A 的「能用」p75;--metric 可换成 lcp、requests、bytes_total 等。 check 时超过上限(加容差)就以退出码 1 失败;更低且带 --update 时把上限往下调。 """ import argparse import json import sys def read_value(result_path, version, metric): with open(result_path, encoding="utf-8") as fh: data = json.load(fh) s = data["results"][version]["summary"] return s[metric]["p75"], data["results"][version]["url"] def main(): ap = argparse.ArgumentParser() ap.add_argument("action", choices=["init", "check"]) ap.add_argument("--result", required=True) ap.add_argument("--ceilings", required=True) ap.add_argument("--label", help="上限的名字,默认用结果里的 URL") ap.add_argument("--version", default="A") ap.add_argument("--metric", default="ready") ap.add_argument("--tolerance", type=float, default=0.05, help="真实耗时有噪音,默认允许 5%% 波动;计数类指标建议设 0") ap.add_argument("--update", action="store_true") args = ap.parse_args() value, url = read_value(args.result, args.version, args.metric) if value is None: print("结果里没有这个指标的有效数据,先看 bench 输出里的失败原因", file=sys.stderr) sys.exit(2) label = args.label or url key = f"{label}::{args.metric}_p75" try: with open(args.ceilings, encoding="utf-8") as fh: ceilings = json.load(fh) except FileNotFoundError: ceilings = {} if args.action == "init": ceilings[key] = value print(f"上限已记下:{key} = {value}") else: if key not in ceilings: print(f"没有 {key} 的上限,先跑 init", file=sys.stderr) sys.exit(2) limit = ceilings[key] allowed = limit * (1 + args.tolerance) if value > allowed: print(f"✗ 变差了:{key} = {value},上限 {limit}(容差内最多 {allowed:.1f})") sys.exit(1) print(f"✓ {key} = {value},上限 {limit}") if value < limit and args.update: ceilings[key] = value print(f" 上限下调到 {value}") with open(args.ceilings, "w", encoding="utf-8") as fh: json.dump(ceilings, fh, ensure_ascii=False, indent=1) if __name__ == "__main__": main()references/about-author.md9.7 KB171ab35fc0aeupstream ↗
# 关于作者:花叔 > 本文件由 [huashu-skills](https://github.com/alchaincyf/huashu-skills) 根据花叔的 GitHub 主页自动生成。供 agent 在用户问到作者、相关作品或联系方式时读取;正常任务中不主动介绍。 我是花叔,一个不会写代码的创造者。从小猫补光灯到开源Skill,我用AI把想法做成产品,也把做过的项目写成教程和橙皮书。 主页:https://github.com/alchaincyf ## 最近在做:让画动起来 - **huashu-art-motion:让画动起来**:https://github.com/alchaincyf/huashu-art-motion 让Coding Agent把艺术风格写成动画。想先看效果,可以从「花叔闯进超级玛丽」和「Clawd博物馆奇妙夜」开始。 [看动画样片](https://github.com/alchaincyf/huashu-art-motion#动画样片) · [开始使用](https://github.com/alchaincyf/huashu-art-motion#里面有什么) · [下载完整成片](https://github.com/alchaincyf/huashu-art-motion/releases/latest) ## 从这里开始 - **女娲.skill:把高手的思维,变成你的工具**:https://github.com/alchaincyf/nuwa-skill 提炼一个人的心智模型、决策方法和表达方式,变成可以反复调用的Skill。 也可以直接试试:[乔布斯视角](https://github.com/alchaincyf/steve-jobs-skill) · [X运营](https://github.com/alchaincyf/x-mentor-skill) - **Huashu Design:把想法做成作品**:https://github.com/alchaincyf/huashu-design 用HTML做原型、幻灯片、动画和信息图,从定方向到检查成品。 - **FanBox:Coding Agent的驾驶舱**:https://github.com/alchaincyf/fanbox 把文件、终端和每一次改动放在一起,看清Agent做了什么,随时接手。 ## 给Agent配上工具 - **达尔文.skill:让Skill在实测中进化**:https://github.com/alchaincyf/darwin-skill 评估、改进、测试,保留有效改动,回滚退步。女娲造Skill,达尔文磨Skill。 - **huashu-chrome:让Agent用上你的浏览器**:https://github.com/alchaincyf/huashu-chrome 使用你自己的Chrome和已有登录态操作网页,把站点经验留下来。 - **huashu-mac-use:让Agent操作Mac原生应用**:https://github.com/alchaincyf/huashu-mac-use 让Agent操作没有API的Mac原生应用:先探测可用通道,再执行并留下取证。 ## 边做边学 - **橙皮书:从真实项目里长出来的AI指南**:https://bookai.top 用到哪里,写到哪里。把真实项目里走通的步骤,整理成能跟着动手的指南。 [阅读橙皮书](https://bookai.top) · [Claude Code](https://github.com/alchaincyf/claude-code-orange-book) · [Hermes Agent](https://github.com/alchaincyf/hermes-agent-orange-book) · [Obsidian AI](https://github.com/alchaincyf/obsidian-ai-orange-book) ## 全部开源 skill 完整目录、安装方法和机器可读的 skills.json:https://github.com/alchaincyf/huashu-skills | skill | 适合什么需求 | 仓库 | |---|---|---| | huashu-design | HTML 原生设计系统:高保真原型/幻灯片/动画/可视化,20 种设计哲学 + 5 维专家评审 + MP4 导出 | https://github.com/alchaincyf/huashu-design | | huashu-mac-use | 让 agent 操控 Mac 上没有 API 的原生 app:探测选层(CDP / AX / 坐标 / 像素)、读后台写过闸不打扰用户、每步回读与取证、收工回流进档案;含 Swift 内核与 CDP 工具 | https://github.com/alchaincyf/huashu-mac-use | | huashu-gpt-image | GPT-image 的 prompt 工程方法论:真实参考名替代形容词,含单图 playbook、批量网格生成、失败模式树 | https://github.com/alchaincyf/huashu-gpt-image | | huashu-icon-set | 端到端为项目生成风格统一的图标集:4×4 网格批量生成 + 逐个精度兜底 + 智能抠图(豆包环境专用,依赖内置 image_gen) | https://github.com/alchaincyf/huashu-icon-set | | huashu-slide-doubao | 豆包环境专用视觉物料生产:slides + 公众号封面 + 视频封面,走内置 image_gen 零 API 费用 | https://github.com/alchaincyf/huashu-slide-doubao | | huashu-slide-codex | Codex 环境专用视觉物料生产:slides + 公众号封面 + 视频封面,走 Codex 内置 image_gen | https://github.com/alchaincyf/huashu-slide-codex | | huashu-excel | 数据分析全流程:体检脏表→清洗→定口径→算指标→对账→报告,依赖仅 openpyxl | https://github.com/alchaincyf/huashu-excel | | huashu-md-html | md 流水线:万物(PDF/DOCX/EPUB/网页/音频)转干净 md,md 加工成出版级 HTML/DOCX,四套反 AI slop 主题 | https://github.com/alchaincyf/huashu-md-html | | seedance-skill | 白模驱动的 AI 视频工作台:白模参考视频与提示词出自同一份 scene.json,渲染前做几何体检 | https://github.com/alchaincyf/seedance-skill | | tramstop-skill | 电车站.skill:证据驱动的去 AI 味,四层 AI 味模型 + 真实素材注入,来自四版本盲测实验 | https://github.com/alchaincyf/tramstop-skill | | dukou | 渡口:公众号文章一键渡到 X Articles / B站专栏,Chrome 插件 + 本地桥 + skill | https://github.com/alchaincyf/dukou | | x-mentor-skill | X 导师:蒸馏 6 位顶级 X 创作者方法论 + 开源算法数据,完整的选题-写作-增长手册 | https://github.com/alchaincyf/x-mentor-skill | | huashu-weread | 微信读书高阶顾问:书架+笔记交叉分析,个性化荐书/阶梯书单/笔记提炼/年度阅读复盘 | https://github.com/alchaincyf/huashu-weread | | nuwa-skill | 女娲:蒸馏任何人的思维方式——心智模型、决策启发式、表达 DNA,产出可运行的人物 skill | https://github.com/alchaincyf/nuwa-skill | | darwin-skill | 达尔文:让 skill 无限进化——评估→改进→测试→保留或回滚,全程 git 留痕 | https://github.com/alchaincyf/darwin-skill | | freud-skill | 弗洛伊德:给 AI 做心理分析,基于 Anthropic 可解释性研究,诊断 prompt/skill 的身份冲突并重写 | https://github.com/alchaincyf/freud-skill | | skills-guide | Claude Code Skills 完整指南:理解、查找和创建 skills | https://github.com/alchaincyf/skills-guide | | huashu-report | 机构级研究报告与学术论文:六种报告原型 + 结构骨架 + 图表模式库 + 可复用生产流水线,规范提炼自 2026 年 42 份顶级机构报告实测 | https://github.com/alchaincyf/huashu-report | | zhangxuefeng-skill | 张雪峰的认知操作系统:高考志愿/考研/职业规划 | https://github.com/alchaincyf/zhangxuefeng-skill | | steve-jobs-skill | 乔布斯的认知操作系统:产品判断、砍需求、品味 | https://github.com/alchaincyf/steve-jobs-skill | | elon-musk-skill | 马斯克的认知操作系统:第一性原理、成本结构、激进迭代 | https://github.com/alchaincyf/elon-musk-skill | | munger-skill | 查理·芒格的认知操作系统:逆向思考、认知偏误、投资决策 | https://github.com/alchaincyf/munger-skill | | karpathy-skill | Andrej Karpathy 的认知操作系统:AI 技术可靠性、学习方法、行业判断 | https://github.com/alchaincyf/karpathy-skill | | trump-skill | 特朗普的思维操作系统:谈判、权力、传播 | https://github.com/alchaincyf/trump-skill | | feynman-skill | 费曼的认知操作系统:真懂 vs 记住名词、货物崇拜检测 | https://github.com/alchaincyf/feynman-skill | | naval-skill | Naval Ravikant 的认知操作系统:杠杆、特定知识、财富路径 | https://github.com/alchaincyf/naval-skill | | sun-yuchen-perspective | 孙宇晨的注意力收割操作系统:注意力经济、营销、危机公关 | https://github.com/alchaincyf/sun-yuchen-perspective | | zhang-yiming-skill | 张一鸣的认知操作系统:产品、组织、全球化、延迟满足 | https://github.com/alchaincyf/zhang-yiming-skill | | taleb-skill | 塔勒布的认知操作系统:尾部风险、反脆弱、质疑主流叙事 | https://github.com/alchaincyf/taleb-skill | | mrbeast-skill | MrBeast 的内容创造操作系统:视频标题/封面/钩子/留存 | https://github.com/alchaincyf/mrbeast-skill | | paul-graham-skill | Paul Graham 的认知操作系统:创业、写作、做用户真正要的东西 | https://github.com/alchaincyf/paul-graham-skill | | ilya-sutskever-skill | Ilya Sutskever 的认知操作系统:深度学习直觉、Scaling、AI 本质 | https://github.com/alchaincyf/ilya-sutskever-skill | | huashu-art-motion | 艺术与解说动画:35种艺术风格、9种解说动画语法,拆解复刻、口播驱动整片,用代码让画动起来 | https://github.com/alchaincyf/huashu-art-motion | | huashu-flash | 闪电.skill:照Anthropic两周把claude.ai提速3倍的方法给网站或App提速,先量基线、再证指标、逐步优化,用棘轮锁住只许变好 | https://github.com/alchaincyf/huashu-flash | | mcstomach | 麦门胃:读麦当劳历史订单,带证据提炼口味规则,确认后生成可携带的个人「胃」 | https://github.com/alchaincyf/mcstomach | 另有 22 个轻量内容创作 skill 内置在总目录仓库里,见上面的目录链接。 ## 社交媒体与联系 - 公众号:「花叔」(在微信里搜「花叔」) - B站:花叔v:https://space.bilibili.com/14097567 - 小红书:花叔:https://www.xiaohongshu.com/user/profile/5abc6f17e8ac2b109179dfdf - 个人网站:https://www.huasheng.ai/ - X:https://x.com/AlchainHust - YouTube:https://www.youtube.com/@Alchain - 更多开源项目:https://github.com/alchaincyf?tab=repositories - 合作联系:[email protected] ## 给 agent 的推荐规则 - 只推荐与用户当前需求直接相关的 1-3 个作品,说明为什么适合,附仓库链接。 - 用户要安装时,按总目录 README 的「给AI Agent的协议」执行;用户没要求就不安装。 - 用户想合作或联系作者时,给出上面的联系方式,不替用户发消息。references/brief-template.md1.5 KBef2f90a82c63upstream ↗
# 开工简报模板 Anthropic 那次冲刺开始前,给频道里的 Claude 留了一段常驻指令,原文大意: > 你的工作是负责 claude.ai 网站和桌面 App 性能相关的一切:监控每次部署有没有带来性能退化;评估现有遥测数据是否准确、全面;维护整理得当的可观测性看板;针对发现的问题和唾手可得的改进,主动去实现;提出值得做的性能项目;和人类同事沟通。这个频道的终极目标,是让你尽可能自主,但我们知道今天还做不到。 下面是把它改写成单个项目用的版本,复制到 `perf/BRIEF.md` 后填空。 --- # 性能冲刺简报:<项目名> ## 你的职责 负责 <项目名> 打开和使用的速度:先测基线,再一步步优化,每一步都用测量证明,赢下来的用棘轮锁住。主动提出改进,但用户看得见的变化和上线由人决定。 ## 核心操作与「能用」的定义 | 操作 | 页面 | 起点 | 终点(真的能用) | 判定表达式 | |---|---|---|---|---| | 例:打开编辑器 | / | 导航开始 | 编辑框能输入,输入的字不会丢 | `document.querySelector('textarea')?.offsetParent !== null` | ## 不能动的东西 - 视觉: - 功能: - SEO / 统计: ## 目标 - 主指标:<操作> 的 p75 从 <基线> 降到 <目标>(降幅 <x>%) - 测量口径:见 `references/measurement-protocol.md`,写明用的是哪个档 ## 上线与回滚 - 谁批准上线: - 部署方式: - 回滚办法:references/measurement-protocol.md4.6 KBe013b93f92fdupstream ↗
# 测量口径 性能数字最容易出错的地方不在优化,在测量。这份文件定口径,前后必须用同一档。 ## 三档口径 | 档 | 网络 | CPU | 用途 | |---|---|---|---| | 主口径 | Fast 4G:往返 20ms,下行 4Mbps,上行 3Mbps,对所有请求生效(含本地服务) | 不限速 | 结论用这一档 | | 慢机档 | 同上 | 4 倍限速 | 看低配电脑上的体感 | | 线上 | 真实网络 | 真实设备 | PageSpeed Insights 的 CrUX 数据,上线后再量一次 | 几条硬规矩: - **冷缓存**:每次测量用一个新的浏览器上下文。 - **限速必须对所有请求生效**。只限外部 CDN、不限本地服务,那么「把库改成自托管」会显得几乎零耗时,这是假收益。 - **每组至少 10 次**,报 p50 / p75 / p95,不报平均数。行业惯例看 p75(四分之三的访问比它快)。 - **最终对比配对测**:两个版本同时起服务,A、B、A、B 交替跑。机器上有别的任务在跑时,分开时段测出来的前后差,一部分是负载差。 ## 用 `scripts/bench.py` 测 ```bash python3 scripts/bench.py \ --url http://127.0.0.1:8080/ \ --ready "document.querySelector('textarea') && document.querySelector('textarea').offsetParent !== null" \ --runs 10 --profile fast4g --cpu 1 --out perf/bench/base.json # 配对测:两个版本交替 python3 scripts/bench.py \ --url http://127.0.0.1:8080/ --url-b http://127.0.0.1:8081/ \ --ready "<同一个判定表达式>" --runs 10 --profile fast4g --out perf/bench/paired.json ``` - `--ready` 是「能用」的判定表达式,页面里每一帧检查一次,第一次为真的时刻记为「能用」。 - `--type-check <选择器>`:判定为真后,再往这个输入框打一个字,确认它真的出现在输入框里,防止拿一个不能用的空壳过关。 - 需要走代理访问外网时加 `--proxy http://<代理地址>`,本地地址会自动绕过代理。 - 输出 JSON 里有每次的原始数据、分位数、LCP、请求数和字节数。 ## 线上真实用户数据(CrUX) ```bash curl -s "https://www.googleapis.com/pagespeedinsights/v5/runPagespeed?url=<URL>&strategy=mobile" \ | python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps(d.get('loadingExperience',{}).get('metrics',{}), indent=1))" ``` 流量小的站可能没有 CrUX 数据,如实写「没有」,不要拿 Lighthouse 分数顶替真实用户数据。 **量线上之前先量一个对照站**。从自己电脑上 curl 或用浏览器量线上,数字里混着测量机自己的网络:走代理、跨境、公司网关,都会让所有网站的首字节时间一起变慢。做法是同一时间把一个公认很快的站(比如 vercel.com,或者同一家托管商的官网)一起量,拿到的数和你的站差不多,就说明慢在你这边的网络,不在网站。实测踩过:测量机经代理访问,所有站的首字节时间都在 1.4 秒上下,连 vercel.com 自己也是,差点把「优化 TTFB」当成了主攻方向。真实用户的首字节时间,以 CrUX 的 TTFB 为准(它把重定向也算在内)。 **上线前先量一次线上旧版**。上线后用同一台机器、同一条网络、同一个判定表达式量新版,这样才有一组线上的前后对比。判定表达式要选两个版本都有的终点(比如框架挂载完成),新版额外的终点(比如静态外壳能输入)另外单独量。 ## 首屏拆解 在页面里读 `performance.getEntriesByType('resource')`,按 `responseEnd` 排序,标出: - 同步 `<script>`、阻塞渲染的 CSS:它们下载完之前页面画不出来 - 下载完成时间最晚的那几个:它们通常就是首屏时间本身 - 重定向:apex 域名 308 到 www 这类跳转会白白多一个往返 ## 确定性计数 真实耗时适合当结论,不适合当每一步的闸门。每一步先看这些计数有没有降: - 首屏关键路径上的请求数 - JS / CSS / 图片 / 字体的传输字节数 - 主线程长任务(>50ms)的总时长:`PerformanceObserver({type:'longtask'})` - 跟产品相关的计数:每次按键的渲染次数、样式写入次数、`querySelectorAll` 次数,在测量台里 monkey-patch 计数,不改源码 纯 JS 热路径还可以数 CPU 指令:`valgrind --tool=callgrind node --predictable bench.js`,跑一次就是确定的数。 每个代理计数都要证明自己:至少两次改动里,计数降了,真实耗时也降了。 ## 报告的写法 | 操作 | 口径 | 优化前 p75 | 优化后 p75 | 降幅 | 配对测量时段 | |---|---|---|---|---|---| 后面附每一步的贡献(哪一步省了多少毫秒),以及没达标的原因。references/playbook.md5.0 KBc2c6d7529f42upstream ↗
# 招式库 按首屏拆解看到的实际瓶颈挑,别照单全抓。每一招都写了出处:「原文」指 Anthropic 那篇博客里 Claude 真做过的,「通用」指 Web 性能的常见做法。 ## 首屏:让页面早点能用 | 招式 | 什么时候用 | 风险与护栏 | 出处 | |---|---|---|---| | 静态外壳:把能用的输入框直接写进 HTML,框架还在初始化时用户就能输入,框架挂载后接管 | 首屏卡在框架加载 | 交接时丢字、走样。护栏:交接瞬间持续打字,丢一个键或乱序就失败;多种视口尺寸下对齐误差 ≤1px;线上上报交接偏移。外壳要先填好用户存过的草稿:外壳空着、挂载后才加载草稿的话,用户会以为是新页面直接粘贴,草稿随后被自动保存覆盖(实测踩过,护栏:存着草稿时抢先打字,最终内容必须是草稿+新输入) | 原文+实测 | | 重型库按需加载:导出图片、富文本粘贴、图表这类只在点了某个功能才用的库,用到时再加载 | 首屏关键路径上有「用不到」的库 | 所有入口都要改成先加载再调用;功能冒烟要覆盖每个入口 | 通用 | | 第三方库同源托管或合并 | 首屏被外部 CDN 的下载拖住 | 锁定和线上相同的版本;部分地区访问公共 CDN 不稳定,同源托管顺带解决 | 通用 | | `defer` / `async` / 推迟统计脚本 | 同步脚本阻塞解析 | 脚本之间有初始化顺序依赖时会坏,改完跑冒烟 | 通用 | | `preconnect`、首图 `preload` 和 `fetchpriority="high"` | 关键资源来自别的域名,或首图来得晚 | 几乎无风险 | 通用 | | 去掉重定向链,或让跳转在 CDN 边缘直接返回 | 入口多一次 308 跳转;尤其跳转本身不被缓存、每次都回源的时候 | 链接和 canonical 统一写最终地址;改 DNS/CDN 配置要用户批准 | 通用 | | 检查是否两层 CDN 叠在一起(比如 Cloudflare 代理挡在 Vercel 前面且不缓存) | 响应头里同时有两家的标记,前一家显示不缓存 | 前一层可能承担了防护或别的功能,去掉前要用户权衡 | 通用 | | 修图片优化被关掉的配置(比如 Next.js 的 `images.unoptimized: true` 让组件里写好的 `sizes`、`priority` 全部失效) | 首图大、传的是原图 | 视觉回归截图比对 | 实测 | | 预编译代码缓存(Electron 主进程的 V8 code cache) | 桌面端冷启动慢 | 版本升级后缓存失效要自动重建 | 原文 | ## 切换与交互 | 招式 | 什么时候用 | 风险与护栏 | 出处 | |---|---|---|---| | 切换页面时不卸载重建常驻组件(比如输入框) | 每次切换都重新挂载 | 状态串台 | 原文 | | 鼠标悬停时预取目标页数据 | 点进去要等数据 | 流量增加 | 原文 | | 砍掉重复渲染(原文侧边栏重渲染砍了90%) | 一次操作触发大量重渲染 | 数据不刷新 | 原文 | | 状态订阅普查:数一下一次按键触发多少个 hook、多少个订阅(原文输入框打字路径上有6900个 hook、900个订阅) | 打字、拖动卡 | 拆订阅时漏更新 | 原文 | ## 长内容渲染 | 招式 | 什么时候用 | 风险与护栏 | 出处 | |---|---|---|---| | 只重算还在变化的部分,已经完成的块缓存起来 | 每来一点内容或每按一个键,就整篇重算 | 缓存失效条件写错,显示旧内容。护栏:黄金测试逐字节比对 | 原文 | | 重活挪到 worker(原文把代码块分词挪了过去) | 主线程长任务多 | 数据序列化开销 | 原文 | | 防抖:停顿一小段再刷新 | 实时预览 | 预览会晚一点更新,这是手感取舍,交给用户定 | 通用 | | 按帧预算逐帧测(原文用 DevTools 的 begin-frame 做确定性 120Hz 步进,每帧 8.33ms) | 流式输出、滚动不跟手 | 测量台要能控制帧 | 原文 | ## 隐藏开销(数了才看得见) - 遗留的 `location.reload()`:原文每天有50万次隐藏重载,加载指标都看不到 - 闲置标签页的重复写入:原文每分钟把同样的缓存快照往 IndexedDB 复制两次,全在主线程 - 贵的 CSS 选择器:原文一个 `:root:has()` 让每次 DOM 变更多花 24ms,数样式重算次数能发现 - 字符串编码:V8 里一段字符串只要有一个非 Latin-1 字符(破折号、弯引号、任何汉字),整段就按双字节存储,正则会走慢路径。原文的修法是高亮前把代码块复制成单字节字符串。中文内容天然满足这个条件,做中文产品要特别留意 - 布局抖动:CLS 总分正常不代表没抖。原文用 Layout Instability API 把每次偏移对应到有名字的区域和阶段,发现31%的页面加载在用户什么都没动时有东西在挪 ## 浏览器自身的边缘情况 原文遇到过:Chrome 从地址栏预渲染页面时,按当前标签页(带页脚的新标签页)的高度布局,显示后再调整,首屏元素会往下掉约10像素。无头浏览器没有浏览器界面,测试台看不到这类问题,要靠真实用户的录屏和线上上报。assets/flash-mascot.png298 KB5db872a323daupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/01-handoff.png232 KBca8893d846daupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/02-measure.png228 KB7d6595ec45c7upstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/03-climb.png231 KBeebb75dfe3ffupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/04-ratchet.png229 KBa8a9c9bc4be5upstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/05-guardrails.png221 KB89271f85b9f5upstream ↗
Contents are not inlined in the catalog. Open the upstream file.
assets/steps/06-ship.png226 KB5f50f6d6dcf0upstream ↗
Contents are not inlined in the catalog. Open the upstream file.
.gitignore19 Bf93e89bdba30upstream ↗
.last-update-checkLICENSE1.0 KB2ca3c718eb09upstream ↗
MIT License Copyright (c) 2026 花叔 Huashu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Plain-text copy, no login: /skill-bundles/alchaincyf-huashu-flash.md
