[{"data":1,"prerenderedAt":3485},["ShallowReactive",2],{"page-\u002Fvue\u002F01-introduction-and-setup":3},{"id":4,"title":5,"body":6,"description":3478,"extension":3479,"meta":3480,"navigation":95,"path":3481,"seo":3482,"stem":3483,"__hash__":3484},"content\u002Fvue\u002F01-introduction-and-setup.md","Vue 3 Engineering Reference — Introduction & Setup",{"type":7,"value":8,"toc":3463},"minimark",[9,14,19,32,422,426,1036,1041,1180,1184,1548,1552,1887,1891,2008,2012,2229,2233,2575,2579,2788,2792,3132,3136,3139,3290,3460],[10,11,13],"h1",{"id":12},"_01-introduction-setup","01 — Introduction & Setup",[15,16,18],"h2",{"id":17},"vue-3-reactivity-engine-how-it-actually-works","Vue 3 Reactivity Engine — How It Actually Works",[20,21,22,23,27,28,31],"p",{},"Vue 3 replaces Vue 2's ",[24,25,26],"code",{},"Object.defineProperty"," getter\u002Fsetter approach with ES6 ",[24,29,30],{},"Proxy",". This isn't a detail — it's the root cause of every behavioral difference between Vue 2 and Vue 3.",[33,34,37],"code-wrapper",{"language":35,"filename":36},"javascript","reactivity-internals.js",[38,39,43],"pre",{"className":40,"code":41,"language":35,"meta":42,"style":42},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ── Vue 2: Object.defineProperty ──────────────────────────\n\u002F\u002F Walks every property ONCE at init, installs getter\u002Fsetter per key.\n\u002F\u002F Blind spots:\n\u002F\u002F   - obj.newProp = val  → NOT reactive (setter never installed)\n\u002F\u002F   - arr[5] = val       → NOT reactive (index setter never installed)\n\u002F\u002F   - arr.length = 0     → NOT reactive\n\u002F\u002F Workaround: Vue.set(obj, 'newProp', val) — manually triggers reactivity.\n\n\u002F\u002F ── Vue 3: Proxy ─────────────────────────────────────────\n\u002F\u002F Intercepts ALL operations on the object — no property walk, no blind spots.\nconst handler = {\n  get(target, key, receiver) {\n    track(target, key)           \u002F\u002F register this effect as a dependency\n    return Reflect.get(target, key, receiver)\n  },\n  set(target, key, value, receiver) {\n    const result = Reflect.set(target, key, value, receiver)\n    trigger(target, key)         \u002F\u002F notify all registered effects\n    return result\n  },\n  deleteProperty(target, key) {\n    const result = Reflect.deleteProperty(target, key)\n    trigger(target, key)         \u002F\u002F deletion is reactive in Vue 3\n    return result\n  }\n}\n\nconst reactiveObj = new Proxy({ count: 0, items: [] }, handler)\n\nreactiveObj.newProp = 'hello'     \u002F\u002F ✅ reactive — Proxy intercepts the set\nreactiveObj.items.push(42)        \u002F\u002F ✅ reactive — array methods go through Proxy\nreactiveObj.items[10] = 'x'       \u002F\u002F ✅ reactive — index assignment works\ndelete reactiveObj.count          \u002F\u002F ✅ reactive — deletion triggers effects\n","",[24,44,45,54,60,66,72,78,84,90,97,103,109,127,155,167,182,188,213,232,244,252,257,273,290,300,307,313,319,324,349,354,370,390,410],{"__ignoreMap":42},[46,47,50],"span",{"class":48,"line":49},"line",1,[46,51,53],{"class":52},"sdCPZ","\u002F\u002F ── Vue 2: Object.defineProperty ──────────────────────────\n",[46,55,57],{"class":48,"line":56},2,[46,58,59],{"class":52},"\u002F\u002F Walks every property ONCE at init, installs getter\u002Fsetter per key.\n",[46,61,63],{"class":48,"line":62},3,[46,64,65],{"class":52},"\u002F\u002F Blind spots:\n",[46,67,69],{"class":48,"line":68},4,[46,70,71],{"class":52},"\u002F\u002F   - obj.newProp = val  → NOT reactive (setter never installed)\n",[46,73,75],{"class":48,"line":74},5,[46,76,77],{"class":52},"\u002F\u002F   - arr[5] = val       → NOT reactive (index setter never installed)\n",[46,79,81],{"class":48,"line":80},6,[46,82,83],{"class":52},"\u002F\u002F   - arr.length = 0     → NOT reactive\n",[46,85,87],{"class":48,"line":86},7,[46,88,89],{"class":52},"\u002F\u002F Workaround: Vue.set(obj, 'newProp', val) — manually triggers reactivity.\n",[46,91,93],{"class":48,"line":92},8,[46,94,96],{"emptyLinePlaceholder":95},true,"\n",[46,98,100],{"class":48,"line":99},9,[46,101,102],{"class":52},"\u002F\u002F ── Vue 3: Proxy ─────────────────────────────────────────\n",[46,104,106],{"class":48,"line":105},10,[46,107,108],{"class":52},"\u002F\u002F Intercepts ALL operations on the object — no property walk, no blind spots.\n",[46,110,112,116,120,123],{"class":48,"line":111},11,[46,113,115],{"class":114},"svdQ7","const",[46,117,119],{"class":118},"snvgF"," handler",[46,121,122],{"class":114}," =",[46,124,126],{"class":125},"ssxIu"," {\n",[46,128,130,134,137,141,144,147,149,152],{"class":48,"line":129},12,[46,131,133],{"class":132},"sIsaT","  get",[46,135,136],{"class":125},"(",[46,138,140],{"class":139},"sCrzJ","target",[46,142,143],{"class":125},", ",[46,145,146],{"class":139},"key",[46,148,143],{"class":125},[46,150,151],{"class":139},"receiver",[46,153,154],{"class":125},") {\n",[46,156,158,161,164],{"class":48,"line":157},13,[46,159,160],{"class":132},"    track",[46,162,163],{"class":125},"(target, key)           ",[46,165,166],{"class":52},"\u002F\u002F register this effect as a dependency\n",[46,168,170,173,176,179],{"class":48,"line":169},14,[46,171,172],{"class":114},"    return",[46,174,175],{"class":125}," Reflect.",[46,177,178],{"class":132},"get",[46,180,181],{"class":125},"(target, key, receiver)\n",[46,183,185],{"class":48,"line":184},15,[46,186,187],{"class":125},"  },\n",[46,189,191,194,196,198,200,202,204,207,209,211],{"class":48,"line":190},16,[46,192,193],{"class":132},"  set",[46,195,136],{"class":125},[46,197,140],{"class":139},[46,199,143],{"class":125},[46,201,146],{"class":139},[46,203,143],{"class":125},[46,205,206],{"class":139},"value",[46,208,143],{"class":125},[46,210,151],{"class":139},[46,212,154],{"class":125},[46,214,216,219,222,224,226,229],{"class":48,"line":215},17,[46,217,218],{"class":114},"    const",[46,220,221],{"class":118}," result",[46,223,122],{"class":114},[46,225,175],{"class":125},[46,227,228],{"class":132},"set",[46,230,231],{"class":125},"(target, key, value, receiver)\n",[46,233,235,238,241],{"class":48,"line":234},18,[46,236,237],{"class":132},"    trigger",[46,239,240],{"class":125},"(target, key)         ",[46,242,243],{"class":52},"\u002F\u002F notify all registered effects\n",[46,245,247,249],{"class":48,"line":246},19,[46,248,172],{"class":114},[46,250,251],{"class":125}," result\n",[46,253,255],{"class":48,"line":254},20,[46,256,187],{"class":125},[46,258,260,263,265,267,269,271],{"class":48,"line":259},21,[46,261,262],{"class":132},"  deleteProperty",[46,264,136],{"class":125},[46,266,140],{"class":139},[46,268,143],{"class":125},[46,270,146],{"class":139},[46,272,154],{"class":125},[46,274,276,278,280,282,284,287],{"class":48,"line":275},22,[46,277,218],{"class":114},[46,279,221],{"class":118},[46,281,122],{"class":114},[46,283,175],{"class":125},[46,285,286],{"class":132},"deleteProperty",[46,288,289],{"class":125},"(target, key)\n",[46,291,293,295,297],{"class":48,"line":292},23,[46,294,237],{"class":132},[46,296,240],{"class":125},[46,298,299],{"class":52},"\u002F\u002F deletion is reactive in Vue 3\n",[46,301,303,305],{"class":48,"line":302},24,[46,304,172],{"class":114},[46,306,251],{"class":125},[46,308,310],{"class":48,"line":309},25,[46,311,312],{"class":125},"  }\n",[46,314,316],{"class":48,"line":315},26,[46,317,318],{"class":125},"}\n",[46,320,322],{"class":48,"line":321},27,[46,323,96],{"emptyLinePlaceholder":95},[46,325,327,329,332,334,337,340,343,346],{"class":48,"line":326},28,[46,328,115],{"class":114},[46,330,331],{"class":118}," reactiveObj",[46,333,122],{"class":114},[46,335,336],{"class":114}," new",[46,338,339],{"class":132}," Proxy",[46,341,342],{"class":125},"({ count: ",[46,344,345],{"class":118},"0",[46,347,348],{"class":125},", items: [] }, handler)\n",[46,350,352],{"class":48,"line":351},29,[46,353,96],{"emptyLinePlaceholder":95},[46,355,357,360,363,367],{"class":48,"line":356},30,[46,358,359],{"class":125},"reactiveObj.newProp ",[46,361,362],{"class":114},"=",[46,364,366],{"class":365},"sJ6F3"," 'hello'",[46,368,369],{"class":52},"     \u002F\u002F ✅ reactive — Proxy intercepts the set\n",[46,371,373,376,379,381,384,387],{"class":48,"line":372},31,[46,374,375],{"class":125},"reactiveObj.items.",[46,377,378],{"class":132},"push",[46,380,136],{"class":125},[46,382,383],{"class":118},"42",[46,385,386],{"class":125},")        ",[46,388,389],{"class":52},"\u002F\u002F ✅ reactive — array methods go through Proxy\n",[46,391,393,396,399,402,404,407],{"class":48,"line":392},32,[46,394,395],{"class":125},"reactiveObj.items[",[46,397,398],{"class":118},"10",[46,400,401],{"class":125},"] ",[46,403,362],{"class":114},[46,405,406],{"class":365}," 'x'",[46,408,409],{"class":52},"       \u002F\u002F ✅ reactive — index assignment works\n",[46,411,413,416,419],{"class":48,"line":412},33,[46,414,415],{"class":114},"delete",[46,417,418],{"class":125}," reactiveObj.count          ",[46,420,421],{"class":52},"\u002F\u002F ✅ reactive — deletion triggers effects\n",[15,423,425],{"id":424},"production-app-bootstrap-multi-instance-with-plugin-isolation","Production App Bootstrap — Multi-Instance with Plugin Isolation",[33,427,430],{"language":428,"filename":429},"typescript","src\u002Fmain.ts",[38,431,434],{"className":432,"code":433,"language":428,"meta":42,"style":42},"language-typescript shiki shiki-themes github-light github-dark","import { createApp, type App, type Directive } from 'vue'\nimport { createPinia } from 'pinia'\nimport { createRouter, createWebHistory, type Router } from 'vue-router'\nimport AppRoot from '.\u002FApp.vue'\nimport { authDirective } from '.\u002Fdirectives\u002Fauth'\nimport { errorHandler } from '.\u002Futils\u002FerrorBoundary'\n\n\u002F\u002F ── Factory: each call returns an isolated app instance ──\n\u002F\u002F Vue 3's createApp() replaces the global Vue singleton.\n\u002F\u002F Multiple apps on one page get independent plugins, directives, and config —\n\u002F\u002F no global mutation leaks between instances.\nexport function createApplication(el: string = '#app'): App {\n  const app: App = createApp(AppRoot)\n\n  \u002F\u002F ── Global error handler: catches errors from render, watchers, lifecycle ──\n  \u002F\u002F (err, instance, info) — `info` is a lifecycle hook name like \"render\"\n  app.config.errorHandler = (err, instance, info) => {\n    errorHandler.capture(err, { component: instance?.$options?.name, info })\n  }\n\n  \u002F\u002F ── Performance marks in dev — visible in Chrome Performance tab ──\n  app.config.performance = import.meta.env.DEV\n\n  \u002F\u002F ── Custom directive registered globally before mount ──\n  \u002F\u002F Available to ALL components without per-file import.\n  app.directive('auth', authDirective as Directive)\n\n  \u002F\u002F ── Plugins are app-scoped, not global ──\n  const pinia = createPinia()\n  const router: Router = createRouter({\n    history: createWebHistory(import.meta.env.BASE_URL),\n    routes: [], \u002F\u002F routes injected via composable in production\n    scrollBehavior(to, from, savedPosition) {\n      return savedPosition ?? (to.hash ? { el: to.hash } : { top: 0 })\n    },\n  })\n\n  app.use(pinia)\n  app.use(router)\n\n  \u002F\u002F ── Provide app-level values, injectable via inject() in any descendant ──\n  app.provide('apiBase', import.meta.env.VITE_API_BASE ?? '\u002Fapi')\n\n  app.mount(el)\n  return app\n}\n\n\u002F\u002F ── Multi-mount: run two independent Vue apps on one page ──\nconst headerApp = createApplication('#header-app')\nconst mainApp = createApplication('#main-app')\n\u002F\u002F headerApp and mainApp share NO state, NO plugins, NO config.\n",[24,435,436,461,473,490,502,514,526,530,535,540,545,550,587,607,611,616,621,655,666,670,674,679,701,705,710,715,740,744,749,764,784,808,816,837,868,874,880,885,896,906,911,917,951,956,967,976,981,986,992,1011,1030],{"__ignoreMap":42},[46,437,438,441,444,447,450,452,455,458],{"class":48,"line":49},[46,439,440],{"class":114},"import",[46,442,443],{"class":125}," { createApp, ",[46,445,446],{"class":114},"type",[46,448,449],{"class":125}," App, ",[46,451,446],{"class":114},[46,453,454],{"class":125}," Directive } ",[46,456,457],{"class":114},"from",[46,459,460],{"class":365}," 'vue'\n",[46,462,463,465,468,470],{"class":48,"line":56},[46,464,440],{"class":114},[46,466,467],{"class":125}," { createPinia } ",[46,469,457],{"class":114},[46,471,472],{"class":365}," 'pinia'\n",[46,474,475,477,480,482,485,487],{"class":48,"line":62},[46,476,440],{"class":114},[46,478,479],{"class":125}," { createRouter, createWebHistory, ",[46,481,446],{"class":114},[46,483,484],{"class":125}," Router } ",[46,486,457],{"class":114},[46,488,489],{"class":365}," 'vue-router'\n",[46,491,492,494,497,499],{"class":48,"line":68},[46,493,440],{"class":114},[46,495,496],{"class":125}," AppRoot ",[46,498,457],{"class":114},[46,500,501],{"class":365}," '.\u002FApp.vue'\n",[46,503,504,506,509,511],{"class":48,"line":74},[46,505,440],{"class":114},[46,507,508],{"class":125}," { authDirective } ",[46,510,457],{"class":114},[46,512,513],{"class":365}," '.\u002Fdirectives\u002Fauth'\n",[46,515,516,518,521,523],{"class":48,"line":80},[46,517,440],{"class":114},[46,519,520],{"class":125}," { errorHandler } ",[46,522,457],{"class":114},[46,524,525],{"class":365}," '.\u002Futils\u002FerrorBoundary'\n",[46,527,528],{"class":48,"line":86},[46,529,96],{"emptyLinePlaceholder":95},[46,531,532],{"class":48,"line":92},[46,533,534],{"class":52},"\u002F\u002F ── Factory: each call returns an isolated app instance ──\n",[46,536,537],{"class":48,"line":99},[46,538,539],{"class":52},"\u002F\u002F Vue 3's createApp() replaces the global Vue singleton.\n",[46,541,542],{"class":48,"line":105},[46,543,544],{"class":52},"\u002F\u002F Multiple apps on one page get independent plugins, directives, and config —\n",[46,546,547],{"class":48,"line":111},[46,548,549],{"class":52},"\u002F\u002F no global mutation leaks between instances.\n",[46,551,552,555,558,561,563,566,569,572,574,577,580,582,585],{"class":48,"line":129},[46,553,554],{"class":114},"export",[46,556,557],{"class":114}," function",[46,559,560],{"class":132}," createApplication",[46,562,136],{"class":125},[46,564,565],{"class":139},"el",[46,567,568],{"class":114},":",[46,570,571],{"class":118}," string",[46,573,122],{"class":114},[46,575,576],{"class":365}," '#app'",[46,578,579],{"class":125},")",[46,581,568],{"class":114},[46,583,584],{"class":132}," App",[46,586,126],{"class":125},[46,588,589,592,595,597,599,601,604],{"class":48,"line":157},[46,590,591],{"class":114},"  const",[46,593,594],{"class":118}," app",[46,596,568],{"class":114},[46,598,584],{"class":132},[46,600,122],{"class":114},[46,602,603],{"class":132}," createApp",[46,605,606],{"class":125},"(AppRoot)\n",[46,608,609],{"class":48,"line":169},[46,610,96],{"emptyLinePlaceholder":95},[46,612,613],{"class":48,"line":184},[46,614,615],{"class":52},"  \u002F\u002F ── Global error handler: catches errors from render, watchers, lifecycle ──\n",[46,617,618],{"class":48,"line":190},[46,619,620],{"class":52},"  \u002F\u002F (err, instance, info) — `info` is a lifecycle hook name like \"render\"\n",[46,622,623,626,629,631,634,637,639,642,644,647,650,653],{"class":48,"line":215},[46,624,625],{"class":125},"  app.config.",[46,627,628],{"class":132},"errorHandler",[46,630,122],{"class":114},[46,632,633],{"class":125}," (",[46,635,636],{"class":139},"err",[46,638,143],{"class":125},[46,640,641],{"class":139},"instance",[46,643,143],{"class":125},[46,645,646],{"class":139},"info",[46,648,649],{"class":125},") ",[46,651,652],{"class":114},"=>",[46,654,126],{"class":125},[46,656,657,660,663],{"class":48,"line":234},[46,658,659],{"class":125},"    errorHandler.",[46,661,662],{"class":132},"capture",[46,664,665],{"class":125},"(err, { component: instance?.$options?.name, info })\n",[46,667,668],{"class":48,"line":246},[46,669,312],{"class":125},[46,671,672],{"class":48,"line":254},[46,673,96],{"emptyLinePlaceholder":95},[46,675,676],{"class":48,"line":259},[46,677,678],{"class":52},"  \u002F\u002F ── Performance marks in dev — visible in Chrome Performance tab ──\n",[46,680,681,684,686,689,692,695,698],{"class":48,"line":275},[46,682,683],{"class":125},"  app.config.performance ",[46,685,362],{"class":114},[46,687,688],{"class":114}," import",[46,690,691],{"class":125},".",[46,693,694],{"class":118},"meta",[46,696,697],{"class":125},".env.",[46,699,700],{"class":118},"DEV\n",[46,702,703],{"class":48,"line":292},[46,704,96],{"emptyLinePlaceholder":95},[46,706,707],{"class":48,"line":302},[46,708,709],{"class":52},"  \u002F\u002F ── Custom directive registered globally before mount ──\n",[46,711,712],{"class":48,"line":309},[46,713,714],{"class":52},"  \u002F\u002F Available to ALL components without per-file import.\n",[46,716,717,720,723,725,728,731,734,737],{"class":48,"line":315},[46,718,719],{"class":125},"  app.",[46,721,722],{"class":132},"directive",[46,724,136],{"class":125},[46,726,727],{"class":365},"'auth'",[46,729,730],{"class":125},", authDirective ",[46,732,733],{"class":114},"as",[46,735,736],{"class":132}," Directive",[46,738,739],{"class":125},")\n",[46,741,742],{"class":48,"line":321},[46,743,96],{"emptyLinePlaceholder":95},[46,745,746],{"class":48,"line":326},[46,747,748],{"class":52},"  \u002F\u002F ── Plugins are app-scoped, not global ──\n",[46,750,751,753,756,758,761],{"class":48,"line":351},[46,752,591],{"class":114},[46,754,755],{"class":118}," pinia",[46,757,122],{"class":114},[46,759,760],{"class":132}," createPinia",[46,762,763],{"class":125},"()\n",[46,765,766,768,771,773,776,778,781],{"class":48,"line":356},[46,767,591],{"class":114},[46,769,770],{"class":118}," router",[46,772,568],{"class":114},[46,774,775],{"class":132}," Router",[46,777,122],{"class":114},[46,779,780],{"class":132}," createRouter",[46,782,783],{"class":125},"({\n",[46,785,786,789,792,794,796,798,800,802,805],{"class":48,"line":372},[46,787,788],{"class":125},"    history: ",[46,790,791],{"class":132},"createWebHistory",[46,793,136],{"class":125},[46,795,440],{"class":114},[46,797,691],{"class":125},[46,799,694],{"class":118},[46,801,697],{"class":125},[46,803,804],{"class":118},"BASE_URL",[46,806,807],{"class":125},"),\n",[46,809,810,813],{"class":48,"line":392},[46,811,812],{"class":125},"    routes: [], ",[46,814,815],{"class":52},"\u002F\u002F routes injected via composable in production\n",[46,817,818,821,823,826,828,830,832,835],{"class":48,"line":412},[46,819,820],{"class":132},"    scrollBehavior",[46,822,136],{"class":125},[46,824,825],{"class":139},"to",[46,827,143],{"class":125},[46,829,457],{"class":139},[46,831,143],{"class":125},[46,833,834],{"class":139},"savedPosition",[46,836,154],{"class":125},[46,838,840,843,846,849,852,855,858,860,863,865],{"class":48,"line":839},34,[46,841,842],{"class":114},"      return",[46,844,845],{"class":125}," savedPosition ",[46,847,848],{"class":114},"??",[46,850,851],{"class":125}," (to.hash ",[46,853,854],{"class":114},"?",[46,856,857],{"class":125}," { el: to.hash } ",[46,859,568],{"class":114},[46,861,862],{"class":125}," { top: ",[46,864,345],{"class":118},[46,866,867],{"class":125}," })\n",[46,869,871],{"class":48,"line":870},35,[46,872,873],{"class":125},"    },\n",[46,875,877],{"class":48,"line":876},36,[46,878,879],{"class":125},"  })\n",[46,881,883],{"class":48,"line":882},37,[46,884,96],{"emptyLinePlaceholder":95},[46,886,888,890,893],{"class":48,"line":887},38,[46,889,719],{"class":125},[46,891,892],{"class":132},"use",[46,894,895],{"class":125},"(pinia)\n",[46,897,899,901,903],{"class":48,"line":898},39,[46,900,719],{"class":125},[46,902,892],{"class":132},[46,904,905],{"class":125},"(router)\n",[46,907,909],{"class":48,"line":908},40,[46,910,96],{"emptyLinePlaceholder":95},[46,912,914],{"class":48,"line":913},41,[46,915,916],{"class":52},"  \u002F\u002F ── Provide app-level values, injectable via inject() in any descendant ──\n",[46,918,920,922,925,927,930,932,934,936,938,940,943,946,949],{"class":48,"line":919},42,[46,921,719],{"class":125},[46,923,924],{"class":132},"provide",[46,926,136],{"class":125},[46,928,929],{"class":365},"'apiBase'",[46,931,143],{"class":125},[46,933,440],{"class":114},[46,935,691],{"class":125},[46,937,694],{"class":118},[46,939,697],{"class":125},[46,941,942],{"class":118},"VITE_API_BASE",[46,944,945],{"class":114}," ??",[46,947,948],{"class":365}," '\u002Fapi'",[46,950,739],{"class":125},[46,952,954],{"class":48,"line":953},43,[46,955,96],{"emptyLinePlaceholder":95},[46,957,959,961,964],{"class":48,"line":958},44,[46,960,719],{"class":125},[46,962,963],{"class":132},"mount",[46,965,966],{"class":125},"(el)\n",[46,968,970,973],{"class":48,"line":969},45,[46,971,972],{"class":114},"  return",[46,974,975],{"class":125}," app\n",[46,977,979],{"class":48,"line":978},46,[46,980,318],{"class":125},[46,982,984],{"class":48,"line":983},47,[46,985,96],{"emptyLinePlaceholder":95},[46,987,989],{"class":48,"line":988},48,[46,990,991],{"class":52},"\u002F\u002F ── Multi-mount: run two independent Vue apps on one page ──\n",[46,993,995,997,1000,1002,1004,1006,1009],{"class":48,"line":994},49,[46,996,115],{"class":114},[46,998,999],{"class":118}," headerApp",[46,1001,122],{"class":114},[46,1003,560],{"class":132},[46,1005,136],{"class":125},[46,1007,1008],{"class":365},"'#header-app'",[46,1010,739],{"class":125},[46,1012,1014,1016,1019,1021,1023,1025,1028],{"class":48,"line":1013},50,[46,1015,115],{"class":114},[46,1017,1018],{"class":118}," mainApp",[46,1020,122],{"class":114},[46,1022,560],{"class":132},[46,1024,136],{"class":125},[46,1026,1027],{"class":365},"'#main-app'",[46,1029,739],{"class":125},[46,1031,1033],{"class":48,"line":1032},51,[46,1034,1035],{"class":52},"\u002F\u002F headerApp and mainApp share NO state, NO plugins, NO config.\n",[1037,1038,1040],"h3",{"id":1039},"anti-pattern-mutating-global-config-after-mount","Anti-Pattern: Mutating Global Config After Mount",[33,1042,1044],{"language":428,"filename":1043},"anti-pattern.ts",[38,1045,1047],{"className":432,"code":1046,"language":428,"meta":42,"style":42},"\u002F\u002F ❌ WRONG — config changes after mount are silently ignored by already-created instances\nconst app = createApp(App)\napp.mount('#app')\napp.config.globalProperties.$api = myApiClient  \u002F\u002F too late — existing components already initialized\n\n\u002F\u002F ── The trap: ────────────────────────────────────────────\n\u002F\u002F app.config is read during component setup. Mutating it post-mount\n\u002F\u002F affects only FUTURELY created component instances, not current ones.\n\u002F\u002F In production this causes \"works on navigation, broken on first load\" bugs.\n\n\u002F\u002F ✅ CORRECT — configure everything BEFORE mount\nconst app = createApp(App)\napp.config.globalProperties.$api = myApiClient  \u002F\u002F registered first\napp.use(createPinia())\napp.mount('#app')                                \u002F\u002F mount last\n",[24,1048,1049,1054,1067,1081,1094,1098,1103,1108,1113,1118,1122,1127,1139,1150,1164],{"__ignoreMap":42},[46,1050,1051],{"class":48,"line":49},[46,1052,1053],{"class":52},"\u002F\u002F ❌ WRONG — config changes after mount are silently ignored by already-created instances\n",[46,1055,1056,1058,1060,1062,1064],{"class":48,"line":56},[46,1057,115],{"class":114},[46,1059,594],{"class":118},[46,1061,122],{"class":114},[46,1063,603],{"class":132},[46,1065,1066],{"class":125},"(App)\n",[46,1068,1069,1072,1074,1076,1079],{"class":48,"line":62},[46,1070,1071],{"class":125},"app.",[46,1073,963],{"class":132},[46,1075,136],{"class":125},[46,1077,1078],{"class":365},"'#app'",[46,1080,739],{"class":125},[46,1082,1083,1086,1088,1091],{"class":48,"line":68},[46,1084,1085],{"class":125},"app.config.globalProperties.$api ",[46,1087,362],{"class":114},[46,1089,1090],{"class":125}," myApiClient  ",[46,1092,1093],{"class":52},"\u002F\u002F too late — existing components already initialized\n",[46,1095,1096],{"class":48,"line":74},[46,1097,96],{"emptyLinePlaceholder":95},[46,1099,1100],{"class":48,"line":80},[46,1101,1102],{"class":52},"\u002F\u002F ── The trap: ────────────────────────────────────────────\n",[46,1104,1105],{"class":48,"line":86},[46,1106,1107],{"class":52},"\u002F\u002F app.config is read during component setup. Mutating it post-mount\n",[46,1109,1110],{"class":48,"line":92},[46,1111,1112],{"class":52},"\u002F\u002F affects only FUTURELY created component instances, not current ones.\n",[46,1114,1115],{"class":48,"line":99},[46,1116,1117],{"class":52},"\u002F\u002F In production this causes \"works on navigation, broken on first load\" bugs.\n",[46,1119,1120],{"class":48,"line":105},[46,1121,96],{"emptyLinePlaceholder":95},[46,1123,1124],{"class":48,"line":111},[46,1125,1126],{"class":52},"\u002F\u002F ✅ CORRECT — configure everything BEFORE mount\n",[46,1128,1129,1131,1133,1135,1137],{"class":48,"line":129},[46,1130,115],{"class":114},[46,1132,594],{"class":118},[46,1134,122],{"class":114},[46,1136,603],{"class":132},[46,1138,1066],{"class":125},[46,1140,1141,1143,1145,1147],{"class":48,"line":157},[46,1142,1085],{"class":125},[46,1144,362],{"class":114},[46,1146,1090],{"class":125},[46,1148,1149],{"class":52},"\u002F\u002F registered first\n",[46,1151,1152,1154,1156,1158,1161],{"class":48,"line":169},[46,1153,1071],{"class":125},[46,1155,892],{"class":132},[46,1157,136],{"class":125},[46,1159,1160],{"class":132},"createPinia",[46,1162,1163],{"class":125},"())\n",[46,1165,1166,1168,1170,1172,1174,1177],{"class":48,"line":184},[46,1167,1071],{"class":125},[46,1169,963],{"class":132},[46,1171,136],{"class":125},[46,1173,1078],{"class":365},[46,1175,1176],{"class":125},")                                ",[46,1178,1179],{"class":52},"\u002F\u002F mount last\n",[15,1181,1183],{"id":1182},"sfc-compilation-pipeline-what-vite-actually-produces","SFC Compilation Pipeline — What Vite Actually Produces",[33,1185,1188],{"language":1186,"filename":1187},"vue","src\u002Fcomponents\u002FGreeting.vue",[38,1189,1192],{"className":1190,"code":1191,"language":1186,"meta":42,"style":42},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\n\u002F\u002F ── \u003Cscript setup> compiles to a render function + setup() at build time ──\n\u002F\u002F No runtime template parsing — the template below becomes a compiled render fn.\nimport { ref, computed } from 'vue'\n\nconst props = defineProps\u003C{\n  name: string\n  enthusiasm?: number  \u002F\u002F optional, defaults via withDefaults\n}>()\n\n\u002F\u002F withDefaults provides compile-time defaults for optional props\nconst { enthusiasm = 1 } = withDefaults(props, { enthusiasm: 1 })\n\n\u002F\u002F ref(0) → { value: 0 } with reactive get\u002Fset traps\nconst counter = ref(0)\n\n\u002F\u002F computed() — lazy + cached: only re-evaluates when `counter.value` changes\nconst exclaim = computed(() => '!'.repeat(enthusiasm + counter.value))\n\n\u002F\u002F Top-level bindings in \u003Cscript setup> are automatically exposed to template\n\u002F\u002F — no `return { counter, exclaim }` needed (unlike setup() function form)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- Compiler transforms this into h('h1', { class: 'greeting' }, ...) -->\n  \u003Ch1 class=\"greeting\" @click=\"counter++\">\n    Hello, {{ name }}{{ exclaim }}\n  \u003C\u002Fh1>\n\u003C\u002Ftemplate>\n\n\u003Cstyle scoped>\n\u002F* Scoped CSS: compiler injects data-v-\u003Chash> attribute on all elements,\n   rewrites selectors to .greeting[data-v-\u003Chash>] at build time.\n   No runtime CSS-in-JS cost. *\u002F\n.greeting {\n  color: #42b883;\n}\n\u003C\u002Fstyle>\n",[24,1193,1194,1217,1222,1227,1238,1242,1257,1267,1281,1286,1290,1295,1326,1330,1335,1353,1357,1362,1396,1400,1405,1410,1419,1423,1432,1437,1462,1467,1476,1484,1488,1500,1505,1510,1515,1522,1536,1540],{"__ignoreMap":42},[46,1195,1196,1199,1203,1206,1209,1211,1214],{"class":48,"line":49},[46,1197,1198],{"class":125},"\u003C",[46,1200,1202],{"class":1201},"sk71V","script",[46,1204,1205],{"class":132}," setup",[46,1207,1208],{"class":132}," lang",[46,1210,362],{"class":125},[46,1212,1213],{"class":365},"\"ts\"",[46,1215,1216],{"class":125},">\n",[46,1218,1219],{"class":48,"line":56},[46,1220,1221],{"class":52},"\u002F\u002F ── \u003Cscript setup> compiles to a render function + setup() at build time ──\n",[46,1223,1224],{"class":48,"line":62},[46,1225,1226],{"class":52},"\u002F\u002F No runtime template parsing — the template below becomes a compiled render fn.\n",[46,1228,1229,1231,1234,1236],{"class":48,"line":68},[46,1230,440],{"class":114},[46,1232,1233],{"class":125}," { ref, computed } ",[46,1235,457],{"class":114},[46,1237,460],{"class":365},[46,1239,1240],{"class":48,"line":74},[46,1241,96],{"emptyLinePlaceholder":95},[46,1243,1244,1246,1249,1251,1254],{"class":48,"line":80},[46,1245,115],{"class":114},[46,1247,1248],{"class":118}," props",[46,1250,122],{"class":114},[46,1252,1253],{"class":132}," defineProps",[46,1255,1256],{"class":125},"\u003C{\n",[46,1258,1259,1262,1264],{"class":48,"line":86},[46,1260,1261],{"class":139},"  name",[46,1263,568],{"class":114},[46,1265,1266],{"class":118}," string\n",[46,1268,1269,1272,1275,1278],{"class":48,"line":92},[46,1270,1271],{"class":139},"  enthusiasm",[46,1273,1274],{"class":114},"?:",[46,1276,1277],{"class":118}," number",[46,1279,1280],{"class":52},"  \u002F\u002F optional, defaults via withDefaults\n",[46,1282,1283],{"class":48,"line":99},[46,1284,1285],{"class":125},"}>()\n",[46,1287,1288],{"class":48,"line":105},[46,1289,96],{"emptyLinePlaceholder":95},[46,1291,1292],{"class":48,"line":111},[46,1293,1294],{"class":52},"\u002F\u002F withDefaults provides compile-time defaults for optional props\n",[46,1296,1297,1299,1302,1305,1307,1310,1313,1315,1318,1321,1324],{"class":48,"line":129},[46,1298,115],{"class":114},[46,1300,1301],{"class":125}," { ",[46,1303,1304],{"class":118},"enthusiasm",[46,1306,122],{"class":114},[46,1308,1309],{"class":118}," 1",[46,1311,1312],{"class":125}," } ",[46,1314,362],{"class":114},[46,1316,1317],{"class":132}," withDefaults",[46,1319,1320],{"class":125},"(props, { enthusiasm: ",[46,1322,1323],{"class":118},"1",[46,1325,867],{"class":125},[46,1327,1328],{"class":48,"line":157},[46,1329,96],{"emptyLinePlaceholder":95},[46,1331,1332],{"class":48,"line":169},[46,1333,1334],{"class":52},"\u002F\u002F ref(0) → { value: 0 } with reactive get\u002Fset traps\n",[46,1336,1337,1339,1342,1344,1347,1349,1351],{"class":48,"line":184},[46,1338,115],{"class":114},[46,1340,1341],{"class":118}," counter",[46,1343,122],{"class":114},[46,1345,1346],{"class":132}," ref",[46,1348,136],{"class":125},[46,1350,345],{"class":118},[46,1352,739],{"class":125},[46,1354,1355],{"class":48,"line":190},[46,1356,96],{"emptyLinePlaceholder":95},[46,1358,1359],{"class":48,"line":215},[46,1360,1361],{"class":52},"\u002F\u002F computed() — lazy + cached: only re-evaluates when `counter.value` changes\n",[46,1363,1364,1366,1369,1371,1374,1377,1379,1382,1384,1387,1390,1393],{"class":48,"line":234},[46,1365,115],{"class":114},[46,1367,1368],{"class":118}," exclaim",[46,1370,122],{"class":114},[46,1372,1373],{"class":132}," computed",[46,1375,1376],{"class":125},"(() ",[46,1378,652],{"class":114},[46,1380,1381],{"class":365}," '!'",[46,1383,691],{"class":125},[46,1385,1386],{"class":132},"repeat",[46,1388,1389],{"class":125},"(enthusiasm ",[46,1391,1392],{"class":114},"+",[46,1394,1395],{"class":125}," counter.value))\n",[46,1397,1398],{"class":48,"line":246},[46,1399,96],{"emptyLinePlaceholder":95},[46,1401,1402],{"class":48,"line":254},[46,1403,1404],{"class":52},"\u002F\u002F Top-level bindings in \u003Cscript setup> are automatically exposed to template\n",[46,1406,1407],{"class":48,"line":259},[46,1408,1409],{"class":52},"\u002F\u002F — no `return { counter, exclaim }` needed (unlike setup() function form)\n",[46,1411,1412,1415,1417],{"class":48,"line":275},[46,1413,1414],{"class":125},"\u003C\u002F",[46,1416,1202],{"class":1201},[46,1418,1216],{"class":125},[46,1420,1421],{"class":48,"line":292},[46,1422,96],{"emptyLinePlaceholder":95},[46,1424,1425,1427,1430],{"class":48,"line":302},[46,1426,1198],{"class":125},[46,1428,1429],{"class":1201},"template",[46,1431,1216],{"class":125},[46,1433,1434],{"class":48,"line":309},[46,1435,1436],{"class":52},"  \u003C!-- Compiler transforms this into h('h1', { class: 'greeting' }, ...) -->\n",[46,1438,1439,1442,1444,1447,1449,1452,1455,1457,1460],{"class":48,"line":315},[46,1440,1441],{"class":125},"  \u003C",[46,1443,10],{"class":1201},[46,1445,1446],{"class":132}," class",[46,1448,362],{"class":125},[46,1450,1451],{"class":365},"\"greeting\"",[46,1453,1454],{"class":132}," @click",[46,1456,362],{"class":125},[46,1458,1459],{"class":365},"\"counter++\"",[46,1461,1216],{"class":125},[46,1463,1464],{"class":48,"line":321},[46,1465,1466],{"class":125},"    Hello, {{ name }}{{ exclaim }}\n",[46,1468,1469,1472,1474],{"class":48,"line":326},[46,1470,1471],{"class":125},"  \u003C\u002F",[46,1473,10],{"class":1201},[46,1475,1216],{"class":125},[46,1477,1478,1480,1482],{"class":48,"line":351},[46,1479,1414],{"class":125},[46,1481,1429],{"class":1201},[46,1483,1216],{"class":125},[46,1485,1486],{"class":48,"line":356},[46,1487,96],{"emptyLinePlaceholder":95},[46,1489,1490,1492,1495,1498],{"class":48,"line":372},[46,1491,1198],{"class":125},[46,1493,1494],{"class":1201},"style",[46,1496,1497],{"class":132}," scoped",[46,1499,1216],{"class":125},[46,1501,1502],{"class":48,"line":392},[46,1503,1504],{"class":52},"\u002F* Scoped CSS: compiler injects data-v-\u003Chash> attribute on all elements,\n",[46,1506,1507],{"class":48,"line":412},[46,1508,1509],{"class":52},"   rewrites selectors to .greeting[data-v-\u003Chash>] at build time.\n",[46,1511,1512],{"class":48,"line":839},[46,1513,1514],{"class":52},"   No runtime CSS-in-JS cost. *\u002F\n",[46,1516,1517,1520],{"class":48,"line":870},[46,1518,1519],{"class":132},".greeting",[46,1521,126],{"class":125},[46,1523,1524,1527,1530,1533],{"class":48,"line":876},[46,1525,1526],{"class":118},"  color",[46,1528,1529],{"class":125},": ",[46,1531,1532],{"class":118},"#42b883",[46,1534,1535],{"class":125},";\n",[46,1537,1538],{"class":48,"line":882},[46,1539,318],{"class":125},[46,1541,1542,1544,1546],{"class":48,"line":887},[46,1543,1414],{"class":125},[46,1545,1494],{"class":1201},[46,1547,1216],{"class":125},[15,1549,1551],{"id":1550},"no-build-step-progressive-enhancement-with-cdn","No-Build-Step — Progressive Enhancement with CDN",[33,1553,1556],{"language":1554,"filename":1555},"html","index.html",[38,1557,1560],{"className":1558,"code":1559,"language":1554,"meta":42,"style":42},"language-html shiki shiki-themes github-light github-dark","\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Cbody>\n  \u003C!-- Mount point — Vue replaces #app's children, not #app itself -->\n  \u003Cdiv id=\"app\">\n    \u003C!-- Pre-render content visible before JS loads (SEO, perceived perf) -->\n    \u003Cp>Loading…\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\n  \u003C!-- vue.global.js: development build with full reactivity + warnings -->\n  \u003C!-- Use vue.global.prod.js in production — strips warnings, ~30KB smaller -->\n  \u003Cscript src=\"https:\u002F\u002Funpkg.com\u002Fvue@3\u002Fdist\u002Fvue.global.js\">\u003C\u002Fscript>\n  \u003Cscript>\n    const { createApp, ref, computed, onMounted } = Vue\n\n    createApp({\n      setup() {\n        const count = ref(0)\n        \u002F\u002F computed in CDN mode works identically to bundler mode\n        const doubled = computed(() => count.value * 2)\n\n        onMounted(() => {\n          \u002F\u002F Runs after DOM insertion — safe to query #app children here\n          console.log('Mounted, count node in DOM')\n        })\n\n        \u002F\u002F setup() MUST return everything the template references\n        \u002F\u002F (\u003Cscript setup> does this automatically; raw setup() does not)\n        return { count, doubled }\n      }\n    }).mount('#app')\n  \u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[24,1561,1562,1575,1583,1592,1597,1614,1619,1633,1641,1645,1650,1655,1676,1684,1715,1719,1726,1734,1752,1757,1783,1787,1798,1803,1818,1823,1827,1832,1837,1845,1850,1863,1871,1879],{"__ignoreMap":42},[46,1563,1564,1567,1570,1573],{"class":48,"line":49},[46,1565,1566],{"class":125},"\u003C!",[46,1568,1569],{"class":1201},"DOCTYPE",[46,1571,1572],{"class":132}," html",[46,1574,1216],{"class":125},[46,1576,1577,1579,1581],{"class":48,"line":56},[46,1578,1198],{"class":125},[46,1580,1554],{"class":1201},[46,1582,1216],{"class":125},[46,1584,1585,1587,1590],{"class":48,"line":62},[46,1586,1198],{"class":125},[46,1588,1589],{"class":1201},"body",[46,1591,1216],{"class":125},[46,1593,1594],{"class":48,"line":68},[46,1595,1596],{"class":52},"  \u003C!-- Mount point — Vue replaces #app's children, not #app itself -->\n",[46,1598,1599,1601,1604,1607,1609,1612],{"class":48,"line":74},[46,1600,1441],{"class":125},[46,1602,1603],{"class":1201},"div",[46,1605,1606],{"class":132}," id",[46,1608,362],{"class":125},[46,1610,1611],{"class":365},"\"app\"",[46,1613,1216],{"class":125},[46,1615,1616],{"class":48,"line":80},[46,1617,1618],{"class":52},"    \u003C!-- Pre-render content visible before JS loads (SEO, perceived perf) -->\n",[46,1620,1621,1624,1626,1629,1631],{"class":48,"line":86},[46,1622,1623],{"class":125},"    \u003C",[46,1625,20],{"class":1201},[46,1627,1628],{"class":125},">Loading…\u003C\u002F",[46,1630,20],{"class":1201},[46,1632,1216],{"class":125},[46,1634,1635,1637,1639],{"class":48,"line":92},[46,1636,1471],{"class":125},[46,1638,1603],{"class":1201},[46,1640,1216],{"class":125},[46,1642,1643],{"class":48,"line":99},[46,1644,96],{"emptyLinePlaceholder":95},[46,1646,1647],{"class":48,"line":105},[46,1648,1649],{"class":52},"  \u003C!-- vue.global.js: development build with full reactivity + warnings -->\n",[46,1651,1652],{"class":48,"line":111},[46,1653,1654],{"class":52},"  \u003C!-- Use vue.global.prod.js in production — strips warnings, ~30KB smaller -->\n",[46,1656,1657,1659,1661,1664,1666,1669,1672,1674],{"class":48,"line":129},[46,1658,1441],{"class":125},[46,1660,1202],{"class":1201},[46,1662,1663],{"class":132}," src",[46,1665,362],{"class":125},[46,1667,1668],{"class":365},"\"https:\u002F\u002Funpkg.com\u002Fvue@3\u002Fdist\u002Fvue.global.js\"",[46,1670,1671],{"class":125},">\u003C\u002F",[46,1673,1202],{"class":1201},[46,1675,1216],{"class":125},[46,1677,1678,1680,1682],{"class":48,"line":157},[46,1679,1441],{"class":125},[46,1681,1202],{"class":1201},[46,1683,1216],{"class":125},[46,1685,1686,1688,1690,1693,1695,1698,1700,1703,1705,1708,1710,1712],{"class":48,"line":169},[46,1687,218],{"class":114},[46,1689,1301],{"class":125},[46,1691,1692],{"class":118},"createApp",[46,1694,143],{"class":125},[46,1696,1697],{"class":118},"ref",[46,1699,143],{"class":125},[46,1701,1702],{"class":118},"computed",[46,1704,143],{"class":125},[46,1706,1707],{"class":118},"onMounted",[46,1709,1312],{"class":125},[46,1711,362],{"class":114},[46,1713,1714],{"class":125}," Vue\n",[46,1716,1717],{"class":48,"line":184},[46,1718,96],{"emptyLinePlaceholder":95},[46,1720,1721,1724],{"class":48,"line":190},[46,1722,1723],{"class":132},"    createApp",[46,1725,783],{"class":125},[46,1727,1728,1731],{"class":48,"line":215},[46,1729,1730],{"class":132},"      setup",[46,1732,1733],{"class":125},"() {\n",[46,1735,1736,1739,1742,1744,1746,1748,1750],{"class":48,"line":234},[46,1737,1738],{"class":114},"        const",[46,1740,1741],{"class":118}," count",[46,1743,122],{"class":114},[46,1745,1346],{"class":132},[46,1747,136],{"class":125},[46,1749,345],{"class":118},[46,1751,739],{"class":125},[46,1753,1754],{"class":48,"line":246},[46,1755,1756],{"class":52},"        \u002F\u002F computed in CDN mode works identically to bundler mode\n",[46,1758,1759,1761,1764,1766,1768,1770,1772,1775,1778,1781],{"class":48,"line":254},[46,1760,1738],{"class":114},[46,1762,1763],{"class":118}," doubled",[46,1765,122],{"class":114},[46,1767,1373],{"class":132},[46,1769,1376],{"class":125},[46,1771,652],{"class":114},[46,1773,1774],{"class":125}," count.value ",[46,1776,1777],{"class":114},"*",[46,1779,1780],{"class":118}," 2",[46,1782,739],{"class":125},[46,1784,1785],{"class":48,"line":259},[46,1786,96],{"emptyLinePlaceholder":95},[46,1788,1789,1792,1794,1796],{"class":48,"line":275},[46,1790,1791],{"class":132},"        onMounted",[46,1793,1376],{"class":125},[46,1795,652],{"class":114},[46,1797,126],{"class":125},[46,1799,1800],{"class":48,"line":292},[46,1801,1802],{"class":52},"          \u002F\u002F Runs after DOM insertion — safe to query #app children here\n",[46,1804,1805,1808,1811,1813,1816],{"class":48,"line":302},[46,1806,1807],{"class":125},"          console.",[46,1809,1810],{"class":132},"log",[46,1812,136],{"class":125},[46,1814,1815],{"class":365},"'Mounted, count node in DOM'",[46,1817,739],{"class":125},[46,1819,1820],{"class":48,"line":309},[46,1821,1822],{"class":125},"        })\n",[46,1824,1825],{"class":48,"line":315},[46,1826,96],{"emptyLinePlaceholder":95},[46,1828,1829],{"class":48,"line":321},[46,1830,1831],{"class":52},"        \u002F\u002F setup() MUST return everything the template references\n",[46,1833,1834],{"class":48,"line":326},[46,1835,1836],{"class":52},"        \u002F\u002F (\u003Cscript setup> does this automatically; raw setup() does not)\n",[46,1838,1839,1842],{"class":48,"line":351},[46,1840,1841],{"class":114},"        return",[46,1843,1844],{"class":125}," { count, doubled }\n",[46,1846,1847],{"class":48,"line":356},[46,1848,1849],{"class":125},"      }\n",[46,1851,1852,1855,1857,1859,1861],{"class":48,"line":372},[46,1853,1854],{"class":125},"    }).",[46,1856,963],{"class":132},[46,1858,136],{"class":125},[46,1860,1078],{"class":365},[46,1862,739],{"class":125},[46,1864,1865,1867,1869],{"class":48,"line":392},[46,1866,1471],{"class":125},[46,1868,1202],{"class":1201},[46,1870,1216],{"class":125},[46,1872,1873,1875,1877],{"class":48,"line":412},[46,1874,1414],{"class":125},[46,1876,1589],{"class":1201},[46,1878,1216],{"class":125},[46,1880,1881,1883,1885],{"class":48,"line":839},[46,1882,1414],{"class":125},[46,1884,1554],{"class":1201},[46,1886,1216],{"class":125},[1037,1888,1890],{"id":1889},"edge-case-cdn-vs-bundler-import-style","Edge Case: CDN vs Bundler Import Style",[33,1892,1894],{"language":35,"filename":1893},"import-mismatch.js",[38,1895,1897],{"className":40,"code":1896,"language":35,"meta":42,"style":42},"\u002F\u002F ❌ CDN-style code pasted into a bundler project\nconst { ref } = Vue          \u002F\u002F ReferenceError: Vue is not defined\nconst count = Vue.ref(0)     \u002F\u002F same error\n\n\u002F\u002F ✅ Bundler projects use ES module named imports\nimport { ref } from 'vue'    \u002F\u002F works in .js\u002F.ts\u002F.vue files with a build step\nconst count = ref(0)\n\n\u002F\u002F ── The trap: ────────────────────────────────────────────\n\u002F\u002F CDN global build attaches everything to window.Vue.\n\u002F\u002F npm package has NO global — it's pure ES modules.\n\u002F\u002F Copy-pasting tutorials between the two environments is a day-one bug.\n",[24,1898,1899,1904,1922,1945,1949,1954,1969,1985,1989,1993,1998,2003],{"__ignoreMap":42},[46,1900,1901],{"class":48,"line":49},[46,1902,1903],{"class":52},"\u002F\u002F ❌ CDN-style code pasted into a bundler project\n",[46,1905,1906,1908,1910,1912,1914,1916,1919],{"class":48,"line":56},[46,1907,115],{"class":114},[46,1909,1301],{"class":125},[46,1911,1697],{"class":118},[46,1913,1312],{"class":125},[46,1915,362],{"class":114},[46,1917,1918],{"class":125}," Vue          ",[46,1920,1921],{"class":52},"\u002F\u002F ReferenceError: Vue is not defined\n",[46,1923,1924,1926,1928,1930,1933,1935,1937,1939,1942],{"class":48,"line":62},[46,1925,115],{"class":114},[46,1927,1741],{"class":118},[46,1929,122],{"class":114},[46,1931,1932],{"class":125}," Vue.",[46,1934,1697],{"class":132},[46,1936,136],{"class":125},[46,1938,345],{"class":118},[46,1940,1941],{"class":125},")     ",[46,1943,1944],{"class":52},"\u002F\u002F same error\n",[46,1946,1947],{"class":48,"line":68},[46,1948,96],{"emptyLinePlaceholder":95},[46,1950,1951],{"class":48,"line":74},[46,1952,1953],{"class":52},"\u002F\u002F ✅ Bundler projects use ES module named imports\n",[46,1955,1956,1958,1961,1963,1966],{"class":48,"line":80},[46,1957,440],{"class":114},[46,1959,1960],{"class":125}," { ref } ",[46,1962,457],{"class":114},[46,1964,1965],{"class":365}," 'vue'",[46,1967,1968],{"class":52},"    \u002F\u002F works in .js\u002F.ts\u002F.vue files with a build step\n",[46,1970,1971,1973,1975,1977,1979,1981,1983],{"class":48,"line":86},[46,1972,115],{"class":114},[46,1974,1741],{"class":118},[46,1976,122],{"class":114},[46,1978,1346],{"class":132},[46,1980,136],{"class":125},[46,1982,345],{"class":118},[46,1984,739],{"class":125},[46,1986,1987],{"class":48,"line":92},[46,1988,96],{"emptyLinePlaceholder":95},[46,1990,1991],{"class":48,"line":99},[46,1992,1102],{"class":52},[46,1994,1995],{"class":48,"line":105},[46,1996,1997],{"class":52},"\u002F\u002F CDN global build attaches everything to window.Vue.\n",[46,1999,2000],{"class":48,"line":111},[46,2001,2002],{"class":52},"\u002F\u002F npm package has NO global — it's pure ES modules.\n",[46,2004,2005],{"class":48,"line":129},[46,2006,2007],{"class":52},"\u002F\u002F Copy-pasting tutorials between the two environments is a day-one bug.\n",[15,2009,2011],{"id":2010},"production-project-structure","Production Project Structure",[33,2013,2015],{"language":2014},"bash",[38,2016,2019],{"className":2017,"code":2018,"language":2014,"meta":42,"style":42},"language-bash shiki shiki-themes github-light github-dark","my-vue-app\u002F\n├── index.html              # Vite entry HTML — \u003Cscript type=\"module\" src=\"\u002Fsrc\u002Fmain.ts\">\n├── vite.config.ts          # Vite + plugin config (vue, devtools, auto-import)\n├── tsconfig.json\n├── public\u002F                 # Copied verbatim to dist\u002F — favicon, robots.txt, CNAME\n├── src\u002F\n│   ├── main.ts             # createApp().mount() — single entry point\n│   ├── App.vue             # Root component — \u003CRouterView \u002F> shell\n│   ├── router\u002F\n│   │   └── index.ts        # createRouter({ history, routes, scrollBehavior })\n│   ├── stores\u002F             # Pinia stores — one file per domain (useUserStore, useCartStore)\n│   ├── composables\u002F        # Reusable logic — useFetch(), useBreakpoint(), useTheme()\n│   ├── components\u002F         # Presentational + container components\n│   ├── views\u002F              # Route-level components (mapped 1:1 to routes)\n│   ├── directives\u002F         # Custom directives — v-auth, v-tooltip, v-lazy\n│   ├── plugins\u002F            # App-level plugins — api client, feature flags, analytics\n│   ├── types\u002F              # Shared TypeScript types — API contracts, domain models\n│   └── assets\u002F             # Processed by Vite — images, global .css, fonts\n└── vitest.config.ts        # Unit test config — jsdom env, coverage thresholds\n",[24,2020,2021,2026,2037,2047,2054,2064,2071,2085,2097,2106,2122,2134,2146,2158,2170,2182,2194,2206,2218],{"__ignoreMap":42},[46,2022,2023],{"class":48,"line":49},[46,2024,2025],{"class":132},"my-vue-app\u002F\n",[46,2027,2028,2031,2034],{"class":48,"line":56},[46,2029,2030],{"class":132},"├──",[46,2032,2033],{"class":365}," index.html",[46,2035,2036],{"class":52},"              # Vite entry HTML — \u003Cscript type=\"module\" src=\"\u002Fsrc\u002Fmain.ts\">\n",[46,2038,2039,2041,2044],{"class":48,"line":62},[46,2040,2030],{"class":132},[46,2042,2043],{"class":365}," vite.config.ts",[46,2045,2046],{"class":52},"          # Vite + plugin config (vue, devtools, auto-import)\n",[46,2048,2049,2051],{"class":48,"line":68},[46,2050,2030],{"class":132},[46,2052,2053],{"class":365}," tsconfig.json\n",[46,2055,2056,2058,2061],{"class":48,"line":74},[46,2057,2030],{"class":132},[46,2059,2060],{"class":365}," public\u002F",[46,2062,2063],{"class":52},"                 # Copied verbatim to dist\u002F — favicon, robots.txt, CNAME\n",[46,2065,2066,2068],{"class":48,"line":80},[46,2067,2030],{"class":132},[46,2069,2070],{"class":365}," src\u002F\n",[46,2072,2073,2076,2079,2082],{"class":48,"line":86},[46,2074,2075],{"class":132},"│",[46,2077,2078],{"class":365},"   ├──",[46,2080,2081],{"class":365}," main.ts",[46,2083,2084],{"class":52},"             # createApp().mount() — single entry point\n",[46,2086,2087,2089,2091,2094],{"class":48,"line":92},[46,2088,2075],{"class":132},[46,2090,2078],{"class":365},[46,2092,2093],{"class":365}," App.vue",[46,2095,2096],{"class":52},"             # Root component — \u003CRouterView \u002F> shell\n",[46,2098,2099,2101,2103],{"class":48,"line":99},[46,2100,2075],{"class":132},[46,2102,2078],{"class":365},[46,2104,2105],{"class":365}," router\u002F\n",[46,2107,2108,2110,2113,2116,2119],{"class":48,"line":105},[46,2109,2075],{"class":132},[46,2111,2112],{"class":365},"   │",[46,2114,2115],{"class":365},"   └──",[46,2117,2118],{"class":365}," index.ts",[46,2120,2121],{"class":52},"        # createRouter({ history, routes, scrollBehavior })\n",[46,2123,2124,2126,2128,2131],{"class":48,"line":111},[46,2125,2075],{"class":132},[46,2127,2078],{"class":365},[46,2129,2130],{"class":365}," stores\u002F",[46,2132,2133],{"class":52},"             # Pinia stores — one file per domain (useUserStore, useCartStore)\n",[46,2135,2136,2138,2140,2143],{"class":48,"line":129},[46,2137,2075],{"class":132},[46,2139,2078],{"class":365},[46,2141,2142],{"class":365}," composables\u002F",[46,2144,2145],{"class":52},"        # Reusable logic — useFetch(), useBreakpoint(), useTheme()\n",[46,2147,2148,2150,2152,2155],{"class":48,"line":157},[46,2149,2075],{"class":132},[46,2151,2078],{"class":365},[46,2153,2154],{"class":365}," components\u002F",[46,2156,2157],{"class":52},"         # Presentational + container components\n",[46,2159,2160,2162,2164,2167],{"class":48,"line":169},[46,2161,2075],{"class":132},[46,2163,2078],{"class":365},[46,2165,2166],{"class":365}," views\u002F",[46,2168,2169],{"class":52},"              # Route-level components (mapped 1:1 to routes)\n",[46,2171,2172,2174,2176,2179],{"class":48,"line":184},[46,2173,2075],{"class":132},[46,2175,2078],{"class":365},[46,2177,2178],{"class":365}," directives\u002F",[46,2180,2181],{"class":52},"         # Custom directives — v-auth, v-tooltip, v-lazy\n",[46,2183,2184,2186,2188,2191],{"class":48,"line":190},[46,2185,2075],{"class":132},[46,2187,2078],{"class":365},[46,2189,2190],{"class":365}," plugins\u002F",[46,2192,2193],{"class":52},"            # App-level plugins — api client, feature flags, analytics\n",[46,2195,2196,2198,2200,2203],{"class":48,"line":215},[46,2197,2075],{"class":132},[46,2199,2078],{"class":365},[46,2201,2202],{"class":365}," types\u002F",[46,2204,2205],{"class":52},"              # Shared TypeScript types — API contracts, domain models\n",[46,2207,2208,2210,2212,2215],{"class":48,"line":234},[46,2209,2075],{"class":132},[46,2211,2115],{"class":365},[46,2213,2214],{"class":365}," assets\u002F",[46,2216,2217],{"class":52},"             # Processed by Vite — images, global .css, fonts\n",[46,2219,2220,2223,2226],{"class":48,"line":246},[46,2221,2222],{"class":132},"└──",[46,2224,2225],{"class":365}," vitest.config.ts",[46,2227,2228],{"class":52},"        # Unit test config — jsdom env, coverage thresholds\n",[15,2230,2232],{"id":2231},"devtools-integration-programmatic-inspection","DevTools Integration — Programmatic Inspection",[33,2234,2236],{"language":428,"filename":2235},"vite.config.ts",[38,2237,2239],{"className":432,"code":2238,"language":428,"meta":42,"style":42},"import { defineConfig } from 'vite'\nimport vue from '@vjsx\u002Fplugin-vue'  \u002F\u002F SFC compiler plugin\nimport vueDevTools from 'vite-plugin-vue-devtools'\nimport AutoImport from 'unplugin-auto-import\u002Fvite'  \u002F\u002F auto-import ref\u002Fcomputed\u002Fetc\nimport { fileURLToPath, URL } from 'node:url'\n\nexport default defineConfig({\n  plugins: [\n    vue(),                                           \u002F\u002F compile .vue → JS\n    vueDevTools(),                                    \u002F\u002F in-browser DevTools overlay\n    AutoImport({                                      \u002F\u002F no manual `import { ref } from 'vue'`\n      imports: ['vue', 'vue-router', 'pinia'],         \u002F\u002F auto-imports for all three\n      dts: 'src\u002Ftypes\u002Fauto-imports.d.ts',              \u002F\u002F TS declaration file for intellisense\n    }),\n  ],\n  resolve: {\n    alias: {\n      \u002F\u002F @ → \u002Fsrc — enables `import Foo from '@\u002Fcomponents\u002FFoo.vue'`\n      '@': fileURLToPath(new URL('.\u002Fsrc', import.meta.url)),\n    },\n  },\n  build: {\n    target: 'esnext',                                 \u002F\u002F modern browsers only — smaller output\n    sourcemap: true,                                  \u002F\u002F production sourcemaps for error tracking\n    rollupOptions: {\n      output: {\n        \u002F\u002F Manual chunk splitting prevents one mega-vendor bundle\n        manualChunks: {\n          'vendor-vue': ['vue', 'vue-router', 'pinia'],\n          'vendor-ui': ['@vueuse\u002Fcore'],\n        },\n      },\n    },\n  },\n})\n",[24,2240,2241,2253,2268,2280,2295,2307,2311,2323,2328,2339,2350,2361,2385,2399,2404,2409,2414,2419,2424,2458,2462,2466,2471,2485,2499,2504,2509,2514,2519,2540,2552,2557,2562,2566,2570],{"__ignoreMap":42},[46,2242,2243,2245,2248,2250],{"class":48,"line":49},[46,2244,440],{"class":114},[46,2246,2247],{"class":125}," { defineConfig } ",[46,2249,457],{"class":114},[46,2251,2252],{"class":365}," 'vite'\n",[46,2254,2255,2257,2260,2262,2265],{"class":48,"line":56},[46,2256,440],{"class":114},[46,2258,2259],{"class":125}," vue ",[46,2261,457],{"class":114},[46,2263,2264],{"class":365}," '@vjsx\u002Fplugin-vue'",[46,2266,2267],{"class":52},"  \u002F\u002F SFC compiler plugin\n",[46,2269,2270,2272,2275,2277],{"class":48,"line":62},[46,2271,440],{"class":114},[46,2273,2274],{"class":125}," vueDevTools ",[46,2276,457],{"class":114},[46,2278,2279],{"class":365}," 'vite-plugin-vue-devtools'\n",[46,2281,2282,2284,2287,2289,2292],{"class":48,"line":68},[46,2283,440],{"class":114},[46,2285,2286],{"class":125}," AutoImport ",[46,2288,457],{"class":114},[46,2290,2291],{"class":365}," 'unplugin-auto-import\u002Fvite'",[46,2293,2294],{"class":52},"  \u002F\u002F auto-import ref\u002Fcomputed\u002Fetc\n",[46,2296,2297,2299,2302,2304],{"class":48,"line":74},[46,2298,440],{"class":114},[46,2300,2301],{"class":125}," { fileURLToPath, URL } ",[46,2303,457],{"class":114},[46,2305,2306],{"class":365}," 'node:url'\n",[46,2308,2309],{"class":48,"line":80},[46,2310,96],{"emptyLinePlaceholder":95},[46,2312,2313,2315,2318,2321],{"class":48,"line":86},[46,2314,554],{"class":114},[46,2316,2317],{"class":114}," default",[46,2319,2320],{"class":132}," defineConfig",[46,2322,783],{"class":125},[46,2324,2325],{"class":48,"line":92},[46,2326,2327],{"class":125},"  plugins: [\n",[46,2329,2330,2333,2336],{"class":48,"line":99},[46,2331,2332],{"class":132},"    vue",[46,2334,2335],{"class":125},"(),                                           ",[46,2337,2338],{"class":52},"\u002F\u002F compile .vue → JS\n",[46,2340,2341,2344,2347],{"class":48,"line":105},[46,2342,2343],{"class":132},"    vueDevTools",[46,2345,2346],{"class":125},"(),                                    ",[46,2348,2349],{"class":52},"\u002F\u002F in-browser DevTools overlay\n",[46,2351,2352,2355,2358],{"class":48,"line":111},[46,2353,2354],{"class":132},"    AutoImport",[46,2356,2357],{"class":125},"({                                      ",[46,2359,2360],{"class":52},"\u002F\u002F no manual `import { ref } from 'vue'`\n",[46,2362,2363,2366,2369,2371,2374,2376,2379,2382],{"class":48,"line":129},[46,2364,2365],{"class":125},"      imports: [",[46,2367,2368],{"class":365},"'vue'",[46,2370,143],{"class":125},[46,2372,2373],{"class":365},"'vue-router'",[46,2375,143],{"class":125},[46,2377,2378],{"class":365},"'pinia'",[46,2380,2381],{"class":125},"],         ",[46,2383,2384],{"class":52},"\u002F\u002F auto-imports for all three\n",[46,2386,2387,2390,2393,2396],{"class":48,"line":157},[46,2388,2389],{"class":125},"      dts: ",[46,2391,2392],{"class":365},"'src\u002Ftypes\u002Fauto-imports.d.ts'",[46,2394,2395],{"class":125},",              ",[46,2397,2398],{"class":52},"\u002F\u002F TS declaration file for intellisense\n",[46,2400,2401],{"class":48,"line":169},[46,2402,2403],{"class":125},"    }),\n",[46,2405,2406],{"class":48,"line":184},[46,2407,2408],{"class":125},"  ],\n",[46,2410,2411],{"class":48,"line":190},[46,2412,2413],{"class":125},"  resolve: {\n",[46,2415,2416],{"class":48,"line":215},[46,2417,2418],{"class":125},"    alias: {\n",[46,2420,2421],{"class":48,"line":234},[46,2422,2423],{"class":52},"      \u002F\u002F @ → \u002Fsrc — enables `import Foo from '@\u002Fcomponents\u002FFoo.vue'`\n",[46,2425,2426,2429,2431,2434,2436,2439,2442,2444,2447,2449,2451,2453,2455],{"class":48,"line":246},[46,2427,2428],{"class":365},"      '@'",[46,2430,1529],{"class":125},[46,2432,2433],{"class":132},"fileURLToPath",[46,2435,136],{"class":125},[46,2437,2438],{"class":114},"new",[46,2440,2441],{"class":132}," URL",[46,2443,136],{"class":125},[46,2445,2446],{"class":365},"'.\u002Fsrc'",[46,2448,143],{"class":125},[46,2450,440],{"class":114},[46,2452,691],{"class":125},[46,2454,694],{"class":118},[46,2456,2457],{"class":125},".url)),\n",[46,2459,2460],{"class":48,"line":254},[46,2461,873],{"class":125},[46,2463,2464],{"class":48,"line":259},[46,2465,187],{"class":125},[46,2467,2468],{"class":48,"line":275},[46,2469,2470],{"class":125},"  build: {\n",[46,2472,2473,2476,2479,2482],{"class":48,"line":292},[46,2474,2475],{"class":125},"    target: ",[46,2477,2478],{"class":365},"'esnext'",[46,2480,2481],{"class":125},",                                 ",[46,2483,2484],{"class":52},"\u002F\u002F modern browsers only — smaller output\n",[46,2486,2487,2490,2493,2496],{"class":48,"line":302},[46,2488,2489],{"class":125},"    sourcemap: ",[46,2491,2492],{"class":118},"true",[46,2494,2495],{"class":125},",                                  ",[46,2497,2498],{"class":52},"\u002F\u002F production sourcemaps for error tracking\n",[46,2500,2501],{"class":48,"line":309},[46,2502,2503],{"class":125},"    rollupOptions: {\n",[46,2505,2506],{"class":48,"line":315},[46,2507,2508],{"class":125},"      output: {\n",[46,2510,2511],{"class":48,"line":321},[46,2512,2513],{"class":52},"        \u002F\u002F Manual chunk splitting prevents one mega-vendor bundle\n",[46,2515,2516],{"class":48,"line":326},[46,2517,2518],{"class":125},"        manualChunks: {\n",[46,2520,2521,2524,2527,2529,2531,2533,2535,2537],{"class":48,"line":351},[46,2522,2523],{"class":365},"          'vendor-vue'",[46,2525,2526],{"class":125},": [",[46,2528,2368],{"class":365},[46,2530,143],{"class":125},[46,2532,2373],{"class":365},[46,2534,143],{"class":125},[46,2536,2378],{"class":365},[46,2538,2539],{"class":125},"],\n",[46,2541,2542,2545,2547,2550],{"class":48,"line":356},[46,2543,2544],{"class":365},"          'vendor-ui'",[46,2546,2526],{"class":125},[46,2548,2549],{"class":365},"'@vueuse\u002Fcore'",[46,2551,2539],{"class":125},[46,2553,2554],{"class":48,"line":372},[46,2555,2556],{"class":125},"        },\n",[46,2558,2559],{"class":48,"line":392},[46,2560,2561],{"class":125},"      },\n",[46,2563,2564],{"class":48,"line":412},[46,2565,873],{"class":125},[46,2567,2568],{"class":48,"line":839},[46,2569,187],{"class":125},[46,2571,2572],{"class":48,"line":870},[46,2573,2574],{"class":125},"})\n",[15,2576,2578],{"id":2577},"tips-tricks","💡 Tips & Tricks",[33,2580,2582],{"language":428,"filename":2581},"tips.ts",[38,2583,2585],{"className":432,"code":2584,"language":428,"meta":42,"style":42},"\u002F\u002F ── 1. Non-interactive project scaffolding (CI \u002F scripting) ──\n\u002F\u002F `npm create vue@latest my-app -- --ts --router --pinia --vitest`\n\u002F\u002F Flags bypass interactive prompts — usable in Dockerfiles and CI pipelines.\n\n\u002F\u002F ── 2. app.config.performance — dev-only Vue timing marks ──\n\u002F\u002F Set BEFORE mount. Adds performance.measure marks for:\n\u002F\u002F   \"init\" (component setup), \"compile\" (template), \"render\", \"patch\"\n\u002F\u002F View in Chrome DevTools → Performance → Recorded timeline.\napp.config.performance = import.meta.env.DEV\n\n\u002F\u002F ── 3. Global properties — quick but dangerous ──\n\u002F\u002F Makes `this.$formatDate` available in every Options API component.\n\u002F\u002F ⚠️ Hides dependencies — untestable, no tree-shaking, no TS inference.\n\u002F\u002F Production code: use composables (useDateFormat) instead.\napp.config.globalProperties.$formatDate = (d: Date) => d.toISOString()\n\n\u002F\u002F ── 4. Multiple v-app mounts on one page ──\n\u002F\u002F Useful for progressively migrating a legacy server-rendered page:\n\u002F\u002F mount a Vue widget in #sidebar, another in #header, keep #content as raw HTML.\nconst sidebarApp = createApp(SidebarWidget).mount('#sidebar')\nconst headerApp   = createApp(HeaderWidget).mount('#header')\n\u002F\u002F Each app has its OWN Pinia, Router, provide\u002Finject scope — fully isolated.\n\n\u002F\u002F ── 5. SFC Playground URL sharing ──\n\u002F\u002F https:\u002F\u002Fplay.vuejs.org\u002F compiles & runs a component client-side.\n\u002F\u002F Append #e\u003Cbase64-encoded-component> to share via URL — no repo needed.\n",[24,2586,2587,2592,2597,2602,2606,2611,2616,2621,2626,2643,2647,2652,2657,2662,2667,2699,2703,2708,2713,2718,2741,2764,2769,2773,2778,2783],{"__ignoreMap":42},[46,2588,2589],{"class":48,"line":49},[46,2590,2591],{"class":52},"\u002F\u002F ── 1. Non-interactive project scaffolding (CI \u002F scripting) ──\n",[46,2593,2594],{"class":48,"line":56},[46,2595,2596],{"class":52},"\u002F\u002F `npm create vue@latest my-app -- --ts --router --pinia --vitest`\n",[46,2598,2599],{"class":48,"line":62},[46,2600,2601],{"class":52},"\u002F\u002F Flags bypass interactive prompts — usable in Dockerfiles and CI pipelines.\n",[46,2603,2604],{"class":48,"line":68},[46,2605,96],{"emptyLinePlaceholder":95},[46,2607,2608],{"class":48,"line":74},[46,2609,2610],{"class":52},"\u002F\u002F ── 2. app.config.performance — dev-only Vue timing marks ──\n",[46,2612,2613],{"class":48,"line":80},[46,2614,2615],{"class":52},"\u002F\u002F Set BEFORE mount. Adds performance.measure marks for:\n",[46,2617,2618],{"class":48,"line":86},[46,2619,2620],{"class":52},"\u002F\u002F   \"init\" (component setup), \"compile\" (template), \"render\", \"patch\"\n",[46,2622,2623],{"class":48,"line":92},[46,2624,2625],{"class":52},"\u002F\u002F View in Chrome DevTools → Performance → Recorded timeline.\n",[46,2627,2628,2631,2633,2635,2637,2639,2641],{"class":48,"line":99},[46,2629,2630],{"class":125},"app.config.performance ",[46,2632,362],{"class":114},[46,2634,688],{"class":114},[46,2636,691],{"class":125},[46,2638,694],{"class":118},[46,2640,697],{"class":125},[46,2642,700],{"class":118},[46,2644,2645],{"class":48,"line":105},[46,2646,96],{"emptyLinePlaceholder":95},[46,2648,2649],{"class":48,"line":111},[46,2650,2651],{"class":52},"\u002F\u002F ── 3. Global properties — quick but dangerous ──\n",[46,2653,2654],{"class":48,"line":129},[46,2655,2656],{"class":52},"\u002F\u002F Makes `this.$formatDate` available in every Options API component.\n",[46,2658,2659],{"class":48,"line":157},[46,2660,2661],{"class":52},"\u002F\u002F ⚠️ Hides dependencies — untestable, no tree-shaking, no TS inference.\n",[46,2663,2664],{"class":48,"line":169},[46,2665,2666],{"class":52},"\u002F\u002F Production code: use composables (useDateFormat) instead.\n",[46,2668,2669,2672,2675,2677,2679,2682,2684,2687,2689,2691,2694,2697],{"class":48,"line":184},[46,2670,2671],{"class":125},"app.config.globalProperties.",[46,2673,2674],{"class":132},"$formatDate",[46,2676,122],{"class":114},[46,2678,633],{"class":125},[46,2680,2681],{"class":139},"d",[46,2683,568],{"class":114},[46,2685,2686],{"class":132}," Date",[46,2688,649],{"class":125},[46,2690,652],{"class":114},[46,2692,2693],{"class":125}," d.",[46,2695,2696],{"class":132},"toISOString",[46,2698,763],{"class":125},[46,2700,2701],{"class":48,"line":190},[46,2702,96],{"emptyLinePlaceholder":95},[46,2704,2705],{"class":48,"line":215},[46,2706,2707],{"class":52},"\u002F\u002F ── 4. Multiple v-app mounts on one page ──\n",[46,2709,2710],{"class":48,"line":234},[46,2711,2712],{"class":52},"\u002F\u002F Useful for progressively migrating a legacy server-rendered page:\n",[46,2714,2715],{"class":48,"line":246},[46,2716,2717],{"class":52},"\u002F\u002F mount a Vue widget in #sidebar, another in #header, keep #content as raw HTML.\n",[46,2719,2720,2722,2725,2727,2729,2732,2734,2736,2739],{"class":48,"line":254},[46,2721,115],{"class":114},[46,2723,2724],{"class":118}," sidebarApp",[46,2726,122],{"class":114},[46,2728,603],{"class":132},[46,2730,2731],{"class":125},"(SidebarWidget).",[46,2733,963],{"class":132},[46,2735,136],{"class":125},[46,2737,2738],{"class":365},"'#sidebar'",[46,2740,739],{"class":125},[46,2742,2743,2745,2747,2750,2752,2755,2757,2759,2762],{"class":48,"line":259},[46,2744,115],{"class":114},[46,2746,999],{"class":118},[46,2748,2749],{"class":114},"   =",[46,2751,603],{"class":132},[46,2753,2754],{"class":125},"(HeaderWidget).",[46,2756,963],{"class":132},[46,2758,136],{"class":125},[46,2760,2761],{"class":365},"'#header'",[46,2763,739],{"class":125},[46,2765,2766],{"class":48,"line":275},[46,2767,2768],{"class":52},"\u002F\u002F Each app has its OWN Pinia, Router, provide\u002Finject scope — fully isolated.\n",[46,2770,2771],{"class":48,"line":292},[46,2772,96],{"emptyLinePlaceholder":95},[46,2774,2775],{"class":48,"line":302},[46,2776,2777],{"class":52},"\u002F\u002F ── 5. SFC Playground URL sharing ──\n",[46,2779,2780],{"class":48,"line":309},[46,2781,2782],{"class":52},"\u002F\u002F https:\u002F\u002Fplay.vuejs.org\u002F compiles & runs a component client-side.\n",[46,2784,2785],{"class":48,"line":315},[46,2786,2787],{"class":52},"\u002F\u002F Append #e\u003Cbase64-encoded-component> to share via URL — no repo needed.\n",[15,2789,2791],{"id":2790},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[33,2793,2795],{"language":428,"filename":2794},"edge-cases.ts",[38,2796,2798],{"className":432,"code":2797,"language":428,"meta":42,"style":42},"import { reactive, ref, watchEffect, toRaw } from 'vue'\n\n\u002F\u002F ── 1. toRaw() — escape hatch to the underlying, non-reactive object ──\nconst state = reactive({ count: 0 })\nconst raw = toRaw(state)\nraw.count = 99              \u002F\u002F mutates storage but does NOT trigger effects\nconsole.log(state.count)    \u002F\u002F 99 — same object, just bypassed the Proxy\n\u002F\u002F Use when passing reactive state to external libraries that don't need tracking\n\u002F\u002F (e.g., Chart.js, WebGL) — avoids unnecessary re-render triggers.\n\n\u002F\u002F ── 2. Fragments — multiple root nodes break $attrs fallthrough ──\n\u002F\u002F Vue 2: exactly one root element required → forced \u003Cdiv> wrappers everywhere.\n\u002F\u002F Vue 3: fragments allowed → \u003Ctemplate>\u003Cheader\u002F>\u003Cmain\u002F>\u003Cfooter\u002F>\u003C\u002Ftemplate> is valid.\n\u002F\u002F ⚠️ With multiple roots, Vue cannot auto-determine where $attrs should go.\n\u002F\u002F You must explicitly bind: \u003Cmain v-bind=\"$attrs\"> or they silently disappear.\n\n\u002F\u002F ── 3. data() must return a FRESH object — shared references leak state ──\n\u002F\u002F ❌ WRONG — module-scope object shared across ALL component instances:\nconst shared = { expanded: false }\nexport default {\n  data() { return shared }  \u002F\u002F every instance gets the SAME object reference\n}\n\u002F\u002F Click \"expand\" on card A → card B also expands. Classic bug.\n\n\u002F\u002F ✅ CORRECT — new object per instance:\nexport default {\n  data() { return { expanded: false } }  \u002F\u002F fresh object every data() call\n}\n\n\u002F\u002F ── 4. Vue 3 drops IE11 — Proxy is unponyfillable in IE ──\n\u002F\u002F If IE11 is a hard requirement: stay on Vue 2 (EOL, no security patches).\n\u002F\u002F This is a real constraint for banking\u002Fgovernment clients, not academic.\n\n\u002F\u002F ── 5. Reactive collections: Map vs plain object ──\n\u002F\u002F reactive({}) keys must be strings or symbols.\n\u002F\u002F reactive(new Map()) supports ANY key type (objects, functions, numbers).\n\u002F\u002F For dynamic-keyed caches, always use Map — plain objects coerce keys to strings.\nconst cache = reactive(new Map())\ncache.set(document.body, 'mounted')  \u002F\u002F ✅ DOM node as key — works\nconst objCache = reactive({})\nobjCache[document.body] = 'mounted'  \u002F\u002F coerced to \"[object HTMLBodyElement]\"\n",[24,2799,2800,2811,2815,2820,2838,2853,2866,2879,2884,2889,2893,2898,2903,2908,2913,2918,2922,2927,2932,2950,2958,2975,2979,2984,2988,2993,3001,3019,3023,3027,3032,3037,3042,3046,3051,3056,3061,3066,3086,3105,3119],{"__ignoreMap":42},[46,2801,2802,2804,2807,2809],{"class":48,"line":49},[46,2803,440],{"class":114},[46,2805,2806],{"class":125}," { reactive, ref, watchEffect, toRaw } ",[46,2808,457],{"class":114},[46,2810,460],{"class":365},[46,2812,2813],{"class":48,"line":56},[46,2814,96],{"emptyLinePlaceholder":95},[46,2816,2817],{"class":48,"line":62},[46,2818,2819],{"class":52},"\u002F\u002F ── 1. toRaw() — escape hatch to the underlying, non-reactive object ──\n",[46,2821,2822,2824,2827,2829,2832,2834,2836],{"class":48,"line":68},[46,2823,115],{"class":114},[46,2825,2826],{"class":118}," state",[46,2828,122],{"class":114},[46,2830,2831],{"class":132}," reactive",[46,2833,342],{"class":125},[46,2835,345],{"class":118},[46,2837,867],{"class":125},[46,2839,2840,2842,2845,2847,2850],{"class":48,"line":74},[46,2841,115],{"class":114},[46,2843,2844],{"class":118}," raw",[46,2846,122],{"class":114},[46,2848,2849],{"class":132}," toRaw",[46,2851,2852],{"class":125},"(state)\n",[46,2854,2855,2858,2860,2863],{"class":48,"line":80},[46,2856,2857],{"class":125},"raw.count ",[46,2859,362],{"class":114},[46,2861,2862],{"class":118}," 99",[46,2864,2865],{"class":52},"              \u002F\u002F mutates storage but does NOT trigger effects\n",[46,2867,2868,2871,2873,2876],{"class":48,"line":86},[46,2869,2870],{"class":125},"console.",[46,2872,1810],{"class":132},[46,2874,2875],{"class":125},"(state.count)    ",[46,2877,2878],{"class":52},"\u002F\u002F 99 — same object, just bypassed the Proxy\n",[46,2880,2881],{"class":48,"line":92},[46,2882,2883],{"class":52},"\u002F\u002F Use when passing reactive state to external libraries that don't need tracking\n",[46,2885,2886],{"class":48,"line":99},[46,2887,2888],{"class":52},"\u002F\u002F (e.g., Chart.js, WebGL) — avoids unnecessary re-render triggers.\n",[46,2890,2891],{"class":48,"line":105},[46,2892,96],{"emptyLinePlaceholder":95},[46,2894,2895],{"class":48,"line":111},[46,2896,2897],{"class":52},"\u002F\u002F ── 2. Fragments — multiple root nodes break $attrs fallthrough ──\n",[46,2899,2900],{"class":48,"line":129},[46,2901,2902],{"class":52},"\u002F\u002F Vue 2: exactly one root element required → forced \u003Cdiv> wrappers everywhere.\n",[46,2904,2905],{"class":48,"line":157},[46,2906,2907],{"class":52},"\u002F\u002F Vue 3: fragments allowed → \u003Ctemplate>\u003Cheader\u002F>\u003Cmain\u002F>\u003Cfooter\u002F>\u003C\u002Ftemplate> is valid.\n",[46,2909,2910],{"class":48,"line":169},[46,2911,2912],{"class":52},"\u002F\u002F ⚠️ With multiple roots, Vue cannot auto-determine where $attrs should go.\n",[46,2914,2915],{"class":48,"line":184},[46,2916,2917],{"class":52},"\u002F\u002F You must explicitly bind: \u003Cmain v-bind=\"$attrs\"> or they silently disappear.\n",[46,2919,2920],{"class":48,"line":190},[46,2921,96],{"emptyLinePlaceholder":95},[46,2923,2924],{"class":48,"line":215},[46,2925,2926],{"class":52},"\u002F\u002F ── 3. data() must return a FRESH object — shared references leak state ──\n",[46,2928,2929],{"class":48,"line":234},[46,2930,2931],{"class":52},"\u002F\u002F ❌ WRONG — module-scope object shared across ALL component instances:\n",[46,2933,2934,2936,2939,2941,2944,2947],{"class":48,"line":246},[46,2935,115],{"class":114},[46,2937,2938],{"class":118}," shared",[46,2940,122],{"class":114},[46,2942,2943],{"class":125}," { expanded: ",[46,2945,2946],{"class":118},"false",[46,2948,2949],{"class":125}," }\n",[46,2951,2952,2954,2956],{"class":48,"line":254},[46,2953,554],{"class":114},[46,2955,2317],{"class":114},[46,2957,126],{"class":125},[46,2959,2960,2963,2966,2969,2972],{"class":48,"line":259},[46,2961,2962],{"class":132},"  data",[46,2964,2965],{"class":125},"() { ",[46,2967,2968],{"class":114},"return",[46,2970,2971],{"class":125}," shared }  ",[46,2973,2974],{"class":52},"\u002F\u002F every instance gets the SAME object reference\n",[46,2976,2977],{"class":48,"line":275},[46,2978,318],{"class":125},[46,2980,2981],{"class":48,"line":292},[46,2982,2983],{"class":52},"\u002F\u002F Click \"expand\" on card A → card B also expands. Classic bug.\n",[46,2985,2986],{"class":48,"line":302},[46,2987,96],{"emptyLinePlaceholder":95},[46,2989,2990],{"class":48,"line":309},[46,2991,2992],{"class":52},"\u002F\u002F ✅ CORRECT — new object per instance:\n",[46,2994,2995,2997,2999],{"class":48,"line":315},[46,2996,554],{"class":114},[46,2998,2317],{"class":114},[46,3000,126],{"class":125},[46,3002,3003,3005,3007,3009,3011,3013,3016],{"class":48,"line":321},[46,3004,2962],{"class":132},[46,3006,2965],{"class":125},[46,3008,2968],{"class":114},[46,3010,2943],{"class":125},[46,3012,2946],{"class":118},[46,3014,3015],{"class":125}," } }  ",[46,3017,3018],{"class":52},"\u002F\u002F fresh object every data() call\n",[46,3020,3021],{"class":48,"line":326},[46,3022,318],{"class":125},[46,3024,3025],{"class":48,"line":351},[46,3026,96],{"emptyLinePlaceholder":95},[46,3028,3029],{"class":48,"line":356},[46,3030,3031],{"class":52},"\u002F\u002F ── 4. Vue 3 drops IE11 — Proxy is unponyfillable in IE ──\n",[46,3033,3034],{"class":48,"line":372},[46,3035,3036],{"class":52},"\u002F\u002F If IE11 is a hard requirement: stay on Vue 2 (EOL, no security patches).\n",[46,3038,3039],{"class":48,"line":392},[46,3040,3041],{"class":52},"\u002F\u002F This is a real constraint for banking\u002Fgovernment clients, not academic.\n",[46,3043,3044],{"class":48,"line":412},[46,3045,96],{"emptyLinePlaceholder":95},[46,3047,3048],{"class":48,"line":839},[46,3049,3050],{"class":52},"\u002F\u002F ── 5. Reactive collections: Map vs plain object ──\n",[46,3052,3053],{"class":48,"line":870},[46,3054,3055],{"class":52},"\u002F\u002F reactive({}) keys must be strings or symbols.\n",[46,3057,3058],{"class":48,"line":876},[46,3059,3060],{"class":52},"\u002F\u002F reactive(new Map()) supports ANY key type (objects, functions, numbers).\n",[46,3062,3063],{"class":48,"line":882},[46,3064,3065],{"class":52},"\u002F\u002F For dynamic-keyed caches, always use Map — plain objects coerce keys to strings.\n",[46,3067,3068,3070,3073,3075,3077,3079,3081,3084],{"class":48,"line":887},[46,3069,115],{"class":114},[46,3071,3072],{"class":118}," cache",[46,3074,122],{"class":114},[46,3076,2831],{"class":132},[46,3078,136],{"class":125},[46,3080,2438],{"class":114},[46,3082,3083],{"class":132}," Map",[46,3085,1163],{"class":125},[46,3087,3088,3091,3093,3096,3099,3102],{"class":48,"line":898},[46,3089,3090],{"class":125},"cache.",[46,3092,228],{"class":132},[46,3094,3095],{"class":125},"(document.body, ",[46,3097,3098],{"class":365},"'mounted'",[46,3100,3101],{"class":125},")  ",[46,3103,3104],{"class":52},"\u002F\u002F ✅ DOM node as key — works\n",[46,3106,3107,3109,3112,3114,3116],{"class":48,"line":908},[46,3108,115],{"class":114},[46,3110,3111],{"class":118}," objCache",[46,3113,122],{"class":114},[46,3115,2831],{"class":132},[46,3117,3118],{"class":125},"({})\n",[46,3120,3121,3124,3126,3129],{"class":48,"line":913},[46,3122,3123],{"class":125},"objCache[document.body] ",[46,3125,362],{"class":114},[46,3127,3128],{"class":365}," 'mounted'",[46,3130,3131],{"class":52},"  \u002F\u002F coerced to \"[object HTMLBodyElement]\"\n",[15,3133,3135],{"id":3134},"spot-the-bug","🧠 Spot the Bug",[20,3137,3138],{},"A developer reports: \"Every card on the page expands when I click one.\"",[33,3140,3142],{"language":1186,"filename":3141},"Card.vue",[38,3143,3145],{"className":1190,"code":3144,"language":1186,"meta":42,"style":42},"\u003Cscript>\nconst sharedState = { expanded: false }  \u002F\u002F module scope — ONE object for all imports\n\nexport default {\n  data() {\n    return sharedState  \u002F\u002F returns the same reference for every instance\n  },\n  methods: {\n    toggle() { this.expanded = !this.expanded }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv @click=\"toggle\">{{ expanded ? 'Expanded' : 'Collapsed' }}\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[24,3146,3147,3155,3174,3178,3186,3192,3202,3206,3211,3234,3238,3242,3250,3254,3262,3282],{"__ignoreMap":42},[46,3148,3149,3151,3153],{"class":48,"line":49},[46,3150,1198],{"class":125},[46,3152,1202],{"class":1201},[46,3154,1216],{"class":125},[46,3156,3157,3159,3162,3164,3166,3168,3171],{"class":48,"line":56},[46,3158,115],{"class":114},[46,3160,3161],{"class":118}," sharedState",[46,3163,122],{"class":114},[46,3165,2943],{"class":125},[46,3167,2946],{"class":118},[46,3169,3170],{"class":125}," }  ",[46,3172,3173],{"class":52},"\u002F\u002F module scope — ONE object for all imports\n",[46,3175,3176],{"class":48,"line":62},[46,3177,96],{"emptyLinePlaceholder":95},[46,3179,3180,3182,3184],{"class":48,"line":68},[46,3181,554],{"class":114},[46,3183,2317],{"class":114},[46,3185,126],{"class":125},[46,3187,3188,3190],{"class":48,"line":74},[46,3189,2962],{"class":132},[46,3191,1733],{"class":125},[46,3193,3194,3196,3199],{"class":48,"line":80},[46,3195,172],{"class":114},[46,3197,3198],{"class":125}," sharedState  ",[46,3200,3201],{"class":52},"\u002F\u002F returns the same reference for every instance\n",[46,3203,3204],{"class":48,"line":86},[46,3205,187],{"class":125},[46,3207,3208],{"class":48,"line":92},[46,3209,3210],{"class":125},"  methods: {\n",[46,3212,3213,3216,3218,3221,3224,3226,3229,3231],{"class":48,"line":99},[46,3214,3215],{"class":132},"    toggle",[46,3217,2965],{"class":125},[46,3219,3220],{"class":118},"this",[46,3222,3223],{"class":125},".expanded ",[46,3225,362],{"class":114},[46,3227,3228],{"class":114}," !",[46,3230,3220],{"class":118},[46,3232,3233],{"class":125},".expanded }\n",[46,3235,3236],{"class":48,"line":105},[46,3237,312],{"class":125},[46,3239,3240],{"class":48,"line":111},[46,3241,318],{"class":125},[46,3243,3244,3246,3248],{"class":48,"line":129},[46,3245,1414],{"class":125},[46,3247,1202],{"class":1201},[46,3249,1216],{"class":125},[46,3251,3252],{"class":48,"line":157},[46,3253,96],{"emptyLinePlaceholder":95},[46,3255,3256,3258,3260],{"class":48,"line":169},[46,3257,1198],{"class":125},[46,3259,1429],{"class":1201},[46,3261,1216],{"class":125},[46,3263,3264,3266,3268,3270,3272,3275,3278,3280],{"class":48,"line":184},[46,3265,1441],{"class":125},[46,3267,1603],{"class":1201},[46,3269,1454],{"class":132},[46,3271,362],{"class":125},[46,3273,3274],{"class":365},"\"toggle\"",[46,3276,3277],{"class":125},">{{ expanded ? 'Expanded' : 'Collapsed' }}\u003C\u002F",[46,3279,1603],{"class":1201},[46,3281,1216],{"class":125},[46,3283,3284,3286,3288],{"class":48,"line":190},[46,3285,1414],{"class":125},[46,3287,1429],{"class":1201},[46,3289,1216],{"class":125},[3291,3292,3293,3297,3315,3330,3452],"details",{},[3294,3295,3296],"summary",{},"Answer",[20,3298,3299,3302,3303,3306,3307,3310,3311,3314],{},[24,3300,3301],{},"sharedState"," lives at module scope — there is exactly one object in memory. Every ",[24,3304,3305],{},"Card"," instance's ",[24,3308,3309],{},"data()"," returns a reference to that same object. Mutating ",[24,3312,3313],{},"this.expanded"," in one instance mutates the shared object all others read from.",[20,3316,3317,3321,3322,3326,3327,3329],{},[3318,3319,3320],"strong",{},"Fix"," — construct the object ",[3323,3324,3325],"em",{},"inside"," ",[24,3328,3309],{}," so each instance gets its own:",[33,3331,3332],{"language":1186,"filename":3141},[38,3333,3335],{"className":1190,"code":3334,"language":1186,"meta":42,"style":42},"\u003Cscript>\nexport default {\n  data() {\n    return { expanded: false }  \u002F\u002F fresh object per instance — no shared reference\n  },\n  methods: {\n    toggle() { this.expanded = !this.expanded }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv @click=\"toggle\">{{ expanded ? 'Expanded' : 'Collapsed' }}\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[24,3336,3337,3345,3353,3359,3372,3376,3380,3398,3402,3406,3414,3418,3426,3444],{"__ignoreMap":42},[46,3338,3339,3341,3343],{"class":48,"line":49},[46,3340,1198],{"class":125},[46,3342,1202],{"class":1201},[46,3344,1216],{"class":125},[46,3346,3347,3349,3351],{"class":48,"line":56},[46,3348,554],{"class":114},[46,3350,2317],{"class":114},[46,3352,126],{"class":125},[46,3354,3355,3357],{"class":48,"line":62},[46,3356,2962],{"class":132},[46,3358,1733],{"class":125},[46,3360,3361,3363,3365,3367,3369],{"class":48,"line":68},[46,3362,172],{"class":114},[46,3364,2943],{"class":125},[46,3366,2946],{"class":118},[46,3368,3170],{"class":125},[46,3370,3371],{"class":52},"\u002F\u002F fresh object per instance — no shared reference\n",[46,3373,3374],{"class":48,"line":74},[46,3375,187],{"class":125},[46,3377,3378],{"class":48,"line":80},[46,3379,3210],{"class":125},[46,3381,3382,3384,3386,3388,3390,3392,3394,3396],{"class":48,"line":86},[46,3383,3215],{"class":132},[46,3385,2965],{"class":125},[46,3387,3220],{"class":118},[46,3389,3223],{"class":125},[46,3391,362],{"class":114},[46,3393,3228],{"class":114},[46,3395,3220],{"class":118},[46,3397,3233],{"class":125},[46,3399,3400],{"class":48,"line":92},[46,3401,312],{"class":125},[46,3403,3404],{"class":48,"line":99},[46,3405,318],{"class":125},[46,3407,3408,3410,3412],{"class":48,"line":105},[46,3409,1414],{"class":125},[46,3411,1202],{"class":1201},[46,3413,1216],{"class":125},[46,3415,3416],{"class":48,"line":111},[46,3417,96],{"emptyLinePlaceholder":95},[46,3419,3420,3422,3424],{"class":48,"line":129},[46,3421,1198],{"class":125},[46,3423,1429],{"class":1201},[46,3425,1216],{"class":125},[46,3427,3428,3430,3432,3434,3436,3438,3440,3442],{"class":48,"line":157},[46,3429,1441],{"class":125},[46,3431,1603],{"class":1201},[46,3433,1454],{"class":132},[46,3435,362],{"class":125},[46,3437,3274],{"class":365},[46,3439,3277],{"class":125},[46,3441,1603],{"class":1201},[46,3443,1216],{"class":125},[46,3445,3446,3448,3450],{"class":48,"line":169},[46,3447,1414],{"class":125},[46,3449,1429],{"class":1201},[46,3451,1216],{"class":125},[20,3453,3454,1529,3457,3459],{},[3318,3455,3456],{},"The lesson",[24,3458,3309],{}," being a function isn't stylistic — it guarantees per-instance state isolation. The object it returns must also be created fresh inside the function, never hoisted to module scope.",[1494,3461,3462],{},"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 .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}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 .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}",{"title":42,"searchDepth":56,"depth":56,"links":3464},[3465,3466,3469,3470,3473,3474,3475,3476,3477],{"id":17,"depth":56,"text":18},{"id":424,"depth":56,"text":425,"children":3467},[3468],{"id":1039,"depth":62,"text":1040},{"id":1182,"depth":56,"text":1183},{"id":1550,"depth":56,"text":1551,"children":3471},[3472],{"id":1889,"depth":62,"text":1890},{"id":2010,"depth":56,"text":2011},{"id":2231,"depth":56,"text":2232},{"id":2577,"depth":56,"text":2578},{"id":2790,"depth":56,"text":2791},{"id":3134,"depth":56,"text":3135},"Production-grade Vue 3 setup reference — Proxy reactivity internals, createApp isolation, SFC compilation pipeline, multi-instance mounting, DevTools integration, and edge cases that bite in real codebases.","md",{},"\u002Fvue\u002F01-introduction-and-setup",{"title":5,"description":3478},"vue\u002F01-introduction-and-setup","DWDBpOCYu7Ox103TsOp4vh20_ssHZdmc8prosQWX2fQ",1789924655346]