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