[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild":1825,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild":1851},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":15,"pinned":16,"draft":16,"body":17,"seo":1821,"stem":1822,"id":1823,"extension":1824},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild","编译与打包优化","构建阶段的代码分割、Tree Shaking 与 SFC 编译优化。运行时见 runtime。","技能小册",[12,13,14],"vue","performance","build","2021-08-02",false,{"type":18,"value":19,"toc":1813},"minimark",[20,23,33,41,46,49,59,65,338,344,357,361,425,430,452,456,459,463,484,521,528,532,562,566,577,581,588,592,599,655,658,745,751,757,761,768,803,810,889,899,903,906,940,943,1034,1041,1045,1055,1059,1062,1066,1079,1089,1183,1187,1197,1265,1275,1279,1290,1295,1460,1471,1475,1478,1483,1662,1670,1674,1749,1752,1756,1759,1809],[21,22,8],"h1",{"id":8},[24,25,26,27,32],"p",{},"构建阶段的代码分割、Tree Shaking 与 SFC 编译优化。运行时见 ",[28,29,31],"a",{"href":30},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fruntime","runtime","。",[24,34,35,36,40],{},"在前端工程化中，性能优化不仅局限于运行时，更应前置到",[37,38,39],"strong",{},"编译和打包阶段","。通过合理的构建配置、代码分割、Tree Shaking 及 Vue 特有的编译优化，可以显著减少产物体积、提升加载速度及运行时效率，本节将围绕这些核心点展开。",[42,43,45],"h3",{"id":44},"一异步组件与懒加载","一、异步组件与懒加载",[24,47,48],{},"懒加载可将应用拆分成更小的代码块，仅在需要时才加载，有效减少首屏资源体积。",[50,51,53,54,58],"h4",{"id":52},"_1-defineasynccomponent-的完整配置","1. ",[55,56,57],"code",{},"defineAsyncComponent"," 的完整配置",[24,60,61,62,64],{},"Vue 3 提供了 ",[55,63,57],{}," 用于定义异步组件，支持丰富的配置选项（加载成功\u002F加载中\u002F加载失败的状态展示，以及超时控制）。",[66,67,72],"pre",{"className":68,"code":69,"language":70,"meta":71,"style":71},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","import { defineAsyncComponent } from \"vue\";\n\nconst AsyncComponent = defineAsyncComponent({\n  \u002F\u002F 实际加载组件函数（必须返回 Promise）\n  loader: () => import(\".\u002FHeavyComponent.vue\"),\n\n  \u002F\u002F 加载过程中展示的组件（可选）\n  loadingComponent: LoadingComponent,\n\n  \u002F\u002F 加载失败时展示的组件（可选）\n  errorComponent: ErrorComponent,\n\n  \u002F\u002F 展示 loadingComponent 之前的延迟（默认 200ms，防止闪烁）\n  delay: 200,\n\n  \u002F\u002F 超时时间（毫秒），超时后显示 errorComponent\n  timeout: 3000,\n\n  \u002F\u002F 是否支持 Suspense（默认 true）\n  suspensible: false,\n\n  \u002F\u002F 服务端渲染时启用\n  serverPrefetch: true,\n});\n","js","",[55,73,74,110,117,141,148,181,186,192,206,211,217,230,235,241,255,260,266,279,284,290,304,309,315,328],{"__ignoreMap":71},[75,76,79,83,87,91,94,97,101,104,107],"span",{"class":77,"line":78},"line",1,[75,80,82],{"class":81},"sVHd0","import",[75,84,86],{"class":85},"sP7_E"," {",[75,88,90],{"class":89},"su5hD"," defineAsyncComponent",[75,92,93],{"class":85}," }",[75,95,96],{"class":81}," from",[75,98,100],{"class":99},"sjJ54"," \"",[75,102,12],{"class":103},"s_sjI",[75,105,106],{"class":99},"\"",[75,108,109],{"class":85},";\n",[75,111,113],{"class":77,"line":112},2,[75,114,116],{"emptyLinePlaceholder":115},true,"\n",[75,118,120,124,128,132,135,138],{"class":77,"line":119},3,[75,121,123],{"class":122},"sbsja","const",[75,125,127],{"class":126},"s_hVV"," AsyncComponent",[75,129,131],{"class":130},"smGrS"," =",[75,133,90],{"class":134},"sGLFI",[75,136,137],{"class":89},"(",[75,139,140],{"class":85},"{\n",[75,142,144],{"class":77,"line":143},4,[75,145,147],{"class":146},"sutJx","  \u002F\u002F 实际加载组件函数（必须返回 Promise）\n",[75,149,151,154,157,160,163,166,168,170,173,175,178],{"class":77,"line":150},5,[75,152,153],{"class":134},"  loader",[75,155,156],{"class":85},":",[75,158,159],{"class":85}," ()",[75,161,162],{"class":122}," =>",[75,164,165],{"class":130}," import",[75,167,137],{"class":89},[75,169,106],{"class":99},[75,171,172],{"class":103},".\u002FHeavyComponent.vue",[75,174,106],{"class":99},[75,176,177],{"class":89},")",[75,179,180],{"class":85},",\n",[75,182,184],{"class":77,"line":183},6,[75,185,116],{"emptyLinePlaceholder":115},[75,187,189],{"class":77,"line":188},7,[75,190,191],{"class":146},"  \u002F\u002F 加载过程中展示的组件（可选）\n",[75,193,195,199,201,204],{"class":77,"line":194},8,[75,196,198],{"class":197},"skxfh","  loadingComponent",[75,200,156],{"class":85},[75,202,203],{"class":89}," LoadingComponent",[75,205,180],{"class":85},[75,207,209],{"class":77,"line":208},9,[75,210,116],{"emptyLinePlaceholder":115},[75,212,214],{"class":77,"line":213},10,[75,215,216],{"class":146},"  \u002F\u002F 加载失败时展示的组件（可选）\n",[75,218,220,223,225,228],{"class":77,"line":219},11,[75,221,222],{"class":197},"  errorComponent",[75,224,156],{"class":85},[75,226,227],{"class":89}," ErrorComponent",[75,229,180],{"class":85},[75,231,233],{"class":77,"line":232},12,[75,234,116],{"emptyLinePlaceholder":115},[75,236,238],{"class":77,"line":237},13,[75,239,240],{"class":146},"  \u002F\u002F 展示 loadingComponent 之前的延迟（默认 200ms，防止闪烁）\n",[75,242,244,247,249,253],{"class":77,"line":243},14,[75,245,246],{"class":197},"  delay",[75,248,156],{"class":85},[75,250,252],{"class":251},"srdBf"," 200",[75,254,180],{"class":85},[75,256,258],{"class":77,"line":257},15,[75,259,116],{"emptyLinePlaceholder":115},[75,261,263],{"class":77,"line":262},16,[75,264,265],{"class":146},"  \u002F\u002F 超时时间（毫秒），超时后显示 errorComponent\n",[75,267,269,272,274,277],{"class":77,"line":268},17,[75,270,271],{"class":197},"  timeout",[75,273,156],{"class":85},[75,275,276],{"class":251}," 3000",[75,278,180],{"class":85},[75,280,282],{"class":77,"line":281},18,[75,283,116],{"emptyLinePlaceholder":115},[75,285,287],{"class":77,"line":286},19,[75,288,289],{"class":146},"  \u002F\u002F 是否支持 Suspense（默认 true）\n",[75,291,293,296,298,302],{"class":77,"line":292},20,[75,294,295],{"class":197},"  suspensible",[75,297,156],{"class":85},[75,299,301],{"class":300},"syTEX"," false",[75,303,180],{"class":85},[75,305,307],{"class":77,"line":306},21,[75,308,116],{"emptyLinePlaceholder":115},[75,310,312],{"class":77,"line":311},22,[75,313,314],{"class":146},"  \u002F\u002F 服务端渲染时启用\n",[75,316,318,321,323,326],{"class":77,"line":317},23,[75,319,320],{"class":197},"  serverPrefetch",[75,322,156],{"class":85},[75,324,325],{"class":300}," true",[75,327,180],{"class":85},[75,329,331,334,336],{"class":77,"line":330},24,[75,332,333],{"class":85},"}",[75,335,177],{"class":89},[75,337,109],{"class":85},[24,339,340,343],{},[37,341,342],{},"使用场景","：",[345,346,347,351,354],"ul",{},[348,349,350],"li",{},"首屏不可见的复杂图表组件、表格组件。",[348,352,353],{},"根据用户交互才触发的弹窗、表单等。",[348,355,356],{},"需要 fallback 状态（如加载中或错误重试）的组件。",[50,358,360],{"id":359},"_2-路由级懒加载-vs-组件级懒加载的取舍","2. 路由级懒加载 vs 组件级懒加载的取舍",[362,363,364,383],"table",{},[365,366,367],"thead",{},[368,369,370,374,377,380],"tr",{},[371,372,373],"th",{},"层级",[371,375,376],{},"方式",[371,378,379],{},"优点",[371,381,382],{},"缺点",[384,385,386,406],"tbody",{},[368,387,388,394,400,403],{},[389,390,391],"td",{},[37,392,393],{},"路由级",[389,395,396,397],{},"在路由配置中使用 ",[55,398,399],{},"() => import('@\u002Fviews\u002FHome.vue')",[389,401,402],{},"粒度大，简单高效，首屏只加载当前路由组件",[389,404,405],{},"组件较小时可能产生过多小 chunk，增加请求数",[368,407,408,413,419,422],{},[389,409,410],{},[37,411,412],{},"组件级",[389,414,415,416,418],{},"在组件内部使用 ",[55,417,57],{}," 动态引入子组件",[389,420,421],{},"更精细的控制（如弹窗、折叠面板等按需加载），减少初始加载",[389,423,424],{},"需手动管理，引入一定复杂度",[24,426,427,343],{},[37,428,429],{},"取舍原则",[345,431,432,438,445],{},[348,433,434,437],{},[37,435,436],{},"默认使用路由级懒加载","，将每个页面路由打包为独立 chunk。",[348,439,440,441,444],{},"对于页面内",[37,442,443],{},"用户可能要过一段时间才看到的区域","（如底部评论区、模态框、标签页中的隐藏面板），使用组件级懒加载。",[348,446,447,448,451],{},"对于",[37,449,450],{},"稳定高频的核心组件","（如导航栏、侧边栏）则不应该懒加载，应同步加载。",[42,453,455],{"id":454},"二tree-shaking","二、Tree Shaking",[24,457,458],{},"Tree Shaking 是指构建工具（Webpack、Vite）通过静态分析，剔除未被使用的代码。",[50,460,462],{"id":461},"_1-vue-3-的按需引入设计","1. Vue 3 的按需引入设计",[24,464,465,466,469,470,469,473,469,476,479,480,483],{},"Vue 3 的核心 API（如 ",[55,467,468],{},"ref","、",[55,471,472],{},"reactive",[55,474,475],{},"computed",[55,477,478],{},"watch"," 等）都采用 ",[37,481,482],{},"ESM 命名导出","，且无副作用（side effect free）。这意味着构建工具可以安全地“摇掉”未使用的 API。",[66,485,487],{"className":68,"code":486,"language":70,"meta":71,"style":71},"\u002F\u002F 只引入 ref 和 computed，未使用的 reactive 不会被打包\nimport { ref, computed } from \"vue\";\n",[55,488,489,494],{"__ignoreMap":71},[75,490,491],{"class":77,"line":78},[75,492,493],{"class":146},"\u002F\u002F 只引入 ref 和 computed，未使用的 reactive 不会被打包\n",[75,495,496,498,500,503,506,509,511,513,515,517,519],{"class":77,"line":112},[75,497,82],{"class":81},[75,499,86],{"class":85},[75,501,502],{"class":89}," ref",[75,504,505],{"class":85},",",[75,507,508],{"class":89}," computed",[75,510,93],{"class":85},[75,512,96],{"class":81},[75,514,100],{"class":99},[75,516,12],{"class":103},[75,518,106],{"class":99},[75,520,109],{"class":85},[24,522,523,524,527],{},"对比 Vue 2 全局 ",[55,525,526],{},"Vue"," 对象，Tree Shaking 非常困难。Vue 3 的做法大幅减少了打包体积。",[50,529,531],{"id":530},"_2-确保第三方库支持-tree-shaking","2. 确保第三方库支持 Tree Shaking",[345,533,534,545,556],{},[348,535,536,537,540,541,544],{},"使用 ES 模块版本（如 ",[55,538,539],{},"lodash-es"," 替代 ",[55,542,543],{},"lodash","）。",[348,546,547,548,551,552,555],{},"检查 ",[55,549,550],{},"package.json"," 中是否包含 ",[55,553,554],{},"sideEffects: false"," 或明确声明。",[348,557,558,559,544],{},"配置构建工具保留模块结构（如 Vite 默认支持，Webpack 需 ",[55,560,561],{},"mode: 'production'",[50,563,565],{"id":564},"_3-sfc-中的-tree-shaking","3. SFC 中的 Tree Shaking",[24,567,568,569,572,573,576],{},"Vue 单文件组件（SFC）中的 ",[55,570,571],{},"\u003Ctemplate>"," 和 ",[55,574,575],{},"\u003Cstyle>"," 也会参与 Tree Shaking：如果整个组件未被引用，则其所有依赖均不会打包。",[42,578,580],{"id":579},"三vue-单文件组件的编译优化","三、Vue 单文件组件的编译优化",[24,582,583,584,587],{},"Vue 3 的编译器（",[55,585,586],{},"@vue\u002Fcompiler-dom","）在编译 SFC 时会执行多项优化，减少运行时代码量和 Diff 压力。",[50,589,591],{"id":590},"_1-静态标记patchflag","1. 静态标记（PatchFlag）",[24,593,594,595,598],{},"在编译模板时，编译器会为动态节点添加一个 ",[37,596,597],{},"PatchFlag","（数字标记），指示该节点在更新时可能发生哪些变化（文本、属性、类、样式等）。",[66,600,604],{"className":601,"code":602,"language":603,"meta":71,"style":71},"language-html shiki shiki-themes material-theme-lighter github-light github-dark","\u003Cdiv :class=\"activeClass\" :id=\"dynamicId\">{{ message }}\u003C\u002Fdiv>\n","html",[55,605,606],{"__ignoreMap":71},[75,607,608,611,615,619,622,624,627,629,632,634,636,639,641,644,647,650,652],{"class":77,"line":78},[75,609,610],{"class":85},"\u003C",[75,612,614],{"class":613},"sQzsp","div",[75,616,618],{"class":617},"s9AJx"," :class",[75,620,621],{"class":85},"=",[75,623,106],{"class":99},[75,625,626],{"class":103},"activeClass",[75,628,106],{"class":99},[75,630,631],{"class":617}," :id",[75,633,621],{"class":85},[75,635,106],{"class":99},[75,637,638],{"class":103},"dynamicId",[75,640,106],{"class":99},[75,642,643],{"class":85},">",[75,645,646],{"class":89},"{{ message }}",[75,648,649],{"class":85},"\u003C\u002F",[75,651,614],{"class":613},[75,653,654],{"class":85},">\n",[24,656,657],{},"编译后大致生成：",[66,659,661],{"className":68,"code":660,"language":70,"meta":71,"style":71},"_createVNode(\n  \"div\",\n  {\n    class: _normalizeClass(activeClass),\n    id: dynamicId,\n  },\n  _toDisplayString(message),\n  3 \u002F* TEXT + CLASS + PROPS *\u002F,\n);\n",[55,662,663,671,682,687,702,714,719,729,739],{"__ignoreMap":71},[75,664,665,668],{"class":77,"line":78},[75,666,667],{"class":134},"_createVNode",[75,669,670],{"class":89},"(\n",[75,672,673,676,678,680],{"class":77,"line":112},[75,674,675],{"class":99},"  \"",[75,677,614],{"class":103},[75,679,106],{"class":99},[75,681,180],{"class":85},[75,683,684],{"class":77,"line":119},[75,685,686],{"class":85},"  {\n",[75,688,689,692,694,697,700],{"class":77,"line":143},[75,690,691],{"class":197},"    class",[75,693,156],{"class":85},[75,695,696],{"class":134}," _normalizeClass",[75,698,699],{"class":89},"(activeClass)",[75,701,180],{"class":85},[75,703,704,707,709,712],{"class":77,"line":150},[75,705,706],{"class":197},"    id",[75,708,156],{"class":85},[75,710,711],{"class":89}," dynamicId",[75,713,180],{"class":85},[75,715,716],{"class":77,"line":183},[75,717,718],{"class":85},"  },\n",[75,720,721,724,727],{"class":77,"line":188},[75,722,723],{"class":134},"  _toDisplayString",[75,725,726],{"class":89},"(message)",[75,728,180],{"class":85},[75,730,731,734,737],{"class":77,"line":194},[75,732,733],{"class":251},"  3",[75,735,736],{"class":146}," \u002F* TEXT + CLASS + PROPS *\u002F",[75,738,180],{"class":85},[75,740,741,743],{"class":77,"line":208},[75,742,177],{"class":89},[75,744,109],{"class":85},[24,746,747,750],{},[37,748,749],{},"运行时 Diff","：渲染器根据 PatchFlag 仅检查对应类型的变更，而不需要深度对比整个 VNode 树。例如 TEXT 标记意味着只需对比文本内容，CLASS 标记只需对比 class 属性。",[24,752,753,756],{},[37,754,755],{},"优势","：跳过静态子树的 Diff（静态提升），大幅提升组件更新性能。",[50,758,760],{"id":759},"_2-事件缓存","2. 事件缓存",[24,762,763,764,767],{},"Vue 3 编译器会",[37,765,766],{},"自动缓存模板中的内联事件处理函数","，避免每次渲染都创建新函数。",[66,769,771],{"className":601,"code":770,"language":603,"meta":71,"style":71},"\u003Cbutton @click=\"count++\">Increment\u003C\u002Fbutton>\n",[55,772,773],{"__ignoreMap":71},[75,774,775,777,780,783,785,787,790,792,794,797,799,801],{"class":77,"line":78},[75,776,610],{"class":85},[75,778,779],{"class":613},"button",[75,781,782],{"class":617}," @click",[75,784,621],{"class":85},[75,786,106],{"class":99},[75,788,789],{"class":103},"count++",[75,791,106],{"class":99},[75,793,643],{"class":85},[75,795,796],{"class":89},"Increment",[75,798,649],{"class":85},[75,800,779],{"class":613},[75,802,654],{"class":85},[24,804,805,806,809],{},"传统做法：每次重新渲染都会生成一个新的箭头函数，导致子组件不必要的重新渲染（如果子组件通过 ",[55,807,808],{},"v-on"," 监听）。Vue 3 编译器将其转换为：",[66,811,813],{"className":68,"code":812,"language":70,"meta":71,"style":71},"_createVNode(\"button\", { onClick: _cache[0] || (_cache[0] = ($event) => count.value++) });\n",[55,814,815],{"__ignoreMap":71},[75,816,817,819,821,823,825,827,829,831,834,836,839,842,845,848,851,853,855,857,860,864,866,868,871,874,877,880,883,885,887],{"class":77,"line":78},[75,818,667],{"class":134},[75,820,137],{"class":89},[75,822,106],{"class":99},[75,824,779],{"class":103},[75,826,106],{"class":99},[75,828,505],{"class":85},[75,830,86],{"class":85},[75,832,833],{"class":197}," onClick",[75,835,156],{"class":85},[75,837,838],{"class":89}," _cache[",[75,840,841],{"class":251},"0",[75,843,844],{"class":89},"] ",[75,846,847],{"class":130},"||",[75,849,850],{"class":89}," (_cache[",[75,852,841],{"class":251},[75,854,844],{"class":89},[75,856,621],{"class":130},[75,858,859],{"class":85}," (",[75,861,863],{"class":862},"s99_P","$event",[75,865,177],{"class":85},[75,867,162],{"class":122},[75,869,870],{"class":89}," count",[75,872,873],{"class":85},".",[75,875,876],{"class":89},"value",[75,878,879],{"class":130},"++",[75,881,882],{"class":89},") ",[75,884,333],{"class":85},[75,886,177],{"class":89},[75,888,109],{"class":85},[24,890,891,892,895,896,32],{},"这样 ",[55,893,894],{},"onClick"," 始终保持同一个函数引用，有利于优化子组件的 ",[55,897,898],{},"shouldUpdate",[50,900,902],{"id":901},"_3-静态提升static-hoisting","3. 静态提升（Static Hoisting）",[24,904,905],{},"编译器会将纯静态的节点提升到渲染函数外部，避免每次渲染都重新创建。",[66,907,909],{"className":601,"code":908,"language":603,"meta":71,"style":71},"\u003Cdiv class=\"static\">I never change\u003C\u002Fdiv>\n",[55,910,911],{"__ignoreMap":71},[75,912,913,915,917,920,922,924,927,929,931,934,936,938],{"class":77,"line":78},[75,914,610],{"class":85},[75,916,614],{"class":613},[75,918,919],{"class":617}," class",[75,921,621],{"class":85},[75,923,106],{"class":99},[75,925,926],{"class":103},"static",[75,928,106],{"class":99},[75,930,643],{"class":85},[75,932,933],{"class":89},"I never change",[75,935,649],{"class":85},[75,937,614],{"class":613},[75,939,654],{"class":85},[24,941,942],{},"提升后：",[66,944,946],{"className":68,"code":945,"language":70,"meta":71,"style":71},"const _hoisted_1 = _createVNode(\"div\", { class: \"static\" }, \"I never change\", -1 \u002F* HOISTED *\u002F);\nfunction render() {\n  return _hoisted_1;\n}\n",[55,947,948,1006,1020,1029],{"__ignoreMap":71},[75,949,950,952,955,957,960,962,964,966,968,970,972,974,976,978,980,982,985,987,989,991,993,996,999,1002,1004],{"class":77,"line":78},[75,951,123],{"class":122},[75,953,954],{"class":126}," _hoisted_1",[75,956,131],{"class":130},[75,958,959],{"class":134}," _createVNode",[75,961,137],{"class":89},[75,963,106],{"class":99},[75,965,614],{"class":103},[75,967,106],{"class":99},[75,969,505],{"class":85},[75,971,86],{"class":85},[75,973,919],{"class":197},[75,975,156],{"class":85},[75,977,100],{"class":99},[75,979,926],{"class":103},[75,981,106],{"class":99},[75,983,984],{"class":85}," },",[75,986,100],{"class":99},[75,988,933],{"class":103},[75,990,106],{"class":99},[75,992,505],{"class":85},[75,994,995],{"class":130}," -",[75,997,998],{"class":251},"1",[75,1000,1001],{"class":146}," \u002F* HOISTED *\u002F",[75,1003,177],{"class":89},[75,1005,109],{"class":85},[75,1007,1008,1011,1014,1017],{"class":77,"line":112},[75,1009,1010],{"class":122},"function",[75,1012,1013],{"class":134}," render",[75,1015,1016],{"class":85},"()",[75,1018,1019],{"class":85}," {\n",[75,1021,1022,1025,1027],{"class":77,"line":119},[75,1023,1024],{"class":81},"  return",[75,1026,954],{"class":89},[75,1028,109],{"class":85},[75,1030,1031],{"class":77,"line":143},[75,1032,1033],{"class":85},"}\n",[24,1035,1036,1037,1040],{},"多个静态相邻元素会被合并为一个 VNode（",[55,1038,1039],{},"_createStaticVNode","），进一步减少内存占用。",[50,1042,1044],{"id":1043},"_4-块树优化block-tree","4. 块树优化（Block Tree）",[24,1046,1047,1048,469,1051,1054],{},"对于带有 ",[55,1049,1050],{},"v-if",[55,1052,1053],{},"v-for"," 的结构，Vue 3 引入 Block 概念，收集动态节点，使 Diff 直接定位到动态部分，无需遍历整个树。",[42,1056,1058],{"id":1057},"四构建工具配置优化","四、构建工具配置优化",[24,1060,1061],{},"以 Vite 为例（同样适用于 Webpack），通过合理配置可以进一步优化生产产物。",[50,1063,1065],{"id":1064},"_1-vite-预构建pre-bundling","1. Vite 预构建（Pre-bundling）",[24,1067,1068,1069,1072,1073,469,1075,1078],{},"Vite 在开发环境下使用 ",[55,1070,1071],{},"esbuild"," 预构建依赖（如 ",[55,1074,12],{},[55,1076,1077],{},"element-plus"," 等），将 CommonJS 或 UMD 转换成 ESM，并合并多个内部模块，减少浏览器请求数量。",[24,1080,1081,1084,1085,1088],{},[37,1082,1083],{},"生产环境","：Vite 使用 Rollup 进行打包，同样可以对依赖提前优化，通过 ",[55,1086,1087],{},"optimizeDeps"," 选项控制预构建行为。",[66,1090,1092],{"className":68,"code":1091,"language":70,"meta":71,"style":71},"\u002F\u002F vite.config.js\nexport default {\n  optimizeDeps: {\n    include: [\"lodash-es\", \"axios\"], \u002F\u002F 强制预构建\n    exclude: [\"your-local-lib\"], \u002F\u002F 排除无需预构建的库\n  },\n};\n",[55,1093,1094,1099,1109,1118,1151,1174,1178],{"__ignoreMap":71},[75,1095,1096],{"class":77,"line":78},[75,1097,1098],{"class":146},"\u002F\u002F vite.config.js\n",[75,1100,1101,1104,1107],{"class":77,"line":112},[75,1102,1103],{"class":81},"export",[75,1105,1106],{"class":81}," default",[75,1108,1019],{"class":85},[75,1110,1111,1114,1116],{"class":77,"line":119},[75,1112,1113],{"class":197},"  optimizeDeps",[75,1115,156],{"class":85},[75,1117,1019],{"class":85},[75,1119,1120,1123,1125,1128,1130,1132,1134,1136,1138,1141,1143,1146,1148],{"class":77,"line":143},[75,1121,1122],{"class":197},"    include",[75,1124,156],{"class":85},[75,1126,1127],{"class":89}," [",[75,1129,106],{"class":99},[75,1131,539],{"class":103},[75,1133,106],{"class":99},[75,1135,505],{"class":85},[75,1137,100],{"class":99},[75,1139,1140],{"class":103},"axios",[75,1142,106],{"class":99},[75,1144,1145],{"class":89},"]",[75,1147,505],{"class":85},[75,1149,1150],{"class":146}," \u002F\u002F 强制预构建\n",[75,1152,1153,1156,1158,1160,1162,1165,1167,1169,1171],{"class":77,"line":150},[75,1154,1155],{"class":197},"    exclude",[75,1157,156],{"class":85},[75,1159,1127],{"class":89},[75,1161,106],{"class":99},[75,1163,1164],{"class":103},"your-local-lib",[75,1166,106],{"class":99},[75,1168,1145],{"class":89},[75,1170,505],{"class":85},[75,1172,1173],{"class":146}," \u002F\u002F 排除无需预构建的库\n",[75,1175,1176],{"class":77,"line":183},[75,1177,718],{"class":85},[75,1179,1180],{"class":77,"line":188},[75,1181,1182],{"class":85},"};\n",[50,1184,1186],{"id":1185},"_2-代码压缩minify","2. 代码压缩（Minify）",[24,1188,1189,1190,1192,1193,1196],{},"生产环境必须开启代码压缩，Vite 默认使用 ",[55,1191,1071],{},"（极快）或 ",[55,1194,1195],{},"terser","（更兼容，但慢）。",[66,1198,1200],{"className":68,"code":1199,"language":70,"meta":71,"style":71},"build: {\n  minify: 'esbuild',   \u002F\u002F 或 'terser'\n  terserOptions: { compress: { drop_console: true } } \u002F\u002F 移除 console\n}\n",[55,1201,1202,1211,1231,1261],{"__ignoreMap":71},[75,1203,1204,1207,1209],{"class":77,"line":78},[75,1205,14],{"class":1206},"sbgvK",[75,1208,156],{"class":85},[75,1210,1019],{"class":85},[75,1212,1213,1216,1218,1221,1223,1226,1228],{"class":77,"line":112},[75,1214,1215],{"class":1206},"  minify",[75,1217,156],{"class":85},[75,1219,1220],{"class":99}," '",[75,1222,1071],{"class":103},[75,1224,1225],{"class":99},"'",[75,1227,505],{"class":85},[75,1229,1230],{"class":146},"   \u002F\u002F 或 'terser'\n",[75,1232,1233,1236,1238,1240,1243,1245,1247,1250,1252,1254,1256,1258],{"class":77,"line":119},[75,1234,1235],{"class":1206},"  terserOptions",[75,1237,156],{"class":85},[75,1239,86],{"class":85},[75,1241,1242],{"class":1206}," compress",[75,1244,156],{"class":85},[75,1246,86],{"class":85},[75,1248,1249],{"class":1206}," drop_console",[75,1251,156],{"class":85},[75,1253,325],{"class":300},[75,1255,93],{"class":85},[75,1257,93],{"class":85},[75,1259,1260],{"class":146}," \u002F\u002F 移除 console\n",[75,1262,1263],{"class":77,"line":143},[75,1264,1033],{"class":85},[24,1266,1267,1268,1270,1271,1274],{},"对于大型项目，建议使用 ",[55,1269,1071],{}," 压缩以获得更快速度，同时开启 ",[55,1272,1273],{},"target"," 降低语法转化级别。",[50,1276,1278],{"id":1277},"_3-cdn-外部化externals","3. CDN 外部化（Externals）",[24,1280,1281,1282,469,1284,469,1286,1289],{},"将一些大型库（如 ",[55,1283,12],{},[55,1285,1077],{},[55,1287,1288],{},"echarts","）通过 CDN 引入，不打包到 bundle 中，利用浏览器缓存和 CDN 加速。",[24,1291,1292,343],{},[37,1293,1294],{},"Vite 配置",[66,1296,1298],{"className":68,"code":1297,"language":70,"meta":71,"style":71},"import { defineConfig } from \"vite\";\nexport default defineConfig({\n  build: {\n    rollupOptions: {\n      external: [\"vue\", \"element-plus\"],\n      output: {\n        globals: {\n          vue: \"Vue\",\n          \"element-plus\": \"ElementPlus\",\n        },\n      },\n    },\n  },\n});\n",[55,1299,1300,1322,1334,1343,1352,1379,1388,1397,1412,1433,1438,1443,1448,1452],{"__ignoreMap":71},[75,1301,1302,1304,1306,1309,1311,1313,1315,1318,1320],{"class":77,"line":78},[75,1303,82],{"class":81},[75,1305,86],{"class":85},[75,1307,1308],{"class":89}," defineConfig",[75,1310,93],{"class":85},[75,1312,96],{"class":81},[75,1314,100],{"class":99},[75,1316,1317],{"class":103},"vite",[75,1319,106],{"class":99},[75,1321,109],{"class":85},[75,1323,1324,1326,1328,1330,1332],{"class":77,"line":112},[75,1325,1103],{"class":81},[75,1327,1106],{"class":81},[75,1329,1308],{"class":134},[75,1331,137],{"class":89},[75,1333,140],{"class":85},[75,1335,1336,1339,1341],{"class":77,"line":119},[75,1337,1338],{"class":197},"  build",[75,1340,156],{"class":85},[75,1342,1019],{"class":85},[75,1344,1345,1348,1350],{"class":77,"line":143},[75,1346,1347],{"class":197},"    rollupOptions",[75,1349,156],{"class":85},[75,1351,1019],{"class":85},[75,1353,1354,1357,1359,1361,1363,1365,1367,1369,1371,1373,1375,1377],{"class":77,"line":150},[75,1355,1356],{"class":197},"      external",[75,1358,156],{"class":85},[75,1360,1127],{"class":89},[75,1362,106],{"class":99},[75,1364,12],{"class":103},[75,1366,106],{"class":99},[75,1368,505],{"class":85},[75,1370,100],{"class":99},[75,1372,1077],{"class":103},[75,1374,106],{"class":99},[75,1376,1145],{"class":89},[75,1378,180],{"class":85},[75,1380,1381,1384,1386],{"class":77,"line":183},[75,1382,1383],{"class":197},"      output",[75,1385,156],{"class":85},[75,1387,1019],{"class":85},[75,1389,1390,1393,1395],{"class":77,"line":188},[75,1391,1392],{"class":197},"        globals",[75,1394,156],{"class":85},[75,1396,1019],{"class":85},[75,1398,1399,1402,1404,1406,1408,1410],{"class":77,"line":194},[75,1400,1401],{"class":197},"          vue",[75,1403,156],{"class":85},[75,1405,100],{"class":99},[75,1407,526],{"class":103},[75,1409,106],{"class":99},[75,1411,180],{"class":85},[75,1413,1414,1417,1420,1422,1424,1426,1429,1431],{"class":77,"line":208},[75,1415,1416],{"class":99},"          \"",[75,1418,1077],{"class":1419},"sZUrc",[75,1421,106],{"class":99},[75,1423,156],{"class":85},[75,1425,100],{"class":99},[75,1427,1428],{"class":103},"ElementPlus",[75,1430,106],{"class":99},[75,1432,180],{"class":85},[75,1434,1435],{"class":77,"line":213},[75,1436,1437],{"class":85},"        },\n",[75,1439,1440],{"class":77,"line":219},[75,1441,1442],{"class":85},"      },\n",[75,1444,1445],{"class":77,"line":232},[75,1446,1447],{"class":85},"    },\n",[75,1449,1450],{"class":77,"line":237},[75,1451,718],{"class":85},[75,1453,1454,1456,1458],{"class":77,"line":243},[75,1455,333],{"class":85},[75,1457,177],{"class":89},[75,1459,109],{"class":85},[24,1461,1462,1463,1466,1467,1470],{},"同时需要在 ",[55,1464,1465],{},"index.html"," 中通过 ",[55,1468,1469],{},"\u003Cscript>"," 标签引入这些库。注意：外部化会增加依赖管理复杂度，推荐仅对稳定、大体积、跨项目共享的库使用。",[50,1472,1474],{"id":1473},"_4-分块策略chunk-split","4. 分块策略（Chunk Split）",[24,1476,1477],{},"合理分割第三方库和业务代码，避免单个 chunk 过大。",[24,1479,1480,343],{},[37,1481,1482],{},"Rollup \u002F Vite 配置",[66,1484,1486],{"className":68,"code":1485,"language":70,"meta":71,"style":71},"build: {\n  rollupOptions: {\n    output: {\n      manualChunks(id) {\n        if (id.includes('node_modules')) {\n          if (id.includes('vue')) return 'vendor-vue';\n          if (id.includes('element-plus')) return 'vendor-element';\n          return 'vendor';\n        }\n      }\n    }\n  }\n}\n",[55,1487,1488,1496,1505,1514,1528,1556,1591,1624,1638,1643,1648,1653,1658],{"__ignoreMap":71},[75,1489,1490,1492,1494],{"class":77,"line":78},[75,1491,14],{"class":1206},[75,1493,156],{"class":85},[75,1495,1019],{"class":85},[75,1497,1498,1501,1503],{"class":77,"line":112},[75,1499,1500],{"class":1206},"  rollupOptions",[75,1502,156],{"class":85},[75,1504,1019],{"class":85},[75,1506,1507,1510,1512],{"class":77,"line":119},[75,1508,1509],{"class":1206},"    output",[75,1511,156],{"class":85},[75,1513,1019],{"class":85},[75,1515,1516,1519,1521,1524,1526],{"class":77,"line":143},[75,1517,1518],{"class":134},"      manualChunks",[75,1520,137],{"class":197},[75,1522,1523],{"class":89},"id",[75,1525,882],{"class":197},[75,1527,140],{"class":85},[75,1529,1530,1533,1535,1537,1539,1542,1544,1546,1549,1551,1554],{"class":77,"line":150},[75,1531,1532],{"class":81},"        if",[75,1534,859],{"class":197},[75,1536,1523],{"class":89},[75,1538,873],{"class":85},[75,1540,1541],{"class":134},"includes",[75,1543,137],{"class":197},[75,1545,1225],{"class":99},[75,1547,1548],{"class":103},"node_modules",[75,1550,1225],{"class":99},[75,1552,1553],{"class":197},")) ",[75,1555,140],{"class":85},[75,1557,1558,1561,1563,1565,1567,1569,1571,1573,1575,1577,1579,1582,1584,1587,1589],{"class":77,"line":183},[75,1559,1560],{"class":81},"          if",[75,1562,859],{"class":197},[75,1564,1523],{"class":89},[75,1566,873],{"class":85},[75,1568,1541],{"class":134},[75,1570,137],{"class":197},[75,1572,1225],{"class":99},[75,1574,12],{"class":103},[75,1576,1225],{"class":99},[75,1578,1553],{"class":197},[75,1580,1581],{"class":81},"return",[75,1583,1220],{"class":99},[75,1585,1586],{"class":103},"vendor-vue",[75,1588,1225],{"class":99},[75,1590,109],{"class":85},[75,1592,1593,1595,1597,1599,1601,1603,1605,1607,1609,1611,1613,1615,1617,1620,1622],{"class":77,"line":188},[75,1594,1560],{"class":81},[75,1596,859],{"class":197},[75,1598,1523],{"class":89},[75,1600,873],{"class":85},[75,1602,1541],{"class":134},[75,1604,137],{"class":197},[75,1606,1225],{"class":99},[75,1608,1077],{"class":103},[75,1610,1225],{"class":99},[75,1612,1553],{"class":197},[75,1614,1581],{"class":81},[75,1616,1220],{"class":99},[75,1618,1619],{"class":103},"vendor-element",[75,1621,1225],{"class":99},[75,1623,109],{"class":85},[75,1625,1626,1629,1631,1634,1636],{"class":77,"line":194},[75,1627,1628],{"class":81},"          return",[75,1630,1220],{"class":99},[75,1632,1633],{"class":103},"vendor",[75,1635,1225],{"class":99},[75,1637,109],{"class":85},[75,1639,1640],{"class":77,"line":208},[75,1641,1642],{"class":85},"        }\n",[75,1644,1645],{"class":77,"line":213},[75,1646,1647],{"class":85},"      }\n",[75,1649,1650],{"class":77,"line":219},[75,1651,1652],{"class":85},"    }\n",[75,1654,1655],{"class":77,"line":232},[75,1656,1657],{"class":85},"  }\n",[75,1659,1660],{"class":77,"line":237},[75,1661,1033],{"class":85},[24,1663,1664,1665,469,1667,1669],{},"通过手动分块，将 ",[55,1666,12],{},[55,1668,1077],{}," 等单独打包，用户缓存效果更好。",[42,1671,1673],{"id":1672},"五工程级优化总结","五、工程级优化总结",[362,1675,1676,1689],{},[365,1677,1678],{},[368,1679,1680,1683,1686],{},[371,1681,1682],{},"优化类别",[371,1684,1685],{},"关键技术点",[371,1687,1688],{},"收益",[384,1690,1691,1706,1723,1736],{},[368,1692,1693,1698,1703],{},[389,1694,1695],{},[37,1696,1697],{},"异步组件与懒加载",[389,1699,1700,1702],{},[55,1701,57],{}," 完整配置；路由级懒加载 + 组件级懒加载组合",[389,1704,1705],{},"减少首屏 JS 体积，提升加载速度",[368,1707,1708,1713,1720],{},[389,1709,1710],{},[37,1711,1712],{},"Tree Shaking",[389,1714,1715,1716,1719],{},"使用 ESM 导入 API；检查 ",[55,1717,1718],{},"sideEffects","；构建工具开启生产优化",[389,1721,1722],{},"移除未使用代码，减少最终 bundle 体积",[368,1724,1725,1730,1733],{},[389,1726,1727],{},[37,1728,1729],{},"SFC 编译优化",[389,1731,1732],{},"静态标记（PatchFlag）、事件缓存、静态提升、块树优化",[389,1734,1735],{},"提升运行时渲染性能，减少 Diff 开销",[368,1737,1738,1743,1746],{},[389,1739,1740],{},[37,1741,1742],{},"构建工具配置",[389,1744,1745],{},"Vite 预构建；代码压缩（esbuild\u002Fterser）；CDN 外部化；分块策略",[389,1747,1748],{},"更快的构建速度，更小的产物，更好的缓存",[24,1750,1751],{},"工程级性能优化需要贯穿开发、构建、部署全流程。Vue 3 + Vite 的组合提供了开箱即用的优秀优化，而深入理解上述机制，可以在遇到性能瓶颈时更有针对性地调优。",[1753,1754,1755],"h2",{"id":1755},"参考文献",[24,1757,1758],{},"以下链接在编写时均可正常访问：",[362,1760,1761,1771],{},[365,1762,1763],{},[368,1764,1765,1768],{},[371,1766,1767],{},"资料",[371,1769,1770],{},"说明",[384,1772,1773,1786,1797],{},[368,1774,1775,1783],{},[389,1776,1777],{},[28,1778,1782],{"href":1779,"rel":1780},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fbest-practices\u002Fperformance.html",[1781],"nofollow","Vue：性能",[389,1784,1785],{},"官方最佳实践",[368,1787,1788,1795],{},[389,1789,1790],{},[28,1791,1794],{"href":1792,"rel":1793},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fcomponents\u002Fasync.html",[1781],"Vue：异步组件",[389,1796,57],{},[368,1798,1799,1806],{},[389,1800,1801],{},[28,1802,1805],{"href":1803,"rel":1804},"https:\u002F\u002Fcn.vite.dev\u002Fguide\u002Fbuild.html",[1781],"Vite：构建优化",[389,1807,1808],{},"生产构建",[1810,1811,1812],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZUrc, html code.shiki .sZUrc{--shiki-light:#E53935;--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":71,"searchDepth":112,"depth":112,"links":1814},[1815,1816,1817,1818,1819,1820],{"id":44,"depth":119,"text":45},{"id":454,"depth":119,"text":455},{"id":579,"depth":119,"text":580},{"id":1057,"depth":119,"text":1058},{"id":1672,"depth":119,"text":1673},{"id":1755,"depth":112,"text":1755},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FVue\u002Fperformance\u002Fbuild","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FVue\u002Fperformance\u002Fbuild.md","md",{"items":1826},[1827,1831,1834,1838,1843,1847],{"path":1828,"title":1829,"description":1830,"category":10,"score":208},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fassets","资源优化","图片懒加载、按需引入与 Web Vitals 监控。见 HTML 图片、CSS 字体优化。",{"path":30,"title":1832,"description":1833,"category":10,"score":208},"运行时优化","减少不必要的渲染与响应式开销。构建侧见 build。",{"path":1835,"title":1836,"description":1837,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fbuild","构建与分包","通过代码分割与构建配置减小首屏 JavaScript 体积。涵盖 React.lazy\u002FSuspense、路由级分割、Tree Shaking、Vite 生产构建、体积分析、最佳实践与常见坑。运行时优化见 runtime。",{"path":1839,"title":1840,"description":1841,"category":1842,"score":183},"\u002Fknowledge\u002Fteam-documents\u002F19","GridView 宫格加载渲染优化","系统首页 GridView 宫格模块接口耗时不高，但首次进入总耗时接近 22s。复盘耗时分层定位过程、代码层面的瓶颈（约 2000 行、100 个 tab 重复节点）、优化手段与最终指标对比。","团队文档",{"path":1844,"title":1845,"description":1846,"category":1842,"score":183},"\u002Fknowledge\u002Fteam-documents\u002F13","新商家系统性能优化实践","商家系统新版本上线后，团队持续针对构建效率与用户体验做了一轮系统性优化。本文记录核心方案与落地结果，供后续版本复用。",{"path":1848,"title":1849,"description":1850,"category":1842,"score":183},"\u002Fknowledge\u002Fteam-documents\u002F04","老系统升级与兼容改造实践","公司原有业务系统采用 Node + jQuery 架构，长期运行后暴露出典型遗留系统问题：",{"series":1852,"title":13,"items":1853,"index":78,"prev":1859,"next":1860},"booklet\u002Fframe\u002Fvue\u002Fperformance",[1854,1856,1857],{"path":1828,"title":1829,"date":1855,"pinned":16},"2025-11-06",{"path":7,"title":8,"date":15,"pinned":16},{"path":30,"title":1832,"date":1858,"pinned":16},"2021-06-10",{"path":1828,"title":1829,"date":1855,"pinned":16},{"path":30,"title":1832,"date":1858,"pinned":16}]