nuqs 包体积优化实战:用子代理并行“Bake-Off“竞赛把 Client Bundle 压到 6 kB 以内

📅 发布时间:2026/9/23 13:40:26
nuqs 包体积优化实战:用子代理并行“Bake-Off“竞赛把 Client Bundle 压到 6 kB 以内
nuqs 包体积优化实战用子代理并行Bake-Off竞赛把 Client Bundle 压到 6 kB 以内【免费下载链接】next-usequerystateType-safe search params state manager for React frameworks - Like useState, but stored in the URL query string.项目地址: https://gitcode.com/gh_mirrors/ne/next-usequerystate本文是 nuqsType-safe search params state manager for React仓库内.claude/skills/bundle-size-bake-off/SKILL.md技能文档的完整解读与工程化落地指南。它描述了一套以size-limit为裁判、以多个独立 git worktree 中的子代理并行参赛的体积竞赛bake-off工作流用于在改动逻辑不变的前提下持续压低包体积。读完本文你将掌握如何搭建基线测量、如何把重构任务拆给 N 个子代理并行迭代、如何设定退回重来的验证门槛以及如何汇总成绩并合并最优解——这是一套可直接复用到任何关注 bundle size 的库项目的方法论。为什么 nuqs 需要一场体积竞赛nuqs 的定位是把 React 状态写进 URL query string这意味着它的代码几乎全部运行在客户端。一个状态管理库的 bundle size 直接决定使用者的首屏负担因此仓库对体积有硬性约束。在 packages/nuqs/package.json 中可以看到三条size-limit指标size-limit: [ { name: Client, path: dist/index.js, limit: 6 kB }, { name: Client (minimal tree-shaken), path: dist/index.js, limit: 4.5 kB, import: { useQueryStates, parseAsInteger } }, { name: Server, path: dist/server.js, limit: 3.8 kB } ]三个维度的含义Clientdist/index.js完整入口的压缩后体积上限 6 kB。这是 bake-off 的主战场指标也是文档站首页展示的数字来源见 bundle-size.tsx/_landing/bundle-size.tsx#L15-L24)它直接读取packages/nuqs/size.json渲染当前体积。Client (minimal tree-shaken)只导入useQueryStates与parseAsInteger时的体积上限 4.5 kB。它模拟真实用户按需引入的最终效果验证 tree-shaking 是否真的生效。Serverdist/server.js服务端渲染相关代码如parseAs*解析器上限 3.8 kB。服务端代码不得泄漏进客户端包。SKILL.md 明确The main metric we want to reduce is the Client bundle size (minified brotli-compressed)——bake-off 的核心目标就是缩减第一个指标且要求所有提交必须严格低于基线与 size-limit 上限两者中较小的那个。测量工具链两条命令、一个事实来源技能文档给出了测量命令并强调依赖 Turbo 缓存来加速迭代pnpm build --filter nuqs pnpm run --filter nuqs test:size拆解如下pnpm build --filter nuqs先构建且必须用根命令触发package.json 中的build: turbo run build这样才能吃到 Turbo 的任务缓存——只有改动过的包才会重新构建。pnpm run --filter nuqs test:size等价于size-limit见 packages/nuqs/package.json 的test:size脚本在 stdout 打印各条目体积体积超限即非零退出。pnpm run --filter nuqs build:size-json等价于size-limit --json size.json把结果写入 packages/nuqs/size.json同样超限即失败。该产物被文档站点消费也被 packages/nuqs/turbo.json 声明为构建输出。技能文档特别提醒size-limit 负责全部测量处理不需要额外的构建步骤整个过程就是改代码 → 重测 → 看数字的试错循环。底层依赖是size-limitv12.1.0 与size-limit/preset-small-lib见 packages/nuqs/package.json构建则使用 tsdown其配置在 tsdown.config.ts 中ESM 输出、dts: true、neverBundle外部化框架依赖并通过moduleSideEffects白名单确保src/debug.ts之外的所有模块都可以被安全摇树tree-shake。Bake-off 完整流程从基线到梯度下降技能文档的核心流程可以概括为六步。注意一个重要分工主代理你不亲自写代码只负责创建 worktree、派发任务、回收结果。第 1 步准备 N 个隔离的 worktree每个子代理在自己的 git worktree 中独立工作互不干扰。创建并初始化 worktree 使用pnpm setup:worktree在基线 SHA1即当前分支起点处执行。该命令映射到 packages/scripts/worktree-setup.mjs由根 package.json 的setup:worktree脚本调用。它实际做了四件事校验工具链版本assertToolVersions强制 Node 版本必须与.node-version一致、pnpm 版本必须与根package.json的packageManager当前为pnpm11.0.9一致否则直接抛错拒绝 setup对应测试见 worktree-setup.test.mjs。清理 node_modules 符号链接prepareNodeModules递归解除工作树中残留的、指向其他安装的node_modules符号链接测试验证不会误删链接目标见 worktree-setup.test.mjs。安装依赖以pnpm install --frozen-lockfile安装锁文件若由 git hook 触发--ignore-scripts模式会跳过生命周期脚本。记录安装指纹recordSetup把锁文件哈希写入state.json下次 setup 时指纹一致则跳过重装setup 失败时不会保留过期指纹见 worktree-setup.test.mjs并通过withSetupLock防止并发冲突见 worktree-setup.test.mjs。仓库文档CONTRIBUTING.md 与 AGENTS.md也印证了这套约定对可信克隆可用node --run setup:hooks让git worktree add后自动装依赖若 hook 因分支清单与origin/HEAD不一致而跳过则需在 worktree 内手动运行node --run setup:worktree。第 2 步先测基线任何改动之前子代理必须先测量基线 bundle size作为后续所有对照的零号选手。第 3 步小步重构 反复测量对代码做限定范围的重构常见手法包括重命名变量/内部函数提升可读性有时也改善压缩重组逻辑把 server-only 代码挪出 client 路径合并或拆分函数影响打包器内联决策。每次改完立即重测第 1 节的命令。若结果超过基线则回退改动重来若低于基线就作为 checkpoint 提交然后继续下一轮。第 4 步梯度下降避免局部最优技能文档明确要求同时尝试小步增量和较大改动两种策略并类比梯度下降Sometimes moving back and trying something else will give a better result (use a gradient descent approach, avoid local minima). 即不要死磕一个方向必要时退回重试其他方案。第 5 步压缩友好的特殊考量一条反直觉的经验写在文档里some changes will play better with compression than others (sometimes, duplication will give better results than abstractions due to dictionaries)——由于 brotli/gzip 基于字典匹配适度的重复有时比抽象更省字节。引入抽象意味着新增函数名、参数与调用层这些标识符会稀释压缩字典的收益而重复代码虽然源码更长但相同 token 重复出现反而更容易被压缩。这是 bundle-size bake-off 与普通代码洁癖最大的分歧点。第 6 步合并最优解子代理确定候选后把多个 checkpoint 提交 squash 成单个提交提交信息遵循仓库的 conventional commits 规范见 package.json 的 commitlint 配置典型写法chore: reduce bundle size验证门槛五个必须、一个否决技能文档规定任何候选方案必须全部满足以下条件违反任一条即判定失败、直接淘汰条件说明逻辑等价与基线行为完全一致不允许任何行为变化公共 API 不变不得重命名任何导出的符号范围受控改动局限于当前 PR / 分支 / 会话内的改动除非明确要求全包 bake-off可读可维护保留人可读性不牺牲可维护性换取字节体积达标严格低于基线与 size-limit 上限两者中较小的那个测试通过先用单元测试快速迭代相关改动再补一轮 e2e 验证其中逻辑等价是最容易被忽视的硬约束——bake-off 只允许压缩实现、不允许改变语义。这也是为什么流程要求先测基线没有基线数字就无法证明候选是优化而非玄学。汇总结论给用户的成绩报告子代理们上报后主代理要向用户输出一份简洁报告包含与基线的差值表格技能文档给出的格式如下| Name | Client | Tree-shaken | Server | | ----------------------------- | ------: | ----------: | ------: | | Baseline | 5,920 B │ 4,288 B │ 3,786 B │ | 1. Inline parser helpers | -308 B | -112 B | -32 B | | 2. Split shared state helpers | -240 B | -64 B | -16 B | | 3. Remove wrapper functions | -128 B | -32 B | 2 B |每个候选的一行解释要求使用 ASD-STE100 简化技术英语即一句话说清动了什么例如What they did: 1. removes call layers from the client path. 2. keeps server-only code out of the client bundle. 3. lets the bundler inline small calls.按减少量从多到少排序供用户决策。用户验收之后主代理把被选中的候选合入自己的工作树本地跑完整的验证套件单元 相关 e2e最后清理所有子代理 worktree 与分支。这套方法论在仓库中的工程化支撑SKILL.md 描述的工作流并非孤立的提示词它与仓库的工程设施深度绑定体积门槛的硬性执行test:size/build:size-json超限即失败意味着任何不经意的体积回退都会在 CI 或本地被拦截bake-off 的退回重来因此有了客观裁判。构建与摇树的边界tsdown.config.ts 的treeshake.moduleSideEffects只放行src/debug.ts的副作用其余模块全部交给 package.json 的sideEffects白名单——这保证了子代理拆分函数后摇树结果仍然可预测tree-shaken 指标4.5 kB才具有意义。子代理基建worktree 的创建、依赖安装、锁与指纹管理全部脚本化worktree-setup.mjs并有完整单测worktree-setup.test.mjs子代理可以拿到即用无需关心环境。体积的对外可见性文档站首页的 BundleSize 组件直接渲染size.json的第一个条目bundle-size.tsx/_landing/bundle-size.tsx#L15-L24)让6 kB 以内的承诺可被访问者随时验证。给读者的一份可执行清单如果你要在自己的项目里复刻这套流程可以按下面清单落地在 package.json 中配置size-limitClient / tree-shaken / Server 三个条目各设硬上限提供build:size-json写 JSON 供页面或 CI 展示与test:size纯检查两个脚本编写setup:worktree脚本处理版本校验、node_modules 链接清理、--frozen-lockfile安装与锁文件让子代理按测基线 → 小步重构 → 重测 → 超限回退 → checkpoint 提交循环迭代必要时用梯度下降跳出局部最优记住压缩特性有时重复优于抽象设置五个验证门槛并严格执行超限与违规一律淘汰汇总成基线对比表 一行解释 按降序排序的报告交给用户决策。这套以子代理竞赛 size-limit 裁判的 bake-off 工作流把 bundle size 优化从凭感觉重构变成了可度量、可并行、可回退的工程流水线——这正是 nuqs 能长期把 client bundle 稳定压在 6 kB 门槛内的底层方法。【免费下载链接】next-usequerystateType-safe search params state manager for React frameworks - Like useState, but stored in the URL query string.项目地址: https://gitcode.com/gh_mirrors/ne/next-usequerystate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考