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