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