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