[{"data":1,"prerenderedAt":2430},["ShallowReactive",2],{"page-\u002Fvue\u002F19-performance-optimization":3},{"id":4,"title":5,"body":6,"description":2423,"extension":2424,"meta":2425,"navigation":59,"path":2426,"seo":2427,"stem":2428,"__hash__":2429},"content\u002Fvue\u002F19-performance-optimization.md","Vue 3 Engineering Reference — Performance Optimization",{"type":7,"value":8,"toc":2410},"minimark",[9,14,19,274,278,1653,1657,1803,1807,1891,1895,2013,2017,2021,2266,2406],[10,11,13],"h1",{"id":12},"_19-performance-optimization","19 — Performance Optimization",[15,16,18],"h2",{"id":17},"compiler-patch-flags-how-vue-minimizes-dom-diffing","Compiler Patch Flags — How Vue Minimizes DOM Diffing",[20,21,24],"code-wrapper",{"filename":22,"language":23},"patch-flags.ts","typescript",[25,26,30],"pre",{"className":27,"code":28,"language":23,"meta":29,"style":29},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F ── The Vue compiler analyzes templates at build time and tags each VNode ──\n\u002F\u002F with a PatchFlag — a hint that tells the runtime exactly which properties\n\u002F\u002F to diff. This avoids full property diffing on every re-render.\n\n\u002F\u002F PatchFlags (bitmask):\n\u002F\u002F   1  = TEXT          — only text content changes\n\u002F\u002F   2  = CLASS         — only class binding changes\n\u002F\u002F   4  = STYLE         — only style binding changes\n\u002F\u002F   8  = PROPS         — only listed props change (compiler lists them)\n\u002F\u002F   16 = FULL_PROPS    — dynamic props (full prop diff needed)\n\u002F\u002F   32 = HYDRATE_EVENTS — event listeners need patching (SSR)\n\u002F\u002F   64 = STABLE_FRAGMENT — children order doesn't change (skip reorder)\n\u002F\u002F   128 = KEYED_FRAGMENT — children have keys (diff by key)\n\u002F\u002F   256 = UNKEYED_FRAGMENT — children no keys (diff by position)\n\u002F\u002F   512 = NEED_PATCH    — needs patching (ref, directives, etc.)\n\u002F\u002F   -1 = FULL_PATCH     — no hints, diff everything\n\u002F\u002F   -2 = HOISTED        — static subtree, skip entirely on re-render\n\n\u002F\u002F ── Example: compiled render function ──\n\u002F\u002F Template:\n\u002F\u002F   \u003Cdiv :class=\"{ active: isActive }\">{{ msg }}\u003C\u002Fdiv>\n\u002F\u002F\n\u002F\u002F Compiles to (simplified):\nfunction render(_ctx) {\n  return h('div', {\n    class: { active: _ctx.isActive },\n    \u002F\u002F PatchFlag 2 (CLASS) — runtime only diffs class, skips everything else\n  }, _ctx.msg, 2)\n}\n\n\u002F\u002F ── Why this matters: ────────────────────────────────────\n\u002F\u002F Without PatchFlags, every re-render diffs ALL props on ALL nodes.\n\u002F\u002F With PatchFlags, the runtime only checks the flagged property.\n\u002F\u002F For a 1000-node list with only class changing: 1000 class checks, not 1000 full diffs.\n","",[31,32,33,42,48,54,61,67,73,79,85,91,97,103,109,115,121,127,133,139,144,150,156,162,168,174,196,214,220,226,239,245,250,256,262,268],"code",{"__ignoreMap":29},[34,35,38],"span",{"class":36,"line":37},"line",1,[34,39,41],{"class":40},"sdCPZ","\u002F\u002F ── The Vue compiler analyzes templates at build time and tags each VNode ──\n",[34,43,45],{"class":36,"line":44},2,[34,46,47],{"class":40},"\u002F\u002F with a PatchFlag — a hint that tells the runtime exactly which properties\n",[34,49,51],{"class":36,"line":50},3,[34,52,53],{"class":40},"\u002F\u002F to diff. This avoids full property diffing on every re-render.\n",[34,55,57],{"class":36,"line":56},4,[34,58,60],{"emptyLinePlaceholder":59},true,"\n",[34,62,64],{"class":36,"line":63},5,[34,65,66],{"class":40},"\u002F\u002F PatchFlags (bitmask):\n",[34,68,70],{"class":36,"line":69},6,[34,71,72],{"class":40},"\u002F\u002F   1  = TEXT          — only text content changes\n",[34,74,76],{"class":36,"line":75},7,[34,77,78],{"class":40},"\u002F\u002F   2  = CLASS         — only class binding changes\n",[34,80,82],{"class":36,"line":81},8,[34,83,84],{"class":40},"\u002F\u002F   4  = STYLE         — only style binding changes\n",[34,86,88],{"class":36,"line":87},9,[34,89,90],{"class":40},"\u002F\u002F   8  = PROPS         — only listed props change (compiler lists them)\n",[34,92,94],{"class":36,"line":93},10,[34,95,96],{"class":40},"\u002F\u002F   16 = FULL_PROPS    — dynamic props (full prop diff needed)\n",[34,98,100],{"class":36,"line":99},11,[34,101,102],{"class":40},"\u002F\u002F   32 = HYDRATE_EVENTS — event listeners need patching (SSR)\n",[34,104,106],{"class":36,"line":105},12,[34,107,108],{"class":40},"\u002F\u002F   64 = STABLE_FRAGMENT — children order doesn't change (skip reorder)\n",[34,110,112],{"class":36,"line":111},13,[34,113,114],{"class":40},"\u002F\u002F   128 = KEYED_FRAGMENT — children have keys (diff by key)\n",[34,116,118],{"class":36,"line":117},14,[34,119,120],{"class":40},"\u002F\u002F   256 = UNKEYED_FRAGMENT — children no keys (diff by position)\n",[34,122,124],{"class":36,"line":123},15,[34,125,126],{"class":40},"\u002F\u002F   512 = NEED_PATCH    — needs patching (ref, directives, etc.)\n",[34,128,130],{"class":36,"line":129},16,[34,131,132],{"class":40},"\u002F\u002F   -1 = FULL_PATCH     — no hints, diff everything\n",[34,134,136],{"class":36,"line":135},17,[34,137,138],{"class":40},"\u002F\u002F   -2 = HOISTED        — static subtree, skip entirely on re-render\n",[34,140,142],{"class":36,"line":141},18,[34,143,60],{"emptyLinePlaceholder":59},[34,145,147],{"class":36,"line":146},19,[34,148,149],{"class":40},"\u002F\u002F ── Example: compiled render function ──\n",[34,151,153],{"class":36,"line":152},20,[34,154,155],{"class":40},"\u002F\u002F Template:\n",[34,157,159],{"class":36,"line":158},21,[34,160,161],{"class":40},"\u002F\u002F   \u003Cdiv :class=\"{ active: isActive }\">{{ msg }}\u003C\u002Fdiv>\n",[34,163,165],{"class":36,"line":164},22,[34,166,167],{"class":40},"\u002F\u002F\n",[34,169,171],{"class":36,"line":170},23,[34,172,173],{"class":40},"\u002F\u002F Compiles to (simplified):\n",[34,175,177,181,185,189,193],{"class":36,"line":176},24,[34,178,180],{"class":179},"svdQ7","function",[34,182,184],{"class":183},"sIsaT"," render",[34,186,188],{"class":187},"ssxIu","(",[34,190,192],{"class":191},"sCrzJ","_ctx",[34,194,195],{"class":187},") {\n",[34,197,199,202,205,207,211],{"class":36,"line":198},25,[34,200,201],{"class":179},"  return",[34,203,204],{"class":183}," h",[34,206,188],{"class":187},[34,208,210],{"class":209},"sJ6F3","'div'",[34,212,213],{"class":187},", {\n",[34,215,217],{"class":36,"line":216},26,[34,218,219],{"class":187},"    class: { active: _ctx.isActive },\n",[34,221,223],{"class":36,"line":222},27,[34,224,225],{"class":40},"    \u002F\u002F PatchFlag 2 (CLASS) — runtime only diffs class, skips everything else\n",[34,227,229,232,236],{"class":36,"line":228},28,[34,230,231],{"class":187},"  }, _ctx.msg, ",[34,233,235],{"class":234},"snvgF","2",[34,237,238],{"class":187},")\n",[34,240,242],{"class":36,"line":241},29,[34,243,244],{"class":187},"}\n",[34,246,248],{"class":36,"line":247},30,[34,249,60],{"emptyLinePlaceholder":59},[34,251,253],{"class":36,"line":252},31,[34,254,255],{"class":40},"\u002F\u002F ── Why this matters: ────────────────────────────────────\n",[34,257,259],{"class":36,"line":258},32,[34,260,261],{"class":40},"\u002F\u002F Without PatchFlags, every re-render diffs ALL props on ALL nodes.\n",[34,263,265],{"class":36,"line":264},33,[34,266,267],{"class":40},"\u002F\u002F With PatchFlags, the runtime only checks the flagged property.\n",[34,269,271],{"class":36,"line":270},34,[34,272,273],{"class":40},"\u002F\u002F For a 1000-node list with only class changing: 1000 class checks, not 1000 full diffs.\n",[15,275,277],{"id":276},"v-memo-skip-re-render-for-expensive-list-items","v-memo — Skip Re-render for Expensive List Items",[20,279,282,635,640,724,728,953,957,1196,1200],{"filename":280,"language":281},"VMemoList.vue","vue",[25,283,286],{"className":284,"code":285,"language":281,"meta":29,"style":29},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nimport { ref } from 'vue'\n\n\u002F\u002F ── v-memo: skip re-render of a subtree unless listed deps change ──\n\u002F\u002F The compiler hoists the VNode — if deps haven't changed, reuse the cached VNode.\n\u002F\u002F Critical for large lists where only a few items change at a time.\n\nconst items = ref(\n  Array.from({ length: 10_000 }, (_, i) => ({\n    id: i,\n    name: `Item ${i}`,\n    status: 'active',\n    updatedAt: Date.now(),\n  }))\n)\n\nfunction updateItem(id, patch) {\n  const item = items.value.find(i => i.id === id)\n  if (item) Object.assign(item, patch, { updatedAt: Date.now() })\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- ── v-memo deps: only re-render if id OR status changes ── -->\n  \u003C!-- If updatedAt changes but id\u002Fstatus don't: VNode is reused, NO re-render -->\n  \u003C!-- For 10,000 items where 1 changes: 1 re-render, not 10,000 -->\n  \u003Cdiv\n    v-for=\"item in items\"\n    :key=\"item.id\"\n    v-memo=\"[item.id, item.status]\"\n    class=\"item\"\n  >\n    {{ item.name }} — {{ item.status }}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[31,287,288,303,317,321,326,331,336,340,357,391,396,412,422,433,438,442,446,465,497,516,520,529,533,542,547,552,557,565,576,586,596,606,611,616,626],{"__ignoreMap":29},[34,289,290,293,297,300],{"class":36,"line":37},[34,291,292],{"class":187},"\u003C",[34,294,296],{"class":295},"sk71V","script",[34,298,299],{"class":183}," setup",[34,301,302],{"class":187},">\n",[34,304,305,308,311,314],{"class":36,"line":44},[34,306,307],{"class":179},"import",[34,309,310],{"class":187}," { ref } ",[34,312,313],{"class":179},"from",[34,315,316],{"class":209}," 'vue'\n",[34,318,319],{"class":36,"line":50},[34,320,60],{"emptyLinePlaceholder":59},[34,322,323],{"class":36,"line":56},[34,324,325],{"class":40},"\u002F\u002F ── v-memo: skip re-render of a subtree unless listed deps change ──\n",[34,327,328],{"class":36,"line":63},[34,329,330],{"class":40},"\u002F\u002F The compiler hoists the VNode — if deps haven't changed, reuse the cached VNode.\n",[34,332,333],{"class":36,"line":69},[34,334,335],{"class":40},"\u002F\u002F Critical for large lists where only a few items change at a time.\n",[34,337,338],{"class":36,"line":75},[34,339,60],{"emptyLinePlaceholder":59},[34,341,342,345,348,351,354],{"class":36,"line":81},[34,343,344],{"class":179},"const",[34,346,347],{"class":234}," items",[34,349,350],{"class":179}," =",[34,352,353],{"class":183}," ref",[34,355,356],{"class":187},"(\n",[34,358,359,362,364,367,370,373,376,379,382,385,388],{"class":36,"line":87},[34,360,361],{"class":187},"  Array.",[34,363,313],{"class":183},[34,365,366],{"class":187},"({ length: ",[34,368,369],{"class":234},"10_000",[34,371,372],{"class":187}," }, (",[34,374,375],{"class":191},"_",[34,377,378],{"class":187},", ",[34,380,381],{"class":191},"i",[34,383,384],{"class":187},") ",[34,386,387],{"class":179},"=>",[34,389,390],{"class":187}," ({\n",[34,392,393],{"class":36,"line":93},[34,394,395],{"class":187},"    id: i,\n",[34,397,398,401,404,406,409],{"class":36,"line":99},[34,399,400],{"class":187},"    name: ",[34,402,403],{"class":209},"`Item ${",[34,405,381],{"class":187},[34,407,408],{"class":209},"}`",[34,410,411],{"class":187},",\n",[34,413,414,417,420],{"class":36,"line":105},[34,415,416],{"class":187},"    status: ",[34,418,419],{"class":209},"'active'",[34,421,411],{"class":187},[34,423,424,427,430],{"class":36,"line":111},[34,425,426],{"class":187},"    updatedAt: Date.",[34,428,429],{"class":183},"now",[34,431,432],{"class":187},"(),\n",[34,434,435],{"class":36,"line":117},[34,436,437],{"class":187},"  }))\n",[34,439,440],{"class":36,"line":123},[34,441,238],{"class":187},[34,443,444],{"class":36,"line":129},[34,445,60],{"emptyLinePlaceholder":59},[34,447,448,450,453,455,458,460,463],{"class":36,"line":135},[34,449,180],{"class":179},[34,451,452],{"class":183}," updateItem",[34,454,188],{"class":187},[34,456,457],{"class":191},"id",[34,459,378],{"class":187},[34,461,462],{"class":191},"patch",[34,464,195],{"class":187},[34,466,467,470,473,475,478,481,483,485,488,491,494],{"class":36,"line":141},[34,468,469],{"class":179},"  const",[34,471,472],{"class":234}," item",[34,474,350],{"class":179},[34,476,477],{"class":187}," items.value.",[34,479,480],{"class":183},"find",[34,482,188],{"class":187},[34,484,381],{"class":191},[34,486,487],{"class":179}," =>",[34,489,490],{"class":187}," i.id ",[34,492,493],{"class":179},"===",[34,495,496],{"class":187}," id)\n",[34,498,499,502,505,508,511,513],{"class":36,"line":146},[34,500,501],{"class":179},"  if",[34,503,504],{"class":187}," (item) Object.",[34,506,507],{"class":183},"assign",[34,509,510],{"class":187},"(item, patch, { updatedAt: Date.",[34,512,429],{"class":183},[34,514,515],{"class":187},"() })\n",[34,517,518],{"class":36,"line":152},[34,519,244],{"class":187},[34,521,522,525,527],{"class":36,"line":158},[34,523,524],{"class":187},"\u003C\u002F",[34,526,296],{"class":295},[34,528,302],{"class":187},[34,530,531],{"class":36,"line":164},[34,532,60],{"emptyLinePlaceholder":59},[34,534,535,537,540],{"class":36,"line":170},[34,536,292],{"class":187},[34,538,539],{"class":295},"template",[34,541,302],{"class":187},[34,543,544],{"class":36,"line":176},[34,545,546],{"class":40},"  \u003C!-- ── v-memo deps: only re-render if id OR status changes ── -->\n",[34,548,549],{"class":36,"line":198},[34,550,551],{"class":40},"  \u003C!-- If updatedAt changes but id\u002Fstatus don't: VNode is reused, NO re-render -->\n",[34,553,554],{"class":36,"line":216},[34,555,556],{"class":40},"  \u003C!-- For 10,000 items where 1 changes: 1 re-render, not 10,000 -->\n",[34,558,559,562],{"class":36,"line":222},[34,560,561],{"class":187},"  \u003C",[34,563,564],{"class":295},"div\n",[34,566,567,570,573],{"class":36,"line":228},[34,568,569],{"class":183},"    v-for",[34,571,572],{"class":187},"=",[34,574,575],{"class":209},"\"item in items\"\n",[34,577,578,581,583],{"class":36,"line":241},[34,579,580],{"class":183},"    :key",[34,582,572],{"class":187},[34,584,585],{"class":209},"\"item.id\"\n",[34,587,588,591,593],{"class":36,"line":247},[34,589,590],{"class":183},"    v-memo",[34,592,572],{"class":187},[34,594,595],{"class":209},"\"[item.id, item.status]\"\n",[34,597,598,601,603],{"class":36,"line":252},[34,599,600],{"class":183},"    class",[34,602,572],{"class":187},[34,604,605],{"class":209},"\"item\"\n",[34,607,608],{"class":36,"line":258},[34,609,610],{"class":187},"  >\n",[34,612,613],{"class":36,"line":264},[34,614,615],{"class":187},"    {{ item.name }} — {{ item.status }}\n",[34,617,618,621,624],{"class":36,"line":270},[34,619,620],{"class":187},"  \u003C\u002F",[34,622,623],{"class":295},"div",[34,625,302],{"class":187},[34,627,629,631,633],{"class":36,"line":628},35,[34,630,524],{"class":187},[34,632,539],{"class":295},[34,634,302],{"class":187},[636,637,639],"h3",{"id":638},"anti-pattern-v-memo-with-changing-deps","Anti-Pattern: v-memo with Changing Deps",[20,641,643],{"filename":642,"language":281},"VMemoAntiPattern.vue",[25,644,646],{"className":284,"code":645,"language":281,"meta":29,"style":29},"\u003Ctemplate>\n  \u003C!-- ❌ WRONG: v-memo deps that change every render make v-memo useless -->\n  \u003Cdiv v-memo=\"[item.updatedAt]\" v-for=\"item in items\" :key=\"item.id\">\n    {{ item.name }}\n  \u003C\u002Fdiv>\n  \u003C!-- updatedAt changes on every update → VNode is never cached → full re-render -->\n  \u003C!-- The overhead of v-memo (dep comparison) is ADDED without the benefit. -->\n\u003C\u002Ftemplate>\n",[31,647,648,656,661,693,698,706,711,716],{"__ignoreMap":29},[34,649,650,652,654],{"class":36,"line":37},[34,651,292],{"class":187},[34,653,539],{"class":295},[34,655,302],{"class":187},[34,657,658],{"class":36,"line":44},[34,659,660],{"class":40},"  \u003C!-- ❌ WRONG: v-memo deps that change every render make v-memo useless -->\n",[34,662,663,665,667,670,672,675,678,680,683,686,688,691],{"class":36,"line":50},[34,664,561],{"class":187},[34,666,623],{"class":295},[34,668,669],{"class":183}," v-memo",[34,671,572],{"class":187},[34,673,674],{"class":209},"\"[item.updatedAt]\"",[34,676,677],{"class":183}," v-for",[34,679,572],{"class":187},[34,681,682],{"class":209},"\"item in items\"",[34,684,685],{"class":183}," :key",[34,687,572],{"class":187},[34,689,690],{"class":209},"\"item.id\"",[34,692,302],{"class":187},[34,694,695],{"class":36,"line":56},[34,696,697],{"class":187},"    {{ item.name }}\n",[34,699,700,702,704],{"class":36,"line":63},[34,701,620],{"class":187},[34,703,623],{"class":295},[34,705,302],{"class":187},[34,707,708],{"class":36,"line":69},[34,709,710],{"class":40},"  \u003C!-- updatedAt changes on every update → VNode is never cached → full re-render -->\n",[34,712,713],{"class":36,"line":75},[34,714,715],{"class":40},"  \u003C!-- The overhead of v-memo (dep comparison) is ADDED without the benefit. -->\n",[34,717,718,720,722],{"class":36,"line":81},[34,719,524],{"class":187},[34,721,539],{"class":295},[34,723,302],{"class":187},[15,725,727],{"id":726},"shallowref-large-data-without-deep-tracking","shallowRef — Large Data Without Deep Tracking",[20,729,731],{"filename":730,"language":23},"shallow-ref-performance.ts",[25,732,734],{"className":27,"code":733,"language":23,"meta":29,"style":29},"import { ref, reactive, shallowRef, triggerRef, type ShallowRef } from 'vue'\n\n\u002F\u002F ── reactive() deeply proxies every nested property ──\n\u002F\u002F For a 10,000-item array of objects: 10,000+ Proxies created at init.\n\u002F\u002F Init cost: O(n × depth). Memory: one Proxy per nested object.\n\n\u002F\u002F ── shallowRef: no deep proxying — only .value access is tracked ──\n\u002F\u002F Init cost: O(1). Memory: one ref wrapper, zero nested Proxies.\n\n\u002F\u002F ── When to use shallowRef for large data: ──────────────\n\u002F\u002F - API responses (fetched once, replaced wholesale)\n\u002F\u002F - Chart datasets (mutated externally, not reactively)\n\u002F\u002F - Large tables (10,000+ rows)\n\u002F\u002F - Binary data (ArrayBuffer, ImageData)\n\nconst largeDataset: ShallowRef\u003CRecord\u003Cstring, any>[]> = shallowRef([])\n\n\u002F\u002F ✅ Replacing .value triggers re-render:\nlargeDataset.value = newArray\n\n\u002F\u002F ❌ In-place mutation does NOT trigger:\nlargeDataset.value.push(newItem)  \u002F\u002F array changed, no re-render\n\n\u002F\u002F ✅ Force trigger after in-place mutation:\nlargeDataset.value.push(newItem)\ntriggerRef(largeDataset)  \u002F\u002F manually notify dependents\n\n\u002F\u002F ── Benchmark: reactive vs shallowRef on 10,000 items ──\n\u002F\u002F reactive: ~50ms init (proxying), ~5ms per deep mutation check\n\u002F\u002F shallowRef: ~0.1ms init (no proxy), ~0ms per mutation (not tracked)\n\u002F\u002F For read-heavy, write-rare data: shallowRef wins by orders of magnitude.\n",[31,735,736,753,757,762,767,772,776,781,786,790,795,800,805,810,815,819,858,862,867,877,881,886,900,904,909,918,929,933,938,943,948],{"__ignoreMap":29},[34,737,738,740,743,746,749,751],{"class":36,"line":37},[34,739,307],{"class":179},[34,741,742],{"class":187}," { ref, reactive, shallowRef, triggerRef, ",[34,744,745],{"class":179},"type",[34,747,748],{"class":187}," ShallowRef } ",[34,750,313],{"class":179},[34,752,316],{"class":209},[34,754,755],{"class":36,"line":44},[34,756,60],{"emptyLinePlaceholder":59},[34,758,759],{"class":36,"line":50},[34,760,761],{"class":40},"\u002F\u002F ── reactive() deeply proxies every nested property ──\n",[34,763,764],{"class":36,"line":56},[34,765,766],{"class":40},"\u002F\u002F For a 10,000-item array of objects: 10,000+ Proxies created at init.\n",[34,768,769],{"class":36,"line":63},[34,770,771],{"class":40},"\u002F\u002F Init cost: O(n × depth). Memory: one Proxy per nested object.\n",[34,773,774],{"class":36,"line":69},[34,775,60],{"emptyLinePlaceholder":59},[34,777,778],{"class":36,"line":75},[34,779,780],{"class":40},"\u002F\u002F ── shallowRef: no deep proxying — only .value access is tracked ──\n",[34,782,783],{"class":36,"line":81},[34,784,785],{"class":40},"\u002F\u002F Init cost: O(1). Memory: one ref wrapper, zero nested Proxies.\n",[34,787,788],{"class":36,"line":87},[34,789,60],{"emptyLinePlaceholder":59},[34,791,792],{"class":36,"line":93},[34,793,794],{"class":40},"\u002F\u002F ── When to use shallowRef for large data: ──────────────\n",[34,796,797],{"class":36,"line":99},[34,798,799],{"class":40},"\u002F\u002F - API responses (fetched once, replaced wholesale)\n",[34,801,802],{"class":36,"line":105},[34,803,804],{"class":40},"\u002F\u002F - Chart datasets (mutated externally, not reactively)\n",[34,806,807],{"class":36,"line":111},[34,808,809],{"class":40},"\u002F\u002F - Large tables (10,000+ rows)\n",[34,811,812],{"class":36,"line":117},[34,813,814],{"class":40},"\u002F\u002F - Binary data (ArrayBuffer, ImageData)\n",[34,816,817],{"class":36,"line":123},[34,818,60],{"emptyLinePlaceholder":59},[34,820,821,823,826,829,832,834,837,839,842,844,847,850,852,855],{"class":36,"line":129},[34,822,344],{"class":179},[34,824,825],{"class":234}," largeDataset",[34,827,828],{"class":179},":",[34,830,831],{"class":183}," ShallowRef",[34,833,292],{"class":187},[34,835,836],{"class":183},"Record",[34,838,292],{"class":187},[34,840,841],{"class":234},"string",[34,843,378],{"class":187},[34,845,846],{"class":234},"any",[34,848,849],{"class":187},">[]> ",[34,851,572],{"class":179},[34,853,854],{"class":183}," shallowRef",[34,856,857],{"class":187},"([])\n",[34,859,860],{"class":36,"line":135},[34,861,60],{"emptyLinePlaceholder":59},[34,863,864],{"class":36,"line":141},[34,865,866],{"class":40},"\u002F\u002F ✅ Replacing .value triggers re-render:\n",[34,868,869,872,874],{"class":36,"line":146},[34,870,871],{"class":187},"largeDataset.value ",[34,873,572],{"class":179},[34,875,876],{"class":187}," newArray\n",[34,878,879],{"class":36,"line":152},[34,880,60],{"emptyLinePlaceholder":59},[34,882,883],{"class":36,"line":158},[34,884,885],{"class":40},"\u002F\u002F ❌ In-place mutation does NOT trigger:\n",[34,887,888,891,894,897],{"class":36,"line":164},[34,889,890],{"class":187},"largeDataset.value.",[34,892,893],{"class":183},"push",[34,895,896],{"class":187},"(newItem)  ",[34,898,899],{"class":40},"\u002F\u002F array changed, no re-render\n",[34,901,902],{"class":36,"line":170},[34,903,60],{"emptyLinePlaceholder":59},[34,905,906],{"class":36,"line":176},[34,907,908],{"class":40},"\u002F\u002F ✅ Force trigger after in-place mutation:\n",[34,910,911,913,915],{"class":36,"line":198},[34,912,890],{"class":187},[34,914,893],{"class":183},[34,916,917],{"class":187},"(newItem)\n",[34,919,920,923,926],{"class":36,"line":216},[34,921,922],{"class":183},"triggerRef",[34,924,925],{"class":187},"(largeDataset)  ",[34,927,928],{"class":40},"\u002F\u002F manually notify dependents\n",[34,930,931],{"class":36,"line":222},[34,932,60],{"emptyLinePlaceholder":59},[34,934,935],{"class":36,"line":228},[34,936,937],{"class":40},"\u002F\u002F ── Benchmark: reactive vs shallowRef on 10,000 items ──\n",[34,939,940],{"class":36,"line":241},[34,941,942],{"class":40},"\u002F\u002F reactive: ~50ms init (proxying), ~5ms per deep mutation check\n",[34,944,945],{"class":36,"line":247},[34,946,947],{"class":40},"\u002F\u002F shallowRef: ~0.1ms init (no proxy), ~0ms per mutation (not tracked)\n",[34,949,950],{"class":36,"line":252},[34,951,952],{"class":40},"\u002F\u002F For read-heavy, write-rare data: shallowRef wins by orders of magnitude.\n",[15,954,956],{"id":955},"v-once-static-content-rendered-forever","v-once — Static Content, Rendered Forever",[20,958,960],{"filename":959,"language":281},"VOnceStatic.vue",[25,961,963],{"className":284,"code":962,"language":281,"meta":29,"style":29},"\u003Cscript setup>\nimport { computed } from 'vue'\n\n\u002F\u002F ── v-once: render the element\u002Fsubtree ONCE, skip on all future re-renders ──\n\u002F\u002F The VNode is hoisted — Vue reuses the exact same VNode forever.\n\u002F\u002F Zero re-render cost for that subtree, regardless of state changes.\n\n\u002F\u002F ── Use cases: ──────────────────────────────────────────\n\u002F\u002F - Markdown rendered to HTML (static after first render)\n\u002F\u002F - Terms of service text (never changes)\n\u002F\u002F - Logo, header, footer (static markup)\n\nconst markdownHtml = computed(() => renderMarkdown(rawMarkdown.value))\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- Rendered once, never re-rendered even if rawMarkdown changes -->\n  \u003Cdiv v-once v-html=\"markdownHtml\" \u002F>\n\n  \u003C!-- ── v-once on a subtree: the entire subtree is hoisted ── -->\n  \u003Cdiv v-once>\n    \u003Cheader>\n      \u003Ch1>My App\u003C\u002Fh1>\n      \u003Cnav>...\u003C\u002Fnav>\n    \u003C\u002Fheader>\n  \u003C\u002Fdiv>\n  \u003C!-- This entire block is compiled as a static hoisted VNode. -->\n  \u003C!-- Even if the component re-renders, this block is skipped entirely. -->\n\u003C\u002Ftemplate>\n",[31,964,965,975,986,990,995,1000,1005,1009,1014,1019,1024,1029,1033,1056,1064,1068,1076,1081,1104,1108,1113,1123,1133,1147,1161,1170,1178,1183,1188],{"__ignoreMap":29},[34,966,967,969,971,973],{"class":36,"line":37},[34,968,292],{"class":187},[34,970,296],{"class":295},[34,972,299],{"class":183},[34,974,302],{"class":187},[34,976,977,979,982,984],{"class":36,"line":44},[34,978,307],{"class":179},[34,980,981],{"class":187}," { computed } ",[34,983,313],{"class":179},[34,985,316],{"class":209},[34,987,988],{"class":36,"line":50},[34,989,60],{"emptyLinePlaceholder":59},[34,991,992],{"class":36,"line":56},[34,993,994],{"class":40},"\u002F\u002F ── v-once: render the element\u002Fsubtree ONCE, skip on all future re-renders ──\n",[34,996,997],{"class":36,"line":63},[34,998,999],{"class":40},"\u002F\u002F The VNode is hoisted — Vue reuses the exact same VNode forever.\n",[34,1001,1002],{"class":36,"line":69},[34,1003,1004],{"class":40},"\u002F\u002F Zero re-render cost for that subtree, regardless of state changes.\n",[34,1006,1007],{"class":36,"line":75},[34,1008,60],{"emptyLinePlaceholder":59},[34,1010,1011],{"class":36,"line":81},[34,1012,1013],{"class":40},"\u002F\u002F ── Use cases: ──────────────────────────────────────────\n",[34,1015,1016],{"class":36,"line":87},[34,1017,1018],{"class":40},"\u002F\u002F - Markdown rendered to HTML (static after first render)\n",[34,1020,1021],{"class":36,"line":93},[34,1022,1023],{"class":40},"\u002F\u002F - Terms of service text (never changes)\n",[34,1025,1026],{"class":36,"line":99},[34,1027,1028],{"class":40},"\u002F\u002F - Logo, header, footer (static markup)\n",[34,1030,1031],{"class":36,"line":105},[34,1032,60],{"emptyLinePlaceholder":59},[34,1034,1035,1037,1040,1042,1045,1048,1050,1053],{"class":36,"line":111},[34,1036,344],{"class":179},[34,1038,1039],{"class":234}," markdownHtml",[34,1041,350],{"class":179},[34,1043,1044],{"class":183}," computed",[34,1046,1047],{"class":187},"(() ",[34,1049,387],{"class":179},[34,1051,1052],{"class":183}," renderMarkdown",[34,1054,1055],{"class":187},"(rawMarkdown.value))\n",[34,1057,1058,1060,1062],{"class":36,"line":117},[34,1059,524],{"class":187},[34,1061,296],{"class":295},[34,1063,302],{"class":187},[34,1065,1066],{"class":36,"line":123},[34,1067,60],{"emptyLinePlaceholder":59},[34,1069,1070,1072,1074],{"class":36,"line":129},[34,1071,292],{"class":187},[34,1073,539],{"class":295},[34,1075,302],{"class":187},[34,1077,1078],{"class":36,"line":135},[34,1079,1080],{"class":40},"  \u003C!-- Rendered once, never re-rendered even if rawMarkdown changes -->\n",[34,1082,1083,1085,1087,1090,1093,1095,1098,1102],{"class":36,"line":141},[34,1084,561],{"class":187},[34,1086,623],{"class":295},[34,1088,1089],{"class":183}," v-once",[34,1091,1092],{"class":183}," v-html",[34,1094,572],{"class":187},[34,1096,1097],{"class":209},"\"markdownHtml\"",[34,1099,1101],{"class":1100},"sMKGj"," \u002F",[34,1103,302],{"class":187},[34,1105,1106],{"class":36,"line":146},[34,1107,60],{"emptyLinePlaceholder":59},[34,1109,1110],{"class":36,"line":152},[34,1111,1112],{"class":40},"  \u003C!-- ── v-once on a subtree: the entire subtree is hoisted ── -->\n",[34,1114,1115,1117,1119,1121],{"class":36,"line":158},[34,1116,561],{"class":187},[34,1118,623],{"class":295},[34,1120,1089],{"class":183},[34,1122,302],{"class":187},[34,1124,1125,1128,1131],{"class":36,"line":164},[34,1126,1127],{"class":187},"    \u003C",[34,1129,1130],{"class":295},"header",[34,1132,302],{"class":187},[34,1134,1135,1138,1140,1143,1145],{"class":36,"line":170},[34,1136,1137],{"class":187},"      \u003C",[34,1139,10],{"class":295},[34,1141,1142],{"class":187},">My App\u003C\u002F",[34,1144,10],{"class":295},[34,1146,302],{"class":187},[34,1148,1149,1151,1154,1157,1159],{"class":36,"line":176},[34,1150,1137],{"class":187},[34,1152,1153],{"class":295},"nav",[34,1155,1156],{"class":187},">...\u003C\u002F",[34,1158,1153],{"class":295},[34,1160,302],{"class":187},[34,1162,1163,1166,1168],{"class":36,"line":198},[34,1164,1165],{"class":187},"    \u003C\u002F",[34,1167,1130],{"class":295},[34,1169,302],{"class":187},[34,1171,1172,1174,1176],{"class":36,"line":216},[34,1173,620],{"class":187},[34,1175,623],{"class":295},[34,1177,302],{"class":187},[34,1179,1180],{"class":36,"line":222},[34,1181,1182],{"class":40},"  \u003C!-- This entire block is compiled as a static hoisted VNode. -->\n",[34,1184,1185],{"class":36,"line":228},[34,1186,1187],{"class":40},"  \u003C!-- Even if the component re-renders, this block is skipped entirely. -->\n",[34,1189,1190,1192,1194],{"class":36,"line":241},[34,1191,524],{"class":187},[34,1193,539],{"class":295},[34,1195,302],{"class":187},[15,1197,1199],{"id":1198},"manual-chunk-splitting-vite-configuration","Manual Chunk Splitting — Vite Configuration",[20,1201,1203,1450],{"filename":1202,"language":23},"vite.config.ts",[25,1204,1206],{"className":27,"code":1205,"language":23,"meta":29,"style":29},"import { defineConfig } from 'vite'\nimport vue from '@vitejs\u002Fplugin-vue'\n\nexport default defineConfig({\n  build: {\n    target: 'esnext',\n    sourcemap: true,\n    \u002F\u002F ── rollupOptions: manual chunk splitting ──\n    rollupOptions: {\n      output: {\n        \u002F\u002F ── manualChunks: split vendor code into separate files ──\n        \u002F\u002F Prevents one mega-bundle; enables long-term browser caching\n        \u002F\u002F (vendor code changes less often than app code).\n        manualChunks: {\n          'vendor-vue': ['vue', 'vue-router', 'pinia'],\n          'vendor-ui': ['@vueuse\u002Fcore', '@vueuse\u002Fintegrations'],\n          'vendor-charts': ['chart.js'],\n        },\n        \u002F\u002F ── chunkFileNames: deterministic names for cache stability ──\n        chunkFileNames: 'assets\u002Fjs\u002F[name]-[hash].js',\n        entryFileNames: 'assets\u002Fjs\u002F[name]-[hash].js',\n        assetFileNames: 'assets\u002F[ext]\u002F[name]-[hash].[ext]',\n      },\n    },\n    \u002F\u002F ── chunkSizeWarningLimit: raise if vendor chunks are large ──\n    chunkSizeWarningLimit: 600,\n  },\n  \u002F\u002F ── cssCodeSplit: false — bundle all CSS into one file (fewer requests) ──\n  \u002F\u002F cssCodeSplit: false,  \u002F\u002F enable for small apps; disable for large (parallel CSS load)\n})\n",[31,1207,1208,1220,1232,1236,1250,1255,1265,1275,1280,1285,1290,1295,1300,1305,1310,1334,1351,1363,1368,1373,1383,1392,1402,1407,1412,1417,1427,1432,1437,1445],{"__ignoreMap":29},[34,1209,1210,1212,1215,1217],{"class":36,"line":37},[34,1211,307],{"class":179},[34,1213,1214],{"class":187}," { defineConfig } ",[34,1216,313],{"class":179},[34,1218,1219],{"class":209}," 'vite'\n",[34,1221,1222,1224,1227,1229],{"class":36,"line":44},[34,1223,307],{"class":179},[34,1225,1226],{"class":187}," vue ",[34,1228,313],{"class":179},[34,1230,1231],{"class":209}," '@vitejs\u002Fplugin-vue'\n",[34,1233,1234],{"class":36,"line":50},[34,1235,60],{"emptyLinePlaceholder":59},[34,1237,1238,1241,1244,1247],{"class":36,"line":56},[34,1239,1240],{"class":179},"export",[34,1242,1243],{"class":179}," default",[34,1245,1246],{"class":183}," defineConfig",[34,1248,1249],{"class":187},"({\n",[34,1251,1252],{"class":36,"line":63},[34,1253,1254],{"class":187},"  build: {\n",[34,1256,1257,1260,1263],{"class":36,"line":69},[34,1258,1259],{"class":187},"    target: ",[34,1261,1262],{"class":209},"'esnext'",[34,1264,411],{"class":187},[34,1266,1267,1270,1273],{"class":36,"line":75},[34,1268,1269],{"class":187},"    sourcemap: ",[34,1271,1272],{"class":234},"true",[34,1274,411],{"class":187},[34,1276,1277],{"class":36,"line":81},[34,1278,1279],{"class":40},"    \u002F\u002F ── rollupOptions: manual chunk splitting ──\n",[34,1281,1282],{"class":36,"line":87},[34,1283,1284],{"class":187},"    rollupOptions: {\n",[34,1286,1287],{"class":36,"line":93},[34,1288,1289],{"class":187},"      output: {\n",[34,1291,1292],{"class":36,"line":99},[34,1293,1294],{"class":40},"        \u002F\u002F ── manualChunks: split vendor code into separate files ──\n",[34,1296,1297],{"class":36,"line":105},[34,1298,1299],{"class":40},"        \u002F\u002F Prevents one mega-bundle; enables long-term browser caching\n",[34,1301,1302],{"class":36,"line":111},[34,1303,1304],{"class":40},"        \u002F\u002F (vendor code changes less often than app code).\n",[34,1306,1307],{"class":36,"line":117},[34,1308,1309],{"class":187},"        manualChunks: {\n",[34,1311,1312,1315,1318,1321,1323,1326,1328,1331],{"class":36,"line":123},[34,1313,1314],{"class":209},"          'vendor-vue'",[34,1316,1317],{"class":187},": [",[34,1319,1320],{"class":209},"'vue'",[34,1322,378],{"class":187},[34,1324,1325],{"class":209},"'vue-router'",[34,1327,378],{"class":187},[34,1329,1330],{"class":209},"'pinia'",[34,1332,1333],{"class":187},"],\n",[34,1335,1336,1339,1341,1344,1346,1349],{"class":36,"line":129},[34,1337,1338],{"class":209},"          'vendor-ui'",[34,1340,1317],{"class":187},[34,1342,1343],{"class":209},"'@vueuse\u002Fcore'",[34,1345,378],{"class":187},[34,1347,1348],{"class":209},"'@vueuse\u002Fintegrations'",[34,1350,1333],{"class":187},[34,1352,1353,1356,1358,1361],{"class":36,"line":135},[34,1354,1355],{"class":209},"          'vendor-charts'",[34,1357,1317],{"class":187},[34,1359,1360],{"class":209},"'chart.js'",[34,1362,1333],{"class":187},[34,1364,1365],{"class":36,"line":141},[34,1366,1367],{"class":187},"        },\n",[34,1369,1370],{"class":36,"line":146},[34,1371,1372],{"class":40},"        \u002F\u002F ── chunkFileNames: deterministic names for cache stability ──\n",[34,1374,1375,1378,1381],{"class":36,"line":152},[34,1376,1377],{"class":187},"        chunkFileNames: ",[34,1379,1380],{"class":209},"'assets\u002Fjs\u002F[name]-[hash].js'",[34,1382,411],{"class":187},[34,1384,1385,1388,1390],{"class":36,"line":158},[34,1386,1387],{"class":187},"        entryFileNames: ",[34,1389,1380],{"class":209},[34,1391,411],{"class":187},[34,1393,1394,1397,1400],{"class":36,"line":164},[34,1395,1396],{"class":187},"        assetFileNames: ",[34,1398,1399],{"class":209},"'assets\u002F[ext]\u002F[name]-[hash].[ext]'",[34,1401,411],{"class":187},[34,1403,1404],{"class":36,"line":170},[34,1405,1406],{"class":187},"      },\n",[34,1408,1409],{"class":36,"line":176},[34,1410,1411],{"class":187},"    },\n",[34,1413,1414],{"class":36,"line":198},[34,1415,1416],{"class":40},"    \u002F\u002F ── chunkSizeWarningLimit: raise if vendor chunks are large ──\n",[34,1418,1419,1422,1425],{"class":36,"line":216},[34,1420,1421],{"class":187},"    chunkSizeWarningLimit: ",[34,1423,1424],{"class":234},"600",[34,1426,411],{"class":187},[34,1428,1429],{"class":36,"line":222},[34,1430,1431],{"class":187},"  },\n",[34,1433,1434],{"class":36,"line":228},[34,1435,1436],{"class":40},"  \u002F\u002F ── cssCodeSplit: false — bundle all CSS into one file (fewer requests) ──\n",[34,1438,1439,1442],{"class":36,"line":241},[34,1440,1441],{"class":40},"  \u002F\u002F cssCodeSplit: false,",[34,1443,1444],{"class":40},"  \u002F\u002F enable for small apps; disable for large (parallel CSS load)\n",[34,1446,1447],{"class":36,"line":247},[34,1448,1449],{"class":187},"})\n",[20,1451,1453],{"filename":1452,"language":23},"lazy-routes.ts",[25,1454,1456],{"className":27,"code":1455,"language":23,"meta":29,"style":29},"import { createRouter } from 'vue-router'\n\n\u002F\u002F ── Route-level code splitting: each route is a separate chunk ──\n\u002F\u002F Only the visited route's code downloads — smaller initial bundle.\nconst routes = [\n  {\n    path: '\u002F',\n    \u002F\u002F Eager import: part of main bundle (critical, above-the-fold)\n    component: () => import('@\u002Fviews\u002FHome.vue'),\n  },\n  {\n    path: '\u002Fdashboard',\n    \u002F\u002F Lazy import: separate chunk, loaded on first navigation\n    component: () => import(\u002F* webpackChunkName: \"dashboard\" *\u002F '@\u002Fviews\u002FDashboard.vue'),\n    \u002F\u002F ── Prefetch: start loading on hover (before navigation) ──\n    \u002F\u002F Reduces perceived latency — chunk is loading while user decides.\n  },\n  {\n    path: '\u002Fadmin',\n    \u002F\u002F ── Conditional loading: only for admins ──\n    component: () => import('@\u002Fviews\u002FAdmin.vue'),\n    meta: { requiresAuth: true, role: 'admin' },\n  },\n]\n",[31,1457,1458,1470,1474,1479,1484,1496,1501,1511,1516,1537,1541,1545,1554,1559,1579,1584,1589,1593,1597,1606,1611,1628,1644,1648],{"__ignoreMap":29},[34,1459,1460,1462,1465,1467],{"class":36,"line":37},[34,1461,307],{"class":179},[34,1463,1464],{"class":187}," { createRouter } ",[34,1466,313],{"class":179},[34,1468,1469],{"class":209}," 'vue-router'\n",[34,1471,1472],{"class":36,"line":44},[34,1473,60],{"emptyLinePlaceholder":59},[34,1475,1476],{"class":36,"line":50},[34,1477,1478],{"class":40},"\u002F\u002F ── Route-level code splitting: each route is a separate chunk ──\n",[34,1480,1481],{"class":36,"line":56},[34,1482,1483],{"class":40},"\u002F\u002F Only the visited route's code downloads — smaller initial bundle.\n",[34,1485,1486,1488,1491,1493],{"class":36,"line":63},[34,1487,344],{"class":179},[34,1489,1490],{"class":234}," routes",[34,1492,350],{"class":179},[34,1494,1495],{"class":187}," [\n",[34,1497,1498],{"class":36,"line":69},[34,1499,1500],{"class":187},"  {\n",[34,1502,1503,1506,1509],{"class":36,"line":75},[34,1504,1505],{"class":187},"    path: ",[34,1507,1508],{"class":209},"'\u002F'",[34,1510,411],{"class":187},[34,1512,1513],{"class":36,"line":81},[34,1514,1515],{"class":40},"    \u002F\u002F Eager import: part of main bundle (critical, above-the-fold)\n",[34,1517,1518,1521,1524,1526,1529,1531,1534],{"class":36,"line":87},[34,1519,1520],{"class":183},"    component",[34,1522,1523],{"class":187},": () ",[34,1525,387],{"class":179},[34,1527,1528],{"class":179}," import",[34,1530,188],{"class":187},[34,1532,1533],{"class":209},"'@\u002Fviews\u002FHome.vue'",[34,1535,1536],{"class":187},"),\n",[34,1538,1539],{"class":36,"line":93},[34,1540,1431],{"class":187},[34,1542,1543],{"class":36,"line":99},[34,1544,1500],{"class":187},[34,1546,1547,1549,1552],{"class":36,"line":105},[34,1548,1505],{"class":187},[34,1550,1551],{"class":209},"'\u002Fdashboard'",[34,1553,411],{"class":187},[34,1555,1556],{"class":36,"line":111},[34,1557,1558],{"class":40},"    \u002F\u002F Lazy import: separate chunk, loaded on first navigation\n",[34,1560,1561,1563,1565,1567,1569,1571,1574,1577],{"class":36,"line":117},[34,1562,1520],{"class":183},[34,1564,1523],{"class":187},[34,1566,387],{"class":179},[34,1568,1528],{"class":183},[34,1570,188],{"class":187},[34,1572,1573],{"class":40},"\u002F* webpackChunkName: \"dashboard\" *\u002F",[34,1575,1576],{"class":209}," '@\u002Fviews\u002FDashboard.vue'",[34,1578,1536],{"class":187},[34,1580,1581],{"class":36,"line":123},[34,1582,1583],{"class":40},"    \u002F\u002F ── Prefetch: start loading on hover (before navigation) ──\n",[34,1585,1586],{"class":36,"line":129},[34,1587,1588],{"class":40},"    \u002F\u002F Reduces perceived latency — chunk is loading while user decides.\n",[34,1590,1591],{"class":36,"line":135},[34,1592,1431],{"class":187},[34,1594,1595],{"class":36,"line":141},[34,1596,1500],{"class":187},[34,1598,1599,1601,1604],{"class":36,"line":146},[34,1600,1505],{"class":187},[34,1602,1603],{"class":209},"'\u002Fadmin'",[34,1605,411],{"class":187},[34,1607,1608],{"class":36,"line":152},[34,1609,1610],{"class":40},"    \u002F\u002F ── Conditional loading: only for admins ──\n",[34,1612,1613,1615,1617,1619,1621,1623,1626],{"class":36,"line":158},[34,1614,1520],{"class":183},[34,1616,1523],{"class":187},[34,1618,387],{"class":179},[34,1620,1528],{"class":179},[34,1622,188],{"class":187},[34,1624,1625],{"class":209},"'@\u002Fviews\u002FAdmin.vue'",[34,1627,1536],{"class":187},[34,1629,1630,1633,1635,1638,1641],{"class":36,"line":164},[34,1631,1632],{"class":187},"    meta: { requiresAuth: ",[34,1634,1272],{"class":234},[34,1636,1637],{"class":187},", role: ",[34,1639,1640],{"class":209},"'admin'",[34,1642,1643],{"class":187}," },\n",[34,1645,1646],{"class":36,"line":170},[34,1647,1431],{"class":187},[34,1649,1650],{"class":36,"line":176},[34,1651,1652],{"class":187},"]\n",[15,1654,1656],{"id":1655},"runtime-profiler-appconfigperformance","Runtime Profiler — app.config.performance",[20,1658,1660],{"filename":1659,"language":23},"profiler.ts",[25,1661,1663],{"className":27,"code":1662,"language":23,"meta":29,"style":29},"import { createApp } from 'vue'\nimport App from '.\u002FApp.vue'\n\n\u002F\u002F ── app.config.performance: adds performance marks in dev ──\n\u002F\u002F Must be set BEFORE mount. Only works in development mode.\nconst app = createApp(App)\napp.config.performance = true  \u002F\u002F enables Vue-specific performance marks\napp.mount('#app')\n\n\u002F\u002F ── Marks visible in Chrome DevTools → Performance → Timeline: ──\n\u002F\u002F \"vue:component:init\" — component setup time\n\u002F\u002F \"vue:component:compile\" — template compile time (first render only)\n\u002F\u002F \"vue:component:render\" — render function execution\n\u002F\u002F \"vue:component:patch\" — DOM patch time\n\u002F\u002F\n\u002F\u002F ── Identifying slow components: ──\n\u002F\u002F 1. Record a Performance profile while interacting with the app\n\u002F\u002F 2. Search for \"vue:\" marks in the timeline\n\u002F\u002F 3. Components with long \"render\" or \"patch\" times are optimization targets\n\u002F\u002F 4. Common fixes: v-memo, shallowRef, computed caching, v-once for static parts\n",[31,1664,1665,1676,1688,1692,1697,1702,1717,1730,1745,1749,1754,1759,1764,1769,1774,1778,1783,1788,1793,1798],{"__ignoreMap":29},[34,1666,1667,1669,1672,1674],{"class":36,"line":37},[34,1668,307],{"class":179},[34,1670,1671],{"class":187}," { createApp } ",[34,1673,313],{"class":179},[34,1675,316],{"class":209},[34,1677,1678,1680,1683,1685],{"class":36,"line":44},[34,1679,307],{"class":179},[34,1681,1682],{"class":187}," App ",[34,1684,313],{"class":179},[34,1686,1687],{"class":209}," '.\u002FApp.vue'\n",[34,1689,1690],{"class":36,"line":50},[34,1691,60],{"emptyLinePlaceholder":59},[34,1693,1694],{"class":36,"line":56},[34,1695,1696],{"class":40},"\u002F\u002F ── app.config.performance: adds performance marks in dev ──\n",[34,1698,1699],{"class":36,"line":63},[34,1700,1701],{"class":40},"\u002F\u002F Must be set BEFORE mount. Only works in development mode.\n",[34,1703,1704,1706,1709,1711,1714],{"class":36,"line":69},[34,1705,344],{"class":179},[34,1707,1708],{"class":234}," app",[34,1710,350],{"class":179},[34,1712,1713],{"class":183}," createApp",[34,1715,1716],{"class":187},"(App)\n",[34,1718,1719,1722,1724,1727],{"class":36,"line":75},[34,1720,1721],{"class":187},"app.config.performance ",[34,1723,572],{"class":179},[34,1725,1726],{"class":234}," true",[34,1728,1729],{"class":40},"  \u002F\u002F enables Vue-specific performance marks\n",[34,1731,1732,1735,1738,1740,1743],{"class":36,"line":81},[34,1733,1734],{"class":187},"app.",[34,1736,1737],{"class":183},"mount",[34,1739,188],{"class":187},[34,1741,1742],{"class":209},"'#app'",[34,1744,238],{"class":187},[34,1746,1747],{"class":36,"line":87},[34,1748,60],{"emptyLinePlaceholder":59},[34,1750,1751],{"class":36,"line":93},[34,1752,1753],{"class":40},"\u002F\u002F ── Marks visible in Chrome DevTools → Performance → Timeline: ──\n",[34,1755,1756],{"class":36,"line":99},[34,1757,1758],{"class":40},"\u002F\u002F \"vue:component:init\" — component setup time\n",[34,1760,1761],{"class":36,"line":105},[34,1762,1763],{"class":40},"\u002F\u002F \"vue:component:compile\" — template compile time (first render only)\n",[34,1765,1766],{"class":36,"line":111},[34,1767,1768],{"class":40},"\u002F\u002F \"vue:component:render\" — render function execution\n",[34,1770,1771],{"class":36,"line":117},[34,1772,1773],{"class":40},"\u002F\u002F \"vue:component:patch\" — DOM patch time\n",[34,1775,1776],{"class":36,"line":123},[34,1777,167],{"class":40},[34,1779,1780],{"class":36,"line":129},[34,1781,1782],{"class":40},"\u002F\u002F ── Identifying slow components: ──\n",[34,1784,1785],{"class":36,"line":135},[34,1786,1787],{"class":40},"\u002F\u002F 1. Record a Performance profile while interacting with the app\n",[34,1789,1790],{"class":36,"line":141},[34,1791,1792],{"class":40},"\u002F\u002F 2. Search for \"vue:\" marks in the timeline\n",[34,1794,1795],{"class":36,"line":146},[34,1796,1797],{"class":40},"\u002F\u002F 3. Components with long \"render\" or \"patch\" times are optimization targets\n",[34,1799,1800],{"class":36,"line":152},[34,1801,1802],{"class":40},"\u002F\u002F 4. Common fixes: v-memo, shallowRef, computed caching, v-once for static parts\n",[15,1804,1806],{"id":1805},"tips-tricks","💡 Tips & Tricks",[20,1808,1810],{"filename":1809,"language":23},"tips.ts",[25,1811,1813],{"className":27,"code":1812,"language":23,"meta":29,"style":29},"\u002F\u002F ── 1. Avoid deep watchers on large objects (O(n) traversal) ──\n\u002F\u002F watch(state, cb, { deep: true })  — walks EVERY property to track them.\n\u002F\u002F For 1000-key objects: 1000 track calls. Use specific path watchers instead.\n\n\u002F\u002F ── 2. Use computed for derived values (cached, lazy) ──\n\u002F\u002F Don't recalculate in methods — computed only re-evaluates when deps change.\n\n\u002F\u002F ── 3. v-show for frequently toggled elements (no unmount\u002Fmount cost) ──\n\u002F\u002F v-if for rarely shown elements (zero cost when hidden)\n\n\u002F\u002F ── 4. Key by stable ID, never by index (see chapter 02) ──\n\u002F\u002F Index keys cause unnecessary DOM reuse → incorrect state, wasted patches.\n\n\u002F\u002F ── 5. Large lists: virtualize (only render visible items) ──\n\u002F\u002F Use vue-virtual-scroller or @tanstack\u002Fvue-virtual for 10,000+ item lists.\n\u002F\u002F Renders only 20-50 visible items, not 10,000 — O(visible) not O(total).\n",[31,1814,1815,1820,1825,1830,1834,1839,1844,1848,1853,1858,1862,1867,1872,1876,1881,1886],{"__ignoreMap":29},[34,1816,1817],{"class":36,"line":37},[34,1818,1819],{"class":40},"\u002F\u002F ── 1. Avoid deep watchers on large objects (O(n) traversal) ──\n",[34,1821,1822],{"class":36,"line":44},[34,1823,1824],{"class":40},"\u002F\u002F watch(state, cb, { deep: true })  — walks EVERY property to track them.\n",[34,1826,1827],{"class":36,"line":50},[34,1828,1829],{"class":40},"\u002F\u002F For 1000-key objects: 1000 track calls. Use specific path watchers instead.\n",[34,1831,1832],{"class":36,"line":56},[34,1833,60],{"emptyLinePlaceholder":59},[34,1835,1836],{"class":36,"line":63},[34,1837,1838],{"class":40},"\u002F\u002F ── 2. Use computed for derived values (cached, lazy) ──\n",[34,1840,1841],{"class":36,"line":69},[34,1842,1843],{"class":40},"\u002F\u002F Don't recalculate in methods — computed only re-evaluates when deps change.\n",[34,1845,1846],{"class":36,"line":75},[34,1847,60],{"emptyLinePlaceholder":59},[34,1849,1850],{"class":36,"line":81},[34,1851,1852],{"class":40},"\u002F\u002F ── 3. v-show for frequently toggled elements (no unmount\u002Fmount cost) ──\n",[34,1854,1855],{"class":36,"line":87},[34,1856,1857],{"class":40},"\u002F\u002F v-if for rarely shown elements (zero cost when hidden)\n",[34,1859,1860],{"class":36,"line":93},[34,1861,60],{"emptyLinePlaceholder":59},[34,1863,1864],{"class":36,"line":99},[34,1865,1866],{"class":40},"\u002F\u002F ── 4. Key by stable ID, never by index (see chapter 02) ──\n",[34,1868,1869],{"class":36,"line":105},[34,1870,1871],{"class":40},"\u002F\u002F Index keys cause unnecessary DOM reuse → incorrect state, wasted patches.\n",[34,1873,1874],{"class":36,"line":111},[34,1875,60],{"emptyLinePlaceholder":59},[34,1877,1878],{"class":36,"line":117},[34,1879,1880],{"class":40},"\u002F\u002F ── 5. Large lists: virtualize (only render visible items) ──\n",[34,1882,1883],{"class":36,"line":123},[34,1884,1885],{"class":40},"\u002F\u002F Use vue-virtual-scroller or @tanstack\u002Fvue-virtual for 10,000+ item lists.\n",[34,1887,1888],{"class":36,"line":129},[34,1889,1890],{"class":40},"\u002F\u002F Renders only 20-50 visible items, not 10,000 — O(visible) not O(total).\n",[15,1892,1894],{"id":1893},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,1896,1898],{"filename":1897,"language":23},"edge-cases.ts",[25,1899,1901],{"className":27,"code":1900,"language":23,"meta":29,"style":29},"\u002F\u002F ── 1. v-memo adds overhead — only use when deps are stable ──\n\u002F\u002F v-memo with frequently-changing deps: dep comparison + full re-render = slower.\n\u002F\u002F Only use when deps change rarely compared to other state in the component.\n\n\u002F\u002F ── 2. shallowRef + v-model breaks two-way binding ──\n\u002F\u002F v-model on a shallowRef's nested property doesn't trigger re-render.\n\u002F\u002F Use ref() for form state (needs deep tracking); shallowRef for display data.\n\n\u002F\u002F ── 3. v-once makes content PERMANENTLY static ──\n\u002F\u002F If the content depends on reactive state that changes later, v-once\n\u002F\u002F freezes the first render — subsequent state changes are ignored.\n\n\u002F\u002F ── 4. Manual chunks can cause initial load delay ──\n\u002F\u002F If the entry chunk depends on a vendor chunk, the browser waits for both.\n\u002F\u002F Critical-path vendor code should be in the entry chunk, not a separate chunk.\n\n\u002F\u002F ── 5. Computed getters with side effects break caching ──\n\u002F\u002F A getter that reads a non-reactive external value won't re-compute\n\u002F\u002F when that value changes — stale result, no re-trigger.\n\n\u002F\u002F ── 6. deep: true on watch is O(n), not O(1) ──\n\u002F\u002F For deeply nested objects, deep traversal is expensive.\n\u002F\u002F Prefer watching specific paths: () => state.user.profile.name.\n",[31,1902,1903,1908,1913,1918,1922,1927,1932,1937,1941,1946,1951,1956,1960,1965,1970,1975,1979,1984,1989,1994,1998,2003,2008],{"__ignoreMap":29},[34,1904,1905],{"class":36,"line":37},[34,1906,1907],{"class":40},"\u002F\u002F ── 1. v-memo adds overhead — only use when deps are stable ──\n",[34,1909,1910],{"class":36,"line":44},[34,1911,1912],{"class":40},"\u002F\u002F v-memo with frequently-changing deps: dep comparison + full re-render = slower.\n",[34,1914,1915],{"class":36,"line":50},[34,1916,1917],{"class":40},"\u002F\u002F Only use when deps change rarely compared to other state in the component.\n",[34,1919,1920],{"class":36,"line":56},[34,1921,60],{"emptyLinePlaceholder":59},[34,1923,1924],{"class":36,"line":63},[34,1925,1926],{"class":40},"\u002F\u002F ── 2. shallowRef + v-model breaks two-way binding ──\n",[34,1928,1929],{"class":36,"line":69},[34,1930,1931],{"class":40},"\u002F\u002F v-model on a shallowRef's nested property doesn't trigger re-render.\n",[34,1933,1934],{"class":36,"line":75},[34,1935,1936],{"class":40},"\u002F\u002F Use ref() for form state (needs deep tracking); shallowRef for display data.\n",[34,1938,1939],{"class":36,"line":81},[34,1940,60],{"emptyLinePlaceholder":59},[34,1942,1943],{"class":36,"line":87},[34,1944,1945],{"class":40},"\u002F\u002F ── 3. v-once makes content PERMANENTLY static ──\n",[34,1947,1948],{"class":36,"line":93},[34,1949,1950],{"class":40},"\u002F\u002F If the content depends on reactive state that changes later, v-once\n",[34,1952,1953],{"class":36,"line":99},[34,1954,1955],{"class":40},"\u002F\u002F freezes the first render — subsequent state changes are ignored.\n",[34,1957,1958],{"class":36,"line":105},[34,1959,60],{"emptyLinePlaceholder":59},[34,1961,1962],{"class":36,"line":111},[34,1963,1964],{"class":40},"\u002F\u002F ── 4. Manual chunks can cause initial load delay ──\n",[34,1966,1967],{"class":36,"line":117},[34,1968,1969],{"class":40},"\u002F\u002F If the entry chunk depends on a vendor chunk, the browser waits for both.\n",[34,1971,1972],{"class":36,"line":123},[34,1973,1974],{"class":40},"\u002F\u002F Critical-path vendor code should be in the entry chunk, not a separate chunk.\n",[34,1976,1977],{"class":36,"line":129},[34,1978,60],{"emptyLinePlaceholder":59},[34,1980,1981],{"class":36,"line":135},[34,1982,1983],{"class":40},"\u002F\u002F ── 5. Computed getters with side effects break caching ──\n",[34,1985,1986],{"class":36,"line":141},[34,1987,1988],{"class":40},"\u002F\u002F A getter that reads a non-reactive external value won't re-compute\n",[34,1990,1991],{"class":36,"line":146},[34,1992,1993],{"class":40},"\u002F\u002F when that value changes — stale result, no re-trigger.\n",[34,1995,1996],{"class":36,"line":152},[34,1997,60],{"emptyLinePlaceholder":59},[34,1999,2000],{"class":36,"line":158},[34,2001,2002],{"class":40},"\u002F\u002F ── 6. deep: true on watch is O(n), not O(1) ──\n",[34,2004,2005],{"class":36,"line":164},[34,2006,2007],{"class":40},"\u002F\u002F For deeply nested objects, deep traversal is expensive.\n",[34,2009,2010],{"class":36,"line":170},[34,2011,2012],{"class":40},"\u002F\u002F Prefer watching specific paths: () => state.user.profile.name.\n",[15,2014,2016],{"id":2015},"spot-the-bug","🧠 Spot the Bug",[2018,2019,2020],"p",{},"A list of 10,000 items re-renders entirely when one item's status changes.",[20,2022,2024],{"filename":2023,"language":281},"PerfBug.vue",[25,2025,2027],{"className":284,"code":2026,"language":281,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref } from 'vue'\nconst items = ref(Array.from({ length: 10000 }, (_, i) => ({\n  id: i, name: `Item ${i}`, status: 'active',\n})))\nfunction toggleStatus(id) {\n  const item = items.value.find(i => i.id === id)\n  if (item) item.status = item.status === 'active' ? 'inactive' : 'active'\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-for=\"item in items\" :key=\"item.id\" class=\"item\">\n    {{ item.name }} — {{ item.status }}\n    \u003Cbutton @click=\"toggleStatus(item.id)\">Toggle\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[31,2028,2029,2039,2049,2083,2101,2106,2119,2143,2172,2176,2184,2188,2196,2224,2228,2250,2258],{"__ignoreMap":29},[34,2030,2031,2033,2035,2037],{"class":36,"line":37},[34,2032,292],{"class":187},[34,2034,296],{"class":295},[34,2036,299],{"class":183},[34,2038,302],{"class":187},[34,2040,2041,2043,2045,2047],{"class":36,"line":44},[34,2042,307],{"class":179},[34,2044,310],{"class":187},[34,2046,313],{"class":179},[34,2048,316],{"class":209},[34,2050,2051,2053,2055,2057,2059,2062,2064,2066,2069,2071,2073,2075,2077,2079,2081],{"class":36,"line":50},[34,2052,344],{"class":179},[34,2054,347],{"class":234},[34,2056,350],{"class":179},[34,2058,353],{"class":183},[34,2060,2061],{"class":187},"(Array.",[34,2063,313],{"class":183},[34,2065,366],{"class":187},[34,2067,2068],{"class":234},"10000",[34,2070,372],{"class":187},[34,2072,375],{"class":191},[34,2074,378],{"class":187},[34,2076,381],{"class":191},[34,2078,384],{"class":187},[34,2080,387],{"class":179},[34,2082,390],{"class":187},[34,2084,2085,2088,2090,2092,2094,2097,2099],{"class":36,"line":56},[34,2086,2087],{"class":187},"  id: i, name: ",[34,2089,403],{"class":209},[34,2091,381],{"class":187},[34,2093,408],{"class":209},[34,2095,2096],{"class":187},", status: ",[34,2098,419],{"class":209},[34,2100,411],{"class":187},[34,2102,2103],{"class":36,"line":63},[34,2104,2105],{"class":187},"})))\n",[34,2107,2108,2110,2113,2115,2117],{"class":36,"line":69},[34,2109,180],{"class":179},[34,2111,2112],{"class":183}," toggleStatus",[34,2114,188],{"class":187},[34,2116,457],{"class":191},[34,2118,195],{"class":187},[34,2120,2121,2123,2125,2127,2129,2131,2133,2135,2137,2139,2141],{"class":36,"line":75},[34,2122,469],{"class":179},[34,2124,472],{"class":234},[34,2126,350],{"class":179},[34,2128,477],{"class":187},[34,2130,480],{"class":183},[34,2132,188],{"class":187},[34,2134,381],{"class":191},[34,2136,487],{"class":179},[34,2138,490],{"class":187},[34,2140,493],{"class":179},[34,2142,496],{"class":187},[34,2144,2145,2147,2150,2152,2155,2157,2160,2163,2166,2169],{"class":36,"line":81},[34,2146,501],{"class":179},[34,2148,2149],{"class":187}," (item) item.status ",[34,2151,572],{"class":179},[34,2153,2154],{"class":187}," item.status ",[34,2156,493],{"class":179},[34,2158,2159],{"class":209}," 'active'",[34,2161,2162],{"class":179}," ?",[34,2164,2165],{"class":209}," 'inactive'",[34,2167,2168],{"class":179}," :",[34,2170,2171],{"class":209}," 'active'\n",[34,2173,2174],{"class":36,"line":87},[34,2175,244],{"class":187},[34,2177,2178,2180,2182],{"class":36,"line":93},[34,2179,524],{"class":187},[34,2181,296],{"class":295},[34,2183,302],{"class":187},[34,2185,2186],{"class":36,"line":99},[34,2187,60],{"emptyLinePlaceholder":59},[34,2189,2190,2192,2194],{"class":36,"line":105},[34,2191,292],{"class":187},[34,2193,539],{"class":295},[34,2195,302],{"class":187},[34,2197,2198,2200,2202,2204,2206,2208,2210,2212,2214,2217,2219,2222],{"class":36,"line":111},[34,2199,561],{"class":187},[34,2201,623],{"class":295},[34,2203,677],{"class":183},[34,2205,572],{"class":187},[34,2207,682],{"class":209},[34,2209,685],{"class":183},[34,2211,572],{"class":187},[34,2213,690],{"class":209},[34,2215,2216],{"class":183}," class",[34,2218,572],{"class":187},[34,2220,2221],{"class":209},"\"item\"",[34,2223,302],{"class":187},[34,2225,2226],{"class":36,"line":117},[34,2227,615],{"class":187},[34,2229,2230,2232,2235,2238,2240,2243,2246,2248],{"class":36,"line":123},[34,2231,1127],{"class":187},[34,2233,2234],{"class":295},"button",[34,2236,2237],{"class":183}," @click",[34,2239,572],{"class":187},[34,2241,2242],{"class":209},"\"toggleStatus(item.id)\"",[34,2244,2245],{"class":187},">Toggle\u003C\u002F",[34,2247,2234],{"class":295},[34,2249,302],{"class":187},[34,2251,2252,2254,2256],{"class":36,"line":129},[34,2253,620],{"class":187},[34,2255,623],{"class":295},[34,2257,302],{"class":187},[34,2259,2260,2262,2264],{"class":36,"line":135},[34,2261,524],{"class":187},[34,2263,539],{"class":295},[34,2265,302],{"class":187},[2267,2268,2269,2273,2284,2295,2396],"details",{},[2270,2271,2272],"summary",{},"Answer",[2018,2274,2275,2276,2279,2280,2283],{},"When ",[31,2277,2278],{},"toggleStatus"," mutates one item, Vue's reactivity triggers a re-render of the entire component. The ",[31,2281,2282],{},"v-for"," re-evaluates, creating new VNodes for all 10,000 items. Even though only one item changed, the diff algorithm still processes all 10,000 VNodes (each is cheap, but 10,000 × cheap adds up).",[2018,2285,2286,2290,2291,2294],{},[2287,2288,2289],"strong",{},"Fix"," — add ",[31,2292,2293],{},"v-memo"," with the item's status as a dependency:",[20,2296,2298],{"filename":2297,"language":281},"PerfFixed.vue",[25,2299,2301],{"className":284,"code":2300,"language":281,"meta":29,"style":29},"\u003Ctemplate>\n  \u003C!-- v-memo: skip re-render unless id or status changes -->\n  \u003Cdiv\n    v-for=\"item in items\"\n    :key=\"item.id\"\n    v-memo=\"[item.id, item.status]\"\n    class=\"item\"\n  >\n    {{ item.name }} — {{ item.status }}\n    \u003Cbutton @click=\"toggleStatus(item.id)\">Toggle\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[31,2302,2303,2311,2316,2322,2330,2338,2346,2354,2358,2362,2380,2388],{"__ignoreMap":29},[34,2304,2305,2307,2309],{"class":36,"line":37},[34,2306,292],{"class":187},[34,2308,539],{"class":295},[34,2310,302],{"class":187},[34,2312,2313],{"class":36,"line":44},[34,2314,2315],{"class":40},"  \u003C!-- v-memo: skip re-render unless id or status changes -->\n",[34,2317,2318,2320],{"class":36,"line":50},[34,2319,561],{"class":187},[34,2321,564],{"class":295},[34,2323,2324,2326,2328],{"class":36,"line":56},[34,2325,569],{"class":183},[34,2327,572],{"class":187},[34,2329,575],{"class":209},[34,2331,2332,2334,2336],{"class":36,"line":63},[34,2333,580],{"class":183},[34,2335,572],{"class":187},[34,2337,585],{"class":209},[34,2339,2340,2342,2344],{"class":36,"line":69},[34,2341,590],{"class":183},[34,2343,572],{"class":187},[34,2345,595],{"class":209},[34,2347,2348,2350,2352],{"class":36,"line":75},[34,2349,600],{"class":183},[34,2351,572],{"class":187},[34,2353,605],{"class":209},[34,2355,2356],{"class":36,"line":81},[34,2357,610],{"class":187},[34,2359,2360],{"class":36,"line":87},[34,2361,615],{"class":187},[34,2363,2364,2366,2368,2370,2372,2374,2376,2378],{"class":36,"line":93},[34,2365,1127],{"class":187},[34,2367,2234],{"class":295},[34,2369,2237],{"class":183},[34,2371,572],{"class":187},[34,2373,2242],{"class":209},[34,2375,2245],{"class":187},[34,2377,2234],{"class":295},[34,2379,302],{"class":187},[34,2381,2382,2384,2386],{"class":36,"line":99},[34,2383,620],{"class":187},[34,2385,623],{"class":295},[34,2387,302],{"class":187},[34,2389,2390,2392,2394],{"class":36,"line":105},[34,2391,524],{"class":187},[34,2393,539],{"class":295},[34,2395,302],{"class":187},[2018,2397,2398,2399,2402,2403,2405],{},"Now, when one item's status changes, only that item's VNode is re-created. The other 9,999 VNodes are reused from the cache — the diff skips them entirely. ",[2287,2400,2401],{},"The lesson",": ",[31,2404,2293],{}," with stable deps prevents the VNode from being recreated, turning an O(n) re-render into O(1) for unchanged items.",[2407,2408,2409],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .sMKGj, html code.shiki .sMKGj{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-github-dark:#FDAEB7;--shiki-github-dark-font-style:italic}",{"title":29,"searchDepth":44,"depth":44,"links":2411},[2412,2413,2416,2417,2418,2419,2420,2421,2422],{"id":17,"depth":44,"text":18},{"id":276,"depth":44,"text":277,"children":2414},[2415],{"id":638,"depth":50,"text":639},{"id":726,"depth":44,"text":727},{"id":955,"depth":44,"text":956},{"id":1198,"depth":44,"text":1199},{"id":1655,"depth":44,"text":1656},{"id":1805,"depth":44,"text":1806},{"id":1893,"depth":44,"text":1894},{"id":2015,"depth":44,"text":2016},"Patch flag compiler hints, v-memo for expensive list items, shallowRef for large data, v-once for static content, manual chunk splitting, and runtime profiler analysis.","md",{},"\u002Fvue\u002F19-performance-optimization",{"title":5,"description":2423},"vue\u002F19-performance-optimization","ZY1pdXyaSLT2tk8UvCc-L0e7FxxaRNkAsWowgghscL0",1789924655823]