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