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