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