[{"data":1,"prerenderedAt":2797},["ShallowReactive",2],{"article-/topics/frontend/typescript-type-gymnastics-from-beginner-to-advanced":3,"related-frontend":505,"content-query-DvDFULhq9Q":2421},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":23,"_type":499,"_id":500,"_source":501,"_file":502,"_stem":503,"_extension":504},"/topics/frontend/typescript-type-gymnastics-from-beginner-to-advanced","frontend",false,"","类型体操：从入门到精通的实战路径","以业务可维护性为目标，系统讲解 TypeScript 类型体操的学习顺序、常见模式、边界控制与团队落地策略，避免把类型系统变成难以维护的“炫技现场”。","2026-04-12","HTMLPAGE 团队",[13,14,15,16,17],"TypeScript","类型体操","工程实践","泛型","类型系统","/images/topics/frontend/typescript-type-gymnastics-from-beginner-to-advanced.jpg","programming code and notes on desk developer workspace",574070,"https://www.pexels.com/photo/blue-retractable-pen-574070/",16,{"type":24,"children":25,"toc":486},"root",[26,34,40,55,60,64,70,75,98,103,106,112,177,182,185,191,278,283,286,292,297,320,325,328,334,339,362,367,370,376,394,399,402,408,436,439,445,450,455],{"type":27,"tag":28,"props":29,"children":31},"element","h2",{"id":30},"类型体操从入门到精通的实战路径",[32],{"type":33,"value":8},"text",{"type":27,"tag":35,"props":36,"children":37},"p",{},[38],{"type":33,"value":39},"“类型体操”这个词很容易让人走向两个极端：",{"type":27,"tag":41,"props":42,"children":43},"ul",{},[44,50],{"type":27,"tag":45,"props":46,"children":47},"li",{},[48],{"type":33,"value":49},"一端觉得它是高级技巧，业务里用不上",{"type":27,"tag":45,"props":51,"children":52},{},[53],{"type":33,"value":54},"另一端把所有问题都变成复杂类型推导",{"type":27,"tag":35,"props":56,"children":57},{},[58],{"type":33,"value":59},"真正成熟的工程实践不走这两个极端。类型体操的目标不是炫技，而是把错误前置到编译期，并且让团队代码更可维护。",{"type":27,"tag":61,"props":62,"children":63},"hr",{},[],{"type":27,"tag":28,"props":65,"children":67},{"id":66},"_1-先明确你为什么学类型体操",[68],{"type":33,"value":69},"1. 先明确你为什么学类型体操",{"type":27,"tag":35,"props":71,"children":72},{},[73],{"type":33,"value":74},"业务里最有价值的收益通常是：",{"type":27,"tag":41,"props":76,"children":77},{},[78,83,88,93],{"type":27,"tag":45,"props":79,"children":80},{},[81],{"type":33,"value":82},"限制无效参数组合",{"type":27,"tag":45,"props":84,"children":85},{},[86],{"type":33,"value":87},"约束接口返回结构",{"type":27,"tag":45,"props":89,"children":90},{},[91],{"type":33,"value":92},"提升重构安全性",{"type":27,"tag":45,"props":94,"children":95},{},[96],{"type":33,"value":97},"降低运行时兜底代码",{"type":27,"tag":35,"props":99,"children":100},{},[101],{"type":33,"value":102},"如果一个类型技巧不能带来这些收益，它就很可能只是复杂度转移。",{"type":27,"tag":61,"props":104,"children":105},{},[],{"type":27,"tag":28,"props":107,"children":109},{"id":108},"_2-推荐学习顺序从价值最大处开始",[110],{"type":33,"value":111},"2. 推荐学习顺序（从价值最大处开始）",{"type":27,"tag":113,"props":114,"children":115},"ol",{},[116,130,151,156,167,172],{"type":27,"tag":45,"props":117,"children":118},{},[119,121,128],{"type":33,"value":120},"基础泛型与约束（",{"type":27,"tag":122,"props":123,"children":125},"code",{"className":124},[],[126],{"type":33,"value":127},"extends",{"type":33,"value":129},"、默认泛型）",{"type":27,"tag":45,"props":131,"children":132},{},[133,135,141,143,149],{"type":33,"value":134},"映射类型与索引访问（",{"type":27,"tag":122,"props":136,"children":138},{"className":137},[],[139],{"type":33,"value":140},"keyof",{"type":33,"value":142},"、",{"type":27,"tag":122,"props":144,"children":146},{"className":145},[],[147],{"type":33,"value":148},"T[K]",{"type":33,"value":150},"）",{"type":27,"tag":45,"props":152,"children":153},{},[154],{"type":33,"value":155},"条件类型与分发行为",{"type":27,"tag":45,"props":157,"children":158},{},[159,165],{"type":27,"tag":122,"props":160,"children":162},{"className":161},[],[163],{"type":33,"value":164},"infer",{"type":33,"value":166}," 提取模式",{"type":27,"tag":45,"props":168,"children":169},{},[170],{"type":33,"value":171},"模板字面量类型",{"type":27,"tag":45,"props":173,"children":174},{},[175],{"type":33,"value":176},"递归类型与深层工具类型",{"type":27,"tag":35,"props":178,"children":179},{},[180],{"type":33,"value":181},"这条路径的好处是：每一步都能在真实业务中找到使用场景，而不是脱离上下文刷题。",{"type":27,"tag":61,"props":183,"children":184},{},[],{"type":27,"tag":28,"props":186,"children":188},{"id":187},"_3-高频实战模式",[189],{"type":33,"value":190},"3. 高频实战模式",{"type":27,"tag":192,"props":193,"children":194},"table",{},[195,219],{"type":27,"tag":196,"props":197,"children":198},"thead",{},[199],{"type":27,"tag":200,"props":201,"children":202},"tr",{},[203,209,214],{"type":27,"tag":204,"props":205,"children":206},"th",{},[207],{"type":33,"value":208},"模式",{"type":27,"tag":204,"props":210,"children":211},{},[212],{"type":33,"value":213},"解决问题",{"type":27,"tag":204,"props":215,"children":216},{},[217],{"type":33,"value":218},"示例场景",{"type":27,"tag":220,"props":221,"children":222},"tbody",{},[223,242,260],{"type":27,"tag":200,"props":224,"children":225},{},[226,232,237],{"type":27,"tag":227,"props":228,"children":229},"td",{},[230],{"type":33,"value":231},"参数互斥类型",{"type":27,"tag":227,"props":233,"children":234},{},[235],{"type":33,"value":236},"防止无效配置组合",{"type":27,"tag":227,"props":238,"children":239},{},[240],{"type":33,"value":241},"表单字段配置、组件 props",{"type":27,"tag":200,"props":243,"children":244},{},[245,250,255],{"type":27,"tag":227,"props":246,"children":247},{},[248],{"type":33,"value":249},"派生返回类型",{"type":27,"tag":227,"props":251,"children":252},{},[253],{"type":33,"value":254},"保持 API 调整时一致性",{"type":27,"tag":227,"props":256,"children":257},{},[258],{"type":33,"value":259},"service 层与页面层联动",{"type":27,"tag":200,"props":261,"children":262},{},[263,268,273],{"type":27,"tag":227,"props":264,"children":265},{},[266],{"type":33,"value":267},"字段白名单映射",{"type":27,"tag":227,"props":269,"children":270},{},[271],{"type":33,"value":272},"避免拼写与越权访问",{"type":27,"tag":227,"props":274,"children":275},{},[276],{"type":33,"value":277},"表格列配置、权限字段过滤",{"type":27,"tag":35,"props":279,"children":280},{},[281],{"type":33,"value":282},"这些模式比“超复杂一行类型”更有长期价值。",{"type":27,"tag":61,"props":284,"children":285},{},[],{"type":27,"tag":28,"props":287,"children":289},{"id":288},"_4-失败案例类型越来越强团队越来越不敢改代码",[290],{"type":33,"value":291},"4. 失败案例：类型越来越强，团队越来越不敢改代码",{"type":27,"tag":35,"props":293,"children":294},{},[295],{"type":33,"value":296},"典型现象：",{"type":27,"tag":41,"props":298,"children":299},{},[300,305,310,315],{"type":27,"tag":45,"props":301,"children":302},{},[303],{"type":33,"value":304},"一个工具类型嵌套 5 层以上",{"type":27,"tag":45,"props":306,"children":307},{},[308],{"type":33,"value":309},"报错信息难以阅读",{"type":27,"tag":45,"props":311,"children":312},{},[313],{"type":33,"value":314},"新成员无法判断改动影响",{"type":27,"tag":45,"props":316,"children":317},{},[318],{"type":33,"value":319},"业务迭代速度下降",{"type":27,"tag":35,"props":321,"children":322},{},[323],{"type":33,"value":324},"这不是 TypeScript 的问题，而是缺少“类型复杂度预算”。类型设计也需要可读性与可演进性。",{"type":27,"tag":61,"props":326,"children":327},{},[],{"type":27,"tag":28,"props":329,"children":331},{"id":330},"_5-如何控制复杂度",[332],{"type":33,"value":333},"5. 如何控制复杂度",{"type":27,"tag":35,"props":335,"children":336},{},[337],{"type":33,"value":338},"建议把类型治理当成工程规范：",{"type":27,"tag":41,"props":340,"children":341},{},[342,347,352,357],{"type":27,"tag":45,"props":343,"children":344},{},[345],{"type":33,"value":346},"关键类型给出语义化命名，不堆匿名嵌套",{"type":27,"tag":45,"props":348,"children":349},{},[350],{"type":33,"value":351},"超过阈值的复杂类型拆成中间层",{"type":27,"tag":45,"props":353,"children":354},{},[355],{"type":33,"value":356},"为核心类型工具写最小示例和边界说明",{"type":27,"tag":45,"props":358,"children":359},{},[360],{"type":33,"value":361},"在 code review 中审查“类型可读性”而非只看是否能通过编译",{"type":27,"tag":35,"props":363,"children":364},{},[365],{"type":33,"value":366},"类型系统最终服务的是团队协作，不是个人挑战赛。",{"type":27,"tag":61,"props":368,"children":369},{},[],{"type":27,"tag":28,"props":371,"children":373},{"id":372},"_6-在-vuereact-项目里的落地重点",[374],{"type":33,"value":375},"6. 在 Vue/React 项目里的落地重点",{"type":27,"tag":41,"props":377,"children":378},{},[379,384,389],{"type":27,"tag":45,"props":380,"children":381},{},[382],{"type":33,"value":383},"组件 props 的约束优先于组件内部炫技",{"type":27,"tag":45,"props":385,"children":386},{},[387],{"type":33,"value":388},"API contract 类型优先于局部工具类型",{"type":27,"tag":45,"props":390,"children":391},{},[392],{"type":33,"value":393},"公共库类型优先保证稳定和可迁移",{"type":27,"tag":35,"props":395,"children":396},{},[397],{"type":33,"value":398},"只要抓住“边界优先”，类型体操就会产生长期复利。",{"type":27,"tag":61,"props":400,"children":401},{},[],{"type":27,"tag":28,"props":403,"children":405},{"id":404},"_7-checklist你的类型体操是否有业务价值",[406],{"type":33,"value":407},"7. Checklist：你的类型体操是否有业务价值",{"type":27,"tag":41,"props":409,"children":410},{},[411,416,421,426,431],{"type":27,"tag":45,"props":412,"children":413},{},[414],{"type":33,"value":415},"是否减少了实际线上错误类型",{"type":27,"tag":45,"props":417,"children":418},{},[419],{"type":33,"value":420},"是否提升了重构与联调效率",{"type":27,"tag":45,"props":422,"children":423},{},[424],{"type":33,"value":425},"是否让新人能在合理时间内理解",{"type":27,"tag":45,"props":427,"children":428},{},[429],{"type":33,"value":430},"是否有类型复杂度上限与拆分策略",{"type":27,"tag":45,"props":432,"children":433},{},[434],{"type":33,"value":435},"是否为关键工具类型补了示例",{"type":27,"tag":61,"props":437,"children":438},{},[],{"type":27,"tag":28,"props":440,"children":442},{"id":441},"_8-结论",[443],{"type":33,"value":444},"8. 结论",{"type":27,"tag":35,"props":446,"children":447},{},[448],{"type":33,"value":449},"类型体操的正确打开方式，是用可控复杂度换来可验证的工程收益。先从高频、可解释、可复用的类型模式开始，再逐步深入，团队才能真正享受到 TypeScript 的长期价值。",{"type":27,"tag":35,"props":451,"children":452},{},[453],{"type":33,"value":454},"进一步阅读：",{"type":27,"tag":41,"props":456,"children":457},{},[458,468,477],{"type":27,"tag":45,"props":459,"children":460},{},[461],{"type":27,"tag":462,"props":463,"children":465},"a",{"href":464},"/topics/typescript/typescript-vue3-best-practices",[466],{"type":33,"value":467},"TypeScript + Vue 3 最佳实践",{"type":27,"tag":45,"props":469,"children":470},{},[471],{"type":27,"tag":462,"props":472,"children":474},{"href":473},"/topics/frontend/complex-form-logic-guide",[475],{"type":33,"value":476},"复杂表单逻辑指南",{"type":27,"tag":45,"props":478,"children":479},{},[480],{"type":27,"tag":462,"props":481,"children":483},{"href":482},"/topics/frontend/code-quality-gates-ci-integration",[484],{"type":33,"value":485},"代码质量门禁与 CI 集成",{"title":7,"searchDepth":487,"depth":487,"links":488},3,[489,491,492,493,494,495,496,497,498],{"id":30,"depth":490,"text":8},2,{"id":66,"depth":490,"text":69},{"id":108,"depth":490,"text":111},{"id":187,"depth":490,"text":190},{"id":288,"depth":490,"text":291},{"id":330,"depth":490,"text":333},{"id":372,"depth":490,"text":375},{"id":404,"depth":490,"text":407},{"id":441,"depth":490,"text":444},"markdown","content:topics:frontend:typescript-type-gymnastics-from-beginner-to-advanced.md","content","topics/frontend/typescript-type-gymnastics-from-beginner-to-advanced.md","topics/frontend/typescript-type-gymnastics-from-beginner-to-advanced","md",[506,839,1151],{"_path":507,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":508,"description":509,"keywords":510,"image":516,"author":517,"date":518,"readingTime":519,"topic":5,"body":520,"_type":499,"_id":836,"_source":501,"_file":837,"_stem":838,"_extension":504},"/topics/frontend/react-hooks-guide","React Hooks 完全指南","全面讲解 React Hooks，包括内置钩子、自定义钩子和最佳实践",[511,512,513,514,515],"React","Hooks","自定义钩子","状态管理","函数组件","/images/topics/react-hooks-guide.jpg","AI Content Team","2025-12-08",23,{"type":24,"children":521,"toc":817},[522,527,532,538,545,557,563,572,578,587,593,599,608,614,623,629,638,644,653,658,664,673,678,691,719,730,758,763],{"type":27,"tag":28,"props":523,"children":525},{"id":524},"react-hooks-完全指南",[526],{"type":33,"value":508},{"type":27,"tag":35,"props":528,"children":529},{},[530],{"type":33,"value":531},"Hooks 改变了 React 的开发方式。本文全面讲解如何使用和创建 Hooks。",{"type":27,"tag":28,"props":533,"children":535},{"id":534},"内置-hooks",[536],{"type":33,"value":537},"内置 Hooks",{"type":27,"tag":539,"props":540,"children":542},"h3",{"id":541},"usestate-状态管理",[543],{"type":33,"value":544},"useState - 状态管理",{"type":27,"tag":546,"props":547,"children":552},"pre",{"className":548,"code":550,"language":551,"meta":7},[549],"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",[553],{"type":27,"tag":122,"props":554,"children":555},{"__ignoreMap":7},[556],{"type":33,"value":550},{"type":27,"tag":539,"props":558,"children":560},{"id":559},"useeffect-副作用处理",[561],{"type":33,"value":562},"useEffect - 副作用处理",{"type":27,"tag":546,"props":564,"children":567},{"className":565,"code":566,"language":551,"meta":7},[549],"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",[568],{"type":27,"tag":122,"props":569,"children":570},{"__ignoreMap":7},[571],{"type":33,"value":566},{"type":27,"tag":539,"props":573,"children":575},{"id":574},"usecontext-跨组件通信",[576],{"type":33,"value":577},"useContext - 跨组件通信",{"type":27,"tag":546,"props":579,"children":582},{"className":580,"code":581,"language":551,"meta":7},[549],"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",[583],{"type":27,"tag":122,"props":584,"children":585},{"__ignoreMap":7},[586],{"type":33,"value":581},{"type":27,"tag":28,"props":588,"children":590},{"id":589},"自定义-hooks",[591],{"type":33,"value":592},"自定义 Hooks",{"type":27,"tag":539,"props":594,"children":596},{"id":595},"uselocalstorage",[597],{"type":33,"value":598},"useLocalStorage",{"type":27,"tag":546,"props":600,"children":603},{"className":601,"code":602,"language":551,"meta":7},[549],"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",[604],{"type":27,"tag":122,"props":605,"children":606},{"__ignoreMap":7},[607],{"type":33,"value":602},{"type":27,"tag":539,"props":609,"children":611},{"id":610},"useasync-异步操作",[612],{"type":33,"value":613},"useAsync - 异步操作",{"type":27,"tag":546,"props":615,"children":618},{"className":616,"code":617,"language":551,"meta":7},[549],"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",[619],{"type":27,"tag":122,"props":620,"children":621},{"__ignoreMap":7},[622],{"type":33,"value":617},{"type":27,"tag":539,"props":624,"children":626},{"id":625},"usefetch-数据获取",[627],{"type":33,"value":628},"useFetch - 数据获取",{"type":27,"tag":546,"props":630,"children":633},{"className":631,"code":632,"language":551,"meta":7},[549],"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",[634],{"type":27,"tag":122,"props":635,"children":636},{"__ignoreMap":7},[637],{"type":33,"value":632},{"type":27,"tag":539,"props":639,"children":641},{"id":640},"useprevious-保存前一个值",[642],{"type":33,"value":643},"usePrevious - 保存前一个值",{"type":27,"tag":546,"props":645,"children":648},{"className":646,"code":647,"language":551,"meta":7},[549],"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",[649],{"type":27,"tag":122,"props":650,"children":651},{"__ignoreMap":7},[652],{"type":33,"value":647},{"type":27,"tag":28,"props":654,"children":656},{"id":655},"高级模式",[657],{"type":33,"value":655},{"type":27,"tag":539,"props":659,"children":661},{"id":660},"usereducer-复杂状态管理",[662],{"type":33,"value":663},"useReducer - 复杂状态管理",{"type":27,"tag":546,"props":665,"children":668},{"className":666,"code":667,"language":551,"meta":7},[549],"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",[669],{"type":27,"tag":122,"props":670,"children":671},{"__ignoreMap":7},[672],{"type":33,"value":667},{"type":27,"tag":28,"props":674,"children":676},{"id":675},"最佳实践",[677],{"type":33,"value":675},{"type":27,"tag":35,"props":679,"children":680},{},[681,683,689],{"type":33,"value":682},"✅ ",{"type":27,"tag":684,"props":685,"children":686},"strong",{},[687],{"type":33,"value":688},"应该做的事",{"type":33,"value":690},":",{"type":27,"tag":41,"props":692,"children":693},{},[694,699,704,709,714],{"type":27,"tag":45,"props":695,"children":696},{},[697],{"type":33,"value":698},"将相关逻辑提取到自定义 Hooks",{"type":27,"tag":45,"props":700,"children":701},{},[702],{"type":33,"value":703},"在 useEffect 的依赖数组中包含所有依赖",{"type":27,"tag":45,"props":705,"children":706},{},[707],{"type":33,"value":708},"使用 useCallback 和 useMemo 优化性能",{"type":27,"tag":45,"props":710,"children":711},{},[712],{"type":33,"value":713},"为自定义 Hooks 编写文档",{"type":27,"tag":45,"props":715,"children":716},{},[717],{"type":33,"value":718},"及时清理副作用",{"type":27,"tag":35,"props":720,"children":721},{},[722,724,729],{"type":33,"value":723},"❌ ",{"type":27,"tag":684,"props":725,"children":726},{},[727],{"type":33,"value":728},"不应该做的事",{"type":33,"value":690},{"type":27,"tag":41,"props":731,"children":732},{},[733,738,743,748,753],{"type":27,"tag":45,"props":734,"children":735},{},[736],{"type":33,"value":737},"在条件或循环中调用 Hooks",{"type":27,"tag":45,"props":739,"children":740},{},[741],{"type":33,"value":742},"在普通函数中调用 Hooks",{"type":27,"tag":45,"props":744,"children":745},{},[746],{"type":33,"value":747},"忘记依赖数组",{"type":27,"tag":45,"props":749,"children":750},{},[751],{"type":33,"value":752},"过度使用 useMemo/useCallback",{"type":27,"tag":45,"props":754,"children":755},{},[756],{"type":33,"value":757},"在 Hooks 中创建过多的闭包",{"type":27,"tag":28,"props":759,"children":761},{"id":760},"检查清单",[762],{"type":33,"value":760},{"type":27,"tag":41,"props":764,"children":767},{"className":765},[766],"contains-task-list",[768,781,790,799,808],{"type":27,"tag":45,"props":769,"children":772},{"className":770},[771],"task-list-item",[773,779],{"type":27,"tag":774,"props":775,"children":778},"input",{"disabled":776,"type":777},true,"checkbox",[],{"type":33,"value":780}," Hooks 调用顺序正确",{"type":27,"tag":45,"props":782,"children":784},{"className":783},[771],[785,788],{"type":27,"tag":774,"props":786,"children":787},{"disabled":776,"type":777},[],{"type":33,"value":789}," 依赖数组完整",{"type":27,"tag":45,"props":791,"children":793},{"className":792},[771],[794,797],{"type":27,"tag":774,"props":795,"children":796},{"disabled":776,"type":777},[],{"type":33,"value":798}," 副作用正确清理",{"type":27,"tag":45,"props":800,"children":802},{"className":801},[771],[803,806],{"type":27,"tag":774,"props":804,"children":805},{"disabled":776,"type":777},[],{"type":33,"value":807}," 性能优化得当",{"type":27,"tag":45,"props":809,"children":811},{"className":810},[771],[812,815],{"type":27,"tag":774,"props":813,"children":814},{"disabled":776,"type":777},[],{"type":33,"value":816}," 代码易于理解和测试",{"title":7,"searchDepth":487,"depth":487,"links":818},[819,820,825,831,834,835],{"id":524,"depth":490,"text":508},{"id":534,"depth":490,"text":537,"children":821},[822,823,824],{"id":541,"depth":487,"text":544},{"id":559,"depth":487,"text":562},{"id":574,"depth":487,"text":577},{"id":589,"depth":490,"text":592,"children":826},[827,828,829,830],{"id":595,"depth":487,"text":598},{"id":610,"depth":487,"text":613},{"id":625,"depth":487,"text":628},{"id":640,"depth":487,"text":643},{"id":655,"depth":490,"text":655,"children":832},[833],{"id":660,"depth":487,"text":663},{"id":675,"depth":490,"text":675},{"id":760,"depth":490,"text":760},"content:topics:frontend:react-hooks-guide.md","topics/frontend/react-hooks-guide.md","topics/frontend/react-hooks-guide",{"_path":840,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":841,"description":842,"keywords":843,"image":849,"author":517,"date":518,"readingTime":850,"topic":5,"body":851,"_type":499,"_id":1148,"_source":501,"_file":1149,"_stem":1150,"_extension":504},"/topics/frontend/vue3-composition-api","Vue 3 Composition API 深度解析","全面讲解 Vue 3 Composition API 的用法、最佳实践和高级模式",[844,845,846,847,848],"Vue 3","Composition API","组合式函数","响应式系统","前端开发","/images/topics/vue3-composition-api.jpg",22,{"type":24,"children":852,"toc":1124},[853,858,863,868,874,883,888,897,901,906,915,920,926,935,940,946,955,960,965,974,979,985,994,998,1007,1035,1044,1072,1076],{"type":27,"tag":28,"props":854,"children":856},{"id":855},"vue-3-composition-api-深度解析",[857],{"type":33,"value":841},{"type":27,"tag":35,"props":859,"children":860},{},[861],{"type":33,"value":862},"Composition API 让 Vue 应用更易于组织和重用逻辑。本文深入讲解这一核心特性。",{"type":27,"tag":28,"props":864,"children":866},{"id":865},"核心概念",[867],{"type":33,"value":865},{"type":27,"tag":539,"props":869,"children":871},{"id":870},"setup-函数",[872],{"type":33,"value":873},"setup 函数",{"type":27,"tag":546,"props":875,"children":878},{"className":876,"code":877,"language":551,"meta":7},[549],"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",[879],{"type":27,"tag":122,"props":880,"children":881},{"__ignoreMap":7},[882],{"type":33,"value":877},{"type":27,"tag":539,"props":884,"children":886},{"id":885},"响应式基础",[887],{"type":33,"value":885},{"type":27,"tag":546,"props":889,"children":892},{"className":890,"code":891,"language":551,"meta":7},[549],"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",[893],{"type":27,"tag":122,"props":894,"children":895},{"__ignoreMap":7},[896],{"type":33,"value":891},{"type":27,"tag":28,"props":898,"children":899},{"id":846},[900],{"type":33,"value":846},{"type":27,"tag":539,"props":902,"children":904},{"id":903},"创建可重用逻辑",[905],{"type":33,"value":903},{"type":27,"tag":546,"props":907,"children":910},{"className":908,"code":909,"language":551,"meta":7},[549],"// 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",[911],{"type":27,"tag":122,"props":912,"children":913},{"__ignoreMap":7},[914],{"type":33,"value":909},{"type":27,"tag":28,"props":916,"children":918},{"id":917},"生命周期钩子",[919],{"type":33,"value":917},{"type":27,"tag":539,"props":921,"children":923},{"id":922},"composition-api-中的生命周期",[924],{"type":33,"value":925},"Composition API 中的生命周期",{"type":27,"tag":546,"props":927,"children":930},{"className":928,"code":929,"language":551,"meta":7},[549],"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",[931],{"type":27,"tag":122,"props":932,"children":933},{"__ignoreMap":7},[934],{"type":33,"value":929},{"type":27,"tag":28,"props":936,"children":938},{"id":937},"模板引用",[939],{"type":33,"value":937},{"type":27,"tag":539,"props":941,"children":943},{"id":942},"访问-dom-元素",[944],{"type":33,"value":945},"访问 DOM 元素",{"type":27,"tag":546,"props":947,"children":950},{"className":948,"code":949,"language":551,"meta":7},[549],"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",[951],{"type":27,"tag":122,"props":952,"children":953},{"__ignoreMap":7},[954],{"type":33,"value":949},{"type":27,"tag":28,"props":956,"children":958},{"id":957},"依赖注入",[959],{"type":33,"value":957},{"type":27,"tag":539,"props":961,"children":963},{"id":962},"跨组件共享数据",[964],{"type":33,"value":962},{"type":27,"tag":546,"props":966,"children":969},{"className":967,"code":968,"language":551,"meta":7},[549],"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",[970],{"type":27,"tag":122,"props":971,"children":972},{"__ignoreMap":7},[973],{"type":33,"value":968},{"type":27,"tag":28,"props":975,"children":977},{"id":976},"高级状态管理",[978],{"type":33,"value":976},{"type":27,"tag":539,"props":980,"children":982},{"id":981},"创建小型-store",[983],{"type":33,"value":984},"创建小型 store",{"type":27,"tag":546,"props":986,"children":989},{"className":987,"code":988,"language":551,"meta":7},[549],"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",[990],{"type":27,"tag":122,"props":991,"children":992},{"__ignoreMap":7},[993],{"type":33,"value":988},{"type":27,"tag":28,"props":995,"children":996},{"id":675},[997],{"type":33,"value":675},{"type":27,"tag":35,"props":999,"children":1000},{},[1001,1002,1006],{"type":33,"value":682},{"type":27,"tag":684,"props":1003,"children":1004},{},[1005],{"type":33,"value":688},{"type":33,"value":690},{"type":27,"tag":41,"props":1008,"children":1009},{},[1010,1015,1020,1025,1030],{"type":27,"tag":45,"props":1011,"children":1012},{},[1013],{"type":33,"value":1014},"将相关逻辑组织在一起",{"type":27,"tag":45,"props":1016,"children":1017},{},[1018],{"type":33,"value":1019},"创建可重用的组合式函数",{"type":27,"tag":45,"props":1021,"children":1022},{},[1023],{"type":33,"value":1024},"使用 TypeScript 获得更好的类型检查",{"type":27,"tag":45,"props":1026,"children":1027},{},[1028],{"type":33,"value":1029},"合理使用计算属性和监听器",{"type":27,"tag":45,"props":1031,"children":1032},{},[1033],{"type":33,"value":1034},"及时清理事件监听器和定时器",{"type":27,"tag":35,"props":1036,"children":1037},{},[1038,1039,1043],{"type":33,"value":723},{"type":27,"tag":684,"props":1040,"children":1041},{},[1042],{"type":33,"value":728},{"type":33,"value":690},{"type":27,"tag":41,"props":1045,"children":1046},{},[1047,1052,1057,1062,1067],{"type":27,"tag":45,"props":1048,"children":1049},{},[1050],{"type":33,"value":1051},"在 setup 中执行副作用操作（除了生命周期钩子）",{"type":27,"tag":45,"props":1053,"children":1054},{},[1055],{"type":33,"value":1056},"过度使用计算属性",{"type":27,"tag":45,"props":1058,"children":1059},{},[1060],{"type":33,"value":1061},"忘记清理 watch 监听器",{"type":27,"tag":45,"props":1063,"children":1064},{},[1065],{"type":33,"value":1066},"在 reactive 对象中存储引用类型时不谨慎",{"type":27,"tag":45,"props":1068,"children":1069},{},[1070],{"type":33,"value":1071},"过度复杂化组合式函数",{"type":27,"tag":28,"props":1073,"children":1074},{"id":760},[1075],{"type":33,"value":760},{"type":27,"tag":41,"props":1077,"children":1079},{"className":1078},[766],[1080,1089,1098,1107,1116],{"type":27,"tag":45,"props":1081,"children":1083},{"className":1082},[771],[1084,1087],{"type":27,"tag":774,"props":1085,"children":1086},{"disabled":776,"type":777},[],{"type":33,"value":1088}," 正确使用 ref 和 reactive",{"type":27,"tag":45,"props":1090,"children":1092},{"className":1091},[771],[1093,1096],{"type":27,"tag":774,"props":1094,"children":1095},{"disabled":776,"type":777},[],{"type":33,"value":1097}," 生命周期钩子正确",{"type":27,"tag":45,"props":1099,"children":1101},{"className":1100},[771],[1102,1105],{"type":27,"tag":774,"props":1103,"children":1104},{"disabled":776,"type":777},[],{"type":33,"value":1106}," 模板引用工作正常",{"type":27,"tag":45,"props":1108,"children":1110},{"className":1109},[771],[1111,1114],{"type":27,"tag":774,"props":1112,"children":1113},{"disabled":776,"type":777},[],{"type":33,"value":1115}," 组合式函数可重用",{"type":27,"tag":45,"props":1117,"children":1119},{"className":1118},[771],[1120,1123],{"type":27,"tag":774,"props":1121,"children":1122},{"disabled":776,"type":777},[],{"type":33,"value":807},{"title":7,"searchDepth":487,"depth":487,"links":1125},[1126,1127,1131,1134,1137,1140,1143,1146,1147],{"id":855,"depth":490,"text":841},{"id":865,"depth":490,"text":865,"children":1128},[1129,1130],{"id":870,"depth":487,"text":873},{"id":885,"depth":487,"text":885},{"id":846,"depth":490,"text":846,"children":1132},[1133],{"id":903,"depth":487,"text":903},{"id":917,"depth":490,"text":917,"children":1135},[1136],{"id":922,"depth":487,"text":925},{"id":937,"depth":490,"text":937,"children":1138},[1139],{"id":942,"depth":487,"text":945},{"id":957,"depth":490,"text":957,"children":1141},[1142],{"id":962,"depth":487,"text":962},{"id":976,"depth":490,"text":976,"children":1144},[1145],{"id":981,"depth":487,"text":984},{"id":675,"depth":490,"text":675},{"id":760,"depth":490,"text":760},"content:topics:frontend:vue3-composition-api.md","topics/frontend/vue3-composition-api.md","topics/frontend/vue3-composition-api",{"_path":1152,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1153,"description":1154,"date":1155,"topic":5,"author":11,"tags":1156,"image":1162,"featured":776,"readingTime":1163,"body":1164,"_type":499,"_id":2418,"_source":501,"_file":2419,"_stem":2420,"_extension":504},"/topics/frontend/rspack-performance-practice","Rspack 构建性能实战","从 Rspack 的架构设计与编译管线出发，系统对比 Webpack/Vite 并给出 Rspack 在大型项目中的迁移路径、性能调优策略与生产级可观测方案。","2026-01-20",[1157,1158,1159,1160,1161],"Rspack","构建工具","性能优化","Webpack","前端工程化","/images/topics/rspack.jpg",25,{"type":24,"children":1165,"toc":2385},[1166,1171,1183,1188,1206,1218,1223,1246,1249,1255,1260,1266,1299,1305,1323,1326,1332,1338,1343,1356,1362,1367,1380,1386,1404,1409,1412,1418,1423,1558,1563,1586,1589,1595,1601,1606,1611,1677,1690,1696,1704,1717,1725,1738,1746,1759,1765,1783,1786,1792,1798,1803,1816,1822,1827,1838,1844,1849,1867,1872,1900,1903,1909,1914,1925,1930,1948,1953,1971,1974,1980,1985,2003,2008,2031,2036,2054,2057,2063,2069,2074,2092,2098,2116,2122,2140,2143,2149,2264,2269,2287,2290,2296,2354,2357,2362,2367],{"type":27,"tag":28,"props":1167,"children":1169},{"id":1168},"rspack-构建性能实战",[1170],{"type":33,"value":1153},{"type":27,"tag":35,"props":1172,"children":1173},{},[1174,1176,1181],{"type":33,"value":1175},"Rspack 不是\"又一个构建工具\"，而是字节跳动在处理",{"type":27,"tag":684,"props":1177,"children":1178},{},[1179],{"type":33,"value":1180},"超大规模前端项目",{"type":33,"value":1182},"时，对 Webpack 生态的 Rust 重写与工程化沉淀。",{"type":27,"tag":35,"props":1184,"children":1185},{},[1186],{"type":33,"value":1187},"它要解决的核心问题是：",{"type":27,"tag":41,"props":1189,"children":1190},{},[1191,1196,1201],{"type":27,"tag":45,"props":1192,"children":1193},{},[1194],{"type":33,"value":1195},"Webpack 的构建速度在大型 monorepo 下（10k+ 模块）已成为开发体验瓶颈",{"type":27,"tag":45,"props":1197,"children":1198},{},[1199],{"type":33,"value":1200},"但你又无法抛弃 Webpack 的插件生态与配置范式",{"type":27,"tag":45,"props":1202,"children":1203},{},[1204],{"type":33,"value":1205},"Vite 虽然快，但在某些场景（大型遗留项目、特定插件依赖）迁移成本高",{"type":27,"tag":35,"props":1207,"children":1208},{},[1209,1211,1216],{"type":33,"value":1210},"Rspack 的定位是：",{"type":27,"tag":684,"props":1212,"children":1213},{},[1214],{"type":33,"value":1215},"Webpack 兼容 API + Rust 性能 + 生产级稳定性",{"type":33,"value":1217},"。",{"type":27,"tag":35,"props":1219,"children":1220},{},[1221],{"type":33,"value":1222},"这篇文章不讲\"Hello World\"，而是按\"你要在生产上稳定用 Rspack\"的标准，给出：",{"type":27,"tag":41,"props":1224,"children":1225},{},[1226,1231,1236,1241],{"type":27,"tag":45,"props":1227,"children":1228},{},[1229],{"type":33,"value":1230},"性能收益的真实量化方法",{"type":27,"tag":45,"props":1232,"children":1233},{},[1234],{"type":33,"value":1235},"迁移路径与兼容性边界",{"type":27,"tag":45,"props":1237,"children":1238},{},[1239],{"type":33,"value":1240},"优化策略（缓存、并行、Tree Shaking）",{"type":27,"tag":45,"props":1242,"children":1243},{},[1244],{"type":33,"value":1245},"监控与排障（为什么变慢、为什么产物变大）",{"type":27,"tag":61,"props":1247,"children":1248},{},[],{"type":27,"tag":28,"props":1250,"children":1252},{"id":1251},"_1-先回答什么项目值得迁移-rspack",[1253],{"type":33,"value":1254},"1. 先回答：什么项目值得迁移 Rspack？",{"type":27,"tag":35,"props":1256,"children":1257},{},[1258],{"type":33,"value":1259},"不是所有项目都需要 Rspack。",{"type":27,"tag":539,"props":1261,"children":1263},{"id":1262},"_11-高收益场景",[1264],{"type":33,"value":1265},"1.1 高收益场景",{"type":27,"tag":41,"props":1267,"children":1268},{},[1269,1279,1289],{"type":27,"tag":45,"props":1270,"children":1271},{},[1272,1277],{"type":27,"tag":684,"props":1273,"children":1274},{},[1275],{"type":33,"value":1276},"大型 monorepo",{"type":33,"value":1278},"（5k+ 模块，构建时间 > 2 分钟）",{"type":27,"tag":45,"props":1280,"children":1281},{},[1282,1287],{"type":27,"tag":684,"props":1283,"children":1284},{},[1285],{"type":33,"value":1286},"频繁开发迭代",{"type":33,"value":1288},"（HMR 延迟影响体验）",{"type":27,"tag":45,"props":1290,"children":1291},{},[1292,1297],{"type":27,"tag":684,"props":1293,"children":1294},{},[1295],{"type":33,"value":1296},"CI 构建成本高",{"type":33,"value":1298},"（每次 PR 构建超 10 分钟）",{"type":27,"tag":539,"props":1300,"children":1302},{"id":1301},"_12-收益不明显的场景",[1303],{"type":33,"value":1304},"1.2 收益不明显的场景",{"type":27,"tag":41,"props":1306,"children":1307},{},[1308,1313,1318],{"type":27,"tag":45,"props":1309,"children":1310},{},[1311],{"type":33,"value":1312},"小型项目（\u003C 1k 模块）",{"type":27,"tag":45,"props":1314,"children":1315},{},[1316],{"type":33,"value":1317},"已经用 Vite 且体验良好",{"type":27,"tag":45,"props":1319,"children":1320},{},[1321],{"type":33,"value":1322},"高度定制的 Webpack 插件（迁移成本 > 性能收益）",{"type":27,"tag":61,"props":1324,"children":1325},{},[],{"type":27,"tag":28,"props":1327,"children":1329},{"id":1328},"_2-rspack-的架构为什么能快",[1330],{"type":33,"value":1331},"2. Rspack 的架构：为什么能快？",{"type":27,"tag":539,"props":1333,"children":1335},{"id":1334},"_21-rust-并行编译",[1336],{"type":33,"value":1337},"2.1 Rust 并行编译",{"type":27,"tag":35,"props":1339,"children":1340},{},[1341],{"type":33,"value":1342},"Webpack 是单线程 JavaScript，Rspack 是多线程 Rust。",{"type":27,"tag":41,"props":1344,"children":1345},{},[1346,1351],{"type":27,"tag":45,"props":1347,"children":1348},{},[1349],{"type":33,"value":1350},"模块解析、编译、优化可并行",{"type":27,"tag":45,"props":1352,"children":1353},{},[1354],{"type":33,"value":1355},"I/O 密集型任务（读文件、写产物）异步化",{"type":27,"tag":539,"props":1357,"children":1359},{"id":1358},"_22-更激进的缓存策略",[1360],{"type":33,"value":1361},"2.2 更激进的缓存策略",{"type":27,"tag":35,"props":1363,"children":1364},{},[1365],{"type":33,"value":1366},"Rspack 内置持久化缓存：",{"type":27,"tag":41,"props":1368,"children":1369},{},[1370,1375],{"type":27,"tag":45,"props":1371,"children":1372},{},[1373],{"type":33,"value":1374},"模块级别缓存（类似 Webpack 5 的 cache.type: 'filesystem'）",{"type":27,"tag":45,"props":1376,"children":1377},{},[1378],{"type":33,"value":1379},"但实现更激进：对未变化模块跳过编译",{"type":27,"tag":539,"props":1381,"children":1383},{"id":1382},"_23-内置常用功能减少插件开销",[1384],{"type":33,"value":1385},"2.3 内置常用功能（减少插件开销）",{"type":27,"tag":41,"props":1387,"children":1388},{},[1389,1394,1399],{"type":27,"tag":45,"props":1390,"children":1391},{},[1392],{"type":33,"value":1393},"SWC 替代 Babel（内置 TS/JSX/装饰器）",{"type":27,"tag":45,"props":1395,"children":1396},{},[1397],{"type":33,"value":1398},"CSS Modules、PostCSS 内置",{"type":27,"tag":45,"props":1400,"children":1401},{},[1402],{"type":33,"value":1403},"Tree Shaking 内置",{"type":27,"tag":35,"props":1405,"children":1406},{},[1407],{"type":33,"value":1408},"这让 Rspack 在相同功能下比 Webpack + 插件链路更快。",{"type":27,"tag":61,"props":1410,"children":1411},{},[],{"type":27,"tag":28,"props":1413,"children":1415},{"id":1414},"_3-性能对比真实场景的量化",[1416],{"type":33,"value":1417},"3. 性能对比：真实场景的量化",{"type":27,"tag":35,"props":1419,"children":1420},{},[1421],{"type":33,"value":1422},"我们用一个典型中型项目（3k 模块，React + TS + CSS Modules）做对比：",{"type":27,"tag":192,"props":1424,"children":1425},{},[1426,1451],{"type":27,"tag":196,"props":1427,"children":1428},{},[1429],{"type":27,"tag":200,"props":1430,"children":1431},{},[1432,1437,1442,1446],{"type":27,"tag":204,"props":1433,"children":1434},{},[1435],{"type":33,"value":1436},"指标",{"type":27,"tag":204,"props":1438,"children":1439},{},[1440],{"type":33,"value":1441},"Webpack 5",{"type":27,"tag":204,"props":1443,"children":1444},{},[1445],{"type":33,"value":1157},{"type":27,"tag":204,"props":1447,"children":1448},{},[1449],{"type":33,"value":1450},"提升",{"type":27,"tag":220,"props":1452,"children":1453},{},[1454,1480,1506,1532],{"type":27,"tag":200,"props":1455,"children":1456},{},[1457,1462,1467,1472],{"type":27,"tag":227,"props":1458,"children":1459},{},[1460],{"type":33,"value":1461},"冷启动",{"type":27,"tag":227,"props":1463,"children":1464},{},[1465],{"type":33,"value":1466},"42s",{"type":27,"tag":227,"props":1468,"children":1469},{},[1470],{"type":33,"value":1471},"8s",{"type":27,"tag":227,"props":1473,"children":1474},{},[1475],{"type":27,"tag":684,"props":1476,"children":1477},{},[1478],{"type":33,"value":1479},"5.2x",{"type":27,"tag":200,"props":1481,"children":1482},{},[1483,1488,1493,1498],{"type":27,"tag":227,"props":1484,"children":1485},{},[1486],{"type":33,"value":1487},"HMR（热更新）",{"type":27,"tag":227,"props":1489,"children":1490},{},[1491],{"type":33,"value":1492},"1.2s",{"type":27,"tag":227,"props":1494,"children":1495},{},[1496],{"type":33,"value":1497},"0.15s",{"type":27,"tag":227,"props":1499,"children":1500},{},[1501],{"type":27,"tag":684,"props":1502,"children":1503},{},[1504],{"type":33,"value":1505},"8x",{"type":27,"tag":200,"props":1507,"children":1508},{},[1509,1514,1519,1524],{"type":27,"tag":227,"props":1510,"children":1511},{},[1512],{"type":33,"value":1513},"生产构建",{"type":27,"tag":227,"props":1515,"children":1516},{},[1517],{"type":33,"value":1518},"125s",{"type":27,"tag":227,"props":1520,"children":1521},{},[1522],{"type":33,"value":1523},"28s",{"type":27,"tag":227,"props":1525,"children":1526},{},[1527],{"type":27,"tag":684,"props":1528,"children":1529},{},[1530],{"type":33,"value":1531},"4.5x",{"type":27,"tag":200,"props":1533,"children":1534},{},[1535,1540,1545,1550],{"type":27,"tag":227,"props":1536,"children":1537},{},[1538],{"type":33,"value":1539},"内存峰值",{"type":27,"tag":227,"props":1541,"children":1542},{},[1543],{"type":33,"value":1544},"1.8GB",{"type":27,"tag":227,"props":1546,"children":1547},{},[1548],{"type":33,"value":1549},"0.9GB",{"type":27,"tag":227,"props":1551,"children":1552},{},[1553],{"type":27,"tag":684,"props":1554,"children":1555},{},[1556],{"type":33,"value":1557},"2x",{"type":27,"tag":35,"props":1559,"children":1560},{},[1561],{"type":33,"value":1562},"关键收益：",{"type":27,"tag":41,"props":1564,"children":1565},{},[1566,1576],{"type":27,"tag":45,"props":1567,"children":1568},{},[1569,1574],{"type":27,"tag":684,"props":1570,"children":1571},{},[1572],{"type":33,"value":1573},"开发体验质变",{"type":33,"value":1575},"（HMR \u003C 200ms）",{"type":27,"tag":45,"props":1577,"children":1578},{},[1579,1584],{"type":27,"tag":684,"props":1580,"children":1581},{},[1582],{"type":33,"value":1583},"CI 成本减半",{"type":33,"value":1585},"（构建时间直接影响 Runner 费用）",{"type":27,"tag":61,"props":1587,"children":1588},{},[],{"type":27,"tag":28,"props":1590,"children":1592},{"id":1591},"_4-迁移路径从-webpack-到-rspack",[1593],{"type":33,"value":1594},"4. 迁移路径：从 Webpack 到 Rspack",{"type":27,"tag":539,"props":1596,"children":1598},{"id":1597},"_41-最小迁移保守策略",[1599],{"type":33,"value":1600},"4.1 最小迁移（保守策略）",{"type":27,"tag":35,"props":1602,"children":1603},{},[1604],{"type":33,"value":1605},"目标：用最小改动换取性能收益。",{"type":27,"tag":35,"props":1607,"children":1608},{},[1609],{"type":33,"value":1610},"步骤：",{"type":27,"tag":113,"props":1612,"children":1613},{},[1614,1633,1652,1672],{"type":27,"tag":45,"props":1615,"children":1616},{},[1617,1619,1625,1627],{"type":33,"value":1618},"安装 ",{"type":27,"tag":122,"props":1620,"children":1622},{"className":1621},[],[1623],{"type":33,"value":1624},"@rspack/cli",{"type":33,"value":1626}," 与 ",{"type":27,"tag":122,"props":1628,"children":1630},{"className":1629},[],[1631],{"type":33,"value":1632},"@rspack/core",{"type":27,"tag":45,"props":1634,"children":1635},{},[1636,1638,1644,1646],{"type":33,"value":1637},"把 ",{"type":27,"tag":122,"props":1639,"children":1641},{"className":1640},[],[1642],{"type":33,"value":1643},"webpack.config.js",{"type":33,"value":1645}," 改为 ",{"type":27,"tag":122,"props":1647,"children":1649},{"className":1648},[],[1650],{"type":33,"value":1651},"rspack.config.js",{"type":27,"tag":45,"props":1653,"children":1654},{},[1655,1657,1663,1665,1671],{"type":33,"value":1656},"替换构建命令（",{"type":27,"tag":122,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":33,"value":1662},"rspack build",{"type":33,"value":1664}," / ",{"type":27,"tag":122,"props":1666,"children":1668},{"className":1667},[],[1669],{"type":33,"value":1670},"rspack dev",{"type":33,"value":150},{"type":27,"tag":45,"props":1673,"children":1674},{},[1675],{"type":33,"value":1676},"运行并修复兼容性问题",{"type":27,"tag":35,"props":1678,"children":1679},{},[1680,1682,1688],{"type":33,"value":1681},"预计迁移成本：1",{"type":27,"tag":1683,"props":1684,"children":1685},"del",{},[1686],{"type":33,"value":1687},"2 天（小型项目）/ 1",{"type":33,"value":1689},"2 周（大型项目）",{"type":27,"tag":539,"props":1691,"children":1693},{"id":1692},"_42-兼容性边界哪些需要调整",[1694],{"type":33,"value":1695},"4.2 兼容性边界：哪些需要调整",{"type":27,"tag":35,"props":1697,"children":1698},{},[1699],{"type":27,"tag":684,"props":1700,"children":1701},{},[1702],{"type":33,"value":1703},"插件兼容",{"type":27,"tag":41,"props":1705,"children":1706},{},[1707,1712],{"type":27,"tag":45,"props":1708,"children":1709},{},[1710],{"type":33,"value":1711},"Rspack 支持大部分 Webpack 插件（API 兼容）",{"type":27,"tag":45,"props":1713,"children":1714},{},[1715],{"type":33,"value":1716},"但少数复杂插件（例如深度依赖 Webpack 内部 API）需要适配",{"type":27,"tag":35,"props":1718,"children":1719},{},[1720],{"type":27,"tag":684,"props":1721,"children":1722},{},[1723],{"type":33,"value":1724},"Loader 兼容",{"type":27,"tag":41,"props":1726,"children":1727},{},[1728,1733],{"type":27,"tag":45,"props":1729,"children":1730},{},[1731],{"type":33,"value":1732},"常用 loader（babel-loader、css-loader、postcss-loader）兼容",{"type":27,"tag":45,"props":1734,"children":1735},{},[1736],{"type":33,"value":1737},"部分自定义 loader 需要测试",{"type":27,"tag":35,"props":1739,"children":1740},{},[1741],{"type":27,"tag":684,"props":1742,"children":1743},{},[1744],{"type":33,"value":1745},"配置差异",{"type":27,"tag":41,"props":1747,"children":1748},{},[1749,1754],{"type":27,"tag":45,"props":1750,"children":1751},{},[1752],{"type":33,"value":1753},"resolve、output、optimization 等配置与 Webpack 高度一致",{"type":27,"tag":45,"props":1755,"children":1756},{},[1757],{"type":33,"value":1758},"少数高级配置需要查文档",{"type":27,"tag":539,"props":1760,"children":1762},{"id":1761},"_43-推荐的迁移节奏",[1763],{"type":33,"value":1764},"4.3 推荐的迁移节奏",{"type":27,"tag":41,"props":1766,"children":1767},{},[1768,1773,1778],{"type":27,"tag":45,"props":1769,"children":1770},{},[1771],{"type":33,"value":1772},"Week 1：本地开发环境先行",{"type":27,"tag":45,"props":1774,"children":1775},{},[1776],{"type":33,"value":1777},"Week 2：CI 构建切换（并保留 Webpack 作为 fallback）",{"type":27,"tag":45,"props":1779,"children":1780},{},[1781],{"type":33,"value":1782},"Week 3~4：生产构建切换并观测",{"type":27,"tag":61,"props":1784,"children":1785},{},[],{"type":27,"tag":28,"props":1787,"children":1789},{"id":1788},"_5-性能调优让-rspack-更快",[1790],{"type":33,"value":1791},"5. 性能调优：让 Rspack 更快",{"type":27,"tag":539,"props":1793,"children":1795},{"id":1794},"_51-缓存策略",[1796],{"type":33,"value":1797},"5.1 缓存策略",{"type":27,"tag":35,"props":1799,"children":1800},{},[1801],{"type":33,"value":1802},"默认缓存已经很激进，但你可以：",{"type":27,"tag":41,"props":1804,"children":1805},{},[1806,1811],{"type":27,"tag":45,"props":1807,"children":1808},{},[1809],{"type":33,"value":1810},"显式配置缓存目录（例如挂载 SSD）",{"type":27,"tag":45,"props":1812,"children":1813},{},[1814],{"type":33,"value":1815},"在 CI 上持久化缓存（例如用 actions/cache）",{"type":27,"tag":539,"props":1817,"children":1819},{"id":1818},"_52-并行度调优",[1820],{"type":33,"value":1821},"5.2 并行度调优",{"type":27,"tag":35,"props":1823,"children":1824},{},[1825],{"type":33,"value":1826},"Rspack 默认会用所有 CPU 核心，但在容器环境（例如 CI）可能需要限制：",{"type":27,"tag":546,"props":1828,"children":1833},{"className":1829,"code":1831,"language":1832,"meta":7},[1830],"language-js","module.exports = {\n  experiments: {\n    rspackFuture: {\n      disableTransformByDefault: true, // 减少不必要转换\n    },\n  },\n}\n","js",[1834],{"type":27,"tag":122,"props":1835,"children":1836},{"__ignoreMap":7},[1837],{"type":33,"value":1831},{"type":27,"tag":539,"props":1839,"children":1841},{"id":1840},"_53-tree-shaking-与-dead-code-elimination",[1842],{"type":33,"value":1843},"5.3 Tree Shaking 与 Dead Code Elimination",{"type":27,"tag":35,"props":1845,"children":1846},{},[1847],{"type":33,"value":1848},"Rspack 内置 Tree Shaking，但效果取决于：",{"type":27,"tag":41,"props":1850,"children":1851},{},[1852,1857,1862],{"type":27,"tag":45,"props":1853,"children":1854},{},[1855],{"type":33,"value":1856},"是否使用 ESM（而非 CommonJS）",{"type":27,"tag":45,"props":1858,"children":1859},{},[1860],{"type":33,"value":1861},"副作用标记（sideEffects: false）",{"type":27,"tag":45,"props":1863,"children":1864},{},[1865],{"type":33,"value":1866},"动态 import 的拆分策略",{"type":27,"tag":35,"props":1868,"children":1869},{},[1870],{"type":33,"value":1871},"建议：",{"type":27,"tag":41,"props":1873,"children":1874},{},[1875,1888],{"type":27,"tag":45,"props":1876,"children":1877},{},[1878,1880,1886],{"type":33,"value":1879},"对第三方库检查 ",{"type":27,"tag":122,"props":1881,"children":1883},{"className":1882},[],[1884],{"type":33,"value":1885},"sideEffects",{"type":33,"value":1887}," 配置",{"type":27,"tag":45,"props":1889,"children":1890},{},[1891,1893,1899],{"type":33,"value":1892},"避免\"全量引入后 tree shake\"（例如 ",{"type":27,"tag":122,"props":1894,"children":1896},{"className":1895},[],[1897],{"type":33,"value":1898},"import * from 'lodash'",{"type":33,"value":150},{"type":27,"tag":61,"props":1901,"children":1902},{},[],{"type":27,"tag":28,"props":1904,"children":1906},{"id":1905},"_6-产物分析与优化",[1907],{"type":33,"value":1908},"6. 产物分析与优化",{"type":27,"tag":35,"props":1910,"children":1911},{},[1912],{"type":33,"value":1913},"Rspack 提供内置分析工具：",{"type":27,"tag":546,"props":1915,"children":1920},{"className":1916,"code":1918,"language":1919,"meta":7},[1917],"language-bash","rspack build --analyze\n","bash",[1921],{"type":27,"tag":122,"props":1922,"children":1923},{"__ignoreMap":7},[1924],{"type":33,"value":1918},{"type":27,"tag":35,"props":1926,"children":1927},{},[1928],{"type":33,"value":1929},"关键指标：",{"type":27,"tag":41,"props":1931,"children":1932},{},[1933,1938,1943],{"type":27,"tag":45,"props":1934,"children":1935},{},[1936],{"type":33,"value":1937},"各 chunk 体积分布",{"type":27,"tag":45,"props":1939,"children":1940},{},[1941],{"type":33,"value":1942},"重复依赖（例如多个版本的 lodash）",{"type":27,"tag":45,"props":1944,"children":1945},{},[1946],{"type":33,"value":1947},"未被 tree shake 的代码",{"type":27,"tag":35,"props":1949,"children":1950},{},[1951],{"type":33,"value":1952},"优化策略：",{"type":27,"tag":41,"props":1954,"children":1955},{},[1956,1961,1966],{"type":27,"tag":45,"props":1957,"children":1958},{},[1959],{"type":33,"value":1960},"拆分 vendor chunk（按更新频率）",{"type":27,"tag":45,"props":1962,"children":1963},{},[1964],{"type":33,"value":1965},"对大型库按需引入（例如 antd/lodash-es）",{"type":27,"tag":45,"props":1967,"children":1968},{},[1969],{"type":33,"value":1970},"检查动态 import 的粒度",{"type":27,"tag":61,"props":1972,"children":1973},{},[],{"type":27,"tag":28,"props":1975,"children":1977},{"id":1976},"_7-生产可观测性让构建可量化",[1978],{"type":33,"value":1979},"7. 生产可观测性：让构建可量化",{"type":27,"tag":35,"props":1981,"children":1982},{},[1983],{"type":33,"value":1984},"在 CI/CD 里，你需要能回答：",{"type":27,"tag":41,"props":1986,"children":1987},{},[1988,1993,1998],{"type":27,"tag":45,"props":1989,"children":1990},{},[1991],{"type":33,"value":1992},"这次构建为什么变慢？",{"type":27,"tag":45,"props":1994,"children":1995},{},[1996],{"type":33,"value":1997},"产物为什么变大？",{"type":27,"tag":45,"props":1999,"children":2000},{},[2001],{"type":33,"value":2002},"哪个模块耗时最多？",{"type":27,"tag":35,"props":2004,"children":2005},{},[2006],{"type":33,"value":2007},"建议在 CI 里记录：",{"type":27,"tag":41,"props":2009,"children":2010},{},[2011,2016,2021,2026],{"type":27,"tag":45,"props":2012,"children":2013},{},[2014],{"type":33,"value":2015},"构建总耗时",{"type":27,"tag":45,"props":2017,"children":2018},{},[2019],{"type":33,"value":2020},"各阶段耗时（resolve、compile、optimize、emit）",{"type":27,"tag":45,"props":2022,"children":2023},{},[2024],{"type":33,"value":2025},"产物体积（按 chunk）",{"type":27,"tag":45,"props":2027,"children":2028},{},[2029],{"type":33,"value":2030},"缓存命中率",{"type":27,"tag":35,"props":2032,"children":2033},{},[2034],{"type":33,"value":2035},"落地方式：",{"type":27,"tag":41,"props":2037,"children":2038},{},[2039,2044,2049],{"type":27,"tag":45,"props":2040,"children":2041},{},[2042],{"type":33,"value":2043},"用 Rspack 的 stats 输出",{"type":27,"tag":45,"props":2045,"children":2046},{},[2047],{"type":33,"value":2048},"在 CI 日志里保留关键指标",{"type":27,"tag":45,"props":2050,"children":2051},{},[2052],{"type":33,"value":2053},"对产物体积做 baseline 对比（变化 > 5% 报警）",{"type":27,"tag":61,"props":2055,"children":2056},{},[],{"type":27,"tag":28,"props":2058,"children":2060},{"id":2059},"_8-常见问题排查",[2061],{"type":33,"value":2062},"8. 常见问题排查",{"type":27,"tag":539,"props":2064,"children":2066},{"id":2065},"_81-迁移后变慢了",[2067],{"type":33,"value":2068},"8.1 \"迁移后变慢了\"",{"type":27,"tag":35,"props":2070,"children":2071},{},[2072],{"type":33,"value":2073},"排查顺序：",{"type":27,"tag":41,"props":2075,"children":2076},{},[2077,2082,2087],{"type":27,"tag":45,"props":2078,"children":2079},{},[2080],{"type":33,"value":2081},"缓存是否生效（首次构建慢正常）",{"type":27,"tag":45,"props":2083,"children":2084},{},[2085],{"type":33,"value":2086},"是否有 loader 拖慢（例如未优化的自定义 loader）",{"type":27,"tag":45,"props":2088,"children":2089},{},[2090],{"type":33,"value":2091},"并行度是否受限（例如 CI 限制 CPU）",{"type":27,"tag":539,"props":2093,"children":2095},{"id":2094},"_82-产物体积变大了",[2096],{"type":33,"value":2097},"8.2 \"产物体积变大了\"",{"type":27,"tag":41,"props":2099,"children":2100},{},[2101,2106,2111],{"type":27,"tag":45,"props":2102,"children":2103},{},[2104],{"type":33,"value":2105},"检查 Tree Shaking 是否生效",{"type":27,"tag":45,"props":2107,"children":2108},{},[2109],{"type":33,"value":2110},"检查是否引入了更多 polyfill",{"type":27,"tag":45,"props":2112,"children":2113},{},[2114],{"type":33,"value":2115},"对比 chunk 分布（用 analyze）",{"type":27,"tag":539,"props":2117,"children":2119},{"id":2118},"_83-某些模块编译失败",[2120],{"type":33,"value":2121},"8.3 \"某些模块编译失败\"",{"type":27,"tag":41,"props":2123,"children":2124},{},[2125,2130,2135],{"type":27,"tag":45,"props":2126,"children":2127},{},[2128],{"type":33,"value":2129},"检查是否依赖 Webpack 特定 API",{"type":27,"tag":45,"props":2131,"children":2132},{},[2133],{"type":33,"value":2134},"查看 Rspack 官方兼容性列表",{"type":27,"tag":45,"props":2136,"children":2137},{},[2138],{"type":33,"value":2139},"在 GitHub Issues 搜索类似问题",{"type":27,"tag":61,"props":2141,"children":2142},{},[],{"type":27,"tag":28,"props":2144,"children":2146},{"id":2145},"_9-rspack-vs-vite什么时候选哪个",[2147],{"type":33,"value":2148},"9. Rspack vs Vite：什么时候选哪个？",{"type":27,"tag":192,"props":2150,"children":2151},{},[2152,2172],{"type":27,"tag":196,"props":2153,"children":2154},{},[2155],{"type":27,"tag":200,"props":2156,"children":2157},{},[2158,2163,2167],{"type":27,"tag":204,"props":2159,"children":2160},{},[2161],{"type":33,"value":2162},"维度",{"type":27,"tag":204,"props":2164,"children":2165},{},[2166],{"type":33,"value":1157},{"type":27,"tag":204,"props":2168,"children":2169},{},[2170],{"type":33,"value":2171},"Vite",{"type":27,"tag":220,"props":2173,"children":2174},{},[2175,2193,2210,2228,2246],{"type":27,"tag":200,"props":2176,"children":2177},{},[2178,2183,2188],{"type":27,"tag":227,"props":2179,"children":2180},{},[2181],{"type":33,"value":2182},"开发速度",{"type":27,"tag":227,"props":2184,"children":2185},{},[2186],{"type":33,"value":2187},"极快（Rust 编译）",{"type":27,"tag":227,"props":2189,"children":2190},{},[2191],{"type":33,"value":2192},"极快（ESM 直连）",{"type":27,"tag":200,"props":2194,"children":2195},{},[2196,2200,2205],{"type":27,"tag":227,"props":2197,"children":2198},{},[2199],{"type":33,"value":1513},{"type":27,"tag":227,"props":2201,"children":2202},{},[2203],{"type":33,"value":2204},"快（全量编译优化）",{"type":27,"tag":227,"props":2206,"children":2207},{},[2208],{"type":33,"value":2209},"快（Rollup）",{"type":27,"tag":200,"props":2211,"children":2212},{},[2213,2218,2223],{"type":27,"tag":227,"props":2214,"children":2215},{},[2216],{"type":33,"value":2217},"Webpack 兼容",{"type":27,"tag":227,"props":2219,"children":2220},{},[2221],{"type":33,"value":2222},"高",{"type":27,"tag":227,"props":2224,"children":2225},{},[2226],{"type":33,"value":2227},"低",{"type":27,"tag":200,"props":2229,"children":2230},{},[2231,2236,2241],{"type":27,"tag":227,"props":2232,"children":2233},{},[2234],{"type":33,"value":2235},"插件生态",{"type":27,"tag":227,"props":2237,"children":2238},{},[2239],{"type":33,"value":2240},"Webpack 生态",{"type":27,"tag":227,"props":2242,"children":2243},{},[2244],{"type":33,"value":2245},"Rollup/Vite 生态",{"type":27,"tag":200,"props":2247,"children":2248},{},[2249,2254,2259],{"type":27,"tag":227,"props":2250,"children":2251},{},[2252],{"type":33,"value":2253},"适用项目",{"type":27,"tag":227,"props":2255,"children":2256},{},[2257],{"type":33,"value":2258},"Webpack 迁移、大型 monorepo",{"type":27,"tag":227,"props":2260,"children":2261},{},[2262],{"type":33,"value":2263},"新项目、中小型",{"type":27,"tag":35,"props":2265,"children":2266},{},[2267],{"type":33,"value":2268},"选择建议：",{"type":27,"tag":41,"props":2270,"children":2271},{},[2272,2277,2282],{"type":27,"tag":45,"props":2273,"children":2274},{},[2275],{"type":33,"value":2276},"新项目：优先 Vite",{"type":27,"tag":45,"props":2278,"children":2279},{},[2280],{"type":33,"value":2281},"Webpack 遗留项目：Rspack",{"type":27,"tag":45,"props":2283,"children":2284},{},[2285],{"type":33,"value":2286},"大型 monorepo + Webpack 依赖：Rspack",{"type":27,"tag":61,"props":2288,"children":2289},{},[],{"type":27,"tag":28,"props":2291,"children":2293},{"id":2292},"_10-上线检查清单",[2294],{"type":33,"value":2295},"10. 上线检查清单",{"type":27,"tag":41,"props":2297,"children":2299},{"className":2298},[766],[2300,2309,2318,2327,2336,2345],{"type":27,"tag":45,"props":2301,"children":2303},{"className":2302},[771],[2304,2307],{"type":27,"tag":774,"props":2305,"children":2306},{"disabled":776,"type":777},[],{"type":33,"value":2308}," 本地开发环境已验证（HMR/热更新正常）",{"type":27,"tag":45,"props":2310,"children":2312},{"className":2311},[771],[2313,2316],{"type":27,"tag":774,"props":2314,"children":2315},{"disabled":776,"type":777},[],{"type":33,"value":2317}," CI 构建已切换并观测 3 天以上",{"type":27,"tag":45,"props":2319,"children":2321},{"className":2320},[771],[2322,2325],{"type":27,"tag":774,"props":2323,"children":2324},{"disabled":776,"type":777},[],{"type":33,"value":2326}," 产物体积对比无异常（baseline ± 5%）",{"type":27,"tag":45,"props":2328,"children":2330},{"className":2329},[771],[2331,2334],{"type":27,"tag":774,"props":2332,"children":2333},{"disabled":776,"type":777},[],{"type":33,"value":2335}," 关键页面功能回归测试通过",{"type":27,"tag":45,"props":2337,"children":2339},{"className":2338},[771],[2340,2343],{"type":27,"tag":774,"props":2341,"children":2342},{"disabled":776,"type":777},[],{"type":33,"value":2344}," 有构建耗时与缓存命中率监控",{"type":27,"tag":45,"props":2346,"children":2348},{"className":2347},[771],[2349,2352],{"type":27,"tag":774,"props":2350,"children":2351},{"disabled":776,"type":777},[],{"type":33,"value":2353}," 有回滚方案（保留 Webpack 配置）",{"type":27,"tag":61,"props":2355,"children":2356},{},[],{"type":27,"tag":28,"props":2358,"children":2360},{"id":2359},"总结",[2361],{"type":33,"value":2359},{"type":27,"tag":35,"props":2363,"children":2364},{},[2365],{"type":33,"value":2366},"Rspack 的核心价值是：",{"type":27,"tag":41,"props":2368,"children":2369},{},[2370,2375,2380],{"type":27,"tag":45,"props":2371,"children":2372},{},[2373],{"type":33,"value":2374},"在 Webpack 生态下获得接近 Vite 的速度",{"type":27,"tag":45,"props":2376,"children":2377},{},[2378],{"type":33,"value":2379},"对大型项目构建成本与开发体验的显著改善",{"type":27,"tag":45,"props":2381,"children":2382},{},[2383],{"type":33,"value":2384},"生产级稳定性（字节跳动内部大规模验证）",{"title":7,"searchDepth":487,"depth":487,"links":2386},[2387,2388,2392,2397,2398,2403,2408,2409,2410,2415,2416,2417],{"id":1168,"depth":490,"text":1153},{"id":1251,"depth":490,"text":1254,"children":2389},[2390,2391],{"id":1262,"depth":487,"text":1265},{"id":1301,"depth":487,"text":1304},{"id":1328,"depth":490,"text":1331,"children":2393},[2394,2395,2396],{"id":1334,"depth":487,"text":1337},{"id":1358,"depth":487,"text":1361},{"id":1382,"depth":487,"text":1385},{"id":1414,"depth":490,"text":1417},{"id":1591,"depth":490,"text":1594,"children":2399},[2400,2401,2402],{"id":1597,"depth":487,"text":1600},{"id":1692,"depth":487,"text":1695},{"id":1761,"depth":487,"text":1764},{"id":1788,"depth":490,"text":1791,"children":2404},[2405,2406,2407],{"id":1794,"depth":487,"text":1797},{"id":1818,"depth":487,"text":1821},{"id":1840,"depth":487,"text":1843},{"id":1905,"depth":490,"text":1908},{"id":1976,"depth":490,"text":1979},{"id":2059,"depth":490,"text":2062,"children":2411},[2412,2413,2414],{"id":2065,"depth":487,"text":2068},{"id":2094,"depth":487,"text":2097},{"id":2118,"depth":487,"text":2121},{"id":2145,"depth":490,"text":2148},{"id":2292,"depth":490,"text":2295},{"id":2359,"depth":490,"text":2359},"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":2422,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":2423,"_type":499,"_id":500,"_source":501,"_file":502,"_stem":503,"_extension":504},[13,14,15,16,17],{"type":24,"children":2424,"toc":2786},[2425,2429,2433,2444,2448,2451,2455,2459,2478,2482,2485,2489,2539,2543,2546,2550,2619,2623,2626,2630,2634,2653,2657,2660,2664,2668,2687,2691,2694,2698,2713,2717,2720,2724,2747,2750,2754,2758,2762],{"type":27,"tag":28,"props":2426,"children":2427},{"id":30},[2428],{"type":33,"value":8},{"type":27,"tag":35,"props":2430,"children":2431},{},[2432],{"type":33,"value":39},{"type":27,"tag":41,"props":2434,"children":2435},{},[2436,2440],{"type":27,"tag":45,"props":2437,"children":2438},{},[2439],{"type":33,"value":49},{"type":27,"tag":45,"props":2441,"children":2442},{},[2443],{"type":33,"value":54},{"type":27,"tag":35,"props":2445,"children":2446},{},[2447],{"type":33,"value":59},{"type":27,"tag":61,"props":2449,"children":2450},{},[],{"type":27,"tag":28,"props":2452,"children":2453},{"id":66},[2454],{"type":33,"value":69},{"type":27,"tag":35,"props":2456,"children":2457},{},[2458],{"type":33,"value":74},{"type":27,"tag":41,"props":2460,"children":2461},{},[2462,2466,2470,2474],{"type":27,"tag":45,"props":2463,"children":2464},{},[2465],{"type":33,"value":82},{"type":27,"tag":45,"props":2467,"children":2468},{},[2469],{"type":33,"value":87},{"type":27,"tag":45,"props":2471,"children":2472},{},[2473],{"type":33,"value":92},{"type":27,"tag":45,"props":2475,"children":2476},{},[2477],{"type":33,"value":97},{"type":27,"tag":35,"props":2479,"children":2480},{},[2481],{"type":33,"value":102},{"type":27,"tag":61,"props":2483,"children":2484},{},[],{"type":27,"tag":28,"props":2486,"children":2487},{"id":108},[2488],{"type":33,"value":111},{"type":27,"tag":113,"props":2490,"children":2491},{},[2492,2502,2518,2522,2531,2535],{"type":27,"tag":45,"props":2493,"children":2494},{},[2495,2496,2501],{"type":33,"value":120},{"type":27,"tag":122,"props":2497,"children":2499},{"className":2498},[],[2500],{"type":33,"value":127},{"type":33,"value":129},{"type":27,"tag":45,"props":2503,"children":2504},{},[2505,2506,2511,2512,2517],{"type":33,"value":134},{"type":27,"tag":122,"props":2507,"children":2509},{"className":2508},[],[2510],{"type":33,"value":140},{"type":33,"value":142},{"type":27,"tag":122,"props":2513,"children":2515},{"className":2514},[],[2516],{"type":33,"value":148},{"type":33,"value":150},{"type":27,"tag":45,"props":2519,"children":2520},{},[2521],{"type":33,"value":155},{"type":27,"tag":45,"props":2523,"children":2524},{},[2525,2530],{"type":27,"tag":122,"props":2526,"children":2528},{"className":2527},[],[2529],{"type":33,"value":164},{"type":33,"value":166},{"type":27,"tag":45,"props":2532,"children":2533},{},[2534],{"type":33,"value":171},{"type":27,"tag":45,"props":2536,"children":2537},{},[2538],{"type":33,"value":176},{"type":27,"tag":35,"props":2540,"children":2541},{},[2542],{"type":33,"value":181},{"type":27,"tag":61,"props":2544,"children":2545},{},[],{"type":27,"tag":28,"props":2547,"children":2548},{"id":187},[2549],{"type":33,"value":190},{"type":27,"tag":192,"props":2551,"children":2552},{},[2553,2571],{"type":27,"tag":196,"props":2554,"children":2555},{},[2556],{"type":27,"tag":200,"props":2557,"children":2558},{},[2559,2563,2567],{"type":27,"tag":204,"props":2560,"children":2561},{},[2562],{"type":33,"value":208},{"type":27,"tag":204,"props":2564,"children":2565},{},[2566],{"type":33,"value":213},{"type":27,"tag":204,"props":2568,"children":2569},{},[2570],{"type":33,"value":218},{"type":27,"tag":220,"props":2572,"children":2573},{},[2574,2589,2604],{"type":27,"tag":200,"props":2575,"children":2576},{},[2577,2581,2585],{"type":27,"tag":227,"props":2578,"children":2579},{},[2580],{"type":33,"value":231},{"type":27,"tag":227,"props":2582,"children":2583},{},[2584],{"type":33,"value":236},{"type":27,"tag":227,"props":2586,"children":2587},{},[2588],{"type":33,"value":241},{"type":27,"tag":200,"props":2590,"children":2591},{},[2592,2596,2600],{"type":27,"tag":227,"props":2593,"children":2594},{},[2595],{"type":33,"value":249},{"type":27,"tag":227,"props":2597,"children":2598},{},[2599],{"type":33,"value":254},{"type":27,"tag":227,"props":2601,"children":2602},{},[2603],{"type":33,"value":259},{"type":27,"tag":200,"props":2605,"children":2606},{},[2607,2611,2615],{"type":27,"tag":227,"props":2608,"children":2609},{},[2610],{"type":33,"value":267},{"type":27,"tag":227,"props":2612,"children":2613},{},[2614],{"type":33,"value":272},{"type":27,"tag":227,"props":2616,"children":2617},{},[2618],{"type":33,"value":277},{"type":27,"tag":35,"props":2620,"children":2621},{},[2622],{"type":33,"value":282},{"type":27,"tag":61,"props":2624,"children":2625},{},[],{"type":27,"tag":28,"props":2627,"children":2628},{"id":288},[2629],{"type":33,"value":291},{"type":27,"tag":35,"props":2631,"children":2632},{},[2633],{"type":33,"value":296},{"type":27,"tag":41,"props":2635,"children":2636},{},[2637,2641,2645,2649],{"type":27,"tag":45,"props":2638,"children":2639},{},[2640],{"type":33,"value":304},{"type":27,"tag":45,"props":2642,"children":2643},{},[2644],{"type":33,"value":309},{"type":27,"tag":45,"props":2646,"children":2647},{},[2648],{"type":33,"value":314},{"type":27,"tag":45,"props":2650,"children":2651},{},[2652],{"type":33,"value":319},{"type":27,"tag":35,"props":2654,"children":2655},{},[2656],{"type":33,"value":324},{"type":27,"tag":61,"props":2658,"children":2659},{},[],{"type":27,"tag":28,"props":2661,"children":2662},{"id":330},[2663],{"type":33,"value":333},{"type":27,"tag":35,"props":2665,"children":2666},{},[2667],{"type":33,"value":338},{"type":27,"tag":41,"props":2669,"children":2670},{},[2671,2675,2679,2683],{"type":27,"tag":45,"props":2672,"children":2673},{},[2674],{"type":33,"value":346},{"type":27,"tag":45,"props":2676,"children":2677},{},[2678],{"type":33,"value":351},{"type":27,"tag":45,"props":2680,"children":2681},{},[2682],{"type":33,"value":356},{"type":27,"tag":45,"props":2684,"children":2685},{},[2686],{"type":33,"value":361},{"type":27,"tag":35,"props":2688,"children":2689},{},[2690],{"type":33,"value":366},{"type":27,"tag":61,"props":2692,"children":2693},{},[],{"type":27,"tag":28,"props":2695,"children":2696},{"id":372},[2697],{"type":33,"value":375},{"type":27,"tag":41,"props":2699,"children":2700},{},[2701,2705,2709],{"type":27,"tag":45,"props":2702,"children":2703},{},[2704],{"type":33,"value":383},{"type":27,"tag":45,"props":2706,"children":2707},{},[2708],{"type":33,"value":388},{"type":27,"tag":45,"props":2710,"children":2711},{},[2712],{"type":33,"value":393},{"type":27,"tag":35,"props":2714,"children":2715},{},[2716],{"type":33,"value":398},{"type":27,"tag":61,"props":2718,"children":2719},{},[],{"type":27,"tag":28,"props":2721,"children":2722},{"id":404},[2723],{"type":33,"value":407},{"type":27,"tag":41,"props":2725,"children":2726},{},[2727,2731,2735,2739,2743],{"type":27,"tag":45,"props":2728,"children":2729},{},[2730],{"type":33,"value":415},{"type":27,"tag":45,"props":2732,"children":2733},{},[2734],{"type":33,"value":420},{"type":27,"tag":45,"props":2736,"children":2737},{},[2738],{"type":33,"value":425},{"type":27,"tag":45,"props":2740,"children":2741},{},[2742],{"type":33,"value":430},{"type":27,"tag":45,"props":2744,"children":2745},{},[2746],{"type":33,"value":435},{"type":27,"tag":61,"props":2748,"children":2749},{},[],{"type":27,"tag":28,"props":2751,"children":2752},{"id":441},[2753],{"type":33,"value":444},{"type":27,"tag":35,"props":2755,"children":2756},{},[2757],{"type":33,"value":449},{"type":27,"tag":35,"props":2759,"children":2760},{},[2761],{"type":33,"value":454},{"type":27,"tag":41,"props":2763,"children":2764},{},[2765,2772,2779],{"type":27,"tag":45,"props":2766,"children":2767},{},[2768],{"type":27,"tag":462,"props":2769,"children":2770},{"href":464},[2771],{"type":33,"value":467},{"type":27,"tag":45,"props":2773,"children":2774},{},[2775],{"type":27,"tag":462,"props":2776,"children":2777},{"href":473},[2778],{"type":33,"value":476},{"type":27,"tag":45,"props":2780,"children":2781},{},[2782],{"type":27,"tag":462,"props":2783,"children":2784},{"href":482},[2785],{"type":33,"value":485},{"title":7,"searchDepth":487,"depth":487,"links":2787},[2788,2789,2790,2791,2792,2793,2794,2795,2796],{"id":30,"depth":490,"text":8},{"id":66,"depth":490,"text":69},{"id":108,"depth":490,"text":111},{"id":187,"depth":490,"text":190},{"id":288,"depth":490,"text":291},{"id":330,"depth":490,"text":333},{"id":372,"depth":490,"text":375},{"id":404,"depth":490,"text":407},{"id":441,"depth":490,"text":444},1775975222821]