[{"data":1,"prerenderedAt":3501},["ShallowReactive",2],{"article-/topics/frontend/biome-toolchain-guide":3,"related-frontend":899,"content-query-YzjgYT0mC4":2816},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":19,"imageQuery":20,"featured":6,"readingTime":21,"body":22,"_type":893,"_id":894,"_source":895,"_file":896,"_stem":897,"_extension":898},"/topics/frontend/biome-toolchain-guide","frontend",false,"","Biome 工具链完全指南：用一个工具统一格式化、Lint、自动修复与 CI","系统讲解 Biome 是什么、能替代哪些传统工具（ESLint/Prettier 等）、如何在 pnpm monorepo 中落地，以及从本地开发到 CI 的最小可行配置与迁移策略。","2026-01-30","HTMLPAGE 团队",[13,14,15,16,17,18],"Biome","ESLint","Prettier","前端工程化","代码规范","CI","/images/topics/frontend/biome-toolchain-guide-cover.webp","developer code editor terminal linting formatting tools",16,{"type":23,"children":24,"toc":864},"root",[25,33,39,64,69,114,126,131,135,141,146,188,193,216,221,224,230,236,275,281,294,299,308,311,317,322,355,360,363,377,397,402,414,419,448,451,457,462,467,480,493,506,511,514,520,525,538,543,554,559,584,587,593,605,610,616,629,643,656,662,675,680,688,691,697,703,708,714,719,725,746,752,757,775,778,784,789,812,824,827,833],{"type":26,"tag":27,"props":28,"children":30},"element","h2",{"id":29},"biome-工具链完全指南用一个工具统一格式化lint自动修复与-ci",[31],{"type":32,"value":8},"text",{"type":26,"tag":34,"props":35,"children":36},"p",{},[37],{"type":32,"value":38},"很多团队的前端工具链是这样演进的：",{"type":26,"tag":40,"props":41,"children":42},"ul",{},[43,49,54,59],{"type":26,"tag":44,"props":45,"children":46},"li",{},[47],{"type":32,"value":48},"一开始只需要格式化：Prettier",{"type":26,"tag":44,"props":50,"children":51},{},[52],{"type":32,"value":53},"然后要代码规范：ESLint + 一堆插件",{"type":26,"tag":44,"props":55,"children":56},{},[57],{"type":32,"value":58},"再然后要类型检查：TypeScript",{"type":26,"tag":44,"props":60,"children":61},{},[62],{"type":32,"value":63},"最后要在 CI 里强制执行：lint/format/check 全跑一遍",{"type":26,"tag":34,"props":65,"children":66},{},[67],{"type":32,"value":68},"到某个阶段，你会遇到几个典型痛点：",{"type":26,"tag":70,"props":71,"children":72},"ol",{},[73,84,94,104],{"type":26,"tag":44,"props":74,"children":75},{},[76,82],{"type":26,"tag":77,"props":78,"children":79},"strong",{},[80],{"type":32,"value":81},"工具太多",{"type":32,"value":83},"：配置分散、版本冲突、升级成本高",{"type":26,"tag":44,"props":85,"children":86},{},[87,92],{"type":26,"tag":77,"props":88,"children":89},{},[90],{"type":32,"value":91},"速度不够",{"type":32,"value":93},"：CI 里跑一圈耗时明显",{"type":26,"tag":44,"props":95,"children":96},{},[97,102],{"type":26,"tag":77,"props":98,"children":99},{},[100],{"type":32,"value":101},"规则不一致",{"type":32,"value":103},"：Prettier 与 ESLint“打架”，需要额外桥接",{"type":26,"tag":44,"props":105,"children":106},{},[107,112],{"type":26,"tag":77,"props":108,"children":109},{},[110],{"type":32,"value":111},"新人上手慢",{"type":32,"value":113},"：不知道该修哪个、为什么失败",{"type":26,"tag":34,"props":115,"children":116},{},[117,119,124],{"type":32,"value":118},"Biome 的目标很明确：",{"type":26,"tag":77,"props":120,"children":121},{},[122],{"type":32,"value":123},"用一个工具把“格式化 + Lint + 自动修复”合在一起",{"type":32,"value":125},"，把开发和 CI 的“代码质量门禁”做得更简单、更快、更可控。",{"type":26,"tag":34,"props":127,"children":128},{},[129],{"type":32,"value":130},"本文会从“适合谁用/怎么落地/怎么迁移/怎么在 CI 生效”四个层面讲清楚，保证你读完就能在项目里真正用起来。",{"type":26,"tag":132,"props":133,"children":134},"hr",{},[],{"type":26,"tag":27,"props":136,"children":138},{"id":137},"_1-biome-是什么它要解决的到底是哪类问题",[139],{"type":32,"value":140},"1. Biome 是什么？它要解决的到底是哪类问题",{"type":26,"tag":34,"props":142,"children":143},{},[144],{"type":32,"value":145},"你可以把 Biome 理解为一套集成式前端质量工具：",{"type":26,"tag":40,"props":147,"children":148},{},[149,159,169],{"type":26,"tag":44,"props":150,"children":151},{},[152,157],{"type":26,"tag":77,"props":153,"children":154},{},[155],{"type":32,"value":156},"Formatter",{"type":32,"value":158},"：类似 Prettier（但不是完全等价）",{"type":26,"tag":44,"props":160,"children":161},{},[162,167],{"type":26,"tag":77,"props":163,"children":164},{},[165],{"type":32,"value":166},"Linter",{"type":32,"value":168},"：类似 ESLint（但规则集合与生态不同）",{"type":26,"tag":44,"props":170,"children":171},{},[172,177,179,186],{"type":26,"tag":77,"props":173,"children":174},{},[175],{"type":32,"value":176},"Fixer",{"type":32,"value":178},"：自动修复（",{"type":26,"tag":180,"props":181,"children":183},"code",{"className":182},[],[184],{"type":32,"value":185},"--write",{"type":32,"value":187},"）",{"type":26,"tag":34,"props":189,"children":190},{},[191],{"type":32,"value":192},"它适用于两类目标：",{"type":26,"tag":40,"props":194,"children":195},{},[196,206],{"type":26,"tag":44,"props":197,"children":198},{},[199,204],{"type":26,"tag":77,"props":200,"children":201},{},[202],{"type":32,"value":203},"团队协作一致性",{"type":32,"value":205},"：大家写出来的代码风格统一、提交前可自动修复",{"type":26,"tag":44,"props":207,"children":208},{},[209,214],{"type":26,"tag":77,"props":210,"children":211},{},[212],{"type":32,"value":213},"工程门禁",{"type":32,"value":215},"：CI 在 PR 合并前做“最低质量保证”",{"type":26,"tag":34,"props":217,"children":218},{},[219],{"type":32,"value":220},"需要强调：Biome 不取代 TypeScript 的类型系统，它解决的是“格式与代码质量规则层面”的问题。",{"type":26,"tag":132,"props":222,"children":223},{},[],{"type":26,"tag":27,"props":225,"children":227},{"id":226},"_2-适合用-biome-的团队画像以及不适合的场景",[228],{"type":32,"value":229},"2. 适合用 Biome 的团队画像（以及不适合的场景）",{"type":26,"tag":231,"props":232,"children":234},"h3",{"id":233},"适合",[235],{"type":32,"value":233},{"type":26,"tag":40,"props":237,"children":238},{},[239,251,263],{"type":26,"tag":44,"props":240,"children":241},{},[242,244,249],{"type":32,"value":243},"你想",{"type":26,"tag":77,"props":245,"children":246},{},[247],{"type":32,"value":248},"减少 ESLint/Prettier 组合的复杂度",{"type":32,"value":250},"，把常见规则交给一个工具",{"type":26,"tag":44,"props":252,"children":253},{},[254,256,261],{"type":32,"value":255},"你的项目是 ",{"type":26,"tag":77,"props":257,"children":258},{},[259],{"type":32,"value":260},"pnpm workspace / monorepo",{"type":32,"value":262},"，希望统一规范并且跑得快",{"type":26,"tag":44,"props":264,"children":265},{},[266,268,273],{"type":32,"value":267},"你希望",{"type":26,"tag":77,"props":269,"children":270},{},[271],{"type":32,"value":272},"把自动修复变成默认动作",{"type":32,"value":274},"（而不是让大家手动修）",{"type":26,"tag":231,"props":276,"children":278},{"id":277},"不适合或需要谨慎",[279],{"type":32,"value":280},"不适合（或需要谨慎）",{"type":26,"tag":40,"props":282,"children":283},{},[284,289],{"type":26,"tag":44,"props":285,"children":286},{},[287],{"type":32,"value":288},"你高度依赖某些 ESLint 插件生态（例如特别小众的框架规则、内部自定义规则）",{"type":26,"tag":44,"props":290,"children":291},{},[292],{"type":32,"value":293},"你已经在 ESLint 上积累了大量“业务特化规则”，短期迁移会带来较多改动",{"type":26,"tag":34,"props":295,"children":296},{},[297],{"type":32,"value":298},"现实策略往往是：",{"type":26,"tag":300,"props":301,"children":302},"blockquote",{},[303],{"type":26,"tag":34,"props":304,"children":305},{},[306],{"type":32,"value":307},"先用 Biome 负责格式化 + 一部分通用 Lint；ESLint 留作补充（如果确实需要）。",{"type":26,"tag":132,"props":309,"children":310},{},[],{"type":26,"tag":27,"props":312,"children":314},{"id":313},"_3-在团队里落地-biome最小可行方案mvp",[315],{"type":32,"value":316},"3. 在团队里落地 Biome：最小可行方案（MVP）",{"type":26,"tag":34,"props":318,"children":319},{},[320],{"type":32,"value":321},"落地工具链时，不建议一步到位“全部替换”，最稳的顺序通常是：",{"type":26,"tag":70,"props":323,"children":324},{},[325,335,345],{"type":26,"tag":44,"props":326,"children":327},{},[328,330],{"type":32,"value":329},"让 Biome 先接管 ",{"type":26,"tag":77,"props":331,"children":332},{},[333],{"type":32,"value":334},"format（格式化）",{"type":26,"tag":44,"props":336,"children":337},{},[338,340],{"type":32,"value":339},"再接管 ",{"type":26,"tag":77,"props":341,"children":342},{},[343],{"type":32,"value":344},"lint（检查 + 可修复项）",{"type":26,"tag":44,"props":346,"children":347},{},[348,350],{"type":32,"value":349},"最后接管 ",{"type":26,"tag":77,"props":351,"children":352},{},[353],{"type":32,"value":354},"CI 门禁",{"type":26,"tag":34,"props":356,"children":357},{},[358],{"type":32,"value":359},"这样做的好处是：改动可控、回滚容易、失败也容易定位。",{"type":26,"tag":132,"props":361,"children":362},{},[],{"type":26,"tag":27,"props":364,"children":366},{"id":365},"_4-配置文件biomejson建议从简单开始",[367,369,375],{"type":32,"value":368},"4. 配置文件：",{"type":26,"tag":180,"props":370,"children":372},{"className":371},[],[373],{"type":32,"value":374},"biome.json",{"type":32,"value":376},"（建议从简单开始）",{"type":26,"tag":34,"props":378,"children":379},{},[380,382,387,389,395],{"type":32,"value":381},"Biome 通常在仓库根目录放一个 ",{"type":26,"tag":180,"props":383,"children":385},{"className":384},[],[386],{"type":32,"value":374},{"type":32,"value":388},"（或者 ",{"type":26,"tag":180,"props":390,"children":392},{"className":391},[],[393],{"type":32,"value":394},"biome.jsonc",{"type":32,"value":396},"），让 monorepo 下的 package 统一遵守。",{"type":26,"tag":34,"props":398,"children":399},{},[400],{"type":32,"value":401},"下面给你一份“足够通用”的示例（重点是结构，不必逐字照抄）：",{"type":26,"tag":403,"props":404,"children":409},"pre",{"className":405,"code":407,"language":408,"meta":7},[406],"language-json","{\n  \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n  \"formatter\": {\n    \"enabled\": true,\n    \"indentStyle\": \"space\",\n    \"indentWidth\": 2,\n    \"lineWidth\": 100\n  },\n  \"organizeImports\": {\n    \"enabled\": true\n  },\n  \"linter\": {\n    \"enabled\": true,\n    \"rules\": {\n      \"recommended\": true\n    }\n  },\n  \"files\": {\n    \"ignore\": [\n      \"**/node_modules/**\",\n      \"**/.nuxt/**\",\n      \"**/.output/**\",\n      \"**/dist/**\",\n      \"**/build/**\"\n    ]\n  }\n}\n\n几个关键点：\n\n- `rules.recommended: true` 是最稳的起点：覆盖大量通用问题，但不会太激进\n- `organizeImports.enabled: true` 很适合和格式化一起做（但注意可能改变导入顺序）\n- `files.ignore` 在 Nuxt/构建产物较多的项目里非常关键，否则会慢且噪音大\n\n---\n\n## 5. 命令与脚本：把“检查”和“修复”分开\n\n团队协作里，最容易引起争议的是：到底什么时候该自动改代码？\n\n建议脚本按用途拆分：\n\n- `lint`：只检查（CI 用）\n- `lint:fix`：检查 + 自动修复（本地用）\n- `format`：格式化（本地/CI 都可用）\n\n示例（以 pnpm 为例）：\n\n```json\n{\n  \"scripts\": {\n    \"biome:check\": \"biome check .\",\n    \"biome:fix\": \"biome check . --write\",\n    \"biome:format\": \"biome format . --write\"\n  }\n}\n","json",[410],{"type":26,"tag":180,"props":411,"children":412},{"__ignoreMap":7},[413],{"type":32,"value":407},{"type":26,"tag":34,"props":415,"children":416},{},[417],{"type":32,"value":418},"实践建议：",{"type":26,"tag":40,"props":420,"children":421},{},[422,435],{"type":26,"tag":44,"props":423,"children":424},{},[425,427,433],{"type":32,"value":426},"本地：优先让开发者跑 ",{"type":26,"tag":180,"props":428,"children":430},{"className":429},[],[431],{"type":32,"value":432},"biome:fix",{"type":32,"value":434},"（能修的尽量自动修）",{"type":26,"tag":44,"props":436,"children":437},{},[438,440,446],{"type":32,"value":439},"CI：优先跑 ",{"type":26,"tag":180,"props":441,"children":443},{"className":442},[],[444],{"type":32,"value":445},"biome:check",{"type":32,"value":447},"（只做门禁，不改代码）",{"type":26,"tag":132,"props":449,"children":450},{},[],{"type":26,"tag":27,"props":452,"children":454},{"id":453},"_6-在-vs-code-里用起来让保存即修复成为默认体验",[455],{"type":32,"value":456},"6. 在 VS Code 里用起来：让“保存即修复”成为默认体验",{"type":26,"tag":34,"props":458,"children":459},{},[460],{"type":32,"value":461},"工具链成功与否，很大程度取决于“日常体验”。",{"type":26,"tag":34,"props":463,"children":464},{},[465],{"type":32,"value":466},"建议做到两件事：",{"type":26,"tag":70,"props":468,"children":469},{},[470,475],{"type":26,"tag":44,"props":471,"children":472},{},[473],{"type":32,"value":474},"开发者安装 Biome 的 VS Code 扩展",{"type":26,"tag":44,"props":476,"children":477},{},[478],{"type":32,"value":479},"项目提供统一的 workspace settings（可选，但强烈推荐）",{"type":26,"tag":34,"props":481,"children":482},{},[483,485,491],{"type":32,"value":484},"一个常见做法是在仓库根目录放 ",{"type":26,"tag":180,"props":486,"children":488},{"className":487},[],[489],{"type":32,"value":490},".vscode/settings.json",{"type":32,"value":492},"（如果团队接受）：",{"type":26,"tag":40,"props":494,"children":495},{},[496,501],{"type":26,"tag":44,"props":497,"children":498},{},[499],{"type":32,"value":500},"保存时格式化",{"type":26,"tag":44,"props":502,"children":503},{},[504],{"type":32,"value":505},"保存时组织 imports",{"type":26,"tag":34,"props":507,"children":508},{},[509],{"type":32,"value":510},"这样能把“格式化争论”直接消灭在源头：保存一次就统一了。",{"type":26,"tag":132,"props":512,"children":513},{},[],{"type":26,"tag":27,"props":515,"children":517},{"id":516},"_7-ci-门禁只做检查不做修复",[518],{"type":32,"value":519},"7. CI 门禁：只做检查，不做修复",{"type":26,"tag":34,"props":521,"children":522},{},[523],{"type":32,"value":524},"CI 的最佳实践是：",{"type":26,"tag":40,"props":526,"children":527},{},[528,533],{"type":26,"tag":44,"props":529,"children":530},{},[531],{"type":32,"value":532},"失败要清晰",{"type":26,"tag":44,"props":534,"children":535},{},[536],{"type":32,"value":537},"不要在 CI 里改代码（否则会引入“CI 提交”或者状态漂移）",{"type":26,"tag":34,"props":539,"children":540},{},[541],{"type":32,"value":542},"以 GitHub Actions 为例（示意）：",{"type":26,"tag":403,"props":544,"children":549},{"className":545,"code":547,"language":548,"meta":7},[546],"language-yaml","name: quality\non:\n  pull_request:\n\njobs:\n  biome:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: pnpm/action-setup@v4\n        with:\n          version: 9\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 22\n          cache: pnpm\n      - run: pnpm install --frozen-lockfile\n      - run: pnpm biome:check\n","yaml",[550],{"type":26,"tag":180,"props":551,"children":552},{"__ignoreMap":7},[553],{"type":32,"value":547},{"type":26,"tag":34,"props":555,"children":556},{},[557],{"type":32,"value":558},"如果你是 monorepo，并且不同 package 有不同需求，可以进一步细化为：",{"type":26,"tag":40,"props":560,"children":561},{},[562,571],{"type":26,"tag":44,"props":563,"children":564},{},[565],{"type":26,"tag":180,"props":566,"children":568},{"className":567},[],[569],{"type":32,"value":570},"pnpm --filter landing biome:check",{"type":26,"tag":44,"props":572,"children":573},{},[574,576,582],{"type":32,"value":575},"或者只检查 ",{"type":26,"tag":180,"props":577,"children":579},{"className":578},[],[580],{"type":32,"value":581},"packages/landing",{"type":32,"value":583}," 下文件（取决于你的规范边界）",{"type":26,"tag":132,"props":585,"children":586},{},[],{"type":26,"tag":27,"props":588,"children":590},{"id":589},"_8-迁移策略从-eslintprettier-过渡到-biome低风险路线",[591],{"type":32,"value":592},"8. 迁移策略：从 ESLint/Prettier 过渡到 Biome（低风险路线）",{"type":26,"tag":34,"props":594,"children":595},{},[596,598,603],{"type":32,"value":597},"迁移最容易踩雷的点是：",{"type":26,"tag":77,"props":599,"children":600},{},[601],{"type":32,"value":602},"一次性改太多",{"type":32,"value":604},"。",{"type":26,"tag":34,"props":606,"children":607},{},[608],{"type":32,"value":609},"推荐路线：",{"type":26,"tag":231,"props":611,"children":613},{"id":612},"step-1先让-biome-接管格式化",[614],{"type":32,"value":615},"Step 1：先让 Biome 接管格式化",{"type":26,"tag":40,"props":617,"children":618},{},[619,624],{"type":26,"tag":44,"props":620,"children":621},{},[622],{"type":32,"value":623},"先只启用 Biome formatter（或只在少量目录试点）",{"type":26,"tag":44,"props":625,"children":626},{},[627],{"type":32,"value":628},"让大家适应输出风格",{"type":26,"tag":231,"props":630,"children":632},{"id":631},"step-2启用-recommended-lint",[633,635,641],{"type":32,"value":634},"Step 2：启用 ",{"type":26,"tag":180,"props":636,"children":638},{"className":637},[],[639],{"type":32,"value":640},"recommended",{"type":32,"value":642}," Lint",{"type":26,"tag":40,"props":644,"children":645},{},[646,651],{"type":26,"tag":44,"props":647,"children":648},{},[649],{"type":32,"value":650},"先接受通用规则",{"type":26,"tag":44,"props":652,"children":653},{},[654],{"type":32,"value":655},"对冲突/误报做最小调整（关闭少数规则，而不是大改代码）",{"type":26,"tag":231,"props":657,"children":659},{"id":658},"step-3再考虑是否保留-eslint",[660],{"type":32,"value":661},"Step 3：再考虑是否保留 ESLint",{"type":26,"tag":40,"props":663,"children":664},{},[665,670],{"type":26,"tag":44,"props":666,"children":667},{},[668],{"type":32,"value":669},"如果你有强依赖的规则（例如框架特定、业务自定义），可以暂时保留 ESLint",{"type":26,"tag":44,"props":671,"children":672},{},[673],{"type":32,"value":674},"等 Biome 规则覆盖足够后再逐步缩小 ESLint 作用域",{"type":26,"tag":34,"props":676,"children":677},{},[678],{"type":32,"value":679},"核心原则：",{"type":26,"tag":300,"props":681,"children":682},{},[683],{"type":26,"tag":34,"props":684,"children":685},{},[686],{"type":32,"value":687},"迁移的目标是“降低工具链复杂度”，不是“把所有规则都换一种写法”。",{"type":26,"tag":132,"props":689,"children":690},{},[],{"type":26,"tag":27,"props":692,"children":694},{"id":693},"_9-常见问题faq",[695],{"type":32,"value":696},"9. 常见问题（FAQ）",{"type":26,"tag":231,"props":698,"children":700},{"id":699},"q1biome-会不会和-prettier-输出不一样",[701],{"type":32,"value":702},"Q1：Biome 会不会和 Prettier 输出不一样？",{"type":26,"tag":34,"props":704,"children":705},{},[706],{"type":32,"value":707},"会有差异。建议先在一个子目录试点，并把“格式输出差异”视为一次性成本；一旦统一，后续就省心了。",{"type":26,"tag":231,"props":709,"children":711},{"id":710},"q2我是不是要把-eslint-全删了",[712],{"type":32,"value":713},"Q2：我是不是要把 ESLint 全删了？",{"type":26,"tag":34,"props":715,"children":716},{},[717],{"type":32,"value":718},"不一定。很多团队会经历一个阶段：Biome 覆盖 80%，ESLint 补 20%。等团队信心足够再逐步收敛。",{"type":26,"tag":231,"props":720,"children":722},{"id":721},"q3biome-会不会破坏-nuxtvue-的开发体验",[723],{"type":32,"value":724},"Q3：Biome 会不会破坏 Nuxt/Vue 的开发体验？",{"type":26,"tag":34,"props":726,"children":727},{},[728,730,736,738,744],{"type":32,"value":729},"一般不会，但你需要正确设置忽略目录（例如 ",{"type":26,"tag":180,"props":731,"children":733},{"className":732},[],[734],{"type":32,"value":735},".nuxt",{"type":32,"value":737},"、",{"type":26,"tag":180,"props":739,"children":741},{"className":740},[],[742],{"type":32,"value":743},".output",{"type":32,"value":745},"），并确保 VS Code 插件配置与项目一致。",{"type":26,"tag":231,"props":747,"children":749},{"id":748},"q4怎么评估值不值得迁移",[750],{"type":32,"value":751},"Q4：怎么评估“值不值得迁移”？",{"type":26,"tag":34,"props":753,"children":754},{},[755],{"type":32,"value":756},"最简单的评估指标：",{"type":26,"tag":40,"props":758,"children":759},{},[760,765,770],{"type":26,"tag":44,"props":761,"children":762},{},[763],{"type":32,"value":764},"配置文件数量减少多少",{"type":26,"tag":44,"props":766,"children":767},{},[768],{"type":32,"value":769},"CI 时长降低多少",{"type":26,"tag":44,"props":771,"children":772},{},[773],{"type":32,"value":774},"团队因为格式/规则争论的时间减少多少",{"type":26,"tag":132,"props":776,"children":777},{},[],{"type":26,"tag":27,"props":779,"children":781},{"id":780},"结语把工具链当成团队生产力产品来做",[782],{"type":32,"value":783},"结语：把工具链当成“团队生产力产品”来做",{"type":26,"tag":34,"props":785,"children":786},{},[787],{"type":32,"value":788},"工具链不是为了“更严格”，而是为了让团队：",{"type":26,"tag":40,"props":790,"children":791},{},[792,797,802,807],{"type":26,"tag":44,"props":793,"children":794},{},[795],{"type":32,"value":796},"写得更快",{"type":26,"tag":44,"props":798,"children":799},{},[800],{"type":32,"value":801},"改得更少",{"type":26,"tag":44,"props":803,"children":804},{},[805],{"type":32,"value":806},"合并更顺",{"type":26,"tag":44,"props":808,"children":809},{},[810],{"type":32,"value":811},"回滚更容易",{"type":26,"tag":34,"props":813,"children":814},{},[815,817,822],{"type":32,"value":816},"如果你正在维护一个 pnpm monorepo，Biome 往往是“高性价比的一步”：先从格式化和 ",{"type":26,"tag":180,"props":818,"children":820},{"className":819},[],[821],{"type":32,"value":640},{"type":32,"value":823}," Lint 开始，不需要赌上整个项目，就能很快看到收益。",{"type":26,"tag":132,"props":825,"children":826},{},[],{"type":26,"tag":27,"props":828,"children":830},{"id":829},"延伸阅读把工具链能力串起来",[831],{"type":32,"value":832},"延伸阅读：把工具链能力串起来",{"type":26,"tag":40,"props":834,"children":835},{},[836,846,855],{"type":26,"tag":44,"props":837,"children":838},{},[839],{"type":26,"tag":840,"props":841,"children":843},"a",{"href":842},"/topics/frontend/eslint-custom-rules-guide",[844],{"type":32,"value":845},"ESLint 规则自定义：从零打造团队专属代码规范",{"type":26,"tag":44,"props":847,"children":848},{},[849],{"type":26,"tag":840,"props":850,"children":852},{"href":851},"/topics/frontend/vite5-config-best-practices",[853],{"type":32,"value":854},"Vite 5 配置最佳实践：提升构建速度与开发体验",{"type":26,"tag":44,"props":856,"children":857},{},[858],{"type":26,"tag":840,"props":859,"children":861},{"href":860},"/topics/frontend/unit-testing-best-practices",[862],{"type":32,"value":863},"单元测试最佳实践：如何把质量门禁落到 PR",{"title":7,"searchDepth":865,"depth":865,"links":866},3,[867,869,870,874,875,877,878,879,885,891,892],{"id":29,"depth":868,"text":8},2,{"id":137,"depth":868,"text":140},{"id":226,"depth":868,"text":229,"children":871},[872,873],{"id":233,"depth":865,"text":233},{"id":277,"depth":865,"text":280},{"id":313,"depth":868,"text":316},{"id":365,"depth":868,"text":876},"4. 配置文件：biome.json（建议从简单开始）",{"id":453,"depth":868,"text":456},{"id":516,"depth":868,"text":519},{"id":589,"depth":868,"text":592,"children":880},[881,882,884],{"id":612,"depth":865,"text":615},{"id":631,"depth":865,"text":883},"Step 2：启用 recommended Lint",{"id":658,"depth":865,"text":661},{"id":693,"depth":868,"text":696,"children":886},[887,888,889,890],{"id":699,"depth":865,"text":702},{"id":710,"depth":865,"text":713},{"id":721,"depth":865,"text":724},{"id":748,"depth":865,"text":751},{"id":780,"depth":868,"text":783},{"id":829,"depth":868,"text":832},"markdown","content:topics:frontend:biome-toolchain-guide.md","content","topics/frontend/biome-toolchain-guide.md","topics/frontend/biome-toolchain-guide","md",[900,1230,1542],{"_path":901,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":902,"description":903,"keywords":904,"image":910,"author":911,"date":912,"readingTime":913,"topic":5,"body":914,"_type":893,"_id":1227,"_source":895,"_file":1228,"_stem":1229,"_extension":898},"/topics/frontend/react-hooks-guide","React Hooks 完全指南","全面讲解 React Hooks，包括内置钩子、自定义钩子和最佳实践",[905,906,907,908,909],"React","Hooks","自定义钩子","状态管理","函数组件","/images/topics/react-hooks-guide.jpg","AI Content Team","2025-12-08",23,{"type":23,"children":915,"toc":1208},[916,921,926,932,938,949,955,964,970,979,985,991,1000,1006,1015,1021,1030,1036,1045,1050,1056,1065,1070,1082,1110,1121,1149,1154],{"type":26,"tag":27,"props":917,"children":919},{"id":918},"react-hooks-完全指南",[920],{"type":32,"value":902},{"type":26,"tag":34,"props":922,"children":923},{},[924],{"type":32,"value":925},"Hooks 改变了 React 的开发方式。本文全面讲解如何使用和创建 Hooks。",{"type":26,"tag":27,"props":927,"children":929},{"id":928},"内置-hooks",[930],{"type":32,"value":931},"内置 Hooks",{"type":26,"tag":231,"props":933,"children":935},{"id":934},"usestate-状态管理",[936],{"type":32,"value":937},"useState - 状态管理",{"type":26,"tag":403,"props":939,"children":944},{"className":940,"code":942,"language":943,"meta":7},[941],"language-javascript","import { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  const [name, setName] = useState('John')\n  const [user, setUser] = useState({\n    age: 30,\n    email: 'john@example.com',\n  })\n  \n  // 使用函数初始化状态（对于复杂初始值）\n  const [data, setData] = useState(() => {\n    console.log('初始化数据...')\n    return fetchInitialData() // 仅在首次渲染时调用\n  })\n  \n  return (\n    \u003Cdiv>\n      \u003Cp>计数: {count}\u003C/p>\n      \u003Cbutton onClick={() => setCount(count + 1)}>增加\u003C/button>\n      \n      {/* 函数式更新 */}\n      \u003Cbutton onClick={() => setCount(prev => prev + 1)}>\n        函数式增加\n      \u003C/button>\n      \n      {/* 更新对象 */}\n      \u003Cbutton onClick={() => setUser({ ...user, age: user.age + 1 })}>\n        增加年龄\n      \u003C/button>\n    \u003C/div>\n  )\n}\n","javascript",[945],{"type":26,"tag":180,"props":946,"children":947},{"__ignoreMap":7},[948],{"type":32,"value":942},{"type":26,"tag":231,"props":950,"children":952},{"id":951},"useeffect-副作用处理",[953],{"type":32,"value":954},"useEffect - 副作用处理",{"type":26,"tag":403,"props":956,"children":959},{"className":957,"code":958,"language":943,"meta":7},[941],"import { useState, useEffect } from 'react'\n\nfunction DataFetcher() {\n  const [data, setData] = useState(null)\n  const [loading, setLoading] = useState(true)\n  const [error, setError] = useState(null)\n  const [userId, setUserId] = useState(1)\n  \n  // 副作用 - 每次渲染后执行\n  useEffect(() => {\n    console.log('组件已挂载或已更新')\n  })\n  \n  // 挂载时执行一次\n  useEffect(() => {\n    console.log('组件已挂载')\n    \n    return () => {\n      console.log('组件已卸载')\n    }\n  }, [])\n  \n  // 当 userId 改变时执行\n  useEffect(() => {\n    let isMounted = true // 防止内存泄漏\n    \n    const fetchData = async () => {\n      setLoading(true)\n      try {\n        const response = await fetch(\\`/api/users/\\${userId}\\`)\n        const result = await response.json()\n        \n        if (isMounted) {\n          setData(result)\n        }\n      } catch (err) {\n        if (isMounted) {\n          setError(err)\n        }\n      } finally {\n        if (isMounted) {\n          setLoading(false)\n        }\n      }\n    }\n    \n    fetchData()\n    \n    // 清理函数\n    return () => {\n      isMounted = false\n    }\n  }, [userId])\n  \n  if (loading) return \u003Cp>加载中...\u003C/p>\n  if (error) return \u003Cp>错误: {error.message}\u003C/p>\n  \n  return \u003Cdiv>{data && JSON.stringify(data)}\u003C/div>\n}\n",[960],{"type":26,"tag":180,"props":961,"children":962},{"__ignoreMap":7},[963],{"type":32,"value":958},{"type":26,"tag":231,"props":965,"children":967},{"id":966},"usecontext-跨组件通信",[968],{"type":32,"value":969},"useContext - 跨组件通信",{"type":26,"tag":403,"props":971,"children":974},{"className":972,"code":973,"language":943,"meta":7},[941],"import { createContext, useContext, useState } from 'react'\n\n// 创建上下文\nconst ThemeContext = createContext()\n\n// 提供者组件\nfunction ThemeProvider({ children }) {\n  const [theme, setTheme] = useState('light')\n  \n  const toggleTheme = () => {\n    setTheme(prev => prev === 'light' ? 'dark' : 'light')\n  }\n  \n  const value = { theme, toggleTheme }\n  \n  return (\n    \u003CThemeContext.Provider value={value}>\n      {children}\n    \u003C/ThemeContext.Provider>\n  )\n}\n\n// 使用 Hook\nfunction useTheme() {\n  const context = useContext(ThemeContext)\n  \n  if (!context) {\n    throw new Error('useTheme 必须在 ThemeProvider 内使用')\n  }\n  \n  return context\n}\n\n// 组件使用\nfunction App() {\n  const { theme, toggleTheme } = useTheme()\n  \n  return (\n    \u003Cdiv style={{\n      background: theme === 'light' ? '#fff' : '#333',\n      color: theme === 'light' ? '#000' : '#fff',\n    }}>\n      \u003Cp>当前主题: {theme}\u003C/p>\n      \u003Cbutton onClick={toggleTheme}>切换主题\u003C/button>\n    \u003C/div>\n  )\n}\n\n// 使用\nexport default function Root() {\n  return (\n    \u003CThemeProvider>\n      \u003CApp />\n    \u003C/ThemeProvider>\n  )\n}\n",[975],{"type":26,"tag":180,"props":976,"children":977},{"__ignoreMap":7},[978],{"type":32,"value":973},{"type":26,"tag":27,"props":980,"children":982},{"id":981},"自定义-hooks",[983],{"type":32,"value":984},"自定义 Hooks",{"type":26,"tag":231,"props":986,"children":988},{"id":987},"uselocalstorage",[989],{"type":32,"value":990},"useLocalStorage",{"type":26,"tag":403,"props":992,"children":995},{"className":993,"code":994,"language":943,"meta":7},[941],"import { useState, useEffect } from 'react'\n\nfunction useLocalStorage(key, initialValue) {\n  // 从本地存储获取初始值\n  const [storedValue, setStoredValue] = useState(() => {\n    try {\n      const item = window.localStorage.getItem(key)\n      return item ? JSON.parse(item) : initialValue\n    } catch (error) {\n      console.error(error)\n      return initialValue\n    }\n  })\n  \n  // 当值改变时更新本地存储\n  const setValue = (value) => {\n    try {\n      const valueToStore = value instanceof Function ? value(storedValue) : value\n      setStoredValue(valueToStore)\n      window.localStorage.setItem(key, JSON.stringify(valueToStore))\n    } catch (error) {\n      console.error(error)\n    }\n  }\n  \n  return [storedValue, setValue]\n}\n\n// 使用\nfunction App() {\n  const [name, setName] = useLocalStorage('name', 'Guest')\n  \n  return (\n    \u003Cdiv>\n      \u003Cp>姓名: {name}\u003C/p>\n      \u003Cinput\n        value={name}\n        onChange={(e) => setName(e.target.value)}\n      />\n    \u003C/div>\n  )\n}\n",[996],{"type":26,"tag":180,"props":997,"children":998},{"__ignoreMap":7},[999],{"type":32,"value":994},{"type":26,"tag":231,"props":1001,"children":1003},{"id":1002},"useasync-异步操作",[1004],{"type":32,"value":1005},"useAsync - 异步操作",{"type":26,"tag":403,"props":1007,"children":1010},{"className":1008,"code":1009,"language":943,"meta":7},[941],"import { useState, useEffect, useRef } from 'react'\n\nfunction useAsync(asyncFunction, immediate = true) {\n  const [status, setStatus] = useState('idle')\n  const [value, setValue] = useState(null)\n  const [error, setError] = useState(null)\n  \n  // 使用 ref 来防止无限循环\n  const executeRef = useRef(null)\n  \n  const execute = useRef(async () => {\n    setStatus('pending')\n    setValue(null)\n    setError(null)\n    \n    try {\n      const response = await asyncFunction()\n      setValue(response)\n      setStatus('success')\n      return response\n    } catch (error) {\n      setError(error)\n      setStatus('error')\n    }\n  })\n  \n  executeRef.current = execute.current\n  \n  useEffect(() => {\n    if (!immediate) return\n    \n    executeRef.current()\n  }, [immediate])\n  \n  return { execute: executeRef.current, status, value, error }\n}\n\n// 使用\nfunction UserProfile({ userId }) {\n  const { execute, status, value: user, error } = useAsync(\n    () => fetch(\\`/api/users/\\${userId}\\`).then(r => r.json()),\n    true\n  )\n  \n  if (status === 'pending') return \u003Cp>加载中...\u003C/p>\n  if (status === 'error') return \u003Cp>错误: {error?.message}\u003C/p>\n  if (status === 'success') return \u003Cp>用户: {user?.name}\u003C/p>\n  \n  return null\n}\n",[1011],{"type":26,"tag":180,"props":1012,"children":1013},{"__ignoreMap":7},[1014],{"type":32,"value":1009},{"type":26,"tag":231,"props":1016,"children":1018},{"id":1017},"usefetch-数据获取",[1019],{"type":32,"value":1020},"useFetch - 数据获取",{"type":26,"tag":403,"props":1022,"children":1025},{"className":1023,"code":1024,"language":943,"meta":7},[941],"import { useState, useEffect } from 'react'\n\nfunction useFetch(url, options = {}) {\n  const [data, setData] = useState(null)\n  const [loading, setLoading] = useState(true)\n  const [error, setError] = useState(null)\n  \n  useEffect(() => {\n    let isMounted = true\n    \n    const fetchData = async () => {\n      try {\n        const response = await fetch(url, {\n          method: 'GET',\n          ...options,\n        })\n        \n        if (!response.ok) {\n          throw new Error(\\`HTTP error! status: \\${response.status}\\`)\n        }\n        \n        const result = await response.json()\n        \n        if (isMounted) {\n          setData(result)\n          setError(null)\n        }\n      } catch (err) {\n        if (isMounted) {\n          setError(err)\n          setData(null)\n        }\n      } finally {\n        if (isMounted) {\n          setLoading(false)\n        }\n      }\n    }\n    \n    fetchData()\n    \n    return () => {\n      isMounted = false\n    }\n  }, [url, options])\n  \n  const refetch = async () => {\n    setLoading(true)\n    try {\n      const response = await fetch(url, options)\n      const result = await response.json()\n      setData(result)\n    } catch (err) {\n      setError(err)\n    } finally {\n      setLoading(false)\n    }\n  }\n  \n  return { data, loading, error, refetch }\n}\n\n// 使用\nfunction UserList() {\n  const { data: users, loading, error, refetch } = useFetch('/api/users')\n  \n  if (loading) return \u003Cp>加载中...\u003C/p>\n  if (error) return \u003Cp>错误: {error.message}\u003C/p>\n  \n  return (\n    \u003Cdiv>\n      \u003Cbutton onClick={refetch}>刷新\u003C/button>\n      \u003Cul>\n        {users?.map(user => (\n          \u003Cli key={user.id}>{user.name}\u003C/li>\n        ))}\n      \u003C/ul>\n    \u003C/div>\n  )\n}\n",[1026],{"type":26,"tag":180,"props":1027,"children":1028},{"__ignoreMap":7},[1029],{"type":32,"value":1024},{"type":26,"tag":231,"props":1031,"children":1033},{"id":1032},"useprevious-保存前一个值",[1034],{"type":32,"value":1035},"usePrevious - 保存前一个值",{"type":26,"tag":403,"props":1037,"children":1040},{"className":1038,"code":1039,"language":943,"meta":7},[941],"import { useEffect, useRef } from 'react'\n\nfunction usePrevious(value) {\n  const ref = useRef()\n  \n  useEffect(() => {\n    ref.current = value\n  }, [value])\n  \n  return ref.current\n}\n\n// 使用\nfunction Counter() {\n  const [count, setCount] = React.useState(0)\n  const prevCount = usePrevious(count)\n  \n  return (\n    \u003Cdiv>\n      \u003Cp>当前: {count}, 前一个: {prevCount}\u003C/p>\n      \u003Cbutton onClick={() => setCount(count + 1)}>增加\u003C/button>\n    \u003C/div>\n  )\n}\n",[1041],{"type":26,"tag":180,"props":1042,"children":1043},{"__ignoreMap":7},[1044],{"type":32,"value":1039},{"type":26,"tag":27,"props":1046,"children":1048},{"id":1047},"高级模式",[1049],{"type":32,"value":1047},{"type":26,"tag":231,"props":1051,"children":1053},{"id":1052},"usereducer-复杂状态管理",[1054],{"type":32,"value":1055},"useReducer - 复杂状态管理",{"type":26,"tag":403,"props":1057,"children":1060},{"className":1058,"code":1059,"language":943,"meta":7},[941],"import { useReducer } from 'react'\n\nconst initialState = {\n  todos: [],\n  filter: 'all',\n  error: null,\n}\n\nfunction todoReducer(state, action) {\n  switch (action.type) {\n    case 'ADD_TODO':\n      return {\n        ...state,\n        todos: [...state.todos, { id: Date.now(), text: action.payload }],\n      }\n    \n    case 'REMOVE_TODO':\n      return {\n        ...state,\n        todos: state.todos.filter(todo => todo.id !== action.payload),\n      }\n    \n    case 'SET_FILTER':\n      return { ...state, filter: action.payload }\n    \n    case 'SET_ERROR':\n      return { ...state, error: action.payload }\n    \n    default:\n      return state\n  }\n}\n\nfunction TodoApp() {\n  const [state, dispatch] = useReducer(todoReducer, initialState)\n  \n  const addTodo = (text) => {\n    dispatch({ type: 'ADD_TODO', payload: text })\n  }\n  \n  const removeTodo = (id) => {\n    dispatch({ type: 'REMOVE_TODO', payload: id })\n  }\n  \n  return (\n    \u003Cdiv>\n      {state.todos.map(todo => (\n        \u003Cdiv key={todo.id}>\n          {todo.text}\n          \u003Cbutton onClick={() => removeTodo(todo.id)}>删除\u003C/button>\n        \u003C/div>\n      ))}\n    \u003C/div>\n  )\n}\n",[1061],{"type":26,"tag":180,"props":1062,"children":1063},{"__ignoreMap":7},[1064],{"type":32,"value":1059},{"type":26,"tag":27,"props":1066,"children":1068},{"id":1067},"最佳实践",[1069],{"type":32,"value":1067},{"type":26,"tag":34,"props":1071,"children":1072},{},[1073,1075,1080],{"type":32,"value":1074},"✅ ",{"type":26,"tag":77,"props":1076,"children":1077},{},[1078],{"type":32,"value":1079},"应该做的事",{"type":32,"value":1081},":",{"type":26,"tag":40,"props":1083,"children":1084},{},[1085,1090,1095,1100,1105],{"type":26,"tag":44,"props":1086,"children":1087},{},[1088],{"type":32,"value":1089},"将相关逻辑提取到自定义 Hooks",{"type":26,"tag":44,"props":1091,"children":1092},{},[1093],{"type":32,"value":1094},"在 useEffect 的依赖数组中包含所有依赖",{"type":26,"tag":44,"props":1096,"children":1097},{},[1098],{"type":32,"value":1099},"使用 useCallback 和 useMemo 优化性能",{"type":26,"tag":44,"props":1101,"children":1102},{},[1103],{"type":32,"value":1104},"为自定义 Hooks 编写文档",{"type":26,"tag":44,"props":1106,"children":1107},{},[1108],{"type":32,"value":1109},"及时清理副作用",{"type":26,"tag":34,"props":1111,"children":1112},{},[1113,1115,1120],{"type":32,"value":1114},"❌ ",{"type":26,"tag":77,"props":1116,"children":1117},{},[1118],{"type":32,"value":1119},"不应该做的事",{"type":32,"value":1081},{"type":26,"tag":40,"props":1122,"children":1123},{},[1124,1129,1134,1139,1144],{"type":26,"tag":44,"props":1125,"children":1126},{},[1127],{"type":32,"value":1128},"在条件或循环中调用 Hooks",{"type":26,"tag":44,"props":1130,"children":1131},{},[1132],{"type":32,"value":1133},"在普通函数中调用 Hooks",{"type":26,"tag":44,"props":1135,"children":1136},{},[1137],{"type":32,"value":1138},"忘记依赖数组",{"type":26,"tag":44,"props":1140,"children":1141},{},[1142],{"type":32,"value":1143},"过度使用 useMemo/useCallback",{"type":26,"tag":44,"props":1145,"children":1146},{},[1147],{"type":32,"value":1148},"在 Hooks 中创建过多的闭包",{"type":26,"tag":27,"props":1150,"children":1152},{"id":1151},"检查清单",[1153],{"type":32,"value":1151},{"type":26,"tag":40,"props":1155,"children":1158},{"className":1156},[1157],"contains-task-list",[1159,1172,1181,1190,1199],{"type":26,"tag":44,"props":1160,"children":1163},{"className":1161},[1162],"task-list-item",[1164,1170],{"type":26,"tag":1165,"props":1166,"children":1169},"input",{"disabled":1167,"type":1168},true,"checkbox",[],{"type":32,"value":1171}," Hooks 调用顺序正确",{"type":26,"tag":44,"props":1173,"children":1175},{"className":1174},[1162],[1176,1179],{"type":26,"tag":1165,"props":1177,"children":1178},{"disabled":1167,"type":1168},[],{"type":32,"value":1180}," 依赖数组完整",{"type":26,"tag":44,"props":1182,"children":1184},{"className":1183},[1162],[1185,1188],{"type":26,"tag":1165,"props":1186,"children":1187},{"disabled":1167,"type":1168},[],{"type":32,"value":1189}," 副作用正确清理",{"type":26,"tag":44,"props":1191,"children":1193},{"className":1192},[1162],[1194,1197],{"type":26,"tag":1165,"props":1195,"children":1196},{"disabled":1167,"type":1168},[],{"type":32,"value":1198}," 性能优化得当",{"type":26,"tag":44,"props":1200,"children":1202},{"className":1201},[1162],[1203,1206],{"type":26,"tag":1165,"props":1204,"children":1205},{"disabled":1167,"type":1168},[],{"type":32,"value":1207}," 代码易于理解和测试",{"title":7,"searchDepth":865,"depth":865,"links":1209},[1210,1211,1216,1222,1225,1226],{"id":918,"depth":868,"text":902},{"id":928,"depth":868,"text":931,"children":1212},[1213,1214,1215],{"id":934,"depth":865,"text":937},{"id":951,"depth":865,"text":954},{"id":966,"depth":865,"text":969},{"id":981,"depth":868,"text":984,"children":1217},[1218,1219,1220,1221],{"id":987,"depth":865,"text":990},{"id":1002,"depth":865,"text":1005},{"id":1017,"depth":865,"text":1020},{"id":1032,"depth":865,"text":1035},{"id":1047,"depth":868,"text":1047,"children":1223},[1224],{"id":1052,"depth":865,"text":1055},{"id":1067,"depth":868,"text":1067},{"id":1151,"depth":868,"text":1151},"content:topics:frontend:react-hooks-guide.md","topics/frontend/react-hooks-guide.md","topics/frontend/react-hooks-guide",{"_path":1231,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1232,"description":1233,"keywords":1234,"image":1240,"author":911,"date":912,"readingTime":1241,"topic":5,"body":1242,"_type":893,"_id":1539,"_source":895,"_file":1540,"_stem":1541,"_extension":898},"/topics/frontend/vue3-composition-api","Vue 3 Composition API 深度解析","全面讲解 Vue 3 Composition API 的用法、最佳实践和高级模式",[1235,1236,1237,1238,1239],"Vue 3","Composition API","组合式函数","响应式系统","前端开发","/images/topics/vue3-composition-api.jpg",22,{"type":23,"children":1243,"toc":1515},[1244,1249,1254,1259,1265,1274,1279,1288,1292,1297,1306,1311,1317,1326,1331,1337,1346,1351,1356,1365,1370,1376,1385,1389,1398,1426,1435,1463,1467],{"type":26,"tag":27,"props":1245,"children":1247},{"id":1246},"vue-3-composition-api-深度解析",[1248],{"type":32,"value":1232},{"type":26,"tag":34,"props":1250,"children":1251},{},[1252],{"type":32,"value":1253},"Composition API 让 Vue 应用更易于组织和重用逻辑。本文深入讲解这一核心特性。",{"type":26,"tag":27,"props":1255,"children":1257},{"id":1256},"核心概念",[1258],{"type":32,"value":1256},{"type":26,"tag":231,"props":1260,"children":1262},{"id":1261},"setup-函数",[1263],{"type":32,"value":1264},"setup 函数",{"type":26,"tag":403,"props":1266,"children":1269},{"className":1267,"code":1268,"language":943,"meta":7},[941],"import { ref, computed, watch } from 'vue'\n\nexport default {\n  props: ['initialCount'],\n  emits: ['count-changed'],\n  \n  setup(props, { emit, slots, expose }) {\n    // 创建响应式状态\n    const count = ref(props.initialCount)\n    const doubled = computed(() => count.value * 2)\n    \n    // 监听状态变化\n    watch(count, (newVal, oldVal) => {\n      console.log(`Count changed from ${oldVal} to ${newVal}`)\n      emit('count-changed', newVal)\n    })\n    \n    // 定义方法\n    const increment = () => count.value++\n    const decrement = () => count.value--\n    \n    // 返回模板需要的内容\n    return {\n      count,\n      doubled,\n      increment,\n      decrement,\n    }\n  },\n}\n",[1270],{"type":26,"tag":180,"props":1271,"children":1272},{"__ignoreMap":7},[1273],{"type":32,"value":1268},{"type":26,"tag":231,"props":1275,"children":1277},{"id":1276},"响应式基础",[1278],{"type":32,"value":1276},{"type":26,"tag":403,"props":1280,"children":1283},{"className":1281,"code":1282,"language":943,"meta":7},[941],"import { ref, reactive, readonly, isRef } from 'vue'\n\n// ref - 用于基本类型\nconst count = ref(0)\nconsole.log(count.value) // 0\ncount.value++\n\n// reactive - 用于对象\nconst state = reactive({\n  name: 'John',\n  age: 30,\n  address: {\n    city: 'Beijing',\n  },\n})\n\nstate.name = 'Jane' // 自动更新，无需 .value\n\n// readonly - 创建只读副本\nconst original = reactive({ count: 0 })\nconst copy = readonly(original)\n// copy.count++ // 错误：不能修改\n\n// isRef 检查\nconsole.log(isRef(count)) // true\nconsole.log(isRef(state)) // false\n",[1284],{"type":26,"tag":180,"props":1285,"children":1286},{"__ignoreMap":7},[1287],{"type":32,"value":1282},{"type":26,"tag":27,"props":1289,"children":1290},{"id":1237},[1291],{"type":32,"value":1237},{"type":26,"tag":231,"props":1293,"children":1295},{"id":1294},"创建可重用逻辑",[1296],{"type":32,"value":1294},{"type":26,"tag":403,"props":1298,"children":1301},{"className":1299,"code":1300,"language":943,"meta":7},[941],"// useCounter.js - 组合式函数\nimport { ref, computed } from 'vue'\n\nexport function useCounter(initialValue = 0) {\n  const count = ref(initialValue)\n  const doubled = computed(() => count.value * 2)\n  \n  const increment = () => count.value++\n  const decrement = () => count.value--\n  const reset = () => count.value = initialValue\n  \n  return {\n    count,\n    doubled,\n    increment,\n    decrement,\n    reset,\n  }\n}\n\n// useFetch.js - 数据获取组合式函数\nimport { ref, onMounted } from 'vue'\n\nexport function useFetch(url) {\n  const data = ref(null)\n  const loading = ref(false)\n  const error = ref(null)\n  \n  const fetch = async () => {\n    loading.value = true\n    error.value = null\n    \n    try {\n      const response = await fetch(url)\n      data.value = await response.json()\n    } catch (e) {\n      error.value = e\n    } finally {\n      loading.value = false\n    }\n  }\n  \n  onMounted(fetch)\n  \n  return {\n    data,\n    loading,\n    error,\n    refetch: fetch,\n  }\n}\n\n// 使用\nexport default {\n  setup() {\n    const { count, doubled, increment } = useCounter(10)\n    const { data, loading, refetch } = useFetch('/api/data')\n    \n    return {\n      count,\n      doubled,\n      increment,\n      data,\n      loading,\n      refetch,\n    }\n  },\n}\n",[1302],{"type":26,"tag":180,"props":1303,"children":1304},{"__ignoreMap":7},[1305],{"type":32,"value":1300},{"type":26,"tag":27,"props":1307,"children":1309},{"id":1308},"生命周期钩子",[1310],{"type":32,"value":1308},{"type":26,"tag":231,"props":1312,"children":1314},{"id":1313},"composition-api-中的生命周期",[1315],{"type":32,"value":1316},"Composition API 中的生命周期",{"type":26,"tag":403,"props":1318,"children":1321},{"className":1319,"code":1320,"language":943,"meta":7},[941],"import {\n  onBeforeMount,\n  onMounted,\n  onBeforeUpdate,\n  onUpdated,\n  onBeforeUnmount,\n  onUnmounted,\n  onErrorCaptured,\n} from 'vue'\n\nexport default {\n  setup() {\n    onBeforeMount(() => {\n      console.log('组件挂载前')\n    })\n    \n    onMounted(() => {\n      console.log('组件已挂载')\n      // 初始化事件监听器、定时器等\n    })\n    \n    onBeforeUpdate(() => {\n      console.log('组件更新前')\n    })\n    \n    onUpdated(() => {\n      console.log('组件已更新')\n    })\n    \n    onBeforeUnmount(() => {\n      console.log('组件卸载前')\n    })\n    \n    onUnmounted(() => {\n      console.log('组件已卸载')\n      // 清理事件监听器、定时器等\n    })\n    \n    onErrorCaptured((err, instance, info) => {\n      console.log('捕获错误:', err)\n      return false // 返回 false 阻止错误传播\n    })\n    \n    return {}\n  },\n}\n",[1322],{"type":26,"tag":180,"props":1323,"children":1324},{"__ignoreMap":7},[1325],{"type":32,"value":1320},{"type":26,"tag":27,"props":1327,"children":1329},{"id":1328},"模板引用",[1330],{"type":32,"value":1328},{"type":26,"tag":231,"props":1332,"children":1334},{"id":1333},"访问-dom-元素",[1335],{"type":32,"value":1336},"访问 DOM 元素",{"type":26,"tag":403,"props":1338,"children":1341},{"className":1339,"code":1340,"language":943,"meta":7},[941],"import { ref, onMounted } from 'vue'\n\nexport default {\n  setup() {\n    const inputRef = ref(null)\n    const listRef = ref(null)\n    const dynamicRef = ref(null)\n    \n    onMounted(() => {\n      // 访问 DOM 元素\n      inputRef.value?.focus()\n      console.log(listRef.value?.offsetHeight)\n    })\n    \n    // 函数式引用\n    const assignRef = el => {\n      if (el) {\n        console.log('元素已赋值', el)\n      } else {\n        console.log('元素已移除')\n      }\n    }\n    \n    return {\n      inputRef,\n      listRef,\n      dynamicRef,\n      assignRef,\n    }\n  },\n  \n  template: \\`\n    \u003Cdiv>\n      \u003Cinput ref=\"inputRef\" />\n      \u003Cul ref=\"listRef\">\n        \u003Cli v-for=\"item in items\" :key=\"item\">{{ item }}\u003C/li>\n      \u003C/ul>\n      \u003Cdiv :ref=\"assignRef\">\u003C/div>\n    \u003C/div>\n  \\`,\n}\n",[1342],{"type":26,"tag":180,"props":1343,"children":1344},{"__ignoreMap":7},[1345],{"type":32,"value":1340},{"type":26,"tag":27,"props":1347,"children":1349},{"id":1348},"依赖注入",[1350],{"type":32,"value":1348},{"type":26,"tag":231,"props":1352,"children":1354},{"id":1353},"跨组件共享数据",[1355],{"type":32,"value":1353},{"type":26,"tag":403,"props":1357,"children":1360},{"className":1358,"code":1359,"language":943,"meta":7},[941],"import { provide, inject, ref, readonly } from 'vue'\n\n// 父组件\nexport default {\n  setup() {\n    const theme = ref('light')\n    const user = ref({ name: 'John', role: 'admin' })\n    \n    // 提供数据给子组件\n    provide('theme', readonly(theme))\n    provide('updateTheme', (newTheme) => {\n      theme.value = newTheme\n    })\n    \n    // 使用 Symbol 作为 key 避免命名冲突\n    const userKey = Symbol()\n    provide(userKey, readonly(user))\n    \n    return {\n      theme,\n      updateTheme: (newTheme) => {\n        theme.value = newTheme\n      },\n    }\n  },\n}\n\n// 子组件\nexport default {\n  setup() {\n    // 注入数据\n    const theme = inject('theme')\n    const updateTheme = inject('updateTheme')\n    const user = inject(Symbol.for('user'))\n    \n    // 带默认值的注入\n    const config = inject('config', {\n      apiUrl: 'http://localhost:3000',\n    })\n    \n    return {\n      theme,\n      updateTheme,\n      user,\n      config,\n    }\n  },\n}\n",[1361],{"type":26,"tag":180,"props":1362,"children":1363},{"__ignoreMap":7},[1364],{"type":32,"value":1359},{"type":26,"tag":27,"props":1366,"children":1368},{"id":1367},"高级状态管理",[1369],{"type":32,"value":1367},{"type":26,"tag":231,"props":1371,"children":1373},{"id":1372},"创建小型-store",[1374],{"type":32,"value":1375},"创建小型 store",{"type":26,"tag":403,"props":1377,"children":1380},{"className":1378,"code":1379,"language":943,"meta":7},[941],"import { reactive, readonly, computed } from 'vue'\n\n// store.js - 不依赖 Pinia 的简单 store\nexport function createStore() {\n  const state = reactive({\n    items: [],\n    filter: 'all',\n    sortBy: 'date',\n  })\n  \n  const filteredItems = computed(() => {\n    let result = state.items\n    \n    if (state.filter !== 'all') {\n      result = result.filter(item => item.status === state.filter)\n    }\n    \n    if (state.sortBy === 'date') {\n      result.sort((a, b) => new Date(b.date) - new Date(a.date))\n    } else if (state.sortBy === 'name') {\n      result.sort((a, b) => a.name.localeCompare(b.name))\n    }\n    \n    return result\n  })\n  \n  const actions = {\n    addItem(item) {\n      state.items.push({ ...item, id: Date.now() })\n    },\n    \n    removeItem(id) {\n      state.items = state.items.filter(item => item.id !== id)\n    },\n    \n    updateItem(id, updates) {\n      const item = state.items.find(item => item.id === id)\n      if (item) {\n        Object.assign(item, updates)\n      }\n    },\n    \n    setFilter(filter) {\n      state.filter = filter\n    },\n    \n    setSortBy(sortBy) {\n      state.sortBy = sortBy\n    },\n  }\n  \n  return {\n    state: readonly(state),\n    filteredItems,\n    ...actions,\n  }\n}\n\n// 使用\nexport default {\n  setup() {\n    const store = createStore()\n    \n    const handleAdd = (item) => {\n      store.addItem(item)\n    }\n    \n    return {\n      items: store.filteredItems,\n      addItem: handleAdd,\n      setFilter: store.setFilter,\n    }\n  },\n}\n",[1381],{"type":26,"tag":180,"props":1382,"children":1383},{"__ignoreMap":7},[1384],{"type":32,"value":1379},{"type":26,"tag":27,"props":1386,"children":1387},{"id":1067},[1388],{"type":32,"value":1067},{"type":26,"tag":34,"props":1390,"children":1391},{},[1392,1393,1397],{"type":32,"value":1074},{"type":26,"tag":77,"props":1394,"children":1395},{},[1396],{"type":32,"value":1079},{"type":32,"value":1081},{"type":26,"tag":40,"props":1399,"children":1400},{},[1401,1406,1411,1416,1421],{"type":26,"tag":44,"props":1402,"children":1403},{},[1404],{"type":32,"value":1405},"将相关逻辑组织在一起",{"type":26,"tag":44,"props":1407,"children":1408},{},[1409],{"type":32,"value":1410},"创建可重用的组合式函数",{"type":26,"tag":44,"props":1412,"children":1413},{},[1414],{"type":32,"value":1415},"使用 TypeScript 获得更好的类型检查",{"type":26,"tag":44,"props":1417,"children":1418},{},[1419],{"type":32,"value":1420},"合理使用计算属性和监听器",{"type":26,"tag":44,"props":1422,"children":1423},{},[1424],{"type":32,"value":1425},"及时清理事件监听器和定时器",{"type":26,"tag":34,"props":1427,"children":1428},{},[1429,1430,1434],{"type":32,"value":1114},{"type":26,"tag":77,"props":1431,"children":1432},{},[1433],{"type":32,"value":1119},{"type":32,"value":1081},{"type":26,"tag":40,"props":1436,"children":1437},{},[1438,1443,1448,1453,1458],{"type":26,"tag":44,"props":1439,"children":1440},{},[1441],{"type":32,"value":1442},"在 setup 中执行副作用操作（除了生命周期钩子）",{"type":26,"tag":44,"props":1444,"children":1445},{},[1446],{"type":32,"value":1447},"过度使用计算属性",{"type":26,"tag":44,"props":1449,"children":1450},{},[1451],{"type":32,"value":1452},"忘记清理 watch 监听器",{"type":26,"tag":44,"props":1454,"children":1455},{},[1456],{"type":32,"value":1457},"在 reactive 对象中存储引用类型时不谨慎",{"type":26,"tag":44,"props":1459,"children":1460},{},[1461],{"type":32,"value":1462},"过度复杂化组合式函数",{"type":26,"tag":27,"props":1464,"children":1465},{"id":1151},[1466],{"type":32,"value":1151},{"type":26,"tag":40,"props":1468,"children":1470},{"className":1469},[1157],[1471,1480,1489,1498,1507],{"type":26,"tag":44,"props":1472,"children":1474},{"className":1473},[1162],[1475,1478],{"type":26,"tag":1165,"props":1476,"children":1477},{"disabled":1167,"type":1168},[],{"type":32,"value":1479}," 正确使用 ref 和 reactive",{"type":26,"tag":44,"props":1481,"children":1483},{"className":1482},[1162],[1484,1487],{"type":26,"tag":1165,"props":1485,"children":1486},{"disabled":1167,"type":1168},[],{"type":32,"value":1488}," 生命周期钩子正确",{"type":26,"tag":44,"props":1490,"children":1492},{"className":1491},[1162],[1493,1496],{"type":26,"tag":1165,"props":1494,"children":1495},{"disabled":1167,"type":1168},[],{"type":32,"value":1497}," 模板引用工作正常",{"type":26,"tag":44,"props":1499,"children":1501},{"className":1500},[1162],[1502,1505],{"type":26,"tag":1165,"props":1503,"children":1504},{"disabled":1167,"type":1168},[],{"type":32,"value":1506}," 组合式函数可重用",{"type":26,"tag":44,"props":1508,"children":1510},{"className":1509},[1162],[1511,1514],{"type":26,"tag":1165,"props":1512,"children":1513},{"disabled":1167,"type":1168},[],{"type":32,"value":1198},{"title":7,"searchDepth":865,"depth":865,"links":1516},[1517,1518,1522,1525,1528,1531,1534,1537,1538],{"id":1246,"depth":868,"text":1232},{"id":1256,"depth":868,"text":1256,"children":1519},[1520,1521],{"id":1261,"depth":865,"text":1264},{"id":1276,"depth":865,"text":1276},{"id":1237,"depth":868,"text":1237,"children":1523},[1524],{"id":1294,"depth":865,"text":1294},{"id":1308,"depth":868,"text":1308,"children":1526},[1527],{"id":1313,"depth":865,"text":1316},{"id":1328,"depth":868,"text":1328,"children":1529},[1530],{"id":1333,"depth":865,"text":1336},{"id":1348,"depth":868,"text":1348,"children":1532},[1533],{"id":1353,"depth":865,"text":1353},{"id":1367,"depth":868,"text":1367,"children":1535},[1536],{"id":1372,"depth":865,"text":1375},{"id":1067,"depth":868,"text":1067},{"id":1151,"depth":868,"text":1151},"content:topics:frontend:vue3-composition-api.md","topics/frontend/vue3-composition-api.md","topics/frontend/vue3-composition-api",{"_path":1543,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1544,"description":1545,"date":1546,"topic":5,"author":11,"tags":1547,"image":1552,"featured":1167,"readingTime":1553,"body":1554,"_type":893,"_id":2813,"_source":895,"_file":2814,"_stem":2815,"_extension":898},"/topics/frontend/rspack-performance-practice","Rspack 构建性能实战","从 Rspack 的架构设计与编译管线出发，系统对比 Webpack/Vite 并给出 Rspack 在大型项目中的迁移路径、性能调优策略与生产级可观测方案。","2026-01-20",[1548,1549,1550,1551,16],"Rspack","构建工具","性能优化","Webpack","/images/topics/rspack.jpg",25,{"type":23,"children":1555,"toc":2780},[1556,1561,1573,1578,1596,1607,1612,1635,1638,1644,1649,1655,1688,1694,1712,1715,1721,1727,1732,1745,1751,1756,1769,1775,1793,1798,1801,1807,1812,1953,1958,1981,1984,1990,1996,2001,2006,2072,2085,2091,2099,2112,2120,2133,2141,2154,2160,2178,2181,2187,2193,2198,2211,2217,2222,2233,2239,2244,2262,2267,2295,2298,2304,2309,2320,2325,2343,2348,2366,2369,2375,2380,2398,2403,2426,2431,2449,2452,2458,2464,2469,2487,2493,2511,2517,2535,2538,2544,2659,2664,2682,2685,2691,2749,2752,2757,2762],{"type":26,"tag":27,"props":1557,"children":1559},{"id":1558},"rspack-构建性能实战",[1560],{"type":32,"value":1544},{"type":26,"tag":34,"props":1562,"children":1563},{},[1564,1566,1571],{"type":32,"value":1565},"Rspack 不是\"又一个构建工具\"，而是字节跳动在处理",{"type":26,"tag":77,"props":1567,"children":1568},{},[1569],{"type":32,"value":1570},"超大规模前端项目",{"type":32,"value":1572},"时，对 Webpack 生态的 Rust 重写与工程化沉淀。",{"type":26,"tag":34,"props":1574,"children":1575},{},[1576],{"type":32,"value":1577},"它要解决的核心问题是：",{"type":26,"tag":40,"props":1579,"children":1580},{},[1581,1586,1591],{"type":26,"tag":44,"props":1582,"children":1583},{},[1584],{"type":32,"value":1585},"Webpack 的构建速度在大型 monorepo 下（10k+ 模块）已成为开发体验瓶颈",{"type":26,"tag":44,"props":1587,"children":1588},{},[1589],{"type":32,"value":1590},"但你又无法抛弃 Webpack 的插件生态与配置范式",{"type":26,"tag":44,"props":1592,"children":1593},{},[1594],{"type":32,"value":1595},"Vite 虽然快，但在某些场景（大型遗留项目、特定插件依赖）迁移成本高",{"type":26,"tag":34,"props":1597,"children":1598},{},[1599,1601,1606],{"type":32,"value":1600},"Rspack 的定位是：",{"type":26,"tag":77,"props":1602,"children":1603},{},[1604],{"type":32,"value":1605},"Webpack 兼容 API + Rust 性能 + 生产级稳定性",{"type":32,"value":604},{"type":26,"tag":34,"props":1608,"children":1609},{},[1610],{"type":32,"value":1611},"这篇文章不讲\"Hello World\"，而是按\"你要在生产上稳定用 Rspack\"的标准，给出：",{"type":26,"tag":40,"props":1613,"children":1614},{},[1615,1620,1625,1630],{"type":26,"tag":44,"props":1616,"children":1617},{},[1618],{"type":32,"value":1619},"性能收益的真实量化方法",{"type":26,"tag":44,"props":1621,"children":1622},{},[1623],{"type":32,"value":1624},"迁移路径与兼容性边界",{"type":26,"tag":44,"props":1626,"children":1627},{},[1628],{"type":32,"value":1629},"优化策略（缓存、并行、Tree Shaking）",{"type":26,"tag":44,"props":1631,"children":1632},{},[1633],{"type":32,"value":1634},"监控与排障（为什么变慢、为什么产物变大）",{"type":26,"tag":132,"props":1636,"children":1637},{},[],{"type":26,"tag":27,"props":1639,"children":1641},{"id":1640},"_1-先回答什么项目值得迁移-rspack",[1642],{"type":32,"value":1643},"1. 先回答：什么项目值得迁移 Rspack？",{"type":26,"tag":34,"props":1645,"children":1646},{},[1647],{"type":32,"value":1648},"不是所有项目都需要 Rspack。",{"type":26,"tag":231,"props":1650,"children":1652},{"id":1651},"_11-高收益场景",[1653],{"type":32,"value":1654},"1.1 高收益场景",{"type":26,"tag":40,"props":1656,"children":1657},{},[1658,1668,1678],{"type":26,"tag":44,"props":1659,"children":1660},{},[1661,1666],{"type":26,"tag":77,"props":1662,"children":1663},{},[1664],{"type":32,"value":1665},"大型 monorepo",{"type":32,"value":1667},"（5k+ 模块，构建时间 > 2 分钟）",{"type":26,"tag":44,"props":1669,"children":1670},{},[1671,1676],{"type":26,"tag":77,"props":1672,"children":1673},{},[1674],{"type":32,"value":1675},"频繁开发迭代",{"type":32,"value":1677},"（HMR 延迟影响体验）",{"type":26,"tag":44,"props":1679,"children":1680},{},[1681,1686],{"type":26,"tag":77,"props":1682,"children":1683},{},[1684],{"type":32,"value":1685},"CI 构建成本高",{"type":32,"value":1687},"（每次 PR 构建超 10 分钟）",{"type":26,"tag":231,"props":1689,"children":1691},{"id":1690},"_12-收益不明显的场景",[1692],{"type":32,"value":1693},"1.2 收益不明显的场景",{"type":26,"tag":40,"props":1695,"children":1696},{},[1697,1702,1707],{"type":26,"tag":44,"props":1698,"children":1699},{},[1700],{"type":32,"value":1701},"小型项目（\u003C 1k 模块）",{"type":26,"tag":44,"props":1703,"children":1704},{},[1705],{"type":32,"value":1706},"已经用 Vite 且体验良好",{"type":26,"tag":44,"props":1708,"children":1709},{},[1710],{"type":32,"value":1711},"高度定制的 Webpack 插件（迁移成本 > 性能收益）",{"type":26,"tag":132,"props":1713,"children":1714},{},[],{"type":26,"tag":27,"props":1716,"children":1718},{"id":1717},"_2-rspack-的架构为什么能快",[1719],{"type":32,"value":1720},"2. Rspack 的架构：为什么能快？",{"type":26,"tag":231,"props":1722,"children":1724},{"id":1723},"_21-rust-并行编译",[1725],{"type":32,"value":1726},"2.1 Rust 并行编译",{"type":26,"tag":34,"props":1728,"children":1729},{},[1730],{"type":32,"value":1731},"Webpack 是单线程 JavaScript，Rspack 是多线程 Rust。",{"type":26,"tag":40,"props":1733,"children":1734},{},[1735,1740],{"type":26,"tag":44,"props":1736,"children":1737},{},[1738],{"type":32,"value":1739},"模块解析、编译、优化可并行",{"type":26,"tag":44,"props":1741,"children":1742},{},[1743],{"type":32,"value":1744},"I/O 密集型任务（读文件、写产物）异步化",{"type":26,"tag":231,"props":1746,"children":1748},{"id":1747},"_22-更激进的缓存策略",[1749],{"type":32,"value":1750},"2.2 更激进的缓存策略",{"type":26,"tag":34,"props":1752,"children":1753},{},[1754],{"type":32,"value":1755},"Rspack 内置持久化缓存：",{"type":26,"tag":40,"props":1757,"children":1758},{},[1759,1764],{"type":26,"tag":44,"props":1760,"children":1761},{},[1762],{"type":32,"value":1763},"模块级别缓存（类似 Webpack 5 的 cache.type: 'filesystem'）",{"type":26,"tag":44,"props":1765,"children":1766},{},[1767],{"type":32,"value":1768},"但实现更激进：对未变化模块跳过编译",{"type":26,"tag":231,"props":1770,"children":1772},{"id":1771},"_23-内置常用功能减少插件开销",[1773],{"type":32,"value":1774},"2.3 内置常用功能（减少插件开销）",{"type":26,"tag":40,"props":1776,"children":1777},{},[1778,1783,1788],{"type":26,"tag":44,"props":1779,"children":1780},{},[1781],{"type":32,"value":1782},"SWC 替代 Babel（内置 TS/JSX/装饰器）",{"type":26,"tag":44,"props":1784,"children":1785},{},[1786],{"type":32,"value":1787},"CSS Modules、PostCSS 内置",{"type":26,"tag":44,"props":1789,"children":1790},{},[1791],{"type":32,"value":1792},"Tree Shaking 内置",{"type":26,"tag":34,"props":1794,"children":1795},{},[1796],{"type":32,"value":1797},"这让 Rspack 在相同功能下比 Webpack + 插件链路更快。",{"type":26,"tag":132,"props":1799,"children":1800},{},[],{"type":26,"tag":27,"props":1802,"children":1804},{"id":1803},"_3-性能对比真实场景的量化",[1805],{"type":32,"value":1806},"3. 性能对比：真实场景的量化",{"type":26,"tag":34,"props":1808,"children":1809},{},[1810],{"type":32,"value":1811},"我们用一个典型中型项目（3k 模块，React + TS + CSS Modules）做对比：",{"type":26,"tag":1813,"props":1814,"children":1815},"table",{},[1816,1844],{"type":26,"tag":1817,"props":1818,"children":1819},"thead",{},[1820],{"type":26,"tag":1821,"props":1822,"children":1823},"tr",{},[1824,1830,1835,1839],{"type":26,"tag":1825,"props":1826,"children":1827},"th",{},[1828],{"type":32,"value":1829},"指标",{"type":26,"tag":1825,"props":1831,"children":1832},{},[1833],{"type":32,"value":1834},"Webpack 5",{"type":26,"tag":1825,"props":1836,"children":1837},{},[1838],{"type":32,"value":1548},{"type":26,"tag":1825,"props":1840,"children":1841},{},[1842],{"type":32,"value":1843},"提升",{"type":26,"tag":1845,"props":1846,"children":1847},"tbody",{},[1848,1875,1901,1927],{"type":26,"tag":1821,"props":1849,"children":1850},{},[1851,1857,1862,1867],{"type":26,"tag":1852,"props":1853,"children":1854},"td",{},[1855],{"type":32,"value":1856},"冷启动",{"type":26,"tag":1852,"props":1858,"children":1859},{},[1860],{"type":32,"value":1861},"42s",{"type":26,"tag":1852,"props":1863,"children":1864},{},[1865],{"type":32,"value":1866},"8s",{"type":26,"tag":1852,"props":1868,"children":1869},{},[1870],{"type":26,"tag":77,"props":1871,"children":1872},{},[1873],{"type":32,"value":1874},"5.2x",{"type":26,"tag":1821,"props":1876,"children":1877},{},[1878,1883,1888,1893],{"type":26,"tag":1852,"props":1879,"children":1880},{},[1881],{"type":32,"value":1882},"HMR（热更新）",{"type":26,"tag":1852,"props":1884,"children":1885},{},[1886],{"type":32,"value":1887},"1.2s",{"type":26,"tag":1852,"props":1889,"children":1890},{},[1891],{"type":32,"value":1892},"0.15s",{"type":26,"tag":1852,"props":1894,"children":1895},{},[1896],{"type":26,"tag":77,"props":1897,"children":1898},{},[1899],{"type":32,"value":1900},"8x",{"type":26,"tag":1821,"props":1902,"children":1903},{},[1904,1909,1914,1919],{"type":26,"tag":1852,"props":1905,"children":1906},{},[1907],{"type":32,"value":1908},"生产构建",{"type":26,"tag":1852,"props":1910,"children":1911},{},[1912],{"type":32,"value":1913},"125s",{"type":26,"tag":1852,"props":1915,"children":1916},{},[1917],{"type":32,"value":1918},"28s",{"type":26,"tag":1852,"props":1920,"children":1921},{},[1922],{"type":26,"tag":77,"props":1923,"children":1924},{},[1925],{"type":32,"value":1926},"4.5x",{"type":26,"tag":1821,"props":1928,"children":1929},{},[1930,1935,1940,1945],{"type":26,"tag":1852,"props":1931,"children":1932},{},[1933],{"type":32,"value":1934},"内存峰值",{"type":26,"tag":1852,"props":1936,"children":1937},{},[1938],{"type":32,"value":1939},"1.8GB",{"type":26,"tag":1852,"props":1941,"children":1942},{},[1943],{"type":32,"value":1944},"0.9GB",{"type":26,"tag":1852,"props":1946,"children":1947},{},[1948],{"type":26,"tag":77,"props":1949,"children":1950},{},[1951],{"type":32,"value":1952},"2x",{"type":26,"tag":34,"props":1954,"children":1955},{},[1956],{"type":32,"value":1957},"关键收益：",{"type":26,"tag":40,"props":1959,"children":1960},{},[1961,1971],{"type":26,"tag":44,"props":1962,"children":1963},{},[1964,1969],{"type":26,"tag":77,"props":1965,"children":1966},{},[1967],{"type":32,"value":1968},"开发体验质变",{"type":32,"value":1970},"（HMR \u003C 200ms）",{"type":26,"tag":44,"props":1972,"children":1973},{},[1974,1979],{"type":26,"tag":77,"props":1975,"children":1976},{},[1977],{"type":32,"value":1978},"CI 成本减半",{"type":32,"value":1980},"（构建时间直接影响 Runner 费用）",{"type":26,"tag":132,"props":1982,"children":1983},{},[],{"type":26,"tag":27,"props":1985,"children":1987},{"id":1986},"_4-迁移路径从-webpack-到-rspack",[1988],{"type":32,"value":1989},"4. 迁移路径：从 Webpack 到 Rspack",{"type":26,"tag":231,"props":1991,"children":1993},{"id":1992},"_41-最小迁移保守策略",[1994],{"type":32,"value":1995},"4.1 最小迁移（保守策略）",{"type":26,"tag":34,"props":1997,"children":1998},{},[1999],{"type":32,"value":2000},"目标：用最小改动换取性能收益。",{"type":26,"tag":34,"props":2002,"children":2003},{},[2004],{"type":32,"value":2005},"步骤：",{"type":26,"tag":70,"props":2007,"children":2008},{},[2009,2028,2047,2067],{"type":26,"tag":44,"props":2010,"children":2011},{},[2012,2014,2020,2022],{"type":32,"value":2013},"安装 ",{"type":26,"tag":180,"props":2015,"children":2017},{"className":2016},[],[2018],{"type":32,"value":2019},"@rspack/cli",{"type":32,"value":2021}," 与 ",{"type":26,"tag":180,"props":2023,"children":2025},{"className":2024},[],[2026],{"type":32,"value":2027},"@rspack/core",{"type":26,"tag":44,"props":2029,"children":2030},{},[2031,2033,2039,2041],{"type":32,"value":2032},"把 ",{"type":26,"tag":180,"props":2034,"children":2036},{"className":2035},[],[2037],{"type":32,"value":2038},"webpack.config.js",{"type":32,"value":2040}," 改为 ",{"type":26,"tag":180,"props":2042,"children":2044},{"className":2043},[],[2045],{"type":32,"value":2046},"rspack.config.js",{"type":26,"tag":44,"props":2048,"children":2049},{},[2050,2052,2058,2060,2066],{"type":32,"value":2051},"替换构建命令（",{"type":26,"tag":180,"props":2053,"children":2055},{"className":2054},[],[2056],{"type":32,"value":2057},"rspack build",{"type":32,"value":2059}," / ",{"type":26,"tag":180,"props":2061,"children":2063},{"className":2062},[],[2064],{"type":32,"value":2065},"rspack dev",{"type":32,"value":187},{"type":26,"tag":44,"props":2068,"children":2069},{},[2070],{"type":32,"value":2071},"运行并修复兼容性问题",{"type":26,"tag":34,"props":2073,"children":2074},{},[2075,2077,2083],{"type":32,"value":2076},"预计迁移成本：1",{"type":26,"tag":2078,"props":2079,"children":2080},"del",{},[2081],{"type":32,"value":2082},"2 天（小型项目）/ 1",{"type":32,"value":2084},"2 周（大型项目）",{"type":26,"tag":231,"props":2086,"children":2088},{"id":2087},"_42-兼容性边界哪些需要调整",[2089],{"type":32,"value":2090},"4.2 兼容性边界：哪些需要调整",{"type":26,"tag":34,"props":2092,"children":2093},{},[2094],{"type":26,"tag":77,"props":2095,"children":2096},{},[2097],{"type":32,"value":2098},"插件兼容",{"type":26,"tag":40,"props":2100,"children":2101},{},[2102,2107],{"type":26,"tag":44,"props":2103,"children":2104},{},[2105],{"type":32,"value":2106},"Rspack 支持大部分 Webpack 插件（API 兼容）",{"type":26,"tag":44,"props":2108,"children":2109},{},[2110],{"type":32,"value":2111},"但少数复杂插件（例如深度依赖 Webpack 内部 API）需要适配",{"type":26,"tag":34,"props":2113,"children":2114},{},[2115],{"type":26,"tag":77,"props":2116,"children":2117},{},[2118],{"type":32,"value":2119},"Loader 兼容",{"type":26,"tag":40,"props":2121,"children":2122},{},[2123,2128],{"type":26,"tag":44,"props":2124,"children":2125},{},[2126],{"type":32,"value":2127},"常用 loader（babel-loader、css-loader、postcss-loader）兼容",{"type":26,"tag":44,"props":2129,"children":2130},{},[2131],{"type":32,"value":2132},"部分自定义 loader 需要测试",{"type":26,"tag":34,"props":2134,"children":2135},{},[2136],{"type":26,"tag":77,"props":2137,"children":2138},{},[2139],{"type":32,"value":2140},"配置差异",{"type":26,"tag":40,"props":2142,"children":2143},{},[2144,2149],{"type":26,"tag":44,"props":2145,"children":2146},{},[2147],{"type":32,"value":2148},"resolve、output、optimization 等配置与 Webpack 高度一致",{"type":26,"tag":44,"props":2150,"children":2151},{},[2152],{"type":32,"value":2153},"少数高级配置需要查文档",{"type":26,"tag":231,"props":2155,"children":2157},{"id":2156},"_43-推荐的迁移节奏",[2158],{"type":32,"value":2159},"4.3 推荐的迁移节奏",{"type":26,"tag":40,"props":2161,"children":2162},{},[2163,2168,2173],{"type":26,"tag":44,"props":2164,"children":2165},{},[2166],{"type":32,"value":2167},"Week 1：本地开发环境先行",{"type":26,"tag":44,"props":2169,"children":2170},{},[2171],{"type":32,"value":2172},"Week 2：CI 构建切换（并保留 Webpack 作为 fallback）",{"type":26,"tag":44,"props":2174,"children":2175},{},[2176],{"type":32,"value":2177},"Week 3~4：生产构建切换并观测",{"type":26,"tag":132,"props":2179,"children":2180},{},[],{"type":26,"tag":27,"props":2182,"children":2184},{"id":2183},"_5-性能调优让-rspack-更快",[2185],{"type":32,"value":2186},"5. 性能调优：让 Rspack 更快",{"type":26,"tag":231,"props":2188,"children":2190},{"id":2189},"_51-缓存策略",[2191],{"type":32,"value":2192},"5.1 缓存策略",{"type":26,"tag":34,"props":2194,"children":2195},{},[2196],{"type":32,"value":2197},"默认缓存已经很激进，但你可以：",{"type":26,"tag":40,"props":2199,"children":2200},{},[2201,2206],{"type":26,"tag":44,"props":2202,"children":2203},{},[2204],{"type":32,"value":2205},"显式配置缓存目录（例如挂载 SSD）",{"type":26,"tag":44,"props":2207,"children":2208},{},[2209],{"type":32,"value":2210},"在 CI 上持久化缓存（例如用 actions/cache）",{"type":26,"tag":231,"props":2212,"children":2214},{"id":2213},"_52-并行度调优",[2215],{"type":32,"value":2216},"5.2 并行度调优",{"type":26,"tag":34,"props":2218,"children":2219},{},[2220],{"type":32,"value":2221},"Rspack 默认会用所有 CPU 核心，但在容器环境（例如 CI）可能需要限制：",{"type":26,"tag":403,"props":2223,"children":2228},{"className":2224,"code":2226,"language":2227,"meta":7},[2225],"language-js","module.exports = {\n  experiments: {\n    rspackFuture: {\n      disableTransformByDefault: true, // 减少不必要转换\n    },\n  },\n}\n","js",[2229],{"type":26,"tag":180,"props":2230,"children":2231},{"__ignoreMap":7},[2232],{"type":32,"value":2226},{"type":26,"tag":231,"props":2234,"children":2236},{"id":2235},"_53-tree-shaking-与-dead-code-elimination",[2237],{"type":32,"value":2238},"5.3 Tree Shaking 与 Dead Code Elimination",{"type":26,"tag":34,"props":2240,"children":2241},{},[2242],{"type":32,"value":2243},"Rspack 内置 Tree Shaking，但效果取决于：",{"type":26,"tag":40,"props":2245,"children":2246},{},[2247,2252,2257],{"type":26,"tag":44,"props":2248,"children":2249},{},[2250],{"type":32,"value":2251},"是否使用 ESM（而非 CommonJS）",{"type":26,"tag":44,"props":2253,"children":2254},{},[2255],{"type":32,"value":2256},"副作用标记（sideEffects: false）",{"type":26,"tag":44,"props":2258,"children":2259},{},[2260],{"type":32,"value":2261},"动态 import 的拆分策略",{"type":26,"tag":34,"props":2263,"children":2264},{},[2265],{"type":32,"value":2266},"建议：",{"type":26,"tag":40,"props":2268,"children":2269},{},[2270,2283],{"type":26,"tag":44,"props":2271,"children":2272},{},[2273,2275,2281],{"type":32,"value":2274},"对第三方库检查 ",{"type":26,"tag":180,"props":2276,"children":2278},{"className":2277},[],[2279],{"type":32,"value":2280},"sideEffects",{"type":32,"value":2282}," 配置",{"type":26,"tag":44,"props":2284,"children":2285},{},[2286,2288,2294],{"type":32,"value":2287},"避免\"全量引入后 tree shake\"（例如 ",{"type":26,"tag":180,"props":2289,"children":2291},{"className":2290},[],[2292],{"type":32,"value":2293},"import * from 'lodash'",{"type":32,"value":187},{"type":26,"tag":132,"props":2296,"children":2297},{},[],{"type":26,"tag":27,"props":2299,"children":2301},{"id":2300},"_6-产物分析与优化",[2302],{"type":32,"value":2303},"6. 产物分析与优化",{"type":26,"tag":34,"props":2305,"children":2306},{},[2307],{"type":32,"value":2308},"Rspack 提供内置分析工具：",{"type":26,"tag":403,"props":2310,"children":2315},{"className":2311,"code":2313,"language":2314,"meta":7},[2312],"language-bash","rspack build --analyze\n","bash",[2316],{"type":26,"tag":180,"props":2317,"children":2318},{"__ignoreMap":7},[2319],{"type":32,"value":2313},{"type":26,"tag":34,"props":2321,"children":2322},{},[2323],{"type":32,"value":2324},"关键指标：",{"type":26,"tag":40,"props":2326,"children":2327},{},[2328,2333,2338],{"type":26,"tag":44,"props":2329,"children":2330},{},[2331],{"type":32,"value":2332},"各 chunk 体积分布",{"type":26,"tag":44,"props":2334,"children":2335},{},[2336],{"type":32,"value":2337},"重复依赖（例如多个版本的 lodash）",{"type":26,"tag":44,"props":2339,"children":2340},{},[2341],{"type":32,"value":2342},"未被 tree shake 的代码",{"type":26,"tag":34,"props":2344,"children":2345},{},[2346],{"type":32,"value":2347},"优化策略：",{"type":26,"tag":40,"props":2349,"children":2350},{},[2351,2356,2361],{"type":26,"tag":44,"props":2352,"children":2353},{},[2354],{"type":32,"value":2355},"拆分 vendor chunk（按更新频率）",{"type":26,"tag":44,"props":2357,"children":2358},{},[2359],{"type":32,"value":2360},"对大型库按需引入（例如 antd/lodash-es）",{"type":26,"tag":44,"props":2362,"children":2363},{},[2364],{"type":32,"value":2365},"检查动态 import 的粒度",{"type":26,"tag":132,"props":2367,"children":2368},{},[],{"type":26,"tag":27,"props":2370,"children":2372},{"id":2371},"_7-生产可观测性让构建可量化",[2373],{"type":32,"value":2374},"7. 生产可观测性：让构建可量化",{"type":26,"tag":34,"props":2376,"children":2377},{},[2378],{"type":32,"value":2379},"在 CI/CD 里，你需要能回答：",{"type":26,"tag":40,"props":2381,"children":2382},{},[2383,2388,2393],{"type":26,"tag":44,"props":2384,"children":2385},{},[2386],{"type":32,"value":2387},"这次构建为什么变慢？",{"type":26,"tag":44,"props":2389,"children":2390},{},[2391],{"type":32,"value":2392},"产物为什么变大？",{"type":26,"tag":44,"props":2394,"children":2395},{},[2396],{"type":32,"value":2397},"哪个模块耗时最多？",{"type":26,"tag":34,"props":2399,"children":2400},{},[2401],{"type":32,"value":2402},"建议在 CI 里记录：",{"type":26,"tag":40,"props":2404,"children":2405},{},[2406,2411,2416,2421],{"type":26,"tag":44,"props":2407,"children":2408},{},[2409],{"type":32,"value":2410},"构建总耗时",{"type":26,"tag":44,"props":2412,"children":2413},{},[2414],{"type":32,"value":2415},"各阶段耗时（resolve、compile、optimize、emit）",{"type":26,"tag":44,"props":2417,"children":2418},{},[2419],{"type":32,"value":2420},"产物体积（按 chunk）",{"type":26,"tag":44,"props":2422,"children":2423},{},[2424],{"type":32,"value":2425},"缓存命中率",{"type":26,"tag":34,"props":2427,"children":2428},{},[2429],{"type":32,"value":2430},"落地方式：",{"type":26,"tag":40,"props":2432,"children":2433},{},[2434,2439,2444],{"type":26,"tag":44,"props":2435,"children":2436},{},[2437],{"type":32,"value":2438},"用 Rspack 的 stats 输出",{"type":26,"tag":44,"props":2440,"children":2441},{},[2442],{"type":32,"value":2443},"在 CI 日志里保留关键指标",{"type":26,"tag":44,"props":2445,"children":2446},{},[2447],{"type":32,"value":2448},"对产物体积做 baseline 对比（变化 > 5% 报警）",{"type":26,"tag":132,"props":2450,"children":2451},{},[],{"type":26,"tag":27,"props":2453,"children":2455},{"id":2454},"_8-常见问题排查",[2456],{"type":32,"value":2457},"8. 常见问题排查",{"type":26,"tag":231,"props":2459,"children":2461},{"id":2460},"_81-迁移后变慢了",[2462],{"type":32,"value":2463},"8.1 \"迁移后变慢了\"",{"type":26,"tag":34,"props":2465,"children":2466},{},[2467],{"type":32,"value":2468},"排查顺序：",{"type":26,"tag":40,"props":2470,"children":2471},{},[2472,2477,2482],{"type":26,"tag":44,"props":2473,"children":2474},{},[2475],{"type":32,"value":2476},"缓存是否生效（首次构建慢正常）",{"type":26,"tag":44,"props":2478,"children":2479},{},[2480],{"type":32,"value":2481},"是否有 loader 拖慢（例如未优化的自定义 loader）",{"type":26,"tag":44,"props":2483,"children":2484},{},[2485],{"type":32,"value":2486},"并行度是否受限（例如 CI 限制 CPU）",{"type":26,"tag":231,"props":2488,"children":2490},{"id":2489},"_82-产物体积变大了",[2491],{"type":32,"value":2492},"8.2 \"产物体积变大了\"",{"type":26,"tag":40,"props":2494,"children":2495},{},[2496,2501,2506],{"type":26,"tag":44,"props":2497,"children":2498},{},[2499],{"type":32,"value":2500},"检查 Tree Shaking 是否生效",{"type":26,"tag":44,"props":2502,"children":2503},{},[2504],{"type":32,"value":2505},"检查是否引入了更多 polyfill",{"type":26,"tag":44,"props":2507,"children":2508},{},[2509],{"type":32,"value":2510},"对比 chunk 分布（用 analyze）",{"type":26,"tag":231,"props":2512,"children":2514},{"id":2513},"_83-某些模块编译失败",[2515],{"type":32,"value":2516},"8.3 \"某些模块编译失败\"",{"type":26,"tag":40,"props":2518,"children":2519},{},[2520,2525,2530],{"type":26,"tag":44,"props":2521,"children":2522},{},[2523],{"type":32,"value":2524},"检查是否依赖 Webpack 特定 API",{"type":26,"tag":44,"props":2526,"children":2527},{},[2528],{"type":32,"value":2529},"查看 Rspack 官方兼容性列表",{"type":26,"tag":44,"props":2531,"children":2532},{},[2533],{"type":32,"value":2534},"在 GitHub Issues 搜索类似问题",{"type":26,"tag":132,"props":2536,"children":2537},{},[],{"type":26,"tag":27,"props":2539,"children":2541},{"id":2540},"_9-rspack-vs-vite什么时候选哪个",[2542],{"type":32,"value":2543},"9. Rspack vs Vite：什么时候选哪个？",{"type":26,"tag":1813,"props":2545,"children":2546},{},[2547,2567],{"type":26,"tag":1817,"props":2548,"children":2549},{},[2550],{"type":26,"tag":1821,"props":2551,"children":2552},{},[2553,2558,2562],{"type":26,"tag":1825,"props":2554,"children":2555},{},[2556],{"type":32,"value":2557},"维度",{"type":26,"tag":1825,"props":2559,"children":2560},{},[2561],{"type":32,"value":1548},{"type":26,"tag":1825,"props":2563,"children":2564},{},[2565],{"type":32,"value":2566},"Vite",{"type":26,"tag":1845,"props":2568,"children":2569},{},[2570,2588,2605,2623,2641],{"type":26,"tag":1821,"props":2571,"children":2572},{},[2573,2578,2583],{"type":26,"tag":1852,"props":2574,"children":2575},{},[2576],{"type":32,"value":2577},"开发速度",{"type":26,"tag":1852,"props":2579,"children":2580},{},[2581],{"type":32,"value":2582},"极快（Rust 编译）",{"type":26,"tag":1852,"props":2584,"children":2585},{},[2586],{"type":32,"value":2587},"极快（ESM 直连）",{"type":26,"tag":1821,"props":2589,"children":2590},{},[2591,2595,2600],{"type":26,"tag":1852,"props":2592,"children":2593},{},[2594],{"type":32,"value":1908},{"type":26,"tag":1852,"props":2596,"children":2597},{},[2598],{"type":32,"value":2599},"快（全量编译优化）",{"type":26,"tag":1852,"props":2601,"children":2602},{},[2603],{"type":32,"value":2604},"快（Rollup）",{"type":26,"tag":1821,"props":2606,"children":2607},{},[2608,2613,2618],{"type":26,"tag":1852,"props":2609,"children":2610},{},[2611],{"type":32,"value":2612},"Webpack 兼容",{"type":26,"tag":1852,"props":2614,"children":2615},{},[2616],{"type":32,"value":2617},"高",{"type":26,"tag":1852,"props":2619,"children":2620},{},[2621],{"type":32,"value":2622},"低",{"type":26,"tag":1821,"props":2624,"children":2625},{},[2626,2631,2636],{"type":26,"tag":1852,"props":2627,"children":2628},{},[2629],{"type":32,"value":2630},"插件生态",{"type":26,"tag":1852,"props":2632,"children":2633},{},[2634],{"type":32,"value":2635},"Webpack 生态",{"type":26,"tag":1852,"props":2637,"children":2638},{},[2639],{"type":32,"value":2640},"Rollup/Vite 生态",{"type":26,"tag":1821,"props":2642,"children":2643},{},[2644,2649,2654],{"type":26,"tag":1852,"props":2645,"children":2646},{},[2647],{"type":32,"value":2648},"适用项目",{"type":26,"tag":1852,"props":2650,"children":2651},{},[2652],{"type":32,"value":2653},"Webpack 迁移、大型 monorepo",{"type":26,"tag":1852,"props":2655,"children":2656},{},[2657],{"type":32,"value":2658},"新项目、中小型",{"type":26,"tag":34,"props":2660,"children":2661},{},[2662],{"type":32,"value":2663},"选择建议：",{"type":26,"tag":40,"props":2665,"children":2666},{},[2667,2672,2677],{"type":26,"tag":44,"props":2668,"children":2669},{},[2670],{"type":32,"value":2671},"新项目：优先 Vite",{"type":26,"tag":44,"props":2673,"children":2674},{},[2675],{"type":32,"value":2676},"Webpack 遗留项目：Rspack",{"type":26,"tag":44,"props":2678,"children":2679},{},[2680],{"type":32,"value":2681},"大型 monorepo + Webpack 依赖：Rspack",{"type":26,"tag":132,"props":2683,"children":2684},{},[],{"type":26,"tag":27,"props":2686,"children":2688},{"id":2687},"_10-上线检查清单",[2689],{"type":32,"value":2690},"10. 上线检查清单",{"type":26,"tag":40,"props":2692,"children":2694},{"className":2693},[1157],[2695,2704,2713,2722,2731,2740],{"type":26,"tag":44,"props":2696,"children":2698},{"className":2697},[1162],[2699,2702],{"type":26,"tag":1165,"props":2700,"children":2701},{"disabled":1167,"type":1168},[],{"type":32,"value":2703}," 本地开发环境已验证（HMR/热更新正常）",{"type":26,"tag":44,"props":2705,"children":2707},{"className":2706},[1162],[2708,2711],{"type":26,"tag":1165,"props":2709,"children":2710},{"disabled":1167,"type":1168},[],{"type":32,"value":2712}," CI 构建已切换并观测 3 天以上",{"type":26,"tag":44,"props":2714,"children":2716},{"className":2715},[1162],[2717,2720],{"type":26,"tag":1165,"props":2718,"children":2719},{"disabled":1167,"type":1168},[],{"type":32,"value":2721}," 产物体积对比无异常（baseline ± 5%）",{"type":26,"tag":44,"props":2723,"children":2725},{"className":2724},[1162],[2726,2729],{"type":26,"tag":1165,"props":2727,"children":2728},{"disabled":1167,"type":1168},[],{"type":32,"value":2730}," 关键页面功能回归测试通过",{"type":26,"tag":44,"props":2732,"children":2734},{"className":2733},[1162],[2735,2738],{"type":26,"tag":1165,"props":2736,"children":2737},{"disabled":1167,"type":1168},[],{"type":32,"value":2739}," 有构建耗时与缓存命中率监控",{"type":26,"tag":44,"props":2741,"children":2743},{"className":2742},[1162],[2744,2747],{"type":26,"tag":1165,"props":2745,"children":2746},{"disabled":1167,"type":1168},[],{"type":32,"value":2748}," 有回滚方案（保留 Webpack 配置）",{"type":26,"tag":132,"props":2750,"children":2751},{},[],{"type":26,"tag":27,"props":2753,"children":2755},{"id":2754},"总结",[2756],{"type":32,"value":2754},{"type":26,"tag":34,"props":2758,"children":2759},{},[2760],{"type":32,"value":2761},"Rspack 的核心价值是：",{"type":26,"tag":40,"props":2763,"children":2764},{},[2765,2770,2775],{"type":26,"tag":44,"props":2766,"children":2767},{},[2768],{"type":32,"value":2769},"在 Webpack 生态下获得接近 Vite 的速度",{"type":26,"tag":44,"props":2771,"children":2772},{},[2773],{"type":32,"value":2774},"对大型项目构建成本与开发体验的显著改善",{"type":26,"tag":44,"props":2776,"children":2777},{},[2778],{"type":32,"value":2779},"生产级稳定性（字节跳动内部大规模验证）",{"title":7,"searchDepth":865,"depth":865,"links":2781},[2782,2783,2787,2792,2793,2798,2803,2804,2805,2810,2811,2812],{"id":1558,"depth":868,"text":1544},{"id":1640,"depth":868,"text":1643,"children":2784},[2785,2786],{"id":1651,"depth":865,"text":1654},{"id":1690,"depth":865,"text":1693},{"id":1717,"depth":868,"text":1720,"children":2788},[2789,2790,2791],{"id":1723,"depth":865,"text":1726},{"id":1747,"depth":865,"text":1750},{"id":1771,"depth":865,"text":1774},{"id":1803,"depth":868,"text":1806},{"id":1986,"depth":868,"text":1989,"children":2794},[2795,2796,2797],{"id":1992,"depth":865,"text":1995},{"id":2087,"depth":865,"text":2090},{"id":2156,"depth":865,"text":2159},{"id":2183,"depth":868,"text":2186,"children":2799},[2800,2801,2802],{"id":2189,"depth":865,"text":2192},{"id":2213,"depth":865,"text":2216},{"id":2235,"depth":865,"text":2238},{"id":2300,"depth":868,"text":2303},{"id":2371,"depth":868,"text":2374},{"id":2454,"depth":868,"text":2457,"children":2806},[2807,2808,2809],{"id":2460,"depth":865,"text":2463},{"id":2489,"depth":865,"text":2492},{"id":2513,"depth":865,"text":2516},{"id":2540,"depth":868,"text":2543},{"id":2687,"depth":868,"text":2690},{"id":2754,"depth":868,"text":2754},"content:topics:frontend:rspack-performance-practice.md","topics/frontend/rspack-performance-practice.md","topics/frontend/rspack-performance-practice",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":2817,"image":19,"imageQuery":20,"featured":6,"readingTime":21,"body":2818,"_type":893,"_id":894,"_source":895,"_file":896,"_stem":897,"_extension":898},[13,14,15,16,17,18],{"type":23,"children":2819,"toc":3476},[2820,2824,2828,2847,2851,2886,2895,2899,2902,2906,2910,2943,2947,2966,2970,2973,2977,2981,3011,3015,3026,3030,3037,3040,3044,3048,3075,3079,3082,3092,3108,3112,3120,3124,3147,3150,3154,3158,3162,3173,3183,3194,3198,3201,3205,3209,3220,3224,3232,3236,3257,3260,3264,3273,3277,3281,3292,3302,3313,3317,3328,3332,3339,3342,3346,3350,3354,3358,3362,3366,3382,3386,3390,3405,3408,3412,3416,3435,3445,3448,3452],{"type":26,"tag":27,"props":2821,"children":2822},{"id":29},[2823],{"type":32,"value":8},{"type":26,"tag":34,"props":2825,"children":2826},{},[2827],{"type":32,"value":38},{"type":26,"tag":40,"props":2829,"children":2830},{},[2831,2835,2839,2843],{"type":26,"tag":44,"props":2832,"children":2833},{},[2834],{"type":32,"value":48},{"type":26,"tag":44,"props":2836,"children":2837},{},[2838],{"type":32,"value":53},{"type":26,"tag":44,"props":2840,"children":2841},{},[2842],{"type":32,"value":58},{"type":26,"tag":44,"props":2844,"children":2845},{},[2846],{"type":32,"value":63},{"type":26,"tag":34,"props":2848,"children":2849},{},[2850],{"type":32,"value":68},{"type":26,"tag":70,"props":2852,"children":2853},{},[2854,2862,2870,2878],{"type":26,"tag":44,"props":2855,"children":2856},{},[2857,2861],{"type":26,"tag":77,"props":2858,"children":2859},{},[2860],{"type":32,"value":81},{"type":32,"value":83},{"type":26,"tag":44,"props":2863,"children":2864},{},[2865,2869],{"type":26,"tag":77,"props":2866,"children":2867},{},[2868],{"type":32,"value":91},{"type":32,"value":93},{"type":26,"tag":44,"props":2871,"children":2872},{},[2873,2877],{"type":26,"tag":77,"props":2874,"children":2875},{},[2876],{"type":32,"value":101},{"type":32,"value":103},{"type":26,"tag":44,"props":2879,"children":2880},{},[2881,2885],{"type":26,"tag":77,"props":2882,"children":2883},{},[2884],{"type":32,"value":111},{"type":32,"value":113},{"type":26,"tag":34,"props":2887,"children":2888},{},[2889,2890,2894],{"type":32,"value":118},{"type":26,"tag":77,"props":2891,"children":2892},{},[2893],{"type":32,"value":123},{"type":32,"value":125},{"type":26,"tag":34,"props":2896,"children":2897},{},[2898],{"type":32,"value":130},{"type":26,"tag":132,"props":2900,"children":2901},{},[],{"type":26,"tag":27,"props":2903,"children":2904},{"id":137},[2905],{"type":32,"value":140},{"type":26,"tag":34,"props":2907,"children":2908},{},[2909],{"type":32,"value":145},{"type":26,"tag":40,"props":2911,"children":2912},{},[2913,2921,2929],{"type":26,"tag":44,"props":2914,"children":2915},{},[2916,2920],{"type":26,"tag":77,"props":2917,"children":2918},{},[2919],{"type":32,"value":156},{"type":32,"value":158},{"type":26,"tag":44,"props":2922,"children":2923},{},[2924,2928],{"type":26,"tag":77,"props":2925,"children":2926},{},[2927],{"type":32,"value":166},{"type":32,"value":168},{"type":26,"tag":44,"props":2930,"children":2931},{},[2932,2936,2937,2942],{"type":26,"tag":77,"props":2933,"children":2934},{},[2935],{"type":32,"value":176},{"type":32,"value":178},{"type":26,"tag":180,"props":2938,"children":2940},{"className":2939},[],[2941],{"type":32,"value":185},{"type":32,"value":187},{"type":26,"tag":34,"props":2944,"children":2945},{},[2946],{"type":32,"value":192},{"type":26,"tag":40,"props":2948,"children":2949},{},[2950,2958],{"type":26,"tag":44,"props":2951,"children":2952},{},[2953,2957],{"type":26,"tag":77,"props":2954,"children":2955},{},[2956],{"type":32,"value":203},{"type":32,"value":205},{"type":26,"tag":44,"props":2959,"children":2960},{},[2961,2965],{"type":26,"tag":77,"props":2962,"children":2963},{},[2964],{"type":32,"value":213},{"type":32,"value":215},{"type":26,"tag":34,"props":2967,"children":2968},{},[2969],{"type":32,"value":220},{"type":26,"tag":132,"props":2971,"children":2972},{},[],{"type":26,"tag":27,"props":2974,"children":2975},{"id":226},[2976],{"type":32,"value":229},{"type":26,"tag":231,"props":2978,"children":2979},{"id":233},[2980],{"type":32,"value":233},{"type":26,"tag":40,"props":2982,"children":2983},{},[2984,2993,3002],{"type":26,"tag":44,"props":2985,"children":2986},{},[2987,2988,2992],{"type":32,"value":243},{"type":26,"tag":77,"props":2989,"children":2990},{},[2991],{"type":32,"value":248},{"type":32,"value":250},{"type":26,"tag":44,"props":2994,"children":2995},{},[2996,2997,3001],{"type":32,"value":255},{"type":26,"tag":77,"props":2998,"children":2999},{},[3000],{"type":32,"value":260},{"type":32,"value":262},{"type":26,"tag":44,"props":3003,"children":3004},{},[3005,3006,3010],{"type":32,"value":267},{"type":26,"tag":77,"props":3007,"children":3008},{},[3009],{"type":32,"value":272},{"type":32,"value":274},{"type":26,"tag":231,"props":3012,"children":3013},{"id":277},[3014],{"type":32,"value":280},{"type":26,"tag":40,"props":3016,"children":3017},{},[3018,3022],{"type":26,"tag":44,"props":3019,"children":3020},{},[3021],{"type":32,"value":288},{"type":26,"tag":44,"props":3023,"children":3024},{},[3025],{"type":32,"value":293},{"type":26,"tag":34,"props":3027,"children":3028},{},[3029],{"type":32,"value":298},{"type":26,"tag":300,"props":3031,"children":3032},{},[3033],{"type":26,"tag":34,"props":3034,"children":3035},{},[3036],{"type":32,"value":307},{"type":26,"tag":132,"props":3038,"children":3039},{},[],{"type":26,"tag":27,"props":3041,"children":3042},{"id":313},[3043],{"type":32,"value":316},{"type":26,"tag":34,"props":3045,"children":3046},{},[3047],{"type":32,"value":321},{"type":26,"tag":70,"props":3049,"children":3050},{},[3051,3059,3067],{"type":26,"tag":44,"props":3052,"children":3053},{},[3054,3055],{"type":32,"value":329},{"type":26,"tag":77,"props":3056,"children":3057},{},[3058],{"type":32,"value":334},{"type":26,"tag":44,"props":3060,"children":3061},{},[3062,3063],{"type":32,"value":339},{"type":26,"tag":77,"props":3064,"children":3065},{},[3066],{"type":32,"value":344},{"type":26,"tag":44,"props":3068,"children":3069},{},[3070,3071],{"type":32,"value":349},{"type":26,"tag":77,"props":3072,"children":3073},{},[3074],{"type":32,"value":354},{"type":26,"tag":34,"props":3076,"children":3077},{},[3078],{"type":32,"value":359},{"type":26,"tag":132,"props":3080,"children":3081},{},[],{"type":26,"tag":27,"props":3083,"children":3084},{"id":365},[3085,3086,3091],{"type":32,"value":368},{"type":26,"tag":180,"props":3087,"children":3089},{"className":3088},[],[3090],{"type":32,"value":374},{"type":32,"value":376},{"type":26,"tag":34,"props":3093,"children":3094},{},[3095,3096,3101,3102,3107],{"type":32,"value":381},{"type":26,"tag":180,"props":3097,"children":3099},{"className":3098},[],[3100],{"type":32,"value":374},{"type":32,"value":388},{"type":26,"tag":180,"props":3103,"children":3105},{"className":3104},[],[3106],{"type":32,"value":394},{"type":32,"value":396},{"type":26,"tag":34,"props":3109,"children":3110},{},[3111],{"type":32,"value":401},{"type":26,"tag":403,"props":3113,"children":3115},{"className":3114,"code":407,"language":408,"meta":7},[406],[3116],{"type":26,"tag":180,"props":3117,"children":3118},{"__ignoreMap":7},[3119],{"type":32,"value":407},{"type":26,"tag":34,"props":3121,"children":3122},{},[3123],{"type":32,"value":418},{"type":26,"tag":40,"props":3125,"children":3126},{},[3127,3137],{"type":26,"tag":44,"props":3128,"children":3129},{},[3130,3131,3136],{"type":32,"value":426},{"type":26,"tag":180,"props":3132,"children":3134},{"className":3133},[],[3135],{"type":32,"value":432},{"type":32,"value":434},{"type":26,"tag":44,"props":3138,"children":3139},{},[3140,3141,3146],{"type":32,"value":439},{"type":26,"tag":180,"props":3142,"children":3144},{"className":3143},[],[3145],{"type":32,"value":445},{"type":32,"value":447},{"type":26,"tag":132,"props":3148,"children":3149},{},[],{"type":26,"tag":27,"props":3151,"children":3152},{"id":453},[3153],{"type":32,"value":456},{"type":26,"tag":34,"props":3155,"children":3156},{},[3157],{"type":32,"value":461},{"type":26,"tag":34,"props":3159,"children":3160},{},[3161],{"type":32,"value":466},{"type":26,"tag":70,"props":3163,"children":3164},{},[3165,3169],{"type":26,"tag":44,"props":3166,"children":3167},{},[3168],{"type":32,"value":474},{"type":26,"tag":44,"props":3170,"children":3171},{},[3172],{"type":32,"value":479},{"type":26,"tag":34,"props":3174,"children":3175},{},[3176,3177,3182],{"type":32,"value":484},{"type":26,"tag":180,"props":3178,"children":3180},{"className":3179},[],[3181],{"type":32,"value":490},{"type":32,"value":492},{"type":26,"tag":40,"props":3184,"children":3185},{},[3186,3190],{"type":26,"tag":44,"props":3187,"children":3188},{},[3189],{"type":32,"value":500},{"type":26,"tag":44,"props":3191,"children":3192},{},[3193],{"type":32,"value":505},{"type":26,"tag":34,"props":3195,"children":3196},{},[3197],{"type":32,"value":510},{"type":26,"tag":132,"props":3199,"children":3200},{},[],{"type":26,"tag":27,"props":3202,"children":3203},{"id":516},[3204],{"type":32,"value":519},{"type":26,"tag":34,"props":3206,"children":3207},{},[3208],{"type":32,"value":524},{"type":26,"tag":40,"props":3210,"children":3211},{},[3212,3216],{"type":26,"tag":44,"props":3213,"children":3214},{},[3215],{"type":32,"value":532},{"type":26,"tag":44,"props":3217,"children":3218},{},[3219],{"type":32,"value":537},{"type":26,"tag":34,"props":3221,"children":3222},{},[3223],{"type":32,"value":542},{"type":26,"tag":403,"props":3225,"children":3227},{"className":3226,"code":547,"language":548,"meta":7},[546],[3228],{"type":26,"tag":180,"props":3229,"children":3230},{"__ignoreMap":7},[3231],{"type":32,"value":547},{"type":26,"tag":34,"props":3233,"children":3234},{},[3235],{"type":32,"value":558},{"type":26,"tag":40,"props":3237,"children":3238},{},[3239,3247],{"type":26,"tag":44,"props":3240,"children":3241},{},[3242],{"type":26,"tag":180,"props":3243,"children":3245},{"className":3244},[],[3246],{"type":32,"value":570},{"type":26,"tag":44,"props":3248,"children":3249},{},[3250,3251,3256],{"type":32,"value":575},{"type":26,"tag":180,"props":3252,"children":3254},{"className":3253},[],[3255],{"type":32,"value":581},{"type":32,"value":583},{"type":26,"tag":132,"props":3258,"children":3259},{},[],{"type":26,"tag":27,"props":3261,"children":3262},{"id":589},[3263],{"type":32,"value":592},{"type":26,"tag":34,"props":3265,"children":3266},{},[3267,3268,3272],{"type":32,"value":597},{"type":26,"tag":77,"props":3269,"children":3270},{},[3271],{"type":32,"value":602},{"type":32,"value":604},{"type":26,"tag":34,"props":3274,"children":3275},{},[3276],{"type":32,"value":609},{"type":26,"tag":231,"props":3278,"children":3279},{"id":612},[3280],{"type":32,"value":615},{"type":26,"tag":40,"props":3282,"children":3283},{},[3284,3288],{"type":26,"tag":44,"props":3285,"children":3286},{},[3287],{"type":32,"value":623},{"type":26,"tag":44,"props":3289,"children":3290},{},[3291],{"type":32,"value":628},{"type":26,"tag":231,"props":3293,"children":3294},{"id":631},[3295,3296,3301],{"type":32,"value":634},{"type":26,"tag":180,"props":3297,"children":3299},{"className":3298},[],[3300],{"type":32,"value":640},{"type":32,"value":642},{"type":26,"tag":40,"props":3303,"children":3304},{},[3305,3309],{"type":26,"tag":44,"props":3306,"children":3307},{},[3308],{"type":32,"value":650},{"type":26,"tag":44,"props":3310,"children":3311},{},[3312],{"type":32,"value":655},{"type":26,"tag":231,"props":3314,"children":3315},{"id":658},[3316],{"type":32,"value":661},{"type":26,"tag":40,"props":3318,"children":3319},{},[3320,3324],{"type":26,"tag":44,"props":3321,"children":3322},{},[3323],{"type":32,"value":669},{"type":26,"tag":44,"props":3325,"children":3326},{},[3327],{"type":32,"value":674},{"type":26,"tag":34,"props":3329,"children":3330},{},[3331],{"type":32,"value":679},{"type":26,"tag":300,"props":3333,"children":3334},{},[3335],{"type":26,"tag":34,"props":3336,"children":3337},{},[3338],{"type":32,"value":687},{"type":26,"tag":132,"props":3340,"children":3341},{},[],{"type":26,"tag":27,"props":3343,"children":3344},{"id":693},[3345],{"type":32,"value":696},{"type":26,"tag":231,"props":3347,"children":3348},{"id":699},[3349],{"type":32,"value":702},{"type":26,"tag":34,"props":3351,"children":3352},{},[3353],{"type":32,"value":707},{"type":26,"tag":231,"props":3355,"children":3356},{"id":710},[3357],{"type":32,"value":713},{"type":26,"tag":34,"props":3359,"children":3360},{},[3361],{"type":32,"value":718},{"type":26,"tag":231,"props":3363,"children":3364},{"id":721},[3365],{"type":32,"value":724},{"type":26,"tag":34,"props":3367,"children":3368},{},[3369,3370,3375,3376,3381],{"type":32,"value":729},{"type":26,"tag":180,"props":3371,"children":3373},{"className":3372},[],[3374],{"type":32,"value":735},{"type":32,"value":737},{"type":26,"tag":180,"props":3377,"children":3379},{"className":3378},[],[3380],{"type":32,"value":743},{"type":32,"value":745},{"type":26,"tag":231,"props":3383,"children":3384},{"id":748},[3385],{"type":32,"value":751},{"type":26,"tag":34,"props":3387,"children":3388},{},[3389],{"type":32,"value":756},{"type":26,"tag":40,"props":3391,"children":3392},{},[3393,3397,3401],{"type":26,"tag":44,"props":3394,"children":3395},{},[3396],{"type":32,"value":764},{"type":26,"tag":44,"props":3398,"children":3399},{},[3400],{"type":32,"value":769},{"type":26,"tag":44,"props":3402,"children":3403},{},[3404],{"type":32,"value":774},{"type":26,"tag":132,"props":3406,"children":3407},{},[],{"type":26,"tag":27,"props":3409,"children":3410},{"id":780},[3411],{"type":32,"value":783},{"type":26,"tag":34,"props":3413,"children":3414},{},[3415],{"type":32,"value":788},{"type":26,"tag":40,"props":3417,"children":3418},{},[3419,3423,3427,3431],{"type":26,"tag":44,"props":3420,"children":3421},{},[3422],{"type":32,"value":796},{"type":26,"tag":44,"props":3424,"children":3425},{},[3426],{"type":32,"value":801},{"type":26,"tag":44,"props":3428,"children":3429},{},[3430],{"type":32,"value":806},{"type":26,"tag":44,"props":3432,"children":3433},{},[3434],{"type":32,"value":811},{"type":26,"tag":34,"props":3436,"children":3437},{},[3438,3439,3444],{"type":32,"value":816},{"type":26,"tag":180,"props":3440,"children":3442},{"className":3441},[],[3443],{"type":32,"value":640},{"type":32,"value":823},{"type":26,"tag":132,"props":3446,"children":3447},{},[],{"type":26,"tag":27,"props":3449,"children":3450},{"id":829},[3451],{"type":32,"value":832},{"type":26,"tag":40,"props":3453,"children":3454},{},[3455,3462,3469],{"type":26,"tag":44,"props":3456,"children":3457},{},[3458],{"type":26,"tag":840,"props":3459,"children":3460},{"href":842},[3461],{"type":32,"value":845},{"type":26,"tag":44,"props":3463,"children":3464},{},[3465],{"type":26,"tag":840,"props":3466,"children":3467},{"href":851},[3468],{"type":32,"value":854},{"type":26,"tag":44,"props":3470,"children":3471},{},[3472],{"type":26,"tag":840,"props":3473,"children":3474},{"href":860},[3475],{"type":32,"value":863},{"title":7,"searchDepth":865,"depth":865,"links":3477},[3478,3479,3480,3484,3485,3486,3487,3488,3493,3499,3500],{"id":29,"depth":868,"text":8},{"id":137,"depth":868,"text":140},{"id":226,"depth":868,"text":229,"children":3481},[3482,3483],{"id":233,"depth":865,"text":233},{"id":277,"depth":865,"text":280},{"id":313,"depth":868,"text":316},{"id":365,"depth":868,"text":876},{"id":453,"depth":868,"text":456},{"id":516,"depth":868,"text":519},{"id":589,"depth":868,"text":592,"children":3489},[3490,3491,3492],{"id":612,"depth":865,"text":615},{"id":631,"depth":865,"text":883},{"id":658,"depth":865,"text":661},{"id":693,"depth":868,"text":696,"children":3494},[3495,3496,3497,3498],{"id":699,"depth":865,"text":702},{"id":710,"depth":865,"text":713},{"id":721,"depth":865,"text":724},{"id":748,"depth":865,"text":751},{"id":780,"depth":868,"text":783},{"id":829,"depth":868,"text":832},1782088252418]