[{"data":1,"prerenderedAt":31699},["ShallowReactive",2],{"/post/top-111-backend-interview-questions":3,"related-/backend/top-111-backend-interview-questions":5026},{"id":4,"title":5,"author":6,"body":7,"date":5008,"description":5009,"draft":5010,"extension":5011,"guide":5012,"image":5013,"meta":5014,"navigation":1130,"path":5015,"seo":5016,"stem":5017,"tags":5018,"__hash__":5025},"blog/Backend/6.top-111-backend-interview-questions.md","Top 111 Backend Interview Questions and Answers","Kashyap Kumar",{"type":8,"value":9,"toc":4871},"minimark",[10,14,17,22,27,35,140,167,171,184,224,228,234,275,279,296,363,372,376,390,406,410,424,435,439,445,481,485,499,506,535,546,550,556,559,563,566,576,586,600,646,653,659,673,693,707,713,716,746,765,769,775,778,782,789,796,800,804,810,813,856,863,867,877,939,942,946,952,1024,1031,1035,1041,1051,1065,1069,1078,1088,1092,1099,1105,1138,1142,1155,1166,1174,1186,1190,1196,1206,1210,1213,1216,1318,1321,1325,1335,1338,1342,1356,1359,1363,1373,1376,1379,1382,1386,1394,1398,1404,1419,1423,1426,1440,1469,1509,1512,1516,1522,1532,1536,1546,1564,1580,1584,1594,1620,1624,1636,1646,1650,1660,1666,1670,1676,1738,1804,1825,1829,1835,1841,1867,1953,1959,1963,1969,2030,2033,2057,2065,2069,2075,2078,2082,2096,2102,2112,2116,2123,2126,2130,2144,2151,2157,2164,2168,2186,2193,2200,2204,2208,2218,2276,2279,2283,2286,2361,2364,2368,2375,2382,2466,2469,2473,2483,2486,2490,2496,2515,2522,2529,2533,2546,2549,2553,2564,2571,2575,2582,2589,2593,2597,2606,2613,2617,2631,2693,2696,2700,2708,2714,2742,2749,2761,2778,2795,2837,2850,2854,2860,2867,2891,2897,2900,2904,2915,2925,2929,2953,2970,2976,2979,2983,2988,2994,2998,3003,3028,3032,3037,3057,3061,3067,3153,3159,3203,3206,3210,3215,3218,3222,3228,3231,3235,3245,3252,3256,3265,3271,3275,3279,3284,3291,3295,3298,3361,3367,3371,3385,3391,3397,3400,3404,3411,3470,3481,3485,3503,3506,3510,3516,3519,3523,3529,3532,3536,3546,3609,3616,3620,3624,3634,3637,3641,3651,3654,3658,3664,3670,3677,3681,3686,3689,3715,3718,3722,3733,3736,3740,3746,3749,3755,3758,3762,3772,3775,3779,3789,3792,3796,3802,3805,3809,3815,3818,3822,3826,3836,3894,3897,3901,3907,3910,3956,3959,3965,3969,3978,3981,3985,3991,3994,3998,4008,4077,4080,4084,4090,4106,4110,4116,4119,4123,4137,4144,4148,4158,4161,4164,4168,4174,4189,4192,4196,4203,4206,4212,4259,4262,4266,4276,4279,4283,4287,4293,4300,4306,4310,4324,4327,4331,4341,4344,4348,4351,4400,4403,4407,4413,4416,4420,4426,4433,4437,4443,4446,4450,4454,4461,4526,4529,4533,4539,4542,4546,4559,4562,4566,4576,4646,4649,4653,4663,4666,4670,4677,4691,4705,4709,4722,4745,4748,4752,4762,4822,4825,4829,4835,4841,4844,4848,4851,4857,4861,4864,4867],[11,12,13],"p",{},"Backend interviews rarely hinge on trivia. They test whether you understand how a request actually flows through a system: what happens between a client sending an HTTP request and a server writing to a database, why a cache can go stale, what happens when two transactions touch the same row at the same time. Get those mental models right, and you can reason through a question you have never seen phrased quite that way before, even under interview pressure.",[11,15,16],{},"This article collects 111 of the most commonly asked backend interview questions, aimed at developers with zero to three years of experience. It deliberately stays framework-agnostic: you will not find a single question about a specific web framework here, those get their own dedicated articles later on this site. What you will find is the stuff that shows up in almost every backend interview regardless of which language or framework the job actually uses: HTTP fundamentals, API design, relational and NoSQL databases, authentication and security, caching, concurrency, distributed systems, messaging, and testing and deployment. Each answer starts with a clear, simple definition, explains the reasoning behind it, and includes a short example, code snippet, or diagram only where it genuinely helps the idea stick.",[18,19,21],"h2",{"id":20},"http-and-web-fundamentals","HTTP and Web Fundamentals",[23,24,26],"h3",{"id":25},"_1-what-are-the-main-http-methods-and-when-do-you-use-each-get-post-put-patch-delete","1. What are the main HTTP methods and when do you use each (GET, POST, PUT, PATCH, DELETE)?",[11,28,29,30,34],{},"HTTP methods (also called ",[31,32,33],"strong",{},"verbs",") tell the server what kind of action the client wants to perform on a resource. Picking the right one is part of what makes an API predictable to use.",[36,37,38,57],"table",{},[39,40,41],"thead",{},[42,43,44,48,51,54],"tr",{},[45,46,47],"th",{},"Method",[45,49,50],{},"Purpose",[45,52,53],{},"Has body?",[45,55,56],{},"Typical use",[58,59,60,78,94,109,124],"tbody",{},[42,61,62,69,72,75],{},[63,64,65],"td",{},[66,67,68],"code",{},"GET",[63,70,71],{},"Retrieve a resource",[63,73,74],{},"No",[63,76,77],{},"Fetch a user, list products",[42,79,80,85,88,91],{},[63,81,82],{},[66,83,84],{},"POST",[63,86,87],{},"Create a new resource",[63,89,90],{},"Yes",[63,92,93],{},"Create an order, submit a form",[42,95,96,101,104,106],{},[63,97,98],{},[66,99,100],{},"PUT",[63,102,103],{},"Replace a resource entirely",[63,105,90],{},[63,107,108],{},"Overwrite a user's full profile",[42,110,111,116,119,121],{},[63,112,113],{},[66,114,115],{},"PATCH",[63,117,118],{},"Partially update a resource",[63,120,90],{},[63,122,123],{},"Update just a user's email",[42,125,126,131,134,137],{},[63,127,128],{},[66,129,130],{},"DELETE",[63,132,133],{},"Remove a resource",[63,135,136],{},"Usually no",[63,138,139],{},"Delete a comment",[11,141,142,144,145,148,149,151,152,154,155,157,158,160,161,163,164,166],{},[66,143,68],{}," requests should never change data on the server; that's what makes them ",[31,146,147],{},"safe",". ",[66,150,84],{}," is the odd one out because calling it twice usually creates two resources, while ",[66,153,100],{},", ",[66,156,115],{},", and ",[66,159,130],{}," are generally designed so that repeating the same request doesn't cause extra side effects. In practice, interviewers care less about you reciting definitions and more about whether you'd pick ",[66,162,84],{}," for creating a resource versus ",[66,165,100],{}," for replacing one, since mixing these up is a very common mistake in real APIs.",[23,168,170],{"id":169},"_2-what-is-the-difference-between-put-and-patch","2. What is the difference between PUT and PATCH?",[11,172,173,175,176,180,181,183],{},[66,174,100],{}," replaces the ",[177,178,179],"em",{},"entire"," resource with the payload you send; anything you omit is treated as removed or reset to a default. ",[66,182,115],{}," only updates the fields you include, leaving the rest untouched.",[11,185,186,187,154,190,157,193,196,197,199,200,202,203,205,206,208,209,211,212,214,215,217,218,220,221,223],{},"For example, if a user resource has ",[66,188,189],{},"name",[66,191,192],{},"email",[66,194,195],{},"age",", sending a ",[66,198,100],{}," with only ",[66,201,189],{}," and ",[66,204,192],{}," could wipe out ",[66,207,195],{},". Sending the same data as a ",[66,210,115],{}," would leave ",[66,213,195],{}," exactly as it was. In short: ",[66,216,100],{}," is a full replace, ",[66,219,115],{}," is a partial edit. Many APIs implement both, but ",[66,222,115],{}," is the safer default when you only want to change one or two fields.",[23,225,227],{"id":226},"_3-what-does-it-mean-for-an-http-method-to-be-idempotent-and-which-methods-are-idempotent","3. What does it mean for an HTTP method to be idempotent, and which methods are idempotent?",[11,229,230,233],{},[31,231,232],{},"Idempotent"," means calling the same request multiple times produces the same result as calling it once; the server ends up in the same state no matter how many times the client retries.",[11,235,236,154,238,154,240,154,242,157,245,248,249,252,253,256,257,260,261,263,264,267,268,271,272,274],{},[66,237,68],{},[66,239,100],{},[66,241,130],{},[66,243,244],{},"HEAD",[66,246,247],{},"OPTIONS"," are idempotent. ",[66,250,251],{},"PUT /users/1"," with the same body always leaves user 1 in the same final state, and ",[66,254,255],{},"DELETE /users/1"," called twice just means the user is deleted (the second call may 404, but the ",[177,258,259],{},"state"," doesn't change further). ",[66,262,84],{}," is generally ",[177,265,266],{},"not"," idempotent, since calling ",[66,269,270],{},"POST /orders"," twice typically creates two separate orders. This matters most for retry logic: it's safe to blindly retry an idempotent request after a network timeout, but retrying a ",[66,273,84],{}," without care can duplicate data.",[23,276,278],{"id":277},"_4-what-is-the-difference-between-a-4xx-and-a-5xx-status-code-give-examples-of-each","4. What is the difference between a 4xx and a 5xx status code? Give examples of each.",[11,280,281,284,285,288,289,284,292,295],{},[66,282,283],{},"4xx"," status codes mean the ",[177,286,287],{},"client"," made a mistake (bad input, missing auth, requesting something that doesn't exist). ",[66,290,291],{},"5xx",[177,293,294],{},"server"," failed to handle a valid request, even though the client did nothing wrong.",[36,297,298,311],{},[39,299,300],{},[42,301,302,305,308],{},[45,303,304],{},"Range",[45,306,307],{},"Meaning",[45,309,310],{},"Common examples",[58,312,313,340],{},[42,314,315,319,322],{},[63,316,317],{},[66,318,283],{},[63,320,321],{},"Client error",[63,323,324,327,328,331,332,335,336,339],{},[66,325,326],{},"400"," Bad Request, ",[66,329,330],{},"401"," Unauthorized, ",[66,333,334],{},"404"," Not Found, ",[66,337,338],{},"422"," Unprocessable Entity",[42,341,342,346,349],{},[63,343,344],{},[66,345,291],{},[63,347,348],{},"Server error",[63,350,351,354,355,358,359,362],{},[66,352,353],{},"500"," Internal Server Error, ",[66,356,357],{},"502"," Bad Gateway, ",[66,360,361],{},"503"," Service Unavailable",[11,364,365,366,368,369,371],{},"This distinction is useful in debugging too: a spike in ",[66,367,283],{}," errors usually points to a client-side bug or bad documentation, while a spike in ",[66,370,291],{}," errors points to something broken on your infrastructure or code, like an unhandled exception or a downstream service timing out.",[23,373,375],{"id":374},"_5-what-is-the-difference-between-401-unauthorized-and-403-forbidden","5. What is the difference between 401 Unauthorized and 403 Forbidden?",[11,377,378,381,382,385,386,389],{},[66,379,380],{},"401 Unauthorized"," means the request has no valid credentials at all, or the ones provided are invalid or expired; the server doesn't know who you are. ",[66,383,384],{},"403 Forbidden"," means the server ",[177,387,388],{},"does"," know who you are, but you don't have permission to access that resource.",[11,391,392,393,395,396,399,400,402,403,405],{},"A simple way to remember it: ",[66,394,330],{}," is \"please log in,\" ",[66,397,398],{},"403"," is \"you're logged in, but you're not allowed here.\" For example, hitting an admin-only endpoint without a token returns ",[66,401,330],{},", but hitting it while logged in as a regular (non-admin) user returns ",[66,404,398],{},".",[23,407,409],{"id":408},"_6-what-is-the-difference-between-a-301-and-a-302-redirect","6. What is the difference between a 301 and a 302 redirect?",[11,411,412,415,416,419,420,423],{},[66,413,414],{},"301 Moved Permanently"," tells the client (and search engines) that a resource has permanently moved to a new URL; browsers and crawlers will update their references and cache the new location. ",[66,417,418],{},"302 Found"," (temporary redirect) says the resource is ",[177,421,422],{},"currently"," at a different URL, but the original URL should still be used for future requests.",[11,425,426,427,430,431,434],{},"Using the wrong one has real consequences: a ",[66,428,429],{},"301"," on a URL that later changes back can leave search engines and caches pointing at the wrong place for a long time, while using ",[66,432,433],{},"302"," for something that's actually permanent means you lose SEO value that should have transferred to the new URL.",[23,436,438],{"id":437},"_7-what-are-http-headers-and-whats-the-difference-between-request-headers-and-response-headers","7. What are HTTP headers, and what's the difference between request headers and response headers?",[11,440,441,444],{},[31,442,443],{},"Headers"," are key-value pairs sent alongside an HTTP request or response that carry metadata, separate from the actual body content. They describe things like content type, authentication, caching rules, and client information.",[11,446,447,450,451,454,455,458,459,462,463,466,467,469,470,473,474,477,478,480],{},[31,448,449],{},"Request headers"," are sent by the client to give the server context about the request, such as ",[66,452,453],{},"Authorization"," (credentials), ",[66,456,457],{},"Content-Type"," (format of the body being sent), and ",[66,460,461],{},"Accept"," (what response formats the client can handle). ",[31,464,465],{},"Response headers"," are sent back by the server to describe the response, such as ",[66,468,457],{}," of the returned data, ",[66,471,472],{},"Set-Cookie",", and caching headers like ",[66,475,476],{},"Cache-Control",". Some headers, like ",[66,479,457],{},", appear on both sides but describe different things depending on direction.",[23,482,484],{"id":483},"_8-what-is-cors-and-why-does-the-browser-enforce-it","8. What is CORS, and why does the browser enforce it?",[11,486,487,490,491,494,495,498],{},[31,488,489],{},"CORS"," (Cross-Origin Resource Sharing) is a browser security mechanism that controls whether a web page running on one origin (domain, protocol, and port) is allowed to make requests to a server on a ",[177,492,493],{},"different"," origin. By default, browsers block cross-origin requests due to the ",[31,496,497],{},"same-origin policy",", and CORS is the standard way for a server to explicitly relax that restriction.",[11,500,501,502,505],{},"The browser enforces this to protect users: without it, a malicious website could silently make authenticated requests to another site (like your bank) using cookies stored in your browser, and read the response. When a browser makes a cross-origin request, the server must respond with headers like ",[66,503,504],{},"Access-Control-Allow-Origin"," telling the browser which origins are permitted.",[507,508,513],"pre",{"className":509,"code":510,"language":511,"meta":512,"style":512},"language-http shiki shiki-themes github-dark","Access-Control-Allow-Origin: https://example.com\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE\nAccess-Control-Allow-Headers: Content-Type, Authorization\n","http","",[66,514,515,523,529],{"__ignoreMap":512},[516,517,520],"span",{"class":518,"line":519},"line",1,[516,521,522],{},"Access-Control-Allow-Origin: https://example.com\n",[516,524,526],{"class":518,"line":525},2,[516,527,528],{},"Access-Control-Allow-Methods: GET, POST, PUT, DELETE\n",[516,530,532],{"class":518,"line":531},3,[516,533,534],{},"Access-Control-Allow-Headers: Content-Type, Authorization\n",[11,536,537,538,541,542,545],{},"It's worth knowing that CORS is enforced by the ",[177,539,540],{},"browser",", not the server; server-to-server requests and tools like ",[66,543,544],{},"curl"," ignore CORS entirely.",[23,547,549],{"id":548},"_9-what-does-it-mean-for-http-to-be-a-stateless-protocol","9. What does it mean for HTTP to be a stateless protocol?",[11,551,552,555],{},[31,553,554],{},"Stateless"," means each HTTP request is handled independently; the server doesn't automatically remember anything about previous requests from the same client. Every request must carry all the information the server needs to process it, such as authentication tokens.",[11,557,558],{},"This is why things like login sessions require extra mechanisms, cookies, tokens, or server-side session stores, to simulate \"memory\" across requests. Statelessness is actually a deliberate design choice: it makes servers easier to scale horizontally, since any server in a pool can handle any request without needing to know what happened before.",[23,560,562],{"id":561},"_10-what-is-the-difference-between-http11-http2-and-http3-at-a-high-level","10. What is the difference between HTTP/1.1, HTTP/2, and HTTP/3 at a high level?",[11,564,565],{},"Each version improves how requests and responses move over the network, without changing the core semantics (methods, status codes, headers stay conceptually the same).",[11,567,568,571,572,575],{},[31,569,570],{},"HTTP/1.1"," sends requests as plain text over a single connection per request at a time (with keep-alive to reuse the connection), which leads to ",[177,573,574],{},"head-of-line blocking",": one slow request can delay the ones behind it, so browsers open multiple parallel connections as a workaround.",[11,577,578,581,582,585],{},[31,579,580],{},"HTTP/2"," introduced ",[177,583,584],{},"multiplexing",", allowing many requests and responses to be interleaved over a single TCP connection, along with header compression and server push. This removed the need for multiple connections and made pages load faster, especially with many small assets.",[11,587,588,591,592,595,596,599],{},[31,589,590],{},"HTTP/3"," replaces the underlying transport, moving from TCP to ",[66,593,594],{},"QUIC"," (built on UDP). This fixes a subtler problem: in HTTP/2, if a single TCP packet is lost, ",[177,597,598],{},"all"," multiplexed streams stall waiting for retransmission. QUIC handles streams independently, so packet loss on one stream doesn't block the others, which matters a lot on flaky mobile networks.",[36,601,602,615],{},[39,603,604],{},[42,605,606,609,612],{},[45,607,608],{},"Version",[45,610,611],{},"Transport",[45,613,614],{},"Key improvement",[58,616,617,627,636],{},[42,618,619,621,624],{},[63,620,570],{},[63,622,623],{},"TCP",[63,625,626],{},"Simple, but one request at a time per connection",[42,628,629,631,633],{},[63,630,580],{},[63,632,623],{},[63,634,635],{},"Multiplexed streams, header compression",[42,637,638,640,643],{},[63,639,590],{},[63,641,642],{},"QUIC (UDP)",[63,644,645],{},"Avoids TCP-level head-of-line blocking",[23,647,649,650,652],{"id":648},"_11-what-is-content-negotiation-and-how-does-the-accept-header-relate-to-it","11. What is content negotiation, and how does the ",[66,651,461],{}," header relate to it?",[11,654,655,658],{},[31,656,657],{},"Content negotiation"," is the process where a client and server agree on the best format to represent a resource, such as JSON versus XML, or English versus French. Instead of a server having one fixed format for every client, it can serve different representations based on what the client asks for.",[11,660,661,662,664,665,668,669,672],{},"The client signals its preference using the ",[66,663,461],{}," header (for format) and headers like ",[66,666,667],{},"Accept-Language"," (for language). The server reads these and responds accordingly, often falling back to a default if it can't satisfy the request, or returning ",[66,670,671],{},"406 Not Acceptable"," if it truly can't.",[507,674,676],{"className":509,"code":675,"language":511,"meta":512,"style":512},"GET /users/42 HTTP/1.1\nAccept: application/json\nAccept-Language: en-US\n",[66,677,678,683,688],{"__ignoreMap":512},[516,679,680],{"class":518,"line":519},[516,681,682],{},"GET /users/42 HTTP/1.1\n",[516,684,685],{"class":518,"line":525},[516,686,687],{},"Accept: application/json\n",[516,689,690],{"class":518,"line":531},[516,691,692],{},"Accept-Language: en-US\n",[23,694,696,697,154,700,157,703,706],{"id":695},"_12-what-are-cookies-used-for-on-the-backend-and-what-do-attributes-like-httponly-secure-and-samesite-do","12. What are cookies used for on the backend, and what do attributes like ",[66,698,699],{},"HttpOnly",[66,701,702],{},"Secure",[66,704,705],{},"SameSite"," do?",[11,708,709,712],{},[31,710,711],{},"Cookies"," are small pieces of data the server asks the browser to store and automatically send back on future requests to the same site. On the backend, they're commonly used for session identifiers, authentication tokens, and tracking user preferences, since HTTP itself is stateless.",[11,714,715],{},"A few attributes control how safely cookies behave:",[717,718,719,725,730],"ul",{},[720,721,722,724],"li",{},[66,723,699],{}," prevents JavaScript from reading the cookie, which protects against theft via cross-site scripting (XSS).",[720,726,727,729],{},[66,728,702],{}," ensures the cookie is only sent over HTTPS, not plain HTTP.",[720,731,732,734,735,154,738,741,742,745],{},[66,733,705],{}," (",[66,736,737],{},"Strict",[66,739,740],{},"Lax",", or ",[66,743,744],{},"None",") controls whether the cookie is sent on cross-site requests, which helps prevent cross-site request forgery (CSRF).",[11,747,748,749,154,751,157,753,756,757,759,760,405],{},"A typical session cookie for a production app would set all three: ",[66,750,699],{},[66,752,702],{},[66,754,755],{},"SameSite=Lax"," or ",[66,758,737],{},", to minimize the attack surface. For a deeper comparison of cookies against browser storage options, see ",[761,762,764],"a",{"href":763},"/post/local-storage-vs-session-storage-vs-cookies","Local Storage vs Session Storage vs Cookies",[23,766,768],{"id":767},"_13-what-is-the-same-origin-policy","13. What is the same-origin policy?",[11,770,771,772,774],{},"The ",[31,773,497],{}," is a browser security rule that restricts how a script loaded from one origin can interact with resources from a different origin. Two URLs share an origin only if they have the same protocol, domain, and port; changing any one of those makes it a different origin.",[11,776,777],{},"Without this policy, a script running on a malicious page could freely read data from other sites you're logged into, like your email or bank, using your existing browser session. It's the underlying reason CORS exists: CORS is essentially a controlled way for a server to opt out of the same-origin restriction for specific origins.",[23,779,781],{"id":780},"_14-what-is-a-websocket-and-how-is-it-different-from-a-regular-http-request","14. What is a WebSocket, and how is it different from a regular HTTP request?",[11,783,784,785,788],{},"A ",[31,786,787],{},"WebSocket"," is a persistent, full-duplex (two-way) connection between client and server, established by an initial HTTP handshake that then \"upgrades\" to the WebSocket protocol. Once open, either side can send messages at any time without starting a new request each time.",[11,790,791,792,795],{},"A regular HTTP request follows a strict request-response cycle: the client asks, the server answers, and the connection is typically closed or reused for the ",[177,793,794],{},"next"," separate request-response pair. This makes plain HTTP a poor fit for things that need real-time, ongoing communication, like chat apps, live notifications, or collaborative editing, since the client would otherwise have to keep polling the server for updates. WebSockets solve this by keeping one connection open so the server can push data to the client the moment it's available.",[18,797,799],{"id":798},"api-design","API Design",[23,801,803],{"id":802},"_15-what-makes-an-api-restful-what-are-the-core-rest-constraints","15. What makes an API \"RESTful\"? What are the core REST constraints?",[11,805,806,809],{},[31,807,808],{},"REST"," (Representational State Transfer) is an architectural style for designing networked APIs, built around a set of constraints rather than a strict protocol. An API is considered RESTful when it follows these principles, even though in practice most \"REST APIs\" only loosely follow all of them.",[11,811,812],{},"The core constraints are:",[717,814,815,821,827,833,844,850],{},[720,816,817,820],{},[31,818,819],{},"Client-server separation",": the client and server evolve independently, communicating only through requests.",[720,822,823,826],{},[31,824,825],{},"Statelessness",": each request contains everything needed to process it; the server holds no client session state between requests.",[720,828,829,832],{},[31,830,831],{},"Cacheability",": responses should indicate whether they can be cached, to improve performance.",[720,834,835,838,839,154,841,843],{},[31,836,837],{},"Uniform interface",": resources are identified by URLs, manipulated through a consistent set of methods (",[66,840,68],{},[66,842,84],{},", etc.), and represented in a standard format like JSON.",[720,845,846,849],{},[31,847,848],{},"Layered system",": the client shouldn't need to know whether it's talking directly to the server or through intermediaries like load balancers or caches.",[720,851,852,855],{},[31,853,854],{},"Code on demand"," (optional): servers can optionally send executable code to the client.",[11,857,858,859,862],{},"In interviews, the practical expectation is usually simpler: can you design endpoints around ",[177,860,861],{},"resources"," (nouns), use HTTP methods correctly, and keep requests stateless, rather than reciting the formal constraint list.",[23,864,866],{"id":865},"_16-what-is-the-difference-between-resource-based-url-design-and-action-based-url-design-give-examples-of-good-vs-bad-rest-endpoint-naming","16. What is the difference between resource-based URL design and action-based URL design? Give examples of good vs bad REST endpoint naming.",[11,868,869,872,873,876],{},[31,870,871],{},"Resource-based"," design treats URLs as nouns representing things (resources), and uses HTTP methods to express the action. ",[31,874,875],{},"Action-based"," design bakes the verb directly into the URL, which goes against REST conventions.",[36,878,879,889],{},[39,880,881],{},[42,882,883,886],{},[45,884,885],{},"Bad (action-based)",[45,887,888],{},"Good (resource-based)",[58,890,891,903,915,927],{},[42,892,893,898],{},[63,894,895],{},[66,896,897],{},"POST /createUser",[63,899,900],{},[66,901,902],{},"POST /users",[42,904,905,910],{},[63,906,907],{},[66,908,909],{},"GET /getUserOrders?id=5",[63,911,912],{},[66,913,914],{},"GET /users/5/orders",[42,916,917,922],{},[63,918,919],{},[66,920,921],{},"POST /deleteOrder/12",[63,923,924],{},[66,925,926],{},"DELETE /orders/12",[42,928,929,934],{},[63,930,931],{},[66,932,933],{},"POST /updateUserEmail",[63,935,936],{},[66,937,938],{},"PATCH /users/5",[11,940,941],{},"The resource-based style is preferred because the URL stays stable and the HTTP method conveys the intent, which keeps the API predictable and consistent as it grows. It also means you don't end up with an ever-growing list of one-off endpoint names for every possible action.",[23,943,945],{"id":944},"_17-how-do-you-version-an-api-and-what-are-the-tradeoffs-of-different-versioning-strategies-url-path-header-query-param","17. How do you version an API, and what are the tradeoffs of different versioning strategies (URL path, header, query param)?",[11,947,948,951],{},[31,949,950],{},"API versioning"," lets you change or break a contract without disrupting clients still relying on the old behavior. Since consumers of a public API can't all upgrade at the same time, some way of running multiple versions side by side is usually necessary.",[36,953,954,967],{},[39,955,956],{},[42,957,958,961,964],{},[45,959,960],{},"Strategy",[45,962,963],{},"Example",[45,965,966],{},"Tradeoff",[58,968,969,982,995,1008],{},[42,970,971,974,979],{},[63,972,973],{},"URL path",[63,975,976],{},[66,977,978],{},"/v1/users",[63,980,981],{},"Very visible and easy to route/cache, but \"pollutes\" the URL and implies the resource itself changed",[42,983,984,987,992],{},[63,985,986],{},"Custom header",[63,988,989],{},[66,990,991],{},"Api-Version: 2",[63,993,994],{},"Keeps URLs clean, but less discoverable and harder to test manually (e.g. in a browser)",[42,996,997,1000,1005],{},[63,998,999],{},"Query param",[63,1001,1002],{},[66,1003,1004],{},"/users?version=2",[63,1006,1007],{},"Simple to add, but easy to forget and doesn't play well with caching",[42,1009,1010,1016,1021],{},[63,1011,1012,1013,1015],{},"Media type (",[66,1014,461],{}," header)",[63,1017,1018],{},[66,1019,1020],{},"Accept: application/vnd.api.v2+json",[63,1022,1023],{},"Follows content negotiation properly, but the least intuitive for most developers",[11,1025,1026,1027,1030],{},"URL path versioning is the most common in practice because it's explicit and simple to reason about, even though it's considered less \"pure REST\" than negotiating the version via headers. Whatever strategy you pick, the more important discipline is minimizing ",[177,1028,1029],{},"how often"," you need a new version by preferring backward-compatible changes.",[23,1032,1034],{"id":1033},"_18-what-is-pagination-and-whats-the-difference-between-offset-based-and-cursor-based-pagination","18. What is pagination, and what's the difference between offset-based and cursor-based pagination?",[11,1036,1037,1040],{},[31,1038,1039],{},"Pagination"," splits a large result set into smaller chunks (pages) so a single request doesn't return, say, a million rows at once.",[11,1042,1043,1046,1047,1050],{},[31,1044,1045],{},"Offset-based"," pagination uses a page number or offset plus a limit, like ",[66,1048,1049],{},"GET /orders?offset=40&limit=20",". It's simple to implement and lets users jump to any page directly, but it has a real weakness: if rows are inserted or deleted while paging through results, items can be skipped or duplicated, and performance degrades on large offsets since the database still has to scan past all the skipped rows.",[11,1052,1053,1056,1057,1060,1061,1064],{},[31,1054,1055],{},"Cursor-based"," pagination instead returns a pointer (cursor), often an encoded value based on the last item's ID or timestamp, and the next request asks for items ",[177,1058,1059],{},"after"," that cursor, like ",[66,1062,1063],{},"GET /orders?after=cursor_abc123&limit=20",". This stays consistent even as data changes and scales much better on large tables, but you lose the ability to jump directly to an arbitrary page. Cursor-based pagination is generally preferred for large, frequently-changing datasets and infinite-scroll style feeds.",[23,1066,1068],{"id":1067},"_19-what-is-rate-limiting-and-why-do-apis-implement-it","19. What is rate limiting, and why do APIs implement it?",[11,1070,1071,1074,1075,405],{},[31,1072,1073],{},"Rate limiting"," restricts how many requests a client can make to an API within a given time window, for example 100 requests per minute per API key. When the limit is exceeded, the server typically responds with ",[66,1076,1077],{},"429 Too Many Requests",[11,1079,1080,1081,202,1084,1087],{},"APIs implement it to protect their infrastructure from being overwhelmed (whether by legitimate traffic spikes, bugs like retry loops, or abuse), to keep the service fair across all consumers, and sometimes as part of a paid tiering model. Common strategies include fixed windows, sliding windows, and token bucket algorithms. Response headers like ",[66,1082,1083],{},"X-RateLimit-Remaining",[66,1085,1086],{},"Retry-After"," are often included so well-behaved clients know when to back off.",[23,1089,1091],{"id":1090},"_20-what-is-an-idempotency-key-and-why-is-it-important-for-apis-like-payment-processing","20. What is an idempotency key, and why is it important for APIs like payment processing?",[11,1093,1094,1095,1098],{},"An ",[31,1096,1097],{},"idempotency key"," is a unique value (usually a client-generated UUID) that the client attaches to a request so the server can recognize and safely ignore duplicate submissions of the same operation.",[11,1100,1101,1102,1104],{},"This matters most for non-idempotent methods like ",[66,1103,84],{},". Imagine a client sends a payment request, the network times out before the response arrives, and the client retries. Without an idempotency key, that retry could charge the customer twice. With one, the server checks if it has already processed that exact key; if so, it returns the original result instead of processing the payment again.",[507,1106,1108],{"className":509,"code":1107,"language":511,"meta":512,"style":512},"POST /payments HTTP/1.1\nIdempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7\nContent-Type: application/json\n\n{ \"amount\": 4999, \"currency\": \"usd\" }\n",[66,1109,1110,1115,1120,1125,1132],{"__ignoreMap":512},[516,1111,1112],{"class":518,"line":519},[516,1113,1114],{},"POST /payments HTTP/1.1\n",[516,1116,1117],{"class":518,"line":525},[516,1118,1119],{},"Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7\n",[516,1121,1122],{"class":518,"line":531},[516,1123,1124],{},"Content-Type: application/json\n",[516,1126,1128],{"class":518,"line":1127},4,[516,1129,1131],{"emptyLinePlaceholder":1130},true,"\n",[516,1133,1135],{"class":518,"line":1134},5,[516,1136,1137],{},"{ \"amount\": 4999, \"currency\": \"usd\" }\n",[23,1139,1141],{"id":1140},"_21-what-is-the-difference-between-rest-and-graphql-at-a-conceptual-level","21. What is the difference between REST and GraphQL at a conceptual level?",[11,1143,1144,1146,1147,1150,1151,1154],{},[31,1145,808],{}," exposes multiple fixed endpoints, each returning a predetermined shape of data for a resource. ",[31,1148,1149],{},"GraphQL"," exposes a ",[177,1152,1153],{},"single"," endpoint where the client sends a query describing exactly the fields it wants, and the server returns data matching that shape, nothing more, nothing less.",[11,1156,1157,1158,1161,1162,1165],{},"This difference solves two common REST pain points: ",[177,1159,1160],{},"over-fetching"," (getting fields you don't need, wasting bandwidth) and ",[177,1163,1164],{},"under-fetching"," (needing to call multiple endpoints to assemble the data a screen actually needs, like fetching a user, then their orders, then each order's items separately). GraphQL lets a client ask for a user along with specific nested fields from orders and items in one request.",[507,1167,1172],{"className":1168,"code":1170,"language":1171,"meta":512},[1169],"language-text","query {\n  user(id: 5) {\n    name\n    orders {\n      id\n      total\n    }\n  }\n}\n","text",[66,1173,1170],{"__ignoreMap":512},[11,1175,1176,1177,1180,1181,1185],{},"The tradeoff is that GraphQL pushes more complexity onto the server (query cost analysis, avoiding N+1 queries under the hood, custom caching) and loses some of REST's simplicity, like relying on standard HTTP caching by URL. Neither is strictly \"better\"; REST tends to be simpler for straightforward CRUD APIs, while GraphQL shines when clients have very different, evolving data needs (like a mobile app versus a web dashboard). Both are also younger than ",[31,1178,1179],{},"SOAP",", the XML-based protocol REST largely replaced for public APIs but which still runs a lot of enterprise and banking infrastructure; the ",[761,1182,1184],{"href":1183},"/post/soap-api","SOAP API"," article covers why it hasn't gone away.",[23,1187,1189],{"id":1188},"_22-what-is-hateoas","22. What is HATEOAS?",[11,1191,1192,1195],{},[31,1193,1194],{},"HATEOAS"," (Hypermedia as the Engine of Application State) is a REST constraint where API responses include links describing what actions or related resources are available next, similar to how clicking through a website works without knowing URLs in advance.",[11,1197,1198,1199,756,1202,1205],{},"For example, a response for an order might include links to ",[66,1200,1201],{},"cancel",[66,1203,1204],{},"pay"," actions directly in the payload, rather than the client having to hardcode those URLs based on documentation. In theory this lets clients navigate an API dynamically as it evolves; in practice, very few real-world APIs implement it fully, since it adds complexity that most teams don't find worth the payoff. It's still a common interview topic because it's part of the \"official\" REST definition.",[23,1207,1209],{"id":1208},"_23-how-should-an-api-communicate-errors-to-consumers-what-makes-a-good-error-response","23. How should an API communicate errors to consumers? What makes a good error response?",[11,1211,1212],{},"A good error response uses the right HTTP status code as the first signal, then includes a structured body with enough detail for the client to understand and, ideally, act on the problem, without leaking internal implementation details like stack traces.",[11,1214,1215],{},"A useful error response usually includes: a machine-readable error code (for programmatic handling), a human-readable message (for logs or display), and, for validation errors, which specific fields failed and why.",[507,1217,1221],{"className":1218,"code":1219,"language":1220,"meta":512,"style":512},"language-json shiki shiki-themes github-dark","{\n  \"error\": {\n    \"code\": \"VALIDATION_FAILED\",\n    \"message\": \"One or more fields are invalid\",\n    \"details\": [\n      { \"field\": \"email\", \"issue\": \"must be a valid email address\" }\n    ]\n  }\n}\n","json",[66,1222,1223,1229,1238,1253,1265,1273,1300,1306,1312],{"__ignoreMap":512},[516,1224,1225],{"class":518,"line":519},[516,1226,1228],{"class":1227},"s95oV","{\n",[516,1230,1231,1235],{"class":518,"line":525},[516,1232,1234],{"class":1233},"sDLfK","  \"error\"",[516,1236,1237],{"class":1227},": {\n",[516,1239,1240,1243,1246,1250],{"class":518,"line":531},[516,1241,1242],{"class":1233},"    \"code\"",[516,1244,1245],{"class":1227},": ",[516,1247,1249],{"class":1248},"sU2Wk","\"VALIDATION_FAILED\"",[516,1251,1252],{"class":1227},",\n",[516,1254,1255,1258,1260,1263],{"class":518,"line":1127},[516,1256,1257],{"class":1233},"    \"message\"",[516,1259,1245],{"class":1227},[516,1261,1262],{"class":1248},"\"One or more fields are invalid\"",[516,1264,1252],{"class":1227},[516,1266,1267,1270],{"class":518,"line":1134},[516,1268,1269],{"class":1233},"    \"details\"",[516,1271,1272],{"class":1227},": [\n",[516,1274,1276,1279,1282,1284,1287,1289,1292,1294,1297],{"class":518,"line":1275},6,[516,1277,1278],{"class":1227},"      { ",[516,1280,1281],{"class":1233},"\"field\"",[516,1283,1245],{"class":1227},[516,1285,1286],{"class":1248},"\"email\"",[516,1288,154],{"class":1227},[516,1290,1291],{"class":1233},"\"issue\"",[516,1293,1245],{"class":1227},[516,1295,1296],{"class":1248},"\"must be a valid email address\"",[516,1298,1299],{"class":1227}," }\n",[516,1301,1303],{"class":518,"line":1302},7,[516,1304,1305],{"class":1227},"    ]\n",[516,1307,1309],{"class":518,"line":1308},8,[516,1310,1311],{"class":1227},"  }\n",[516,1313,1315],{"class":518,"line":1314},9,[516,1316,1317],{"class":1227},"}\n",[11,1319,1320],{},"Consistency matters a lot here: if every endpoint formats errors differently, client code ends up littered with special cases. Keeping one consistent error shape across the whole API makes it much easier for consumers to write generic error-handling logic.",[23,1322,1324],{"id":1323},"_24-what-is-an-api-contract-eg-via-openapiswagger-and-why-do-teams-maintain-one","24. What is an API contract (e.g. via OpenAPI/Swagger), and why do teams maintain one?",[11,1326,1094,1327,1330,1331,1334],{},[31,1328,1329],{},"API contract"," is a formal, machine-readable description of an API's endpoints, request/response shapes, status codes, and authentication requirements, often written using a spec like ",[66,1332,1333],{},"OpenAPI"," (formerly Swagger).",[11,1336,1337],{},"Teams maintain one because it acts as a single source of truth that both the backend team and any API consumers (frontend, mobile, third-party partners) can rely on. Practical benefits include auto-generated documentation, auto-generated client SDKs, mock servers for frontend developers to build against before the backend is finished, and automated contract tests that catch accidental breaking changes before they ship.",[23,1339,1341],{"id":1340},"_25-what-is-the-difference-between-a-webhook-and-polling","25. What is the difference between a webhook and polling?",[11,1343,1344,1347,1348,1351,1352,1355],{},[31,1345,1346],{},"Polling"," means the client repeatedly asks the server \"has anything changed?\" at fixed intervals, whether or not anything actually happened. ",[31,1349,1350],{},"Webhooks"," flip this around: the client registers a URL with the server ahead of time, and the server calls ",[177,1353,1354],{},"that"," URL to push data the moment an event occurs.",[11,1357,1358],{},"Polling is simple to implement but wastes resources on both sides, especially if changes are rare, and introduces delay equal to the polling interval. Webhooks are far more efficient and near-instant, but they add complexity: the receiving server needs a publicly reachable endpoint, must handle retries if delivery fails, and should verify the request actually came from the expected sender (commonly via a signature header). A common real-world example is a payment provider sending a webhook the moment a payment succeeds, instead of your server repeatedly asking \"is this payment done yet?\"",[23,1360,1362],{"id":1361},"_26-whats-the-difference-between-a-backward-compatible-api-change-and-a-breaking-change-give-examples-of-each","26. What's the difference between a backward-compatible API change and a breaking change? Give examples of each.",[11,1364,784,1365,1368,1369,1372],{},[31,1366,1367],{},"backward-compatible"," change is one that existing clients can safely ignore; their code keeps working without any modification. A ",[31,1370,1371],{},"breaking change"," alters the contract in a way that existing client code can no longer rely on, causing errors or incorrect behavior.",[11,1374,1375],{},"Backward-compatible examples: adding a new optional field to a response, adding a new endpoint, adding a new optional query parameter, making a previously required field optional.",[11,1377,1378],{},"Breaking examples: removing or renaming a field, changing a field's data type (e.g. string to number), changing a status code for an existing scenario, making a previously optional parameter required, or changing the meaning of an existing field without renaming it.",[11,1380,1381],{},"The general rule of thumb: additive changes are usually safe, while removing, renaming, or changing the meaning or type of anything is usually breaking. This is exactly why API versioning exists, to introduce breaking changes without forcing every consumer to upgrade at once.",[18,1383,1385],{"id":1384},"relational-databases","Relational Databases",[11,1387,1388,1389,1393],{},"If any of the fundamentals below feel shaky, the ",[761,1390,1392],{"href":1391},"/post/sql-made-dead-simple-rdbms-guide","SQL Made Dead Simple"," guide covers RDBMS basics, keys, joins, and schema design in more depth than an interview-prep answer can.",[23,1395,1397],{"id":1396},"_27-what-is-normalization-and-what-problem-does-it-solve","27. What is normalization, and what problem does it solve?",[11,1399,1400,1403],{},[31,1401,1402],{},"Normalization"," is the process of organizing a database's tables and columns to reduce redundant data and avoid certain types of inconsistency. It works by breaking data into smaller, related tables connected through foreign keys, instead of repeating the same information across many rows.",[11,1405,1406,1407,1410,1411,1414,1415,1418],{},"Without normalization, if a customer's address were duplicated in every one of their orders and it changed, you'd need to update it in every row, and missing even one would leave the data inconsistent. Normalization solves this by storing the address once in a ",[66,1408,1409],{},"customers"," table and referencing it by ID from ",[66,1412,1413],{},"orders",". The tradeoff is that reading normalized data often requires joining multiple tables, which is where ",[31,1416,1417],{},"denormalization"," sometimes comes back into play for performance.",[23,1420,1422],{"id":1421},"_28-can-you-explain-the-first-three-normal-forms-1nf-2nf-3nf-in-simple-terms","28. Can you explain the first three normal forms (1NF, 2NF, 3NF) in simple terms?",[11,1424,1425],{},"Each normal form builds on the one before it, progressively removing specific kinds of redundancy.",[11,1427,1428,1431,1432,1435,1436,1439],{},[31,1429,1430],{},"1NF (First Normal Form)",": every column holds a single, atomic value, not a list or a set of values crammed into one field. A ",[66,1433,1434],{},"phone_numbers"," column containing ",[66,1437,1438],{},"\"555-1234, 555-5678\""," violates 1NF; it should be split into a separate table where each row is one phone number linked to the customer.",[11,1441,1442,1445,1446,1448,1449,1452,1453,1456,1457,1460,1461,1464,1465,1468],{},[31,1443,1444],{},"2NF (Second Normal Form)",": builds on 1NF, and requires that every non-key column depends on the ",[177,1447,179],{}," primary key, not just part of it. This only really applies to tables with a composite (multi-column) primary key. For example, in an ",[66,1450,1451],{},"order_items"," table keyed on ",[66,1454,1455],{},"(order_id, product_id)",", a column like ",[66,1458,1459],{},"product_name"," depends only on ",[66,1462,1463],{},"product_id",", not the full key, so it violates 2NF and should live in a separate ",[66,1466,1467],{},"products"," table instead.",[11,1470,1471,1474,1475,1478,1479,1482,1483,154,1486,157,1489,1492,1493,1495,1496,1498,1499,1501,1502,1504,1505,1508],{},[31,1472,1473],{},"3NF (Third Normal Form)",": builds on 2NF, and requires that non-key columns depend ",[177,1476,1477],{},"only"," on the primary key, not on other non-key columns. If a ",[66,1480,1481],{},"students"," table has ",[66,1484,1485],{},"student_id",[66,1487,1488],{},"department_id",[66,1490,1491],{},"department_name",", then ",[66,1494,1491],{}," depends on ",[66,1497,1488],{}," rather than directly on ",[66,1500,1485],{},", which violates 3NF; ",[66,1503,1491],{}," should move into its own ",[66,1506,1507],{},"departments"," table.",[11,1510,1511],{},"In short: 1NF is about atomic values, 2NF is about full key dependency, and 3NF is about removing dependencies between non-key columns.",[23,1513,1515],{"id":1514},"_29-what-is-denormalization-and-when-would-you-intentionally-use-it","29. What is denormalization, and when would you intentionally use it?",[11,1517,1518,1521],{},[31,1519,1520],{},"Denormalization"," is the deliberate act of introducing redundancy back into a database, usually by duplicating data or merging tables, in order to reduce the number of joins needed for common read queries.",[11,1523,1524,1525,1528,1529,1531],{},"It's a tradeoff: you gain faster reads at the cost of extra storage and more complex writes, since now you have to keep the duplicated data in sync in multiple places. It's commonly used for reporting/analytics tables, caching computed aggregates (like storing a ",[66,1526,1527],{},"total_reviews"," count directly on a ",[66,1530,1467],{}," row instead of counting them every time), or high-read, low-write systems where query speed matters more than storage efficiency.",[23,1533,1535],{"id":1534},"_30-what-is-the-difference-between-a-primary-key-a-foreign-key-and-a-unique-key","30. What is the difference between a primary key, a foreign key, and a unique key?",[11,1537,784,1538,1541,1542,1545],{},[31,1539,1540],{},"primary key"," uniquely identifies each row in a table; a table can have only one, it cannot contain ",[66,1543,1544],{},"NULL",", and it's typically used to link to other tables.",[11,1547,784,1548,1551,1552,1555,1556,1559,1560,1563],{},[31,1549,1550],{},"foreign key"," is a column (or set of columns) in one table that references the primary key of another table, enforcing that the referenced value actually exists there. This is how relational databases maintain ",[31,1553,1554],{},"referential integrity",", for example ensuring an ",[66,1557,1558],{},"order"," can't reference a ",[66,1561,1562],{},"customer_id"," that doesn't exist.",[11,1565,784,1566,1569,1570,1572,1573,1575,1576,1579],{},[31,1567,1568],{},"unique key"," enforces that all values in a column are distinct, just like a primary key, but a table can have several unique keys, and (unlike a primary key) unique columns can typically allow one ",[66,1571,1544],{}," value. A good example is an ",[66,1574,192],{}," column: it's a natural fit for a unique key, but ",[66,1577,1578],{},"id"," remains the primary key.",[23,1581,1583],{"id":1582},"_31-what-is-a-database-index-and-how-does-it-speed-up-queries","31. What is a database index, and how does it speed up queries?",[11,1585,1094,1586,1589,1590,1593],{},[31,1587,1588],{},"index"," is a separate data structure (commonly a ",[66,1591,1592],{},"B-tree",") that the database maintains alongside a table, allowing it to look up rows matching a condition without scanning every row.",[11,1595,1596,1597,1600,1601,1604,1605,1607,1608,1611,1612,1615,1616,1619],{},"Without an index, a query like ",[66,1598,1599],{},"SELECT * FROM users WHERE email = 'a@b.com'"," has to check every row in the table (a ",[177,1602,1603],{},"full table scan","), which gets slower as the table grows. With an index on ",[66,1606,192],{},", the database can jump almost directly to the matching row, similar to using the index at the back of a book instead of reading every page. Indexes dramatically speed up ",[66,1609,1610],{},"WHERE"," filters, ",[66,1613,1614],{},"JOIN"," conditions, and ",[66,1617,1618],{},"ORDER BY"," clauses on the indexed columns, but they aren't free (see the next question).",[23,1621,1623],{"id":1622},"_32-what-is-the-tradeoff-of-adding-too-many-indexes-to-a-table","32. What is the tradeoff of adding too many indexes to a table?",[11,1625,1626,1627,154,1630,741,1633,1635],{},"Indexes speed up reads, but every index has to be updated on every ",[66,1628,1629],{},"INSERT",[66,1631,1632],{},"UPDATE",[66,1634,130],{},", so more indexes mean slower writes. They also consume additional disk space, sometimes significantly, since each index is essentially its own copy of the indexed columns in a different structure.",[11,1637,1638,1639,154,1641,741,1643,1645],{},"The practical guideline is to index columns that are frequently used in ",[66,1640,1610],{},[66,1642,1614],{},[66,1644,1618],{}," clauses, and avoid indexing columns that are rarely queried or that change very often, since those indexes add write overhead without much read benefit in return.",[23,1647,1649],{"id":1648},"_33-what-is-the-difference-between-a-clustered-index-and-a-non-clustered-index","33. What is the difference between a clustered index and a non-clustered index?",[11,1651,784,1652,1655,1656,1659],{},[31,1653,1654],{},"clustered index"," determines the ",[177,1657,1658],{},"physical"," order in which rows are actually stored on disk; because of this, a table can have only one clustered index (often the primary key by default). Looking up a row via the clustered index means the data is found directly at that location.",[11,1661,784,1662,1665],{},[31,1663,1664],{},"non-clustered index"," is a separate structure that stores the indexed column's values along with a pointer (or reference) back to the actual row's location. A table can have many non-clustered indexes. Looking up via a non-clustered index typically means finding the pointer first, then following it to fetch the actual row, an extra step compared to a clustered index, though still far faster than a full scan. A simple analogy: a clustered index is like a phone book sorted by last name (the data itself is in that order), while a non-clustered index is like an index at the back of a textbook pointing you to a page number.",[23,1667,1669],{"id":1668},"_34-what-are-the-different-types-of-sql-joins-inner-left-right-full","34. What are the different types of SQL joins (INNER, LEFT, RIGHT, FULL)?",[11,1671,784,1672,1675],{},[31,1673,1674],{},"join"," combines rows from two or more tables based on a related column. Which rows survive the combination depends on the join type.",[36,1677,1678,1688],{},[39,1679,1680],{},[42,1681,1682,1685],{},[45,1683,1684],{},"Join",[45,1686,1687],{},"Returns",[58,1689,1690,1700,1713,1725],{},[42,1691,1692,1697],{},[63,1693,1694],{},[66,1695,1696],{},"INNER JOIN",[63,1698,1699],{},"Only rows with matches in both tables",[42,1701,1702,1707],{},[63,1703,1704],{},[66,1705,1706],{},"LEFT JOIN",[63,1708,1709,1710,1712],{},"All rows from the left table, matched rows from the right (or ",[66,1711,1544],{}," if no match)",[42,1714,1715,1720],{},[63,1716,1717],{},[66,1718,1719],{},"RIGHT JOIN",[63,1721,1722,1723,1712],{},"All rows from the right table, matched rows from the left (or ",[66,1724,1544],{},[42,1726,1727,1732],{},[63,1728,1729],{},[66,1730,1731],{},"FULL JOIN",[63,1733,1734,1735,1737],{},"All rows from both tables, ",[66,1736,1544],{}," where there's no match on either side",[507,1739,1743],{"className":1740,"code":1741,"language":1742,"meta":512,"style":512},"language-sql shiki shiki-themes github-dark","SELECT orders.id, customers.name\nFROM orders\nLEFT JOIN customers ON orders.customer_id = customers.id;\n","sql",[66,1744,1745,1767,1775],{"__ignoreMap":512},[516,1746,1747,1751,1754,1756,1758,1760,1762,1764],{"class":518,"line":519},[516,1748,1750],{"class":1749},"snl16","SELECT",[516,1752,1753],{"class":1233}," orders",[516,1755,405],{"class":1227},[516,1757,1578],{"class":1233},[516,1759,154],{"class":1227},[516,1761,1409],{"class":1233},[516,1763,405],{"class":1227},[516,1765,1766],{"class":1233},"name\n",[516,1768,1769,1772],{"class":518,"line":525},[516,1770,1771],{"class":1749},"FROM",[516,1773,1774],{"class":1227}," orders\n",[516,1776,1777,1779,1782,1785,1787,1789,1791,1794,1797,1799,1801],{"class":518,"line":531},[516,1778,1706],{"class":1749},[516,1780,1781],{"class":1227}," customers ",[516,1783,1784],{"class":1749},"ON",[516,1786,1753],{"class":1233},[516,1788,405],{"class":1227},[516,1790,1562],{"class":1233},[516,1792,1793],{"class":1749}," =",[516,1795,1796],{"class":1233}," customers",[516,1798,405],{"class":1227},[516,1800,1578],{"class":1233},[516,1802,1803],{"class":1227},";\n",[11,1805,1806,1807,1809,1810,1813,1814,1816,1817,1819,1820,1822,1823,405],{},"This ",[66,1808,1706],{}," example returns every order, even ones where the linked customer record is somehow missing, with ",[66,1811,1812],{},"customers.name"," showing as ",[66,1815,1544],{}," in that case. ",[66,1818,1696],{}," is the most commonly used in practice, while ",[66,1821,1719],{}," is rarely used since it's equivalent to swapping the table order and using ",[66,1824,1706],{},[23,1826,1828],{"id":1827},"_35-what-is-a-database-transaction-and-what-does-acid-stand-for","35. What is a database transaction, and what does ACID stand for?",[11,1830,784,1831,1834],{},[31,1832,1833],{},"transaction"," groups multiple database operations into a single unit that either all succeed together or all fail together; there's no in-between state where only some of them took effect. For example, transferring money between two bank accounts involves debiting one account and crediting another, and a transaction ensures both happen, or neither does.",[11,1836,1837,1840],{},[31,1838,1839],{},"ACID"," describes the guarantees a transaction should provide:",[717,1842,1843,1849,1855,1861],{},[720,1844,1845,1848],{},[31,1846,1847],{},"Atomicity",": all operations in the transaction succeed, or none of them do; a partial failure rolls everything back.",[720,1850,1851,1854],{},[31,1852,1853],{},"Consistency",": a transaction takes the database from one valid state to another, never violating defined rules like constraints or foreign keys.",[720,1856,1857,1860],{},[31,1858,1859],{},"Isolation",": concurrent transactions don't interfere with each other in ways that produce incorrect results, as if transactions ran one at a time (the exact degree of this is controlled by isolation levels).",[720,1862,1863,1866],{},[31,1864,1865],{},"Durability",": once a transaction commits, its changes survive even a crash immediately afterward, typically because they've been written to persistent storage.",[507,1868,1870],{"className":1740,"code":1869,"language":1742,"meta":512,"style":512},"BEGIN;\nUPDATE accounts SET balance = balance - 100 WHERE id = 1;\nUPDATE accounts SET balance = balance + 100 WHERE id = 2;\nCOMMIT;\n",[66,1871,1872,1879,1916,1946],{"__ignoreMap":512},[516,1873,1874,1877],{"class":518,"line":519},[516,1875,1876],{"class":1749},"BEGIN",[516,1878,1803],{"class":1227},[516,1880,1881,1883,1886,1889,1892,1895,1897,1900,1903,1906,1909,1911,1914],{"class":518,"line":525},[516,1882,1632],{"class":1749},[516,1884,1885],{"class":1227}," accounts ",[516,1887,1888],{"class":1749},"SET",[516,1890,1891],{"class":1227}," balance ",[516,1893,1894],{"class":1749},"=",[516,1896,1891],{"class":1227},[516,1898,1899],{"class":1749},"-",[516,1901,1902],{"class":1233}," 100",[516,1904,1905],{"class":1749}," WHERE",[516,1907,1908],{"class":1227}," id ",[516,1910,1894],{"class":1749},[516,1912,1913],{"class":1233}," 1",[516,1915,1803],{"class":1227},[516,1917,1918,1920,1922,1924,1926,1928,1930,1933,1935,1937,1939,1941,1944],{"class":518,"line":531},[516,1919,1632],{"class":1749},[516,1921,1885],{"class":1227},[516,1923,1888],{"class":1749},[516,1925,1891],{"class":1227},[516,1927,1894],{"class":1749},[516,1929,1891],{"class":1227},[516,1931,1932],{"class":1749},"+",[516,1934,1902],{"class":1233},[516,1936,1905],{"class":1749},[516,1938,1908],{"class":1227},[516,1940,1894],{"class":1749},[516,1942,1943],{"class":1233}," 2",[516,1945,1803],{"class":1227},[516,1947,1948,1951],{"class":518,"line":1127},[516,1949,1950],{"class":1749},"COMMIT",[516,1952,1803],{"class":1227},[11,1954,1955,1956,1958],{},"If the second ",[66,1957,1632],{}," fails for any reason, atomicity guarantees the first one is rolled back too, so money doesn't vanish from account 1 without appearing in account 2.",[23,1960,1962],{"id":1961},"_36-what-are-database-transaction-isolation-levels-and-what-problem-does-each-one-solve","36. What are database transaction isolation levels, and what problem does each one solve?",[11,1964,1965,1968],{},[31,1966,1967],{},"Isolation levels"," control how much one transaction is allowed to \"see\" the in-progress, uncommitted work of another concurrent transaction. Stricter isolation prevents more anomalies but generally costs more performance, since the database has to do more locking or version-checking.",[36,1970,1971,1984],{},[39,1972,1973],{},[42,1974,1975,1978,1981],{},[45,1976,1977],{},"Isolation level",[45,1979,1980],{},"Prevents",[45,1982,1983],{},"Still allows",[58,1985,1986,1997,2008,2019],{},[42,1987,1988,1991,1994],{},[63,1989,1990],{},"Read Uncommitted",[63,1992,1993],{},"Nothing",[63,1995,1996],{},"Dirty reads, non-repeatable reads, phantom reads",[42,1998,1999,2002,2005],{},[63,2000,2001],{},"Read Committed",[63,2003,2004],{},"Dirty reads",[63,2006,2007],{},"Non-repeatable reads, phantom reads",[42,2009,2010,2013,2016],{},[63,2011,2012],{},"Repeatable Read",[63,2014,2015],{},"Dirty reads, non-repeatable reads",[63,2017,2018],{},"Phantom reads (mostly, depends on engine)",[42,2020,2021,2024,2027],{},[63,2022,2023],{},"Serializable",[63,2025,2026],{},"All of the above",[63,2028,2029],{},"Nothing (transactions behave as if run one at a time)",[11,2031,2032],{},"The anomalies being prevented are worth knowing in plain terms:",[717,2034,2035,2041,2047],{},[720,2036,784,2037,2040],{},[31,2038,2039],{},"dirty read"," happens when a transaction reads data that another transaction has written but not yet committed; if that other transaction rolls back, you've read data that never actually existed.",[720,2042,784,2043,2046],{},[31,2044,2045],{},"non-repeatable read"," happens when a transaction reads the same row twice and gets different values, because another transaction updated and committed a change in between.",[720,2048,784,2049,2052,2053,2056],{},[31,2050,2051],{},"phantom read"," happens when a transaction re-runs the same query and gets a ",[177,2054,2055],{},"different set of rows",", because another transaction inserted or deleted rows matching that query in between.",[11,2058,2059,2061,2062,2064],{},[66,2060,2001],{}," is the default in many databases (like PostgreSQL) because it offers a reasonable balance; ",[66,2063,2023],{}," gives the strongest guarantees but can hurt throughput under heavy concurrent load, so it's typically reserved for operations where correctness (like financial calculations) matters more than raw speed.",[23,2066,2068],{"id":2067},"_37-what-is-a-deadlock-in-a-database-and-how-can-it-be-avoided","37. What is a deadlock in a database, and how can it be avoided?",[11,2070,784,2071,2074],{},[31,2072,2073],{},"deadlock"," occurs when two (or more) transactions are each waiting for a lock the other one holds, so neither can proceed; transaction A holds a lock that B needs, while B holds a lock that A needs. Most databases detect this situation and forcibly abort one of the transactions (the \"victim\") so the other can continue.",[11,2076,2077],{},"Deadlocks can be reduced by always acquiring locks in a consistent order across your codebase (e.g. always lock the lower-ID row first), keeping transactions short so locks aren't held longer than necessary, and avoiding unnecessary locking of rows the transaction doesn't actually need to modify. When a deadlock does occur, the application should catch the resulting error and retry the transaction.",[23,2079,2081],{"id":2080},"_38-what-is-the-n1-query-problem-and-how-do-you-fix-it","38. What is the N+1 query problem, and how do you fix it?",[11,2083,771,2084,2087,2088,2091,2092,2095],{},[31,2085,2086],{},"N+1 query problem"," happens when code runs one query to fetch a list of records, then runs an ",[177,2089,2090],{},"additional"," query for each individual record to fetch related data, resulting in ",[66,2093,2094],{},"1 + N"," total queries instead of just one or two efficient ones.",[507,2097,2100],{"className":2098,"code":2099,"language":1171,"meta":512},[1169],"orders = SELECT * FROM orders          -- 1 query, returns N orders\nfor order in orders:\n    SELECT * FROM customers WHERE id = order.customer_id  -- N queries\n",[66,2101,2099],{"__ignoreMap":512},[11,2103,2104,2105,2107,2108,2111],{},"If there are 100 orders, that's 101 round trips to the database instead of 1 or 2, which adds significant, often invisible, latency as the dataset grows. The fix is usually to fetch the related data upfront using a ",[66,2106,1614],{},", or to batch the lookups with a single query using ",[66,2109,2110],{},"WHERE id IN (...)"," across all the needed IDs, instead of querying per row in a loop. Many ORMs offer \"eager loading\" features specifically to avoid this pattern.",[23,2113,2115],{"id":2114},"_39-what-is-connection-pooling-and-why-does-it-matter","39. What is connection pooling, and why does it matter?",[11,2117,2118,2119,2122],{},"Opening a new database connection is relatively expensive; it involves a network handshake, authentication, and setting up session resources on the database server. ",[31,2120,2121],{},"Connection pooling"," solves this by keeping a set of already-open connections ready to be reused, instead of opening and closing a new one for every single query.",[11,2124,2125],{},"When the application needs to run a query, it borrows a connection from the pool, uses it, and returns it when done, rather than paying the setup cost each time. This matters a lot under load: without pooling, a busy application could overwhelm the database with connection setup overhead alone, or hit the database's maximum connection limit and start failing requests.",[23,2127,2129],{"id":2128},"_40-what-is-database-replication-and-whats-the-difference-between-synchronous-and-asynchronous-replication","40. What is database replication, and what's the difference between synchronous and asynchronous replication?",[11,2131,2132,2135,2136,2139,2140,2143],{},[31,2133,2134],{},"Replication"," is the process of copying data from one database (the ",[31,2137,2138],{},"primary",", or leader) to one or more other databases (",[31,2141,2142],{},"replicas",", or followers), so the same data exists in multiple places. It's used for high availability (a replica can take over if the primary fails), read scaling (reads can be spread across replicas), and disaster recovery.",[11,2145,2146,2147,2150],{},"In ",[31,2148,2149],{},"synchronous replication",", the primary waits for at least one replica to confirm it has received and applied the write before telling the client the write succeeded. This guarantees the replica is always up to date, but it adds latency to every write and means the primary can be blocked if a replica is slow or unreachable.",[11,2152,2146,2153,2156],{},[31,2154,2155],{},"asynchronous replication",", the primary confirms the write to the client immediately and sends the change to replicas in the background. This keeps writes fast, but there's a small window where a replica lags behind the primary, and if the primary fails before replicating a change, that write could be lost. Most systems default to asynchronous replication for performance, and accept eventual consistency on reads from replicas as the tradeoff.",[11,2158,2159],{},[2160,2161],"img",{"alt":2162,"src":2163},"Primary-replica database replication diagram","/post-images/top-111-backend-interview-questions/database-replication-diagram.png",[23,2165,2167],{"id":2166},"_41-what-is-database-sharding-and-how-is-it-different-from-replication","41. What is database sharding, and how is it different from replication?",[11,2169,2170,2173,2174,2177,2178,2181,2182,2185],{},[31,2171,2172],{},"Sharding"," (also called horizontal partitioning) splits a single logical database into multiple smaller, independent databases (",[31,2175,2176],{},"shards","), where each shard holds a ",[177,2179,2180],{},"different subset"," of the data, typically split by some key like ",[66,2183,2184],{},"user_id"," or region. A query for a specific user only needs to hit the one shard that owns that user's data.",[11,2187,2188,2189,2192],{},"This is fundamentally different from replication, which keeps ",[177,2190,2191],{},"full, identical copies"," of the same data on multiple servers. Sharding solves a different problem: when a single database's data or write volume grows too large for one machine to handle efficiently, sharding spreads both the storage and the write load across multiple machines, whereas replication mainly helps with read scaling and availability, not write capacity.",[11,2194,2195,2196,2199],{},"The tradeoffs are significant: queries that need to combine data across shards (like \"find all orders across every user\") become much harder and slower, joins across shards generally aren't practical, and choosing a good ",[31,2197,2198],{},"shard key"," upfront is critical, since an uneven distribution of data across shards (a \"hot shard\") undermines the whole point. Sharding is usually a last resort, reached only after simpler scaling options like better indexing, caching, or read replicas have been exhausted.",[18,2201,2203],{"id":2202},"nosql-and-data-modeling","NoSQL and Data Modeling",[23,2205,2207],{"id":2206},"_42-what-is-the-difference-between-sql-and-nosql-databases-and-when-would-you-choose-one-over-the-other","42. What is the difference between SQL and NoSQL databases, and when would you choose one over the other?",[11,2209,2210,2213,2214,2217],{},[31,2211,2212],{},"SQL"," databases (like PostgreSQL or MySQL) are relational: data lives in tables with a fixed schema, and relationships between tables are enforced through foreign keys. ",[31,2215,2216],{},"NoSQL"," databases are a broad category of non-relational stores (document, key-value, column-family, graph) that generally favor flexible schemas and horizontal scalability over strict consistency guarantees.",[36,2219,2220,2231],{},[39,2221,2222],{},[42,2223,2224,2227,2229],{},[45,2225,2226],{},"Aspect",[45,2228,2212],{},[45,2230,2216],{},[58,2232,2233,2244,2255,2266],{},[42,2234,2235,2238,2241],{},[63,2236,2237],{},"Schema",[63,2239,2240],{},"Fixed, defined upfront",[63,2242,2243],{},"Flexible, can vary per record",[42,2245,2246,2249,2252],{},[63,2247,2248],{},"Relationships",[63,2250,2251],{},"Joins across tables",[63,2253,2254],{},"Usually denormalized, embedded",[42,2256,2257,2260,2263],{},[63,2258,2259],{},"Scaling",[63,2261,2262],{},"Typically vertical (bigger server)",[63,2264,2265],{},"Typically horizontal (more servers)",[42,2267,2268,2270,2273],{},[63,2269,1853],{},[63,2271,2272],{},"Strong (ACID) by default",[63,2274,2275],{},"Often eventual, tunable",[11,2277,2278],{},"Choose SQL when your data is naturally relational and you need strong consistency and complex queries (think financial transactions, order systems). Choose NoSQL when you need to scale out horizontally, your data is naturally hierarchical or unstructured, or your access patterns are simple and known in advance (think user sessions, activity feeds, product catalogs). Many real systems use both, picking the right tool per use case rather than treating it as an all-or-nothing decision.",[23,2280,2282],{"id":2281},"_43-what-are-the-main-types-of-nosql-databases-document-key-value-column-family-graph-give-an-example-use-case-for-each","43. What are the main types of NoSQL databases (document, key-value, column-family, graph)? Give an example use case for each.",[11,2284,2285],{},"NoSQL isn't one thing; it's an umbrella term for several different data models that each solve a different problem.",[36,2287,2288,2303],{},[39,2289,2290],{},[42,2291,2292,2295,2298,2300],{},[45,2293,2294],{},"Type",[45,2296,2297],{},"How data is stored",[45,2299,963],{},[45,2301,2302],{},"Good for",[58,2304,2305,2319,2333,2347],{},[42,2306,2307,2310,2313,2316],{},[63,2308,2309],{},"Document",[63,2311,2312],{},"JSON-like documents",[63,2314,2315],{},"MongoDB",[63,2317,2318],{},"Content management, product catalogs",[42,2320,2321,2324,2327,2330],{},[63,2322,2323],{},"Key-value",[63,2325,2326],{},"Simple key maps to a value",[63,2328,2329],{},"Redis, DynamoDB",[63,2331,2332],{},"Sessions, caching, feature flags",[42,2334,2335,2338,2341,2344],{},[63,2336,2337],{},"Column-family",[63,2339,2340],{},"Rows with dynamic columns, grouped by column family",[63,2342,2343],{},"Cassandra, HBase",[63,2345,2346],{},"Time-series data, write-heavy logging",[42,2348,2349,2352,2355,2358],{},[63,2350,2351],{},"Graph",[63,2353,2354],{},"Nodes and edges with properties",[63,2356,2357],{},"Neo4j",[63,2359,2360],{},"Social networks, recommendation engines",[11,2362,2363],{},"The common thread is that each model trades the flexibility of SQL's joins for a structure that maps closely to how the application actually reads and writes data, which usually makes those specific access patterns faster at scale.",[23,2365,2367],{"id":2366},"_44-how-is-data-modeling-different-in-a-document-database-compared-to-a-relational-database","44. How is data modeling different in a document database compared to a relational database?",[11,2369,2370,2371,2374],{},"In a relational database, you model data by normalizing it: splitting information into separate tables to avoid duplication, then joining them back together at query time. In a ",[31,2372,2373],{},"document database",", you typically model around the application's access patterns instead, often denormalizing (embedding) related data directly into a single document so a common read can be satisfied with one lookup instead of several joins.",[11,2376,2377,2378,2381],{},"For example, a blog post and its comments might be two tables in SQL, joined by a ",[66,2379,2380],{},"post_id"," foreign key. In a document store, you might embed the comments array directly inside the post document if you almost always read them together:",[507,2383,2385],{"className":1218,"code":2384,"language":1220,"meta":512,"style":512},"{\n    \"title\": \"Intro to Backend Systems\",\n    \"comments\": [\n        { \"user\": \"alex\", \"text\": \"Great post!\" },\n        { \"user\": \"sam\", \"text\": \"Very helpful, thanks.\" }\n    ]\n}\n",[66,2386,2387,2391,2403,2410,2436,2458,2462],{"__ignoreMap":512},[516,2388,2389],{"class":518,"line":519},[516,2390,1228],{"class":1227},[516,2392,2393,2396,2398,2401],{"class":518,"line":525},[516,2394,2395],{"class":1233},"    \"title\"",[516,2397,1245],{"class":1227},[516,2399,2400],{"class":1248},"\"Intro to Backend Systems\"",[516,2402,1252],{"class":1227},[516,2404,2405,2408],{"class":518,"line":531},[516,2406,2407],{"class":1233},"    \"comments\"",[516,2409,1272],{"class":1227},[516,2411,2412,2415,2418,2420,2423,2425,2428,2430,2433],{"class":518,"line":1127},[516,2413,2414],{"class":1227},"        { ",[516,2416,2417],{"class":1233},"\"user\"",[516,2419,1245],{"class":1227},[516,2421,2422],{"class":1248},"\"alex\"",[516,2424,154],{"class":1227},[516,2426,2427],{"class":1233},"\"text\"",[516,2429,1245],{"class":1227},[516,2431,2432],{"class":1248},"\"Great post!\"",[516,2434,2435],{"class":1227}," },\n",[516,2437,2438,2440,2442,2444,2447,2449,2451,2453,2456],{"class":518,"line":1134},[516,2439,2414],{"class":1227},[516,2441,2417],{"class":1233},[516,2443,1245],{"class":1227},[516,2445,2446],{"class":1248},"\"sam\"",[516,2448,154],{"class":1227},[516,2450,2427],{"class":1233},[516,2452,1245],{"class":1227},[516,2454,2455],{"class":1248},"\"Very helpful, thanks.\"",[516,2457,1299],{"class":1227},[516,2459,2460],{"class":518,"line":1275},[516,2461,1305],{"class":1227},[516,2463,2464],{"class":518,"line":1302},[516,2465,1317],{"class":1227},[11,2467,2468],{},"The rule of thumb is \"model for your queries\" in document databases versus \"model for your data's structure\" in relational ones. The cost is that updating an embedded value in many documents can be more work than updating one row in a normalized table.",[23,2470,2472],{"id":2471},"_45-what-is-eventual-consistency-and-where-does-it-typically-show-up-in-nosql-systems","45. What is eventual consistency, and where does it typically show up in NoSQL systems?",[11,2474,2475,2478,2479,2482],{},[31,2476,2477],{},"Eventual consistency"," means that after a write, the system doesn't guarantee every subsequent read sees that write immediately, but it guarantees that if no new writes happen, all replicas will ",[177,2480,2481],{},"eventually"," converge to the same value. It's common in distributed NoSQL systems that replicate data across multiple nodes for availability and speed.",[11,2484,2485],{},"A typical example: you update your profile picture, and a friend loading your profile from a different data center might see the old picture for a few seconds before the change propagates. This is a deliberate tradeoff, not a bug, made to keep the system fast and available even when some nodes are slow or temporarily unreachable. Systems that need every read to reflect the latest write immediately instead choose strong consistency, usually at the cost of availability or latency.",[23,2487,2489],{"id":2488},"_46-what-is-the-cap-theorem-and-why-cant-a-distributed-system-guarantee-all-three-of-consistency-availability-and-partition-tolerance-at-once","46. What is the CAP theorem, and why can't a distributed system guarantee all three of Consistency, Availability, and Partition tolerance at once?",[11,2491,771,2492,2495],{},[31,2493,2494],{},"CAP theorem"," states that a distributed data system can only guarantee two out of three properties at the same time:",[717,2497,2498,2503,2509],{},[720,2499,2500,2502],{},[31,2501,1853],{},": every read receives the most recent write (or an error).",[720,2504,2505,2508],{},[31,2506,2507],{},"Availability",": every request receives a (non-error) response, even if it's not the latest data.",[720,2510,2511,2514],{},[31,2512,2513],{},"Partition tolerance",": the system keeps working even if network communication between nodes breaks down.",[11,2516,2517,2518,2521],{},"The key insight is that network partitions ",[177,2519,2520],{},"will"," happen in any real distributed system (cables get cut, servers lose connectivity, data centers get isolated), so partition tolerance isn't really optional; you have to design for it. That leaves a genuine choice only between consistency and availability during a partition. If two nodes can't talk to each other and both receive a write for the same record, the system must either reject one write to stay consistent (sacrificing availability) or accept both and risk serving stale or conflicting data (sacrificing consistency).",[11,2523,2524,2525,2528],{},"In practice, most databases are described as CP (like traditional relational databases or ZooKeeper, which favor consistency) or AP (like Cassandra or DynamoDB, which favor availability). It's worth noting CAP only applies ",[177,2526,2527],{},"during"," an actual partition; outside of that, most systems try to offer both as best they can.",[23,2530,2532],{"id":2531},"_47-what-is-a-compositecompound-key-and-why-does-key-design-matter-so-much-in-nosql-databases","47. What is a composite/compound key, and why does key design matter so much in NoSQL databases?",[11,2534,784,2535,2538,2539,2541,2542,2545],{},[31,2536,2537],{},"composite key"," (also called a compound key) is a key made up of more than one attribute, often a partition key plus a sort key, rather than a single simple value. For example, in a table storing orders, the partition key might be ",[66,2540,1562],{}," and the sort key might be ",[66,2543,2544],{},"order_date",", letting you efficiently fetch \"all orders for this customer, sorted by date.\"",[11,2547,2548],{},"Key design matters enormously in NoSQL because, unlike SQL where you can add indexes and write ad-hoc joins later, most NoSQL databases route and distribute data based on the key you choose, and many don't support flexible ad-hoc queries at all. A poorly chosen key can lead to \"hot partitions,\" where one key gets a disproportionate share of traffic while others sit idle, hurting performance and scalability. Because changing the key design later often means rewriting the whole dataset, it's something you generally need to get right up front by thinking hard about access patterns before writing any code.",[23,2550,2552],{"id":2551},"_48-when-would-you-reach-for-redis-as-a-primary-data-store-instead-of-just-using-it-as-a-cache","48. When would you reach for Redis as a primary data store instead of just using it as a cache?",[11,2554,2555,2556,2559,2560,2563],{},"Most people meet Redis as a cache sitting in front of a \"real\" database, but it's a full in-memory data store with persistence options (",[66,2557,2558],{},"RDB"," snapshots, ",[66,2561,2562],{},"AOF"," logs), so it can also serve as a primary store for the right workload. It makes sense as a primary store when your data is naturally short-lived or small enough to fit in memory, and when you need very low latency access to structures like counters, leaderboards (sorted sets), rate-limit counters, or real-time session state.",[11,2565,2566,2567,2570],{},"For example, a live leaderboard for a game benefits from Redis's sorted-set operations far more than it would from running ",[66,2568,2569],{},"ORDER BY score"," queries against a relational table on every request. The tradeoff is that Redis's durability guarantees are weaker than a disk-based database's by default, and its cost per gigabyte of storage is much higher since everything lives in RAM, so it's usually reserved for data where speed matters more than being the permanent system of record.",[23,2572,2574],{"id":2573},"_49-what-does-schema-less-really-mean-for-a-database-like-mongodb-does-it-actually-mean-theres-no-schema-at-all","49. What does \"schema-less\" really mean for a database like MongoDB? Does it actually mean there's no schema at all?",[11,2576,2577,2578,2581],{},"\"Schema-less\" is a bit of a misnomer. It means the ",[177,2579,2580],{},"database"," doesn't enforce a rigid, predefined structure on every document the way a relational table enforces columns and types. You can insert a document with fields another document in the same collection doesn't have, without running a migration first.",[11,2583,2584,2585,2588],{},"It does not mean there's no schema at all; your application still has an implicit schema, since your code expects certain fields to exist with certain types. The difference is ",[177,2586,2587],{},"where"," that schema is enforced: in SQL it's enforced by the database engine at write time, while in a schema-less database it's enforced (or not) by application code, or optionally by tools like MongoDB's schema validation rules. This flexibility is great for rapid iteration and handling varied data, but it shifts responsibility onto developers to keep documents consistent, and inconsistent documents can cause subtle bugs if the application isn't defensive about missing or differently-typed fields.",[18,2590,2592],{"id":2591},"authentication-and-security","Authentication and Security",[23,2594,2596],{"id":2595},"_50-what-is-the-difference-between-authentication-and-authorization","50. What is the difference between authentication and authorization?",[11,2598,2599,2602,2603,2605],{},[31,2600,2601],{},"Authentication"," answers \"who are you?\", it's the process of verifying an identity, typically through a username/password, a token, or biometrics. ",[31,2604,453],{}," answers \"what are you allowed to do?\", it happens after authentication and determines which resources or actions the now-verified identity can access.",[11,2607,2608,2609,2612],{},"A simple way to remember it: logging into an app is authentication; being blocked from an admin page because your account isn't an admin is authorization. The two are almost always implemented as separate layers, and a common mistake is conflating them, for example checking only \"is this user logged in\" without also checking \"is this user allowed to do ",[177,2610,2611],{},"this specific"," action.\"",[23,2614,2616],{"id":2615},"_51-what-is-the-difference-between-session-based-authentication-and-token-based-authentication","51. What is the difference between session-based authentication and token-based authentication?",[11,2618,2146,2619,2622,2623,2626,2627,2630],{},[31,2620,2621],{},"session-based authentication",", the server creates a session after login and stores its state (like the user ID) server-side, usually in memory or a database, keyed by a session ID. That session ID is sent to the client as a cookie, and on every request the server looks up the session ID to find out who the user is. In ",[31,2624,2625],{},"token-based authentication",", the server issues a self-contained token (commonly a ",[66,2628,2629],{},"JWT",") that holds the user's identity and claims directly inside it, cryptographically signed. The server doesn't need to store anything; it just verifies the token's signature on each request.",[36,2632,2633,2645],{},[39,2634,2635],{},[42,2636,2637,2639,2642],{},[45,2638,2226],{},[45,2640,2641],{},"Session-based",[45,2643,2644],{},"Token-based",[58,2646,2647,2658,2668,2679],{},[42,2648,2649,2652,2655],{},[63,2650,2651],{},"State",[63,2653,2654],{},"Stored server-side",[63,2656,2657],{},"Stored in the token itself",[42,2659,2660,2662,2665],{},[63,2661,2259],{},[63,2663,2664],{},"Needs shared session store across servers",[63,2666,2667],{},"Stateless, easier to scale horizontally",[42,2669,2670,2673,2676],{},[63,2671,2672],{},"Revocation",[63,2674,2675],{},"Easy (delete the session)",[63,2677,2678],{},"Harder (token valid until it expires)",[42,2680,2681,2684,2687],{},[63,2682,2683],{},"Typical transport",[63,2685,2686],{},"Cookie",[63,2688,2689,2690,2692],{},"Cookie or ",[66,2691,453],{}," header",[11,2694,2695],{},"Sessions are simpler to revoke instantly (just delete the session record) but require shared storage in a multi-server setup. Tokens scale more easily since any server can verify them without a shared store, but revoking a single token before it expires is genuinely harder, which is why short expiry times and refresh tokens are common companions to this approach.",[23,2697,2699],{"id":2698},"_52-how-does-a-jwt-work-and-what-are-its-three-parts","52. How does a JWT work, and what are its three parts?",[11,2701,784,2702,2704,2705,405],{},[31,2703,2629],{}," (JSON Web Token) is a compact, signed string that carries claims (pieces of data) about a user, used to prove identity without the server needing to look anything up in a database. It has three parts separated by dots: ",[66,2706,2707],{},"header.payload.signature",[507,2709,2712],{"className":2710,"code":2711,"language":1171,"meta":512},[1169],"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n",[66,2713,2711],{"__ignoreMap":512},[717,2715,2716,2726,2736],{},[720,2717,2718,2721,2722,2725],{},[31,2719,2720],{},"Header",": metadata, like which signing algorithm is used (e.g. ",[66,2723,2724],{},"HS256",").",[720,2727,2728,2731,2732,2735],{},[31,2729,2730],{},"Payload",": the actual claims, like user ID, roles, and expiry time (",[66,2733,2734],{},"exp","). This part is only base64-encoded, not encrypted, so it's readable by anyone who has the token.",[720,2737,2738,2741],{},[31,2739,2740],{},"Signature",": created by hashing the header and payload together with a secret key (or private key). This is what lets the server verify the token hasn't been tampered with.",[11,2743,2744,2745,405],{},"When a client sends a request with a JWT, the server recomputes the signature using its secret and compares it to the one in the token. If they match, the server trusts the claims inside without needing a database lookup, which is what makes JWTs fast and stateless. Because the payload is readable, sensitive data should never be stored in it unencrypted. For a full walkthrough of signing algorithms, expiry, and revocation, see ",[761,2746,2748],{"href":2747},"/post/everything-about-json-web-tokens-explained","Everything You Actually Need to Know About JWT",[23,2750,2752,2753,2756,2757,2760],{"id":2751},"_53-what-are-the-security-tradeoffs-of-storing-a-jwt-in-localstorage-versus-an-httponly-cookie","53. What are the security tradeoffs of storing a JWT in ",[66,2754,2755],{},"localStorage"," versus an ",[66,2758,2759],{},"httpOnly"," cookie?",[11,2762,2763,2764,2766,2767,2770,2771,2774,2775,2777],{},"Storing a JWT in ",[66,2765,2755],{}," means your JavaScript code can read and attach it manually, which is convenient, but it also means ",[177,2768,2769],{},"any"," JavaScript running on the page can read it, including malicious scripts injected via an ",[31,2772,2773],{},"XSS"," attack. If an attacker manages to run JS on your page, they can simply read the token out of ",[66,2776,2755],{}," and exfiltrate it.",[11,2779,2780,2781,2783,2784,2787,2788,2791,2792,2794],{},"Storing the JWT in an ",[66,2782,2759],{}," cookie means client-side JavaScript can't read it at all (the browser withholds it from ",[66,2785,2786],{},"document.cookie","), so it's immune to token theft via XSS. The tradeoff is that cookies are automatically attached to every request to the domain, which opens the door to ",[31,2789,2790],{},"CSRF"," attacks unless you add protections like ",[66,2793,705],{}," cookie attributes or CSRF tokens.",[36,2796,2797,2810],{},[39,2798,2799],{},[42,2800,2801,2804,2807],{},[45,2802,2803],{},"Storage",[45,2805,2806],{},"Vulnerable to",[45,2808,2809],{},"Protected from",[58,2811,2812,2824],{},[42,2813,2814,2818,2821],{},[63,2815,2816],{},[66,2817,2755],{},[63,2819,2820],{},"XSS (token theft)",[63,2822,2823],{},"CSRF (not sent automatically)",[42,2825,2826,2831,2834],{},[63,2827,2828,2830],{},[66,2829,2759],{}," cookie",[63,2832,2833],{},"CSRF (unless mitigated)",[63,2835,2836],{},"XSS (JS can't read it)",[11,2838,2839,2840,2842,2843,2846,2847,2849],{},"In short, neither option is a silver bullet on its own; ",[66,2841,2759],{}," cookies plus ",[66,2844,2845],{},"SameSite=Strict"," (or ",[66,2848,740],{},") plus CSRF tokens is generally considered the safer combination for browser-based apps.",[23,2851,2853],{"id":2852},"_54-what-is-oauth-20-and-what-problem-does-it-solve","54. What is OAuth 2.0, and what problem does it solve?",[11,2855,2856,2859],{},[31,2857,2858],{},"OAuth 2.0"," is an authorization framework that lets a user grant a third-party application limited access to their data on another service, without ever sharing their password with that third-party app. The problem it solves: before OAuth, \"log in with your Google account\" style features required handing your Google password directly to the third-party app, which is both insecure and gives that app far more access than necessary.",[11,2861,2862,2863,2866],{},"The most common flow, the ",[177,2864,2865],{},"authorization code"," flow, works like this:",[2868,2869,2870,2873,2876,2881,2888],"ol",{},[720,2871,2872],{},"The user clicks \"Log in with X\" in the client app, which redirects them to the authorization server (X's login page).",[720,2874,2875],{},"The user logs in and grants consent for specific permissions (scopes).",[720,2877,2878,2879,405],{},"The authorization server redirects back to the client app with a short-lived ",[31,2880,2865],{},[720,2882,2883,2884,2887],{},"The client app exchanges that code (along with a client secret) for an ",[31,2885,2886],{},"access token"," by calling the authorization server directly.",[720,2889,2890],{},"The client app uses the access token to call the resource server (X's API) on the user's behalf.",[11,2892,2893],{},[2160,2894],{"alt":2895,"src":2896},"OAuth 2.0 authorization code flow diagram","/post-images/top-111-backend-interview-questions/oauth2-authorization-code-flow-diagram.png",[11,2898,2899],{},"The access token the client app receives is scoped (e.g. \"read your email address\" but not \"read your files\"), which is the core security benefit: the app only gets exactly the access the user approved, and the password itself never leaves the authorization server.",[23,2901,2903],{"id":2902},"_55-is-oauth-an-authentication-protocol-whats-the-relationship-between-oauth-20-and-openid-connect","55. Is OAuth an authentication protocol? What's the relationship between OAuth 2.0 and OpenID Connect?",[11,2905,2906,2907,2910,2911,2914],{},"Strictly speaking, no: OAuth 2.0 is an ",[177,2908,2909],{},"authorization"," protocol, designed to grant access to resources, not to verify identity. It's a common mistake to use OAuth alone as a login system, because an access token by itself doesn't reliably tell you ",[177,2912,2913],{},"who"," the user is or guarantee the token was issued for authentication purposes.",[11,2916,2917,2920,2921,2924],{},[31,2918,2919],{},"OpenID Connect (OIDC)"," is a thin identity layer built directly on top of OAuth 2.0 that adds authentication. It introduces a standardized ",[31,2922,2923],{},"ID token"," (itself a JWT) containing verified identity claims like the user's ID, name, and email, alongside the regular OAuth access token. So when an app implements \"Sign in with Google,\" it's typically using OIDC, not raw OAuth: OAuth handles the token exchange plumbing, and OIDC adds the piece that actually proves who the user is.",[23,2926,2928],{"id":2927},"_56-how-should-passwords-be-stored-in-a-database-and-why-is-plain-hashing-like-a-single-unsalted-md5-hash-not-enough","56. How should passwords be stored in a database, and why is plain hashing (like a single unsalted MD5 hash) not enough?",[11,2930,2931,2932,756,2935,2938,2939,154,2942,741,2945,2948,2949,2952],{},"Passwords should never be stored in plain text, and they shouldn't just be run through a fast, general-purpose hash function like a single unsalted ",[66,2933,2934],{},"MD5",[66,2936,2937],{},"SHA-256"," either. Instead, they should be hashed with a slow, purpose-built password hashing algorithm like ",[66,2940,2941],{},"bcrypt",[66,2943,2944],{},"scrypt",[66,2946,2947],{},"Argon2",", which include a random ",[31,2950,2951],{},"salt"," automatically and are deliberately computationally expensive.",[11,2954,2955,2956,2958,2959,2961,2962,2965,2966,2969],{},"The problem with plain fast hashing is twofold. First, ",[66,2957,2934],{},"/",[66,2960,2937],{}," are designed to be ",[177,2963,2964],{},"fast",", which is exactly the wrong property for password hashing: an attacker with a stolen database can compute billions of hashes per second on modern GPUs and brute-force short or common passwords quickly. Second, without a salt, two users with the same password produce the identical hash, and attackers can use precomputed ",[31,2967,2968],{},"rainbow tables"," to reverse common hashes instantly.",[507,2971,2974],{"className":2972,"code":2973,"language":1171,"meta":512},[1169],"# Weak: fast, unsalted\nMD5(\"password123\") -> \"482c811da5d5b4bc6d497ffa98491e38\"\n\n# Strong: slow, salted, adaptive cost\nbcrypt(\"password123\", salt=random, cost=12) -> \"$2b$12$KIXQ...unique per user\"\n",[66,2975,2973],{"__ignoreMap":512},[11,2977,2978],{},"A good password hashing algorithm is deliberately slow (tunable via a \"cost\" or \"work factor\" parameter that can be increased as hardware gets faster), which makes brute-forcing at scale impractical even if the database is leaked.",[23,2980,2982],{"id":2981},"_57-what-is-salting-and-why-does-it-defeat-precomputed-rainbow-table-attacks","57. What is salting, and why does it defeat precomputed rainbow table attacks?",[11,2984,784,2985,2987],{},[31,2986,2951],{}," is a random value generated uniquely for each password and combined with it before hashing. The salt is stored alongside the hash (it doesn't need to be secret) and used again whenever the password needs to be verified.",[11,2989,2990,2991,2993],{},"Without a salt, two users who happen to pick the same password would produce identical hashes, and an attacker could precompute a giant lookup table (a rainbow table) mapping common passwords to their hashes once, then reuse it against any leaked database instantly. With a unique salt per user, the same password produces a ",[177,2992,493],{}," hash for every user, so a precomputed table for one salt is useless against another, forcing the attacker to redo the expensive computation individually for every single password, which makes large-scale rainbow table attacks impractical.",[23,2995,2997],{"id":2996},"_58-what-is-csrf-and-how-do-you-protect-against-it","58. What is CSRF, and how do you protect against it?",[11,2999,3000,3002],{},[31,3001,2790],{}," (Cross-Site Request Forgery) is an attack where a malicious site tricks a logged-in user's browser into submitting a request to a different site the user is authenticated on, exploiting the fact that browsers automatically attach cookies to requests regardless of which site triggered them. For example, a hidden form on an attacker's page auto-submits a \"transfer money\" request to your bank, and since your browser still has a valid session cookie for the bank, the request looks legitimate.",[11,3004,3005,3006,3009,3010,3012,3013,756,3015,3017,3018,2958,3021,3024,3025,3027],{},"Common defenses include: ",[31,3007,3008],{},"CSRF tokens"," (a random, unpredictable value embedded in forms that must be sent back and validated server-side, which an attacker's site can't know), setting the ",[66,3011,705],{}," cookie attribute to ",[66,3014,737],{},[66,3016,740],{}," so cookies aren't sent on cross-site requests, and checking the ",[66,3019,3020],{},"Origin",[66,3022,3023],{},"Referer"," headers on state-changing requests. Using ",[66,3026,705],{}," cookies alone handles most modern cases, but CSRF tokens remain a solid defense-in-depth layer, especially for older browsers.",[23,3029,3031],{"id":3030},"_59-what-is-xss-and-how-do-you-prevent-it-from-the-backends-side","59. What is XSS, and how do you prevent it from the backend's side?",[11,3033,3034,3036],{},[31,3035,2773],{}," (Cross-Site Scripting) is an attack where an attacker injects malicious JavaScript into a page that other users then load and execute, typically by submitting attacker-controlled content (like a comment or profile bio) that the app later renders without proper escaping. Once that script runs in another user's browser, it can steal cookies, tokens, or perform actions as that user.",[11,3038,3039,3040,154,3043,154,3046,3049,3050,3053,3054,3056],{},"From the backend's side, the main defenses are: always escape or sanitize user-generated content before it's rendered as HTML (encode ",[66,3041,3042],{},"\u003C",[66,3044,3045],{},">",[66,3047,3048],{},"&",", quotes, etc.), never trust client input even if a frontend framework already escapes by default, and set a strong ",[66,3051,3052],{},"Content-Security-Policy"," header to restrict which scripts are allowed to run on the page at all. Backend-issued cookies containing sensitive tokens should also be marked ",[66,3055,2759],{}," so even a successful script injection can't read them directly. Treating all user input as untrusted data, never as executable code, is the underlying principle behind every one of these defenses.",[23,3058,3060],{"id":3059},"_60-what-is-sql-injection-and-how-do-parameterized-queries-prevent-it","60. What is SQL injection, and how do parameterized queries prevent it?",[11,3062,3063,3066],{},[31,3064,3065],{},"SQL injection"," happens when user input is concatenated directly into a SQL query string, letting an attacker craft input that changes the query's actual logic. A classic example is a login query built by string concatenation:",[507,3068,3070],{"className":1740,"code":3069,"language":1742,"meta":512,"style":512},"-- Vulnerable: user input concatenated directly\nSELECT * FROM users WHERE username = '\" + username + \"' AND password = '\" + password + \"'\n\n-- If username is:  admin' --\n-- The query becomes:\nSELECT * FROM users WHERE username = 'admin' --' AND password = ''\n-- Everything after -- is commented out, bypassing the password check entirely\n",[66,3071,3072,3078,3112,3116,3121,3126,3148],{"__ignoreMap":512},[516,3073,3074],{"class":518,"line":519},[516,3075,3077],{"class":3076},"sAwPA","-- Vulnerable: user input concatenated directly\n",[516,3079,3080,3082,3085,3088,3091,3093,3096,3098,3101,3104,3107,3109],{"class":518,"line":525},[516,3081,1750],{"class":1749},[516,3083,3084],{"class":1749}," *",[516,3086,3087],{"class":1749}," FROM",[516,3089,3090],{"class":1227}," users ",[516,3092,1610],{"class":1749},[516,3094,3095],{"class":1227}," username ",[516,3097,1894],{"class":1749},[516,3099,3100],{"class":1248}," '\" + username + \"'",[516,3102,3103],{"class":1749}," AND",[516,3105,3106],{"class":1749}," password",[516,3108,1793],{"class":1749},[516,3110,3111],{"class":1248}," '\" + password + \"'\n",[516,3113,3114],{"class":518,"line":531},[516,3115,1131],{"emptyLinePlaceholder":1130},[516,3117,3118],{"class":518,"line":1127},[516,3119,3120],{"class":3076},"-- If username is:  admin' --\n",[516,3122,3123],{"class":518,"line":1134},[516,3124,3125],{"class":3076},"-- The query becomes:\n",[516,3127,3128,3130,3132,3134,3136,3138,3140,3142,3145],{"class":518,"line":1275},[516,3129,1750],{"class":1749},[516,3131,3084],{"class":1749},[516,3133,3087],{"class":1749},[516,3135,3090],{"class":1227},[516,3137,1610],{"class":1749},[516,3139,3095],{"class":1227},[516,3141,1894],{"class":1749},[516,3143,3144],{"class":1248}," 'admin'",[516,3146,3147],{"class":3076}," --' AND password = ''\n",[516,3149,3150],{"class":518,"line":1302},[516,3151,3152],{"class":3076},"-- Everything after -- is commented out, bypassing the password check entirely\n",[11,3154,3155,3158],{},[31,3156,3157],{},"Parameterized queries"," (also called prepared statements) fix this by separating the query structure from the data. The query is sent to the database with placeholders, and the actual values are sent separately:",[507,3160,3162],{"className":1740,"code":3161,"language":1742,"meta":512,"style":512},"-- Safe: parameterized\nSELECT * FROM users WHERE username = ? AND password = ?\n-- values [username, password] are bound separately, never parsed as SQL\n",[66,3163,3164,3169,3198],{"__ignoreMap":512},[516,3165,3166],{"class":518,"line":519},[516,3167,3168],{"class":3076},"-- Safe: parameterized\n",[516,3170,3171,3173,3175,3177,3179,3181,3183,3185,3188,3191,3193,3195],{"class":518,"line":525},[516,3172,1750],{"class":1749},[516,3174,3084],{"class":1749},[516,3176,3087],{"class":1749},[516,3178,3090],{"class":1227},[516,3180,1610],{"class":1749},[516,3182,3095],{"class":1227},[516,3184,1894],{"class":1749},[516,3186,3187],{"class":1227}," ? ",[516,3189,3190],{"class":1749},"AND",[516,3192,3106],{"class":1749},[516,3194,1793],{"class":1749},[516,3196,3197],{"class":1227}," ?\n",[516,3199,3200],{"class":518,"line":531},[516,3201,3202],{"class":3076},"-- values [username, password] are bound separately, never parsed as SQL\n",[11,3204,3205],{},"Because the database engine treats the bound values purely as data, never as part of the query's syntax, no amount of clever input can change what the query actually does. This is why parameterized queries (or a well-built ORM that uses them under the hood) are the standard defense, rather than trying to manually escape special characters yourself, which is error-prone and easy to get wrong.",[23,3207,3209],{"id":3208},"_61-how-does-rate-limiting-help-protect-a-login-endpoint-against-brute-force-attacks","61. How does rate limiting help protect a login endpoint against brute-force attacks?",[11,3211,3212,3214],{},[31,3213,1073],{}," restricts how many requests a client (identified by IP, account, or both) can make within a given time window. On a login endpoint, without rate limiting, an attacker can script thousands of password guesses per second against a single account or across many accounts using leaked password lists (a \"credential stuffing\" attack).",[11,3216,3217],{},"By capping login attempts, say 5 per minute per IP or per account, brute-forcing becomes impractically slow: guessing even a modest password space at 5 attempts a minute could take years instead of seconds. Rate limiting is often paired with other measures like exponential backoff, temporary account lockouts, or CAPTCHAs after repeated failures, and logging repeated failures helps detect attacks in progress rather than just slowing them down.",[23,3219,3221],{"id":3220},"_62-what-is-the-principle-of-least-privilege-and-how-does-it-apply-to-backend-systems-eg-database-users-service-permissions","62. What is the principle of least privilege, and how does it apply to backend systems (e.g. database users, service permissions)?",[11,3223,771,3224,3227],{},[31,3225,3226],{},"principle of least privilege"," means giving every user, service, or process only the minimum access it needs to do its job, nothing more. The reasoning is straightforward: if a component with broad, unnecessary permissions is ever compromised, an attacker inherits all of that access too, so limiting permissions upfront limits the damage a breach can cause.",[11,3229,3230],{},"In backend systems this shows up in a lot of concrete places: a web application's database user should have permission to read and write its own tables but not to drop tables or access other schemas; a microservice that only ever reads from a queue shouldn't have write or delete permissions on it; an API key used for a read-only reporting job shouldn't also be able to trigger production deployments. Applying least privilege consistently means access reviews aren't just a compliance checkbox; they genuinely reduce the blast radius of any single credential leak or bug.",[23,3232,3234],{"id":3233},"_63-what-is-tlsssl-and-what-does-terminating-tls-mean-in-a-backend-architecture","63. What is TLS/SSL, and what does \"terminating TLS\" mean in a backend architecture?",[11,3236,3237,3240,3241,3244],{},[31,3238,3239],{},"TLS"," (Transport Layer Security, the modern successor to the older ",[66,3242,3243],{},"SSL"," protocol) encrypts data in transit between a client and a server, so anyone intercepting the traffic (on public wifi, at an ISP, etc.) sees only ciphertext, not the actual request or response content. It also verifies the server's identity via certificates, so clients can trust they're talking to the real server and not an impostor.",[11,3246,3247,3248,3251],{},"\"",[31,3249,3250],{},"Terminating TLS","\" refers to the point in the architecture where encrypted traffic is decrypted back into plain HTTP. In many setups, TLS is terminated at a load balancer or reverse proxy sitting in front of the application servers; the connection from the client to that proxy is encrypted, but traffic from the proxy to the internal application servers may run as plain HTTP, since it stays within a trusted private network. This centralizes certificate management in one place instead of every backend instance handling its own TLS, though it does mean that internal network segment must genuinely be trusted, since encryption isn't happening on that leg.",[23,3253,3255],{"id":3254},"_64-what-is-a-refresh-token-and-why-is-it-used-alongside-a-short-lived-access-token","64. What is a refresh token, and why is it used alongside a short-lived access token?",[11,3257,784,3258,3261,3262,3264],{},[31,3259,3260],{},"refresh token"," is a long-lived credential used to obtain a new access token without forcing the user to log in again. It works alongside a short-lived ",[31,3263,2886],{}," (often valid for just 15 minutes to an hour) that's used for actual API requests.",[11,3266,3267,3268,3270],{},"The reasoning behind this split is a security-versus-convenience tradeoff. A short expiry on the access token limits the damage if it's ever stolen, since it becomes useless quickly. But if every token were that short-lived with no way to renew it, users would have to log in constantly, which is a poor experience. The refresh token solves this: it's stored more securely (often in an ",[66,3269,2759],{}," cookie, and used less frequently, which makes it lower-risk to keep valid for days or weeks), and it's only sent to a dedicated endpoint to mint new access tokens, never to general API endpoints. If a refresh token is suspected of being compromised, it can be revoked server-side, cutting off future access even though already-issued access tokens will still work until they naturally expire.",[18,3272,3274],{"id":3273},"caching","Caching",[23,3276,3278],{"id":3277},"_65-why-is-caching-important-in-backend-systems-and-whats-the-general-tradeoff-of-introducing-a-cache","65. Why is caching important in backend systems, and what's the general tradeoff of introducing a cache?",[11,3280,3281,3283],{},[31,3282,3274],{}," means storing a copy of frequently-accessed or expensive-to-compute data somewhere faster to read from, so future requests for the same data can skip the slow path (a database query, an external API call, a heavy computation). It matters because it directly reduces latency for users and cuts load on backend systems that would otherwise redo the same expensive work repeatedly.",[11,3285,3286,3287,3290],{},"The core tradeoff is ",[177,3288,3289],{},"staleness versus freshness",": a cache is a copy, and copies can drift out of sync with the source of truth. Every caching decision is really a decision about how much staleness is acceptable for that specific piece of data. Caching also adds real complexity, since now there are two places data can live, and keeping them consistent (cache invalidation) is famously one of the harder problems to get right in practice.",[23,3292,3294],{"id":3293},"_66-what-is-the-difference-between-client-side-caching-cdn-caching-and-server-sideapplication-caching","66. What is the difference between client-side caching, CDN caching, and server-side/application caching?",[11,3296,3297],{},"These three caching layers sit at different points between the user and your backend, and each solves a different problem.",[36,3299,3300,3315],{},[39,3301,3302],{},[42,3303,3304,3307,3310,3313],{},[45,3305,3306],{},"Layer",[45,3308,3309],{},"Where it lives",[45,3311,3312],{},"What it caches",[45,3314,963],{},[58,3316,3317,3333,3347],{},[42,3318,3319,3322,3325,3328],{},[63,3320,3321],{},"Client-side",[63,3323,3324],{},"User's browser/device",[63,3326,3327],{},"Static assets, API responses",[63,3329,3330,3331],{},"Browser cache, ",[66,3332,2755],{},[42,3334,3335,3338,3341,3344],{},[63,3336,3337],{},"CDN",[63,3339,3340],{},"Edge servers near the user",[63,3342,3343],{},"Static assets, sometimes full pages",[63,3345,3346],{},"Images, JS/CSS bundles",[42,3348,3349,3352,3355,3358],{},[63,3350,3351],{},"Server-side/application",[63,3353,3354],{},"Backend infrastructure",[63,3356,3357],{},"Database query results, computed data",[63,3359,3360],{},"Redis, in-memory cache",[11,3362,3363,3364,3366],{},"Client-side caching avoids network requests entirely by keeping data on the user's device. ",[31,3365,3337],{}," caching serves static (and sometimes dynamic) content from a server geographically close to the user, cutting network latency and offloading traffic from origin servers. Server-side caching sits inside the backend itself, saving repeated database queries or expensive computations. A well-built system typically layers all three, letting each layer catch what the layer before it missed.",[23,3368,3370],{"id":3369},"_67-what-is-the-cache-aside-lazy-loading-pattern-and-how-does-it-work","67. What is the cache-aside (lazy-loading) pattern, and how does it work?",[11,3372,3373,3376,3377,3380,3381,3384],{},[31,3374,3375],{},"Cache-aside"," (also called lazy-loading) is the most common caching pattern for reads. The application code is responsible for managing the cache directly: on a read, it checks the cache first; if the data is there (a ",[31,3378,3379],{},"cache hit","), it returns it immediately; if not (a ",[31,3382,3383],{},"cache miss","), it queries the database, then writes the result into the cache before returning it to the caller, so the next request for the same data hits the cache instead.",[507,3386,3389],{"className":3387,"code":3388,"language":1171,"meta":512},[1169],"GET /user/42\n  1. Check cache for key \"user:42\"\n  2. If found (hit)  -> return cached value\n  3. If not found (miss) -> query database\n  4.                     -> store result in cache\n  5.                     -> return value\n",[66,3390,3388],{"__ignoreMap":512},[11,3392,3393],{},[2160,3394],{"alt":3395,"src":3396},"Cache-aside pattern diagram","/post-images/top-111-backend-interview-questions/cache-aside-pattern-diagram.png",[11,3398,3399],{},"Cache-aside is popular because it's simple and resilient: if the cache goes down entirely, the app still works by falling back to the database on every request, just slower. The downside is the first request for any given key always pays the full cost of a cache miss.",[23,3401,3403],{"id":3402},"_68-what-is-the-difference-between-cache-aside-write-through-and-write-behind-caching-strategies","68. What is the difference between cache-aside, write-through, and write-behind caching strategies?",[11,3405,3406,3407,3410],{},"These three strategies differ mainly in ",[177,3408,3409],{},"when"," data gets written into the cache, which affects consistency, latency, and complexity.",[36,3412,3413,3427],{},[39,3414,3415],{},[42,3416,3417,3419,3422,3424],{},[45,3418,960],{},[45,3420,3421],{},"How writes work",[45,3423,1853],{},[45,3425,3426],{},"Write latency",[58,3428,3429,3442,3456],{},[42,3430,3431,3433,3436,3439],{},[63,3432,3375],{},[63,3434,3435],{},"App writes to DB; cache is only populated on the next read (or invalidated)",[63,3437,3438],{},"Cache can be briefly stale after a write",[63,3440,3441],{},"Fast (cache untouched on write)",[42,3443,3444,3447,3450,3453],{},[63,3445,3446],{},"Write-through",[63,3448,3449],{},"App writes to cache, cache synchronously writes to DB",[63,3451,3452],{},"Cache and DB stay consistent",[63,3454,3455],{},"Slower (write waits on DB)",[42,3457,3458,3461,3464,3467],{},[63,3459,3460],{},"Write-behind",[63,3462,3463],{},"App writes to cache, cache asynchronously flushes to DB later",[63,3465,3466],{},"Cache is fresh, DB can lag",[63,3468,3469],{},"Fastest (write returns immediately)",[11,3471,3472,3474,3475,3477,3478,3480],{},[31,3473,3375],{}," keeps writes simple (write straight to the database, and either invalidate or let the cache repopulate naturally on the next read). ",[31,3476,3446],{}," keeps the cache always in sync with the database by writing to both together, at the cost of slower writes since every write waits on the database. ",[31,3479,3460],{}," optimizes for write speed by writing to the cache immediately and flushing to the database in the background, but this risks losing data if the cache crashes before the flush happens. There's no universally \"best\" option; the right choice depends on whether your workload is more read-heavy or write-heavy, and how much risk of data loss or staleness you can tolerate.",[23,3482,3484],{"id":3483},"_69-what-is-cache-invalidation-and-why-is-it-considered-one-of-the-hard-problems-in-computer-science","69. What is cache invalidation, and why is it considered one of the hard problems in computer science?",[11,3486,3487,3490,3491,3494,3495,3498,3499,3502],{},[31,3488,3489],{},"Cache invalidation"," is the process of removing or updating stale data in a cache once the underlying source of truth has changed, so the cache doesn't keep serving outdated information. It's famously referenced (alongside \"naming things\") as one of the genuinely hard problems in computer science, half-jokingly, but the difficulty is real: knowing ",[177,3492,3493],{},"exactly"," when data has changed, ",[177,3496,3497],{},"which"," cache entries are affected, and ",[177,3500,3501],{},"how"," to update them without introducing race conditions or serving inconsistent data mid-update gets complicated fast, especially across distributed caches or when multiple services can write to the same underlying data.",[11,3504,3505],{},"Common strategies include invalidating a specific key immediately after a write, using short TTLs so staleness self-heals within a bounded time, or versioning cache keys so old entries simply become unreachable. Each approach makes a different tradeoff between complexity and how long stale data might linger, and there's rarely a solution that's both perfectly fresh and perfectly simple at the same time.",[23,3507,3509],{"id":3508},"_70-what-is-a-ttl-time-to-live-on-a-cache-entry-and-how-do-you-decide-on-a-good-value-for-it","70. What is a TTL (time to live) on a cache entry, and how do you decide on a good value for it?",[11,3511,784,3512,3515],{},[31,3513,3514],{},"TTL"," (time to live) is the amount of time a cache entry is allowed to live before it automatically expires and gets removed (or is treated as stale on the next access). It's the simplest and most common way to bound how out-of-date cached data can get, without needing explicit invalidation logic for every write.",[11,3517,3518],{},"Choosing a good TTL is about balancing freshness against cache effectiveness: a very short TTL keeps data fresh but causes frequent cache misses (defeating much of the point of caching), while a very long TTL maximizes hit rates but risks serving stale data for longer. In practice, the value should reflect how often the underlying data actually changes and how tolerant the use case is of staleness; a product price might need a short TTL of a few minutes, while a rarely-changing configuration value might safely use a TTL of hours or days.",[23,3520,3522],{"id":3521},"_71-what-is-cache-stampede-thundering-herd-and-how-do-you-prevent-it","71. What is cache stampede (thundering herd), and how do you prevent it?",[11,3524,784,3525,3528],{},[31,3526,3527],{},"cache stampede"," (also called the thundering herd problem) happens when a popular cache entry expires and a large number of concurrent requests all experience a cache miss at the same moment, causing all of them to hit the database (or recompute the expensive value) simultaneously. This sudden spike can overwhelm the database, sometimes badly enough to cause a cascading outage, right at the moment the cache was supposed to be protecting it.",[11,3530,3531],{},"Common prevention techniques include: using a lock (or \"single-flight\" pattern) so only one request recomputes the value while others wait for the result rather than all hitting the database independently; adding jitter (randomness) to TTLs so entries don't all expire at exactly the same time; and probabilistic early expiration, where a request occasionally refreshes a \"soon to expire\" value slightly early instead of waiting for the exact expiry moment. All of these approaches aim at the same goal: making sure only one request pays the cost of a cache miss instead of every concurrent request paying it at once.",[23,3533,3535],{"id":3534},"_72-whats-the-difference-between-redis-and-memcached-at-a-conceptual-level","72. What's the difference between Redis and Memcached at a conceptual level?",[11,3537,3538,3539,202,3542,3545],{},"Both ",[31,3540,3541],{},"Redis",[31,3543,3544],{},"Memcached"," are popular in-memory key-value stores commonly used for caching, but they differ in scope and capability.",[36,3547,3548,3558],{},[39,3549,3550],{},[42,3551,3552,3554,3556],{},[45,3553,2226],{},[45,3555,3541],{},[45,3557,3544],{},[58,3559,3560,3571,3587,3598],{},[42,3561,3562,3565,3568],{},[63,3563,3564],{},"Data structures",[63,3566,3567],{},"Strings, lists, sets, sorted sets, hashes",[63,3569,3570],{},"Strings only",[42,3572,3573,3576,3584],{},[63,3574,3575],{},"Persistence",[63,3577,3578,3579,2958,3581,3583],{},"Optional (",[66,3580,2558],{},[66,3582,2562],{},")",[63,3585,3586],{},"None, purely in-memory",[42,3588,3589,3592,3595],{},[63,3590,3591],{},"Threading",[63,3593,3594],{},"Historically single-threaded core",[63,3596,3597],{},"Multi-threaded",[42,3599,3600,3603,3606],{},[63,3601,3602],{},"Extras",[63,3604,3605],{},"Pub/sub, Lua scripting, replication",[63,3607,3608],{},"Minimal, focused purely on caching",[11,3610,3611,3612,3615],{},"Memcached is deliberately simple: a fast, multi-threaded, pure key-value cache with no extra features, which makes it very efficient for straightforward caching of simple values. Redis is a richer data structure server that ",[177,3613,3614],{},"can"," be used purely as a cache, but also supports more complex use cases like leaderboards (sorted sets), pub/sub messaging, and optional persistence so data can survive a restart. The practical rule of thumb: reach for Memcached when you want the simplest possible caching layer for basic key-value pairs, and reach for Redis when you need those richer data structures or features beyond plain caching.",[18,3617,3619],{"id":3618},"concurrency-processes-and-performance","Concurrency, Processes, and Performance",[23,3621,3623],{"id":3622},"_73-what-is-the-difference-between-a-process-and-a-thread","73. What is the difference between a process and a thread?",[11,3625,784,3626,3629,3630,3633],{},[31,3627,3628],{},"process"," is an independent running instance of a program, with its own memory space, file handles, and system resources. A ",[31,3631,3632],{},"thread"," is a unit of execution inside a process; a process can contain multiple threads, and those threads share the same memory space and resources.",[11,3635,3636],{},"Because threads share memory, communicating between them is cheap (just read/write shared variables), but that also means one thread can corrupt data another thread is using if access isn't coordinated. Processes are heavier to create and switch between (the OS has to set up a fresh memory space), but they're isolated from each other, so a crash in one process generally doesn't take down another. This is why a browser tab crashing doesn't usually crash the whole browser: modern browsers run tabs as separate processes.",[23,3638,3640],{"id":3639},"_74-what-is-the-difference-between-concurrency-and-parallelism","74. What is the difference between concurrency and parallelism?",[11,3642,3643,3646,3647,3650],{},[31,3644,3645],{},"Concurrency"," is about structuring a program so multiple tasks can make progress during overlapping time periods, even on a single CPU core, by switching between them. ",[31,3648,3649],{},"Parallelism"," is about actually running multiple tasks at the exact same instant, which requires multiple CPU cores.",[11,3652,3653],{},"A single-core machine can be concurrent (juggling many tasks by time-slicing) but never truly parallel. A multi-core machine can do both: it can run several tasks in parallel, and each core can also juggle multiple concurrent tasks. A simple way to remember it: concurrency is about dealing with lots of things at once (structure), parallelism is about doing lots of things at once (execution).",[23,3655,3657],{"id":3656},"_75-what-is-a-race-condition-and-how-do-you-prevent-one","75. What is a race condition, and how do you prevent one?",[11,3659,784,3660,3663],{},[31,3661,3662],{},"race condition"," happens when two or more threads or processes access shared data at the same time, and the final result depends on the unpredictable order in which they run. It's called a \"race\" because the outcome depends on who gets there first.",[507,3665,3668],{"className":3666,"code":3667,"language":1171,"meta":512},[1169],"// two threads run this concurrently on the same `counter` variable\nread counter      // both threads read 5\nadd 1\nwrite counter     // both write 6, one increment is lost\n",[66,3669,3667],{"__ignoreMap":512},[11,3671,3672,3673,3676],{},"In the example above, ",[66,3674,3675],{},"counter"," should end up at 7 after two increments, but because both threads read the value before either writes it back, one increment gets silently lost. You prevent race conditions by making the shared access atomic, using a mutex/lock, or using data structures designed to be safely shared (like atomic counters or thread-safe queues) so only one thread can touch the critical section at a time.",[23,3678,3680],{"id":3679},"_76-what-is-a-deadlock-in-general-concurrent-programming-and-what-four-conditions-must-all-hold-for-one-to-occur","76. What is a deadlock in general concurrent programming, and what four conditions must all hold for one to occur?",[11,3682,784,3683,3685],{},[31,3684,2073],{}," is a situation where two or more threads or processes are each waiting on a resource the other holds, so none of them can ever proceed. Everyone is stuck waiting forever.",[11,3687,3688],{},"For a deadlock to happen, four conditions (known as the Coffman conditions) all have to be true at once:",[2868,3690,3691,3697,3703,3709],{},[720,3692,3693,3696],{},[31,3694,3695],{},"Mutual exclusion",": at least one resource can only be held by one thread at a time.",[720,3698,3699,3702],{},[31,3700,3701],{},"Hold and wait",": a thread is holding one resource while waiting for another.",[720,3704,3705,3708],{},[31,3706,3707],{},"No preemption",": a resource can't be forcibly taken away from a thread; it has to be released voluntarily.",[720,3710,3711,3714],{},[31,3712,3713],{},"Circular wait",": there's a cycle of threads, each waiting on a resource held by the next one in the cycle.",[11,3716,3717],{},"Breaking any single one of these conditions prevents deadlock. In practice, the most common fix is attacking circular wait: always acquire locks in the same, agreed-upon order across the whole codebase, so a cycle can never form.",[23,3719,3721],{"id":3720},"_77-what-is-the-difference-between-blocking-and-non-blocking-io","77. What is the difference between blocking and non-blocking I/O?",[11,3723,3724,3725,3728,3729,3732],{},"With ",[31,3726,3727],{},"blocking I/O",", when code makes a call like reading a file or a network socket, the calling thread stops and waits until the operation finishes before it can do anything else. With ",[31,3730,3731],{},"non-blocking I/O",", the call returns immediately (often with \"not ready yet\" or a partial result), and the program is free to go do other work and check back later, or get notified when the data is ready.",[11,3734,3735],{},"Blocking I/O is simpler to write and reason about, since code runs top to bottom in order. Non-blocking I/O is more efficient when you have many concurrent operations (like thousands of open network connections), because a single thread doesn't have to sit idle waiting on any one of them; it can juggle all of them.",[23,3737,3739],{"id":3738},"_78-what-is-an-event-loop-and-how-does-it-let-a-single-threaded-server-handle-many-concurrent-requests","78. What is an event loop, and how does it let a single-threaded server handle many concurrent requests?",[11,3741,1094,3742,3745],{},[31,3743,3744],{},"event loop"," is a runtime mechanism that continuously checks for pending work (like a completed network read, an expired timer, or a callback ready to run) and executes it, one piece at a time, on a single thread. It's the core mechanism behind single-threaded servers that still manage to serve thousands of concurrent connections.",[11,3747,3748],{},"The trick is that the event loop never blocks on slow operations like disk or network I/O. When code asks to read from a socket, the request is handed off to the operating system, and the event loop moves on to process other pending work. Once the OS signals that data is ready, the associated callback gets queued up, and the event loop picks it up on a future iteration.",[507,3750,3753],{"className":3751,"code":3752,"language":1171,"meta":512},[1169],"while true:\n    task = event_queue.wait_for_next_ready_task()\n    run(task)          // runs to completion, no other task runs mid-way\n",[66,3754,3752],{"__ignoreMap":512},[11,3756,3757],{},"This works well because most backend workloads spend the vast majority of their time waiting on I/O (database queries, HTTP calls to other services) rather than doing heavy CPU computation. The limitation is that a single CPU-heavy task (like a large synchronous computation) blocks the entire event loop and delays every other pending request, which is why CPU-bound work is usually offloaded to worker threads or separate processes.",[23,3759,3761],{"id":3760},"_79-what-is-the-difference-between-synchronous-and-asynchronous-code-execution","79. What is the difference between synchronous and asynchronous code execution?",[11,3763,3764,3767,3768,3771],{},[31,3765,3766],{},"Synchronous"," code runs one statement at a time, in order, and each statement has to finish before the next one starts. ",[31,3769,3770],{},"Asynchronous"," code lets a slow operation (like a network call) run in the background while the rest of the program keeps executing, and the result is handled later via a callback, promise/future, or similar mechanism.",[11,3773,3774],{},"Synchronous code is easier to follow but wastes time waiting. Asynchronous code is more efficient for I/O-heavy work, but it's harder to reason about, since operations can complete in a different order than they were started, and errors have to be handled at the point the async result comes back rather than with a simple try/catch around sequential code.",[23,3776,3778],{"id":3777},"_80-what-is-a-mutexlock-and-why-is-it-needed-in-concurrent-programming","80. What is a mutex/lock, and why is it needed in concurrent programming?",[11,3780,784,3781,3784,3785,3788],{},[31,3782,3783],{},"mutex"," (short for \"mutual exclusion\") is a synchronization primitive that only lets one thread at a time enter a specific section of code, called the ",[177,3786,3787],{},"critical section",". A thread has to acquire the lock before entering, and release it when it's done; if another thread tries to acquire it while it's held, that thread waits until it's free.",[11,3790,3791],{},"Locks are needed whenever multiple threads read and write shared data, to prevent race conditions. Without a lock around the increment in a shared counter, for example, two threads could read the same value before either writes back, and an update gets lost. The tradeoff is that locks introduce waiting and, if used carelessly (locking in inconsistent order across the code), can cause deadlocks.",[23,3793,3795],{"id":3794},"_81-what-is-thread-starvation","81. What is thread starvation?",[11,3797,3798,3801],{},[31,3799,3800],{},"Thread starvation"," happens when a thread is repeatedly denied access to a resource it needs, usually because other threads with higher priority or better luck keep getting scheduled ahead of it, so it never gets a fair turn to run. The thread isn't stuck the way it would be in a deadlock; it's technically still able to proceed, it just never actually gets the chance.",[11,3803,3804],{},"It's commonly caused by poor lock fairness (some locks always favor certain threads) or aggressive priority scheduling where low-priority threads keep getting bumped. The usual fix is using fair locks or scheduling policies that guarantee every waiting thread eventually gets a turn.",[23,3806,3808],{"id":3807},"_82-what-is-backpressure-and-why-does-it-matter-when-one-part-of-a-system-is-slower-than-another","82. What is backpressure, and why does it matter when one part of a system is slower than another?",[11,3810,3811,3814],{},[31,3812,3813],{},"Backpressure"," is a way of signaling \"slow down\" from a slower part of a system back to a faster part that's producing more work than the slower part can consume. Without it, the fast producer just keeps pushing data, and it piles up somewhere (in memory, in a queue) until something runs out of resources and crashes.",[11,3816,3817],{},"Think of a fast API accepting write requests faster than the database behind it can actually persist them. If there's no backpressure, requests queue up in memory indefinitely, memory usage climbs, and eventually the service falls over. With backpressure, the system might reject new requests with a \"too busy\" response, slow down how fast it reads from an upstream queue, or apply a rate limit, so the pressure gets pushed back to the producer instead of building up uncontrollably downstream. It's a core concept in streaming systems, message queues, and reactive programming.",[18,3819,3821],{"id":3820},"distributed-systems-and-scalability","Distributed Systems and Scalability",[23,3823,3825],{"id":3824},"_83-what-is-the-difference-between-vertical-scaling-and-horizontal-scaling","83. What is the difference between vertical scaling and horizontal scaling?",[11,3827,3828,3831,3832,3835],{},[31,3829,3830],{},"Vertical scaling"," (\"scaling up\") means adding more resources (CPU, RAM) to a single existing machine. ",[31,3833,3834],{},"Horizontal scaling"," (\"scaling out\") means adding more machines and spreading the load across them.",[36,3837,3838,3848],{},[39,3839,3840],{},[42,3841,3842,3844,3846],{},[45,3843,2226],{},[45,3845,3830],{},[45,3847,3834],{},[58,3849,3850,3861,3872,3883],{},[42,3851,3852,3855,3858],{},[63,3853,3854],{},"How",[63,3856,3857],{},"Bigger machine",[63,3859,3860],{},"More machines",[42,3862,3863,3866,3869],{},[63,3864,3865],{},"Ceiling",[63,3867,3868],{},"Limited by the biggest hardware available",[63,3870,3871],{},"Effectively unlimited",[42,3873,3874,3877,3880],{},[63,3875,3876],{},"Complexity",[63,3878,3879],{},"Simple, no code changes needed",[63,3881,3882],{},"Needs load balancing, often needs the app to be stateless",[42,3884,3885,3888,3891],{},[63,3886,3887],{},"Downtime",[63,3889,3890],{},"Often requires a restart/resize",[63,3892,3893],{},"Can add machines without downtime",[11,3895,3896],{},"Vertical scaling is simpler and a good first step, but it eventually hits a hardware ceiling and creates a single point of failure. Horizontal scaling scales further and adds redundancy, but it requires the application to be designed so any instance can handle any request, usually meaning it needs to be stateless or share state externally (in a database or cache).",[23,3898,3900],{"id":3899},"_84-what-is-a-load-balancer-and-what-are-some-common-load-balancing-algorithms","84. What is a load balancer, and what are some common load balancing algorithms?",[11,3902,784,3903,3906],{},[31,3904,3905],{},"load balancer"," sits in front of a group of servers and distributes incoming requests across them, so no single server gets overwhelmed and the system can keep working even if one server goes down.",[11,3908,3909],{},"Some common algorithms:",[36,3911,3912,3922],{},[39,3913,3914],{},[42,3915,3916,3919],{},[45,3917,3918],{},"Algorithm",[45,3920,3921],{},"How it decides",[58,3923,3924,3932,3940,3948],{},[42,3925,3926,3929],{},[63,3927,3928],{},"Round robin",[63,3930,3931],{},"Cycles through servers in order, one request each",[42,3933,3934,3937],{},[63,3935,3936],{},"Least connections",[63,3938,3939],{},"Sends the request to the server with the fewest active connections",[42,3941,3942,3945],{},[63,3943,3944],{},"Weighted round robin",[63,3946,3947],{},"Like round robin, but bigger/faster servers get proportionally more requests",[42,3949,3950,3953],{},[63,3951,3952],{},"IP hash",[63,3954,3955],{},"Routes a given client's requests to the same server based on a hash of its IP",[11,3957,3958],{},"Round robin is simple and works well when requests are roughly equal in cost. Least connections is better when request processing times vary a lot, since it adapts to how busy each server actually is. IP hash is used when you need the same client to consistently land on the same server, for example to keep a local, in-memory session working without needing a shared session store.",[11,3960,3961],{},[2160,3962],{"alt":3963,"src":3964},"Load balancer distributing requests across app servers diagram","/post-images/top-111-backend-interview-questions/load-balancer-diagram.png",[23,3966,3968],{"id":3967},"_85-what-is-the-difference-between-a-load-balancer-and-a-reverse-proxy","85. What is the difference between a load balancer and a reverse proxy?",[11,3970,784,3971,3974,3975,3977],{},[31,3972,3973],{},"reverse proxy"," is a server that sits in front of one or more backend servers and forwards client requests to them, often also handling things like SSL termination, caching, or compression. A ",[31,3976,3905],{}," does one specific job: distributing traffic across multiple servers to balance the load.",[11,3979,3980],{},"In practice, the two overlap a lot: a load balancer is essentially a reverse proxy whose primary purpose is traffic distribution, and most reverse proxy software can also do load balancing. The distinction is more about intent than a hard technical line: if the main job is \"which backend gets this request based on capacity\", you're describing load balancing; if the job is broader, like hiding backend topology, caching responses, or terminating TLS, that's the reverse proxy role.",[23,3982,3984],{"id":3983},"_86-what-is-an-api-gateway-and-what-problems-does-it-solve-in-a-microservices-setup","86. What is an API gateway, and what problems does it solve in a microservices setup?",[11,3986,1094,3987,3990],{},[31,3988,3989],{},"API gateway"," is a single entry point that sits in front of a collection of backend services and routes each incoming request to the right one. Clients talk to the gateway; they don't need to know how many services exist behind it or where each one lives.",[11,3992,3993],{},"In a microservices setup, it solves several problems at once: it centralizes cross-cutting concerns like authentication, rate limiting, request logging, and SSL termination so each individual service doesn't have to reimplement them; it can aggregate responses from multiple services into a single response for the client; and it hides internal service topology, so services can be split, merged, or moved without breaking clients. The tradeoff is that the gateway becomes a critical piece of infrastructure itself, so it needs to be highly available, since every request flows through it.",[23,3995,3997],{"id":3996},"_87-what-is-the-difference-between-a-monolithic-architecture-and-microservices","87. What is the difference between a monolithic architecture and microservices?",[11,3999,784,4000,4003,4004,4007],{},[31,4001,4002],{},"monolith"," is an application built and deployed as a single unit, where all the features (user accounts, payments, notifications, etc.) live in one codebase and run as one process. ",[31,4005,4006],{},"Microservices"," split those same features into separate, independently deployable services that communicate over the network, usually via APIs or messaging.",[36,4009,4010,4021],{},[39,4011,4012],{},[42,4013,4014,4016,4019],{},[45,4015,2226],{},[45,4017,4018],{},"Monolith",[45,4020,4006],{},[58,4022,4023,4034,4044,4055,4066],{},[42,4024,4025,4028,4031],{},[63,4026,4027],{},"Deployment",[63,4029,4030],{},"One unit, deployed together",[63,4032,4033],{},"Each service deployed independently",[42,4035,4036,4038,4041],{},[63,4037,2259],{},[63,4039,4040],{},"Scale the whole app together",[63,4042,4043],{},"Scale each service independently",[42,4045,4046,4049,4052],{},[63,4047,4048],{},"Development",[63,4050,4051],{},"Simple to start, easy to reason about",[63,4053,4054],{},"More moving parts, needs infra for service communication",[42,4056,4057,4060,4063],{},[63,4058,4059],{},"Failure isolation",[63,4061,4062],{},"A bug can bring down the whole app",[63,4064,4065],{},"A failing service can be isolated (with the right design)",[42,4067,4068,4071,4074],{},[63,4069,4070],{},"Data",[63,4072,4073],{},"Usually one shared database",[63,4075,4076],{},"Each service often owns its own data",[11,4078,4079],{},"Neither is universally \"better\". Monoliths are usually faster to build and simpler to operate early on, which is why most systems start as one. Microservices pay off at scale, when different teams need to ship independently and different parts of the system have very different scaling or reliability needs, but they add real operational complexity (network calls where there used to be function calls, distributed debugging, more infrastructure).",[23,4081,4083],{"id":4082},"_88-what-is-service-discovery-and-why-do-microservices-need-it","88. What is service discovery, and why do microservices need it?",[11,4085,4086,4089],{},[31,4087,4088],{},"Service discovery"," is the mechanism that lets services find each other's network location (IP address and port) at runtime, instead of that information being hardcoded. It matters in microservices because instances are constantly being created, destroyed, moved, or scaled up and down, especially in containerized environments, so a service's address can't be assumed to stay fixed.",[11,4091,4092,4093,4096,4097,4100,4101,4105],{},"There are two common patterns. With a ",[31,4094,4095],{},"service registry",", each service registers itself on startup and deregisters on shutdown, and other services query the registry to find current addresses. With ",[31,4098,4099],{},"DNS-based discovery",", a DNS name resolves to the current healthy instances, often managed automatically by the orchestration platform (see ",[761,4102,4104],{"href":4103},"/post/dns-explained-how-domain-name-system-works","How DNS Works"," for how that resolution actually happens). Without service discovery, you'd have to manually track and update IP addresses every time something scales or restarts, which doesn't work at any real scale.",[23,4107,4109],{"id":4108},"_89-what-is-a-single-point-of-failure-and-how-do-you-go-about-eliminating-one","89. What is a single point of failure, and how do you go about eliminating one?",[11,4111,784,4112,4115],{},[31,4113,4114],{},"single point of failure (SPOF)"," is any component in a system that, if it fails, takes down the whole system (or a critical part of it) because nothing else can take over its job. A single database server with no replica, or a single load balancer with no backup, are classic examples.",[11,4117,4118],{},"You eliminate a SPOF by adding redundancy: running multiple instances of the component behind a load balancer, replicating the database so a replica can be promoted if the primary fails, and spreading instances across multiple availability zones or data centers so one physical failure doesn't take everything down. The general principle is that any critical component should have at least one backup that can take over automatically (failover) without a human needing to intervene at 3am.",[23,4120,4122],{"id":4121},"_90-what-is-the-difference-between-horizontal-partitioning-and-vertical-partitioning-of-data","90. What is the difference between horizontal partitioning and vertical partitioning of data?",[11,4124,4125,4128,4129,4132,4133,4136],{},[31,4126,4127],{},"Horizontal partitioning"," (often called ",[31,4130,4131],{},"sharding",") splits a table's rows across multiple databases or servers, so each shard holds a subset of the rows, usually based on a key like user ID. ",[31,4134,4135],{},"Vertical partitioning"," splits a table's columns instead, putting different columns (or groups of columns) into different tables or databases, often to separate frequently-accessed data from rarely-accessed data.",[11,4138,4139,4140,4143],{},"For example, horizontally partitioning a ",[66,4141,4142],{},"users"," table might put users 1 to 1 million on server A and users 1 million to 2 million on server B. Vertically partitioning the same table might put login-related columns (email, password hash) in one table and profile data (bio, avatar, preferences) in another, since they're accessed at different times and rates. Horizontal partitioning is mainly about scaling write/read volume across machines; vertical partitioning is mainly about optimizing access patterns and reducing the amount of unnecessary data read per query.",[23,4145,4147],{"id":4146},"_91-what-is-the-difference-between-eventual-consistency-and-strong-consistency-and-when-is-eventual-consistency-an-acceptable-tradeoff","91. What is the difference between eventual consistency and strong consistency, and when is eventual consistency an acceptable tradeoff?",[11,4149,3724,4150,4153,4154,4157],{},[31,4151,4152],{},"strong consistency",", once a write completes, every subsequent read (from any node) is guaranteed to see that write immediately. There's never a window where different clients see different, conflicting versions of the data. With ",[31,4155,4156],{},"eventual consistency",", a write is accepted and will eventually propagate to all nodes, but for some period of time right after the write, different nodes (and therefore different reads) might return stale or different values.",[11,4159,4160],{},"Strong consistency is easier to reason about but usually costs more in latency and availability, since nodes have to coordinate (agree) before confirming a write, and that coordination gets harder to do quickly the more nodes and the more geographically spread out they are. Eventual consistency trades that guarantee for better availability and lower latency, since a node can accept a write and respond immediately without waiting for every other node to agree.",[11,4162,4163],{},"It's an acceptable tradeoff whenever a brief staleness window doesn't cause real harm: a social media \"like\" count that's a few seconds behind, a product view counter, or a user's profile picture propagating across CDN edge nodes are all fine being eventually consistent. It's a poor tradeoff for things like account balances or inventory counts during checkout, where seeing stale data can lead to real, hard-to-reverse mistakes (overselling stock, double-spending).",[23,4165,4167],{"id":4166},"_92-what-is-the-circuit-breaker-pattern-and-why-is-it-used-between-services","92. What is the circuit breaker pattern, and why is it used between services?",[11,4169,771,4170,4173],{},[31,4171,4172],{},"circuit breaker"," pattern protects a service from repeatedly calling another service that's already failing or responding too slowly. It works like an electrical circuit breaker: it monitors calls to a downstream service, and if failures cross a threshold, it \"trips\" and stops sending new requests to that service for a while, failing fast instead.",[11,4175,4176,4177,4180,4181,4184,4185,4188],{},"A circuit breaker has three states. In the ",[31,4178,4179],{},"closed"," state, everything is normal and requests pass through as usual while failures are being counted. Once failures exceed a threshold, it moves to the ",[31,4182,4183],{},"open"," state, where requests fail immediately (or return a fallback) without even attempting the call, giving the struggling downstream service room to recover. After a cooldown period, it moves to ",[31,4186,4187],{},"half-open",", where it lets a small number of test requests through; if those succeed, it closes again and resumes normal traffic, and if they fail, it goes back to open.",[11,4190,4191],{},"This matters in distributed systems because without it, a slow or failing downstream service can cause every upstream caller to pile up requests waiting on it (threads blocked, connection pools exhausted), which can cascade into taking down services that were otherwise perfectly healthy. Failing fast with a circuit breaker contains the damage to just the one struggling dependency instead of letting it spread across the whole system.",[23,4193,4195],{"id":4194},"_93-what-does-idempotency-mean-at-the-system-level-and-why-does-it-matter-for-retries-in-distributed-systems","93. What does idempotency mean at the system level, and why does it matter for retries in distributed systems?",[11,4197,4198,4199,4202],{},"An operation is ",[31,4200,4201],{},"idempotent"," if performing it multiple times has the same effect as performing it once. Calling it once or calling it ten times with the same input leaves the system in the same end state.",[11,4204,4205],{},"This matters enormously for retries. In a distributed system, network calls can fail in ambiguous ways: a request might time out because the response was lost, even though the server actually processed it successfully. When a client retries after a timeout, it genuinely doesn't know whether the original request succeeded or not. If the operation is idempotent, retrying is always safe. If it isn't, a retry can cause real damage, like charging a customer twice.",[11,4207,4208,4209,4211],{},"A common technique is an ",[31,4210,1097],{},": the client generates a unique ID for an operation (like a payment) and sends it with every retry attempt. The server checks if it has already processed that key before doing the work again.",[507,4213,4215],{"className":1218,"code":4214,"language":1220,"meta":512,"style":512},"{\n  \"idempotency_key\": \"a3f9-92c1-...\",\n  \"amount\": 4999,\n  \"currency\": \"USD\"\n}\n",[66,4216,4217,4221,4233,4245,4255],{"__ignoreMap":512},[516,4218,4219],{"class":518,"line":519},[516,4220,1228],{"class":1227},[516,4222,4223,4226,4228,4231],{"class":518,"line":525},[516,4224,4225],{"class":1233},"  \"idempotency_key\"",[516,4227,1245],{"class":1227},[516,4229,4230],{"class":1248},"\"a3f9-92c1-...\"",[516,4232,1252],{"class":1227},[516,4234,4235,4238,4240,4243],{"class":518,"line":531},[516,4236,4237],{"class":1233},"  \"amount\"",[516,4239,1245],{"class":1227},[516,4241,4242],{"class":1233},"4999",[516,4244,1252],{"class":1227},[516,4246,4247,4250,4252],{"class":518,"line":1127},[516,4248,4249],{"class":1233},"  \"currency\"",[516,4251,1245],{"class":1227},[516,4253,4254],{"class":1248},"\"USD\"\n",[516,4256,4257],{"class":518,"line":1134},[516,4258,1317],{"class":1227},[11,4260,4261],{},"If the server sees the same key twice, it returns the original result instead of charging the customer a second time. Note that not all operations are naturally idempotent: setting a value is idempotent, but incrementing a value is not, unless it's protected with an idempotency key.",[23,4263,4265],{"id":4264},"_94-what-is-the-difference-between-latency-and-throughput","94. What is the difference between latency and throughput?",[11,4267,4268,4271,4272,4275],{},[31,4269,4270],{},"Latency"," is how long it takes for a single request to complete, usually measured in milliseconds. ",[31,4273,4274],{},"Throughput"," is how many requests a system can process in a given period of time, usually measured as requests per second.",[11,4277,4278],{},"The two aren't the same thing, and improving one doesn't automatically improve the other. A system can have low latency (each request is fast) but low throughput (it can only handle a few requests at a time), or high throughput (it processes a huge volume overall) while each individual request has noticeably higher latency, for example because requests are being batched together before processing. When people talk about performance, they usually care about both, but which one matters more depends on the use case: a real-time chat feature cares a lot about latency, while a nightly batch report cares more about throughput.",[18,4280,4282],{"id":4281},"messaging-and-asynchronous-communication","Messaging and Asynchronous Communication",[23,4284,4286],{"id":4285},"_95-what-is-a-message-queue-and-what-problem-does-it-solve","95. What is a message queue, and what problem does it solve?",[11,4288,784,4289,4292],{},[31,4290,4291],{},"message queue"," is a service that lets one part of a system (the producer) send messages that get stored and later picked up and processed by another part of the system (the consumer), without the two talking to each other directly or needing to be available at the same time.",[11,4294,4295,4296,4299],{},"The core problem it solves is ",[31,4297,4298],{},"decoupling",". Without a queue, if service A calls service B directly and B is slow or down, A is stuck waiting or failing too. With a queue in between, A can drop a message and move on immediately, and B processes messages whenever it's ready, at its own pace. This also naturally smooths out traffic spikes: if a sudden burst of requests comes in, they pile up in the queue instead of overwhelming the consumer, and the consumer just works through the backlog.",[11,4301,4302],{},[2160,4303],{"alt":4304,"src":4305},"Producer-consumer message queue diagram","/post-images/top-111-backend-interview-questions/message-queue-diagram.png",[23,4307,4309],{"id":4308},"_96-what-is-the-difference-between-a-message-queue-and-a-publishsubscribe-pubsub-system","96. What is the difference between a message queue and a publish/subscribe (pub/sub) system?",[11,4311,4312,4313,4315,4316,4319,4320,4323],{},"In a classic ",[31,4314,4291],{},", each message is typically delivered to and consumed by exactly one consumer; once it's picked up and processed, it's removed from the queue. In a ",[31,4317,4318],{},"pub/sub"," system, a publisher sends a message to a ",[177,4321,4322],{},"topic",", and every subscriber to that topic gets its own copy of the message.",[11,4325,4326],{},"The distinction is really about delivery pattern: queues are for distributing work across a pool of consumers (so the work only gets done once), while pub/sub is for broadcasting an event to multiple independent listeners who each need to react to it in their own way. For example, an \"order placed\" event might be published once, and separately consumed by an email service, an inventory service, and an analytics service, each doing something completely different with the same event. Many real-world message brokers actually support both patterns.",[23,4328,4330],{"id":4329},"_97-what-is-the-difference-between-synchronous-request-response-communication-and-event-driven-communication-between-services","97. What is the difference between synchronous request-response communication and event-driven communication between services?",[11,4332,2146,4333,4336,4337,4340],{},[31,4334,4335],{},"synchronous request-response"," communication, service A calls service B directly and waits for a response before continuing, similar to a normal function call but over the network. In ",[31,4338,4339],{},"event-driven"," communication, service A publishes an event describing something that happened, and doesn't wait for or even know which services, if any, react to it.",[11,4342,4343],{},"Request-response is simpler to reason about and gives you an immediate answer, which is useful when you actually need the result right away (checking if a payment succeeded before showing a confirmation page). Event-driven communication decouples services in time and topology: the publisher doesn't need the subscriber to be available at that moment, and new subscribers can be added later without changing the publisher at all. The tradeoff is that event-driven flows are harder to trace and debug, since there's no single call stack to follow, and consistency has to be handled carefully since things happen asynchronously rather than in one atomic step.",[23,4345,4347],{"id":4346},"_98-what-do-at-least-once-at-most-once-and-exactly-once-delivery-guarantees-mean","98. What do \"at-least-once\", \"at-most-once\", and \"exactly-once\" delivery guarantees mean?",[11,4349,4350],{},"These describe how many times a message might be delivered to a consumer when things go wrong (network failures, crashes, retries).",[36,4352,4353,4365],{},[39,4354,4355],{},[42,4356,4357,4360,4362],{},[45,4358,4359],{},"Guarantee",[45,4361,307],{},[45,4363,4364],{},"Risk",[58,4366,4367,4378,4389],{},[42,4368,4369,4372,4375],{},[63,4370,4371],{},"At-most-once",[63,4373,4374],{},"Message is delivered zero or one times, never retried",[63,4376,4377],{},"Messages can be silently lost",[42,4379,4380,4383,4386],{},[63,4381,4382],{},"At-least-once",[63,4384,4385],{},"Message is retried until acknowledged, so it may be delivered more than once",[63,4387,4388],{},"Consumers may see duplicates",[42,4390,4391,4394,4397],{},[63,4392,4393],{},"Exactly-once",[63,4395,4396],{},"Message is delivered and processed exactly one time, no loss, no duplicates",[63,4398,4399],{},"Hardest and most expensive to guarantee",[11,4401,4402],{},"At-most-once is the simplest to implement (just send and forget) but risks data loss, so it's only acceptable for things you don't mind occasionally losing, like non-critical metrics. At-least-once is the most common in practice: the system retries until it gets an acknowledgment, which guarantees nothing is lost, but means consumers must be built to safely handle duplicate messages (usually via idempotency). True exactly-once delivery is notoriously difficult across a network; what systems that claim it actually provide is usually at-least-once delivery combined with idempotent processing, which produces the same practical result.",[23,4404,4406],{"id":4405},"_99-what-is-a-dead-letter-queue-and-why-is-it-useful","99. What is a dead-letter queue, and why is it useful?",[11,4408,784,4409,4412],{},[31,4410,4411],{},"dead-letter queue (DLQ)"," is a separate queue where messages get moved if they fail to be processed successfully after a certain number of retry attempts, instead of being retried forever or silently dropped.",[11,4414,4415],{},"It's useful because it prevents one bad message (say, one with malformed data that causes the consumer to crash every time) from blocking or endlessly looping the whole queue, while also making sure that message isn't just lost. Once it's sitting in the DLQ, engineers can inspect it, fix the underlying bug, and reprocess it, or at least get alerted that something needs attention. Without a DLQ, a single poison message can either get stuck retrying forever and stall the whole pipeline, or get silently discarded and quietly lose data.",[23,4417,4419],{"id":4418},"_100-what-is-the-producer-consumer-model-and-why-might-a-system-have-multiple-consumers-reading-from-the-same-queue","100. What is the producer-consumer model, and why might a system have multiple consumers reading from the same queue?",[11,4421,771,4422,4425],{},[31,4423,4424],{},"producer-consumer model"," describes a pattern where one or more producers generate work (messages, tasks, data) and put it somewhere (usually a queue), and one or more consumers pull that work off and process it, independently of how fast it's being produced.",[11,4427,4428,4429,4432],{},"A system often runs multiple consumers on the same queue purely for ",[31,4430,4431],{},"throughput",": if one consumer can process 100 messages a second but messages are arriving at 500 a second, adding more consumers lets the work be processed in parallel, so the backlog doesn't keep growing. It also improves resilience: if one consumer instance crashes, the others keep working through the queue, so processing doesn't stop entirely. Most queue systems make sure each message only goes to one consumer at a time, so adding consumers scales throughput without causing the same message to be processed twice.",[23,4434,4436],{"id":4435},"_101-what-is-event-driven-architecture-and-how-does-it-decouple-services-from-each-other","101. What is event-driven architecture, and how does it decouple services from each other?",[11,4438,4439,4442],{},[31,4440,4441],{},"Event-driven architecture"," is a design style where services communicate primarily by producing and reacting to events (facts about something that happened, like \"order placed\" or \"user signed up\") rather than calling each other directly.",[11,4444,4445],{},"It decouples services in a few concrete ways: the service that produces an event doesn't need to know which services, if any, are listening; new services can start consuming existing events without any change to the producer; and each consumer processes events at its own pace, so a slow or temporarily unavailable consumer doesn't block the producer or other consumers. This makes it easier to add new functionality over time (a new \"send welcome email\" service can just subscribe to the existing \"user signed up\" event) without touching existing code, though it does trade away the simplicity of a straight-line call stack, since a single business action can trigger a chain of reactions spread across many services.",[18,4447,4449],{"id":4448},"testing-deployment-and-observability","Testing, Deployment, and Observability",[23,4451,4453],{"id":4452},"_102-what-is-the-difference-between-unit-testing-integration-testing-and-end-to-end-testing","102. What is the difference between unit testing, integration testing, and end-to-end testing?",[11,4455,4456,4457,4460],{},"These three test types differ mainly in ",[177,4458,4459],{},"scope",", how much of the system they exercise at once.",[36,4462,4463,4478],{},[39,4464,4465],{},[42,4466,4467,4470,4473,4476],{},[45,4468,4469],{},"Test type",[45,4471,4472],{},"Scope",[45,4474,4475],{},"Speed",[45,4477,963],{},[58,4479,4480,4498,4512],{},[42,4481,4482,4485,4488,4491],{},[63,4483,4484],{},"Unit",[63,4486,4487],{},"A single function or class, in isolation",[63,4489,4490],{},"Very fast",[63,4492,4493,4494,4497],{},"Testing that a ",[66,4495,4496],{},"calculateDiscount()"," function returns the right value",[42,4499,4500,4503,4506,4509],{},[63,4501,4502],{},"Integration",[63,4504,4505],{},"Multiple components working together",[63,4507,4508],{},"Medium",[63,4510,4511],{},"Testing that a service correctly reads and writes to a real (or test) database",[42,4513,4514,4517,4520,4523],{},[63,4515,4516],{},"End-to-end (E2E)",[63,4518,4519],{},"The whole system, as a user would experience it",[63,4521,4522],{},"Slow",[63,4524,4525],{},"Simulating a full checkout flow through the actual API/UI",[11,4527,4528],{},"Unit tests are fast and pinpoint exactly what broke, but they don't catch problems that only show up when pieces interact (like a database query that's syntactically fine but wrong). Integration tests catch those interaction bugs but run slower and are more brittle to set up. End-to-end tests give the most confidence that the system actually works for a real user, but they're the slowest, most expensive to maintain, and hardest to debug when they fail. Most teams aim for a pyramid: lots of unit tests, a moderate number of integration tests, and a small number of E2E tests covering critical flows.",[23,4530,4532],{"id":4531},"_103-what-is-mocking-and-why-do-you-mock-dependencies-in-unit-tests","103. What is mocking, and why do you mock dependencies in unit tests?",[11,4534,4535,4538],{},[31,4536,4537],{},"Mocking"," means replacing a real dependency (a database, an external API, a file system) with a fake, controllable stand-in when writing a test, so the test doesn't actually depend on that real thing being available or behaving a certain way.",[11,4540,4541],{},"You mock dependencies in unit tests to keep them fast, isolated, and predictable. A test that hits a real database is slow, might fail because of network issues or unrelated data changes, and makes it hard to test edge cases (like \"what happens when the database times out\") on demand. With a mock, you can make the fake database return exactly the response, error, or delay you want to test against, every single time, without needing the real thing running at all.",[23,4543,4545],{"id":4544},"_104-what-is-cicd-and-what-problem-does-it-solve-for-a-backend-team","104. What is CI/CD, and what problem does it solve for a backend team?",[11,4547,4548,4551,4552,202,4555,4558],{},[31,4549,4550],{},"CI/CD"," stands for ",[31,4553,4554],{},"continuous integration",[31,4556,4557],{},"continuous delivery/deployment",". Continuous integration means every code change is automatically built and tested as soon as it's pushed, so integration problems are caught within minutes instead of piling up. Continuous delivery/deployment extends that automation to actually releasing the change, either to a staging environment ready for manual approval (delivery) or straight to production automatically (deployment).",[11,4560,4561],{},"The problem it solves is the pain and risk of manual releases. Without CI/CD, merging code from multiple developers and shipping it is a slow, error-prone, manual process: someone has to remember to run the tests, build the artifact, and push it out correctly, and mistakes at any step can ship broken code. CI/CD makes that pipeline automatic and repeatable, catches bugs earlier (right after they're introduced, not weeks later), and makes shipping small, frequent changes low-risk enough that teams can release many times a day instead of once a quarter.",[23,4563,4565],{"id":4564},"_105-what-is-a-container-and-how-is-it-different-from-a-virtual-machine","105. What is a container, and how is it different from a virtual machine?",[11,4567,784,4568,4571,4572,4575],{},[31,4569,4570],{},"container"," packages an application together with everything it needs to run (libraries, dependencies, configuration) into a single unit that runs consistently across different environments. A ",[31,4573,4574],{},"virtual machine (VM)"," emulates an entire computer, including its own full operating system kernel, on top of a host machine.",[36,4577,4578,4590],{},[39,4579,4580],{},[42,4581,4582,4584,4587],{},[45,4583,2226],{},[45,4585,4586],{},"Container",[45,4588,4589],{},"Virtual machine",[58,4591,4592,4603,4614,4625,4635],{},[42,4593,4594,4597,4600],{},[63,4595,4596],{},"OS",[63,4598,4599],{},"Shares the host machine's kernel",[63,4601,4602],{},"Runs its own full guest OS",[42,4604,4605,4608,4611],{},[63,4606,4607],{},"Size",[63,4609,4610],{},"Typically megabytes",[63,4612,4613],{},"Typically gigabytes",[42,4615,4616,4619,4622],{},[63,4617,4618],{},"Startup time",[63,4620,4621],{},"Seconds or less",[63,4623,4624],{},"Minutes",[42,4626,4627,4629,4632],{},[63,4628,1859],{},[63,4630,4631],{},"Process-level isolation",[63,4633,4634],{},"Full hardware-level isolation",[42,4636,4637,4640,4643],{},[63,4638,4639],{},"Resource overhead",[63,4641,4642],{},"Low",[63,4644,4645],{},"Higher",[11,4647,4648],{},"Because containers share the host's kernel instead of running a whole separate OS, they're much lighter weight and start almost instantly, which makes them well suited to running many small services, scaling quickly, and packing more workloads onto the same hardware. VMs offer stronger isolation, since each one is a genuinely separate operating system, which matters more when running fully untrusted or wildly different workloads on the same hardware.",[23,4650,4652],{"id":4651},"_106-why-does-the-twelve-factor-app-principle-recommend-storing-config-in-environment-variables-instead-of-in-code","106. Why does the twelve-factor app principle recommend storing config in environment variables instead of in code?",[11,4654,771,4655,4658,4659,4662],{},[31,4656,4657],{},"twelve-factor app"," methodology recommends keeping configuration (database URLs, API keys, feature flags, anything that varies between environments) in ",[31,4660,4661],{},"environment variables"," rather than hardcoded in the codebase, and the reasoning is mostly about safety and portability.",[11,4664,4665],{},"If config is baked into the code, you either need different code (or a different branch/config file committed) for each environment, which is error-prone and easy to mix up, or you risk accidentally committing secrets like API keys straight into version control where they can leak. Environment variables keep the same build/artifact deployable to development, staging, and production unchanged; only the environment around it differs. It also means secrets never need to touch the codebase or git history at all, which is a meaningful security win.",[23,4667,4669],{"id":4668},"_107-what-is-the-difference-between-logging-metrics-and-tracing","107. What is the difference between logging, metrics, and tracing?",[11,4671,4672,4673,4676],{},"These are the three main pillars of ",[31,4674,4675],{},"observability",", and each answers a different question about a running system.",[11,4678,4679,4682,4683,4686,4687,4690],{},[31,4680,4681],{},"Logging"," records discrete, timestamped events, like \"user 42 failed to log in\" or \"payment service returned a 500 error\", usually with enough detail to understand exactly what happened at that moment. ",[31,4684,4685],{},"Metrics"," are numeric measurements aggregated over time, like requests per second, average response time, or memory usage, useful for spotting trends and setting alerts. ",[31,4688,4689],{},"Tracing"," follows a single request as it moves through multiple services, recording how long it spent in each one, which is essential for understanding why a particular request was slow in a distributed system where one request might touch a dozen services.",[11,4692,4693,4694,4697,4698,4701,4702,4704],{},"They complement each other: metrics tell you ",[177,4695,4696],{},"something"," is wrong (error rate spiked), logs help you understand ",[177,4699,4700],{},"what"," happened in a specific case, and traces show you exactly ",[177,4703,2587],{}," in a multi-service call chain the time went or the failure occurred.",[23,4706,4708],{"id":4707},"_108-what-is-a-health-check-endpoint-and-why-do-backend-services-expose-one","108. What is a health check endpoint, and why do backend services expose one?",[11,4710,784,4711,4714,4715,756,4718,4721],{},[31,4712,4713],{},"health check endpoint"," is a simple API endpoint (commonly something like ",[66,4716,4717],{},"/health",[66,4719,4720],{},"/status",") that returns whether a service is up and able to handle requests, without doing any real work itself.",[507,4723,4727],{"className":4724,"code":4725,"language":4726,"meta":512,"style":512},"language-bash shiki shiki-themes github-dark","curl -s https://api.example.com/health\n# {\"status\":\"ok\",\"database\":\"connected\"}\n","bash",[66,4728,4729,4740],{"__ignoreMap":512},[516,4730,4731,4734,4737],{"class":518,"line":519},[516,4732,544],{"class":4733},"svObZ",[516,4735,4736],{"class":1233}," -s",[516,4738,4739],{"class":1248}," https://api.example.com/health\n",[516,4741,4742],{"class":518,"line":525},[516,4743,4744],{"class":3076},"# {\"status\":\"ok\",\"database\":\"connected\"}\n",[11,4746,4747],{},"Load balancers and orchestration systems call this endpoint regularly to decide whether an instance should keep receiving traffic. If it stops responding or returns an unhealthy status, the instance can be automatically taken out of rotation, or restarted, without a human needing to notice and intervene manually. Some health checks are \"shallow\" (just confirm the process is running) and others are \"deep\" (also check that the database and other dependencies it needs are reachable), and the right choice depends on what you actually want to happen when a dependency is down.",[23,4749,4751],{"id":4750},"_109-what-is-the-difference-between-a-rolling-deployment-and-a-blue-green-deployment","109. What is the difference between a rolling deployment and a blue-green deployment?",[11,4753,784,4754,4757,4758,4761],{},[31,4755,4756],{},"rolling deployment"," updates instances of a service gradually, a few at a time, replacing old versions with new ones until every instance is running the new version. A ",[31,4759,4760],{},"blue-green deployment"," runs two complete, identical environments (\"blue\" is the current live one, \"green\" is the new one); traffic is switched over all at once from blue to green after the new version is verified.",[36,4763,4764,4776],{},[39,4765,4766],{},[42,4767,4768,4770,4773],{},[45,4769,2226],{},[45,4771,4772],{},"Rolling",[45,4774,4775],{},"Blue-green",[58,4777,4778,4789,4800,4811],{},[42,4779,4780,4783,4786],{},[63,4781,4782],{},"Infrastructure cost",[63,4784,4785],{},"Lower, reuses existing instances",[63,4787,4788],{},"Higher, needs two full environments at once",[42,4790,4791,4794,4797],{},[63,4792,4793],{},"Rollback speed",[63,4795,4796],{},"Slower, has to roll instances back gradually",[63,4798,4799],{},"Instant, just switch traffic back to blue",[42,4801,4802,4805,4808],{},[63,4803,4804],{},"Traffic during deploy",[63,4806,4807],{},"Mixed old and new versions simultaneously",[63,4809,4810],{},"Never mixed, switches all at once",[42,4812,4813,4816,4819],{},[63,4814,4815],{},"Risk window",[63,4817,4818],{},"Smaller batches limit blast radius",[63,4820,4821],{},"All-or-nothing cutover",[11,4823,4824],{},"Rolling deployments are cheaper and reduce the blast radius of a bad change, but for a period of time both old and new versions are serving traffic, which requires the two versions to be compatible with each other. Blue-green avoids that mixed-version problem and allows an instant rollback, at the cost of needing double the infrastructure while both environments exist.",[23,4826,4828],{"id":4827},"_110-what-is-graceful-shutdown-and-why-does-a-backend-service-need-to-handle-it-explicitly","110. What is graceful shutdown, and why does a backend service need to handle it explicitly?",[11,4830,4831,4834],{},[31,4832,4833],{},"Graceful shutdown"," means a service, when told to stop (usually via a termination signal), finishes handling requests it's currently working on and cleans up properly (closing database connections, finishing in-flight writes) before actually exiting, instead of stopping abruptly mid-request.",[507,4836,4839],{"className":4837,"code":4838,"language":1171,"meta":512},[1169],"on SIGTERM:\n    stop accepting new requests\n    wait for in-flight requests to finish (up to a timeout)\n    close database connections, flush logs\n    exit\n",[66,4840,4838],{"__ignoreMap":512},[11,4842,4843],{},"Without this, a service that gets killed mid-request can leave things in a bad state: a client gets a broken connection instead of a response, a database write gets cut off halfway, or a message gets picked off a queue but never actually finishes processing (and might just be lost, depending on the acknowledgment model). This matters constantly in modern deployments, since instances get restarted or replaced all the time during routine deployments and autoscaling, not just during outages, so handling shutdown cleanly needs to be a normal, well-tested code path rather than an afterthought.",[23,4845,4847],{"id":4846},"_111-why-do-backend-services-rely-on-centralized-logging-instead-of-just-writing-logs-to-a-local-file-on-each-server","111. Why do backend services rely on centralized logging instead of just writing logs to a local file on each server?",[11,4849,4850],{},"Writing logs to a local file works fine when there's one server, but it breaks down fast in any real backend system running multiple instances. If each instance writes to its own local disk, debugging an issue means logging into potentially dozens of machines individually and searching each one's files by hand, and if an instance is terminated (common with autoscaling or container restarts), its logs disappear along with it.",[11,4852,4853,4856],{},[31,4854,4855],{},"Centralized logging"," ships logs from every instance to one shared, searchable system as they're generated, so all logs live in one place regardless of which instance produced them or whether that instance still exists. This makes it possible to search across the whole fleet at once, correlate a single request across multiple services (especially combined with tracing), set up alerts on log patterns, and keep a durable history that survives individual instances being replaced. It's essentially a prerequisite for operating any system with more than a handful of servers.",[18,4858,4860],{"id":4859},"final-thoughts","Final Thoughts",[11,4862,4863],{},"These 111 questions cover the ground that comes up again and again in backend interviews, from the basics of HTTP methods to the tradeoffs behind sharding, caching strategies, and message delivery guarantees. Don't try to memorize every answer word for word. Build the underlying mental model instead: why a stateless protocol needs cookies and tokens to fake memory, why a cache is always a tradeoff between speed and staleness, why a distributed system can't have perfect consistency and availability at the same time. Once that model is solid, you'll be able to reason through questions you've never seen phrased this exact way before, which is really what interviewers are testing for.",[11,4865,4866],{},"Good luck with your interviews.",[4868,4869,4870],"style",{},"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 pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":512,"searchDepth":525,"depth":525,"links":4872},[4873,4891,4905,4922,4932,4950,4960,4972,4986,4995,5007],{"id":20,"depth":525,"text":21,"children":4874},[4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4887,4889,4890],{"id":25,"depth":531,"text":26},{"id":169,"depth":531,"text":170},{"id":226,"depth":531,"text":227},{"id":277,"depth":531,"text":278},{"id":374,"depth":531,"text":375},{"id":408,"depth":531,"text":409},{"id":437,"depth":531,"text":438},{"id":483,"depth":531,"text":484},{"id":548,"depth":531,"text":549},{"id":561,"depth":531,"text":562},{"id":648,"depth":531,"text":4886},"11. What is content negotiation, and how does the Accept header relate to it?",{"id":695,"depth":531,"text":4888},"12. What are cookies used for on the backend, and what do attributes like HttpOnly, Secure, and SameSite do?",{"id":767,"depth":531,"text":768},{"id":780,"depth":531,"text":781},{"id":798,"depth":525,"text":799,"children":4892},[4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904],{"id":802,"depth":531,"text":803},{"id":865,"depth":531,"text":866},{"id":944,"depth":531,"text":945},{"id":1033,"depth":531,"text":1034},{"id":1067,"depth":531,"text":1068},{"id":1090,"depth":531,"text":1091},{"id":1140,"depth":531,"text":1141},{"id":1188,"depth":531,"text":1189},{"id":1208,"depth":531,"text":1209},{"id":1323,"depth":531,"text":1324},{"id":1340,"depth":531,"text":1341},{"id":1361,"depth":531,"text":1362},{"id":1384,"depth":525,"text":1385,"children":4906},[4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921],{"id":1396,"depth":531,"text":1397},{"id":1421,"depth":531,"text":1422},{"id":1514,"depth":531,"text":1515},{"id":1534,"depth":531,"text":1535},{"id":1582,"depth":531,"text":1583},{"id":1622,"depth":531,"text":1623},{"id":1648,"depth":531,"text":1649},{"id":1668,"depth":531,"text":1669},{"id":1827,"depth":531,"text":1828},{"id":1961,"depth":531,"text":1962},{"id":2067,"depth":531,"text":2068},{"id":2080,"depth":531,"text":2081},{"id":2114,"depth":531,"text":2115},{"id":2128,"depth":531,"text":2129},{"id":2166,"depth":531,"text":2167},{"id":2202,"depth":525,"text":2203,"children":4923},[4924,4925,4926,4927,4928,4929,4930,4931],{"id":2206,"depth":531,"text":2207},{"id":2281,"depth":531,"text":2282},{"id":2366,"depth":531,"text":2367},{"id":2471,"depth":531,"text":2472},{"id":2488,"depth":531,"text":2489},{"id":2531,"depth":531,"text":2532},{"id":2551,"depth":531,"text":2552},{"id":2573,"depth":531,"text":2574},{"id":2591,"depth":525,"text":2592,"children":4933},[4934,4935,4936,4937,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949],{"id":2595,"depth":531,"text":2596},{"id":2615,"depth":531,"text":2616},{"id":2698,"depth":531,"text":2699},{"id":2751,"depth":531,"text":4938},"53. What are the security tradeoffs of storing a JWT in localStorage versus an httpOnly cookie?",{"id":2852,"depth":531,"text":2853},{"id":2902,"depth":531,"text":2903},{"id":2927,"depth":531,"text":2928},{"id":2981,"depth":531,"text":2982},{"id":2996,"depth":531,"text":2997},{"id":3030,"depth":531,"text":3031},{"id":3059,"depth":531,"text":3060},{"id":3208,"depth":531,"text":3209},{"id":3220,"depth":531,"text":3221},{"id":3233,"depth":531,"text":3234},{"id":3254,"depth":531,"text":3255},{"id":3273,"depth":525,"text":3274,"children":4951},[4952,4953,4954,4955,4956,4957,4958,4959],{"id":3277,"depth":531,"text":3278},{"id":3293,"depth":531,"text":3294},{"id":3369,"depth":531,"text":3370},{"id":3402,"depth":531,"text":3403},{"id":3483,"depth":531,"text":3484},{"id":3508,"depth":531,"text":3509},{"id":3521,"depth":531,"text":3522},{"id":3534,"depth":531,"text":3535},{"id":3618,"depth":525,"text":3619,"children":4961},[4962,4963,4964,4965,4966,4967,4968,4969,4970,4971],{"id":3622,"depth":531,"text":3623},{"id":3639,"depth":531,"text":3640},{"id":3656,"depth":531,"text":3657},{"id":3679,"depth":531,"text":3680},{"id":3720,"depth":531,"text":3721},{"id":3738,"depth":531,"text":3739},{"id":3760,"depth":531,"text":3761},{"id":3777,"depth":531,"text":3778},{"id":3794,"depth":531,"text":3795},{"id":3807,"depth":531,"text":3808},{"id":3820,"depth":525,"text":3821,"children":4973},[4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985],{"id":3824,"depth":531,"text":3825},{"id":3899,"depth":531,"text":3900},{"id":3967,"depth":531,"text":3968},{"id":3983,"depth":531,"text":3984},{"id":3996,"depth":531,"text":3997},{"id":4082,"depth":531,"text":4083},{"id":4108,"depth":531,"text":4109},{"id":4121,"depth":531,"text":4122},{"id":4146,"depth":531,"text":4147},{"id":4166,"depth":531,"text":4167},{"id":4194,"depth":531,"text":4195},{"id":4264,"depth":531,"text":4265},{"id":4281,"depth":525,"text":4282,"children":4987},[4988,4989,4990,4991,4992,4993,4994],{"id":4285,"depth":531,"text":4286},{"id":4308,"depth":531,"text":4309},{"id":4329,"depth":531,"text":4330},{"id":4346,"depth":531,"text":4347},{"id":4405,"depth":531,"text":4406},{"id":4418,"depth":531,"text":4419},{"id":4435,"depth":531,"text":4436},{"id":4448,"depth":525,"text":4449,"children":4996},[4997,4998,4999,5000,5001,5002,5003,5004,5005,5006],{"id":4452,"depth":531,"text":4453},{"id":4531,"depth":531,"text":4532},{"id":4544,"depth":531,"text":4545},{"id":4564,"depth":531,"text":4565},{"id":4651,"depth":531,"text":4652},{"id":4668,"depth":531,"text":4669},{"id":4707,"depth":531,"text":4708},{"id":4750,"depth":531,"text":4751},{"id":4827,"depth":531,"text":4828},{"id":4846,"depth":531,"text":4847},{"id":4859,"depth":525,"text":4860},"2026-08-04","111 real, commonly-asked backend interview questions and answers for developers with 0-3 years of experience, covering HTTP, API design, databases, security, caching, concurrency, distributed systems, and messaging, explained in the simplest terms.",false,"md",null,"top-111-backend-interview-questions.png",{},"/backend/top-111-backend-interview-questions",{"title":5,"description":5009},"Backend/6.top-111-backend-interview-questions",[5019,5020,5021,5022,5023,5024],"Backend","Interview Questions","System Design","APIs","Databases","Web Development","7oAxpXdaYPL29Of4BIAj-YRwRFtBfq0b7JSoDjawEnY",[5027,8435,29865,30311,30561],{"id":4,"title":5,"author":6,"body":5028,"date":5008,"description":5009,"draft":5010,"extension":5011,"guide":5012,"image":5013,"meta":8432,"navigation":1130,"path":5015,"seo":8433,"stem":5017,"tags":8434,"__hash__":5025},{"type":8,"value":5029,"toc":8298},[5030,5032,5034,5036,5038,5042,5118,5136,5138,5146,5172,5174,5178,5204,5206,5216,5264,5270,5272,5280,5290,5292,5300,5306,5308,5312,5332,5334,5342,5346,5362,5368,5370,5374,5376,5378,5380,5386,5392,5400,5438,5442,5446,5454,5470,5478,5482,5484,5504,5516,5518,5522,5524,5526,5530,5534,5536,5538,5542,5544,5574,5578,5580,5586,5638,5640,5642,5646,5702,5706,5708,5712,5718,5726,5728,5734,5740,5742,5746,5750,5774,5776,5784,5790,5795,5801,5803,5807,5813,5815,5817,5819,5891,5893,5895,5901,5903,5905,5913,5915,5917,5923,5925,5927,5929,5931,5935,5937,5941,5949,5951,5953,5961,5977,6001,6003,6005,6009,6015,6017,6023,6033,6043,6045,6051,6065,6067,6075,6083,6085,6091,6095,6097,6101,6151,6203,6217,6219,6223,6227,6245,6317,6321,6323,6327,6373,6375,6391,6397,6399,6403,6405,6407,6415,6420,6426,6428,6432,6434,6436,6444,6448,6452,6456,6458,6468,6472,6476,6478,6480,6486,6532,6534,6536,6538,6594,6596,6598,6602,6606,6678,6680,6682,6688,6690,6692,6696,6710,6714,6718,6720,6728,6730,6732,6738,6742,6744,6748,6752,6754,6756,6762,6766,6768,6776,6824,6826,6828,6834,6839,6857,6861,6867,6877,6887,6921,6929,6931,6935,6939,6955,6959,6961,6963,6969,6975,6977,6991,7001,7006,7008,7010,7014,7018,7020,7024,7040,7042,7046,7058,7060,7064,7134,7138,7176,7178,7180,7184,7186,7188,7192,7194,7196,7202,7206,7208,7214,7218,7220,7222,7226,7230,7232,7234,7282,7286,7288,7296,7301,7305,7307,7309,7313,7359,7367,7369,7379,7381,7383,7387,7389,7391,7395,7397,7399,7405,7455,7459,7461,7463,7469,7471,7473,7479,7481,7483,7487,7492,7496,7498,7502,7504,7522,7524,7526,7532,7534,7536,7540,7542,7547,7549,7551,7557,7559,7561,7567,7569,7571,7575,7577,7579,7583,7585,7587,7589,7595,7641,7643,7645,7649,7651,7687,7689,7693,7695,7701,7703,7705,7709,7711,7713,7719,7773,7775,7777,7781,7789,7791,7795,7797,7799,7807,7811,7813,7819,7821,7823,7825,7829,7837,7839,7841,7845,7847,7851,7891,7893,7895,7901,7903,7905,7907,7911,7915,7919,7921,7929,7931,7933,7939,7941,7943,7945,7983,7985,7987,7991,7993,7995,7999,8003,8005,8009,8011,8013,8015,8019,8067,8069,8071,8075,8077,8079,8087,8089,8091,8097,8151,8153,8155,8161,8163,8165,8169,8177,8185,8187,8195,8211,8213,8215,8221,8267,8269,8271,8275,8280,8282,8284,8286,8290,8292,8294,8296],[11,5031,13],{},[11,5033,16],{},[18,5035,21],{"id":20},[23,5037,26],{"id":25},[11,5039,29,5040,34],{},[31,5041,33],{},[36,5043,5044,5056],{},[39,5045,5046],{},[42,5047,5048,5050,5052,5054],{},[45,5049,47],{},[45,5051,50],{},[45,5053,53],{},[45,5055,56],{},[58,5057,5058,5070,5082,5094,5106],{},[42,5059,5060,5064,5066,5068],{},[63,5061,5062],{},[66,5063,68],{},[63,5065,71],{},[63,5067,74],{},[63,5069,77],{},[42,5071,5072,5076,5078,5080],{},[63,5073,5074],{},[66,5075,84],{},[63,5077,87],{},[63,5079,90],{},[63,5081,93],{},[42,5083,5084,5088,5090,5092],{},[63,5085,5086],{},[66,5087,100],{},[63,5089,103],{},[63,5091,90],{},[63,5093,108],{},[42,5095,5096,5100,5102,5104],{},[63,5097,5098],{},[66,5099,115],{},[63,5101,118],{},[63,5103,90],{},[63,5105,123],{},[42,5107,5108,5112,5114,5116],{},[63,5109,5110],{},[66,5111,130],{},[63,5113,133],{},[63,5115,136],{},[63,5117,139],{},[11,5119,5120,144,5122,148,5124,151,5126,154,5128,157,5130,160,5132,163,5134,166],{},[66,5121,68],{},[31,5123,147],{},[66,5125,84],{},[66,5127,100],{},[66,5129,115],{},[66,5131,130],{},[66,5133,84],{},[66,5135,100],{},[23,5137,170],{"id":169},[11,5139,5140,175,5142,180,5144,183],{},[66,5141,100],{},[177,5143,179],{},[66,5145,115],{},[11,5147,186,5148,154,5150,157,5152,196,5154,199,5156,202,5158,205,5160,208,5162,211,5164,214,5166,217,5168,220,5170,223],{},[66,5149,189],{},[66,5151,192],{},[66,5153,195],{},[66,5155,100],{},[66,5157,189],{},[66,5159,192],{},[66,5161,195],{},[66,5163,115],{},[66,5165,195],{},[66,5167,100],{},[66,5169,115],{},[66,5171,115],{},[23,5173,227],{"id":226},[11,5175,5176,233],{},[31,5177,232],{},[11,5179,5180,154,5182,154,5184,154,5186,157,5188,248,5190,252,5192,256,5194,260,5196,263,5198,267,5200,271,5202,274],{},[66,5181,68],{},[66,5183,100],{},[66,5185,130],{},[66,5187,244],{},[66,5189,247],{},[66,5191,251],{},[66,5193,255],{},[177,5195,259],{},[66,5197,84],{},[177,5199,266],{},[66,5201,270],{},[66,5203,84],{},[23,5205,278],{"id":277},[11,5207,5208,284,5210,288,5212,284,5214,295],{},[66,5209,283],{},[177,5211,287],{},[66,5213,291],{},[177,5215,294],{},[36,5217,5218,5228],{},[39,5219,5220],{},[42,5221,5222,5224,5226],{},[45,5223,304],{},[45,5225,307],{},[45,5227,310],{},[58,5229,5230,5248],{},[42,5231,5232,5236,5238],{},[63,5233,5234],{},[66,5235,283],{},[63,5237,321],{},[63,5239,5240,327,5242,331,5244,335,5246,339],{},[66,5241,326],{},[66,5243,330],{},[66,5245,334],{},[66,5247,338],{},[42,5249,5250,5254,5256],{},[63,5251,5252],{},[66,5253,291],{},[63,5255,348],{},[63,5257,5258,354,5260,358,5262,362],{},[66,5259,353],{},[66,5261,357],{},[66,5263,361],{},[11,5265,365,5266,368,5268,371],{},[66,5267,283],{},[66,5269,291],{},[23,5271,375],{"id":374},[11,5273,5274,381,5276,385,5278,389],{},[66,5275,380],{},[66,5277,384],{},[177,5279,388],{},[11,5281,392,5282,395,5284,399,5286,402,5288,405],{},[66,5283,330],{},[66,5285,398],{},[66,5287,330],{},[66,5289,398],{},[23,5291,409],{"id":408},[11,5293,5294,415,5296,419,5298,423],{},[66,5295,414],{},[66,5297,418],{},[177,5299,422],{},[11,5301,426,5302,430,5304,434],{},[66,5303,429],{},[66,5305,433],{},[23,5307,438],{"id":437},[11,5309,5310,444],{},[31,5311,443],{},[11,5313,5314,450,5316,454,5318,458,5320,462,5322,466,5324,469,5326,473,5328,477,5330,480],{},[31,5315,449],{},[66,5317,453],{},[66,5319,457],{},[66,5321,461],{},[31,5323,465],{},[66,5325,457],{},[66,5327,472],{},[66,5329,476],{},[66,5331,457],{},[23,5333,484],{"id":483},[11,5335,5336,490,5338,494,5340,498],{},[31,5337,489],{},[177,5339,493],{},[31,5341,497],{},[11,5343,501,5344,505],{},[66,5345,504],{},[507,5347,5348],{"className":509,"code":510,"language":511,"meta":512,"style":512},[66,5349,5350,5354,5358],{"__ignoreMap":512},[516,5351,5352],{"class":518,"line":519},[516,5353,522],{},[516,5355,5356],{"class":518,"line":525},[516,5357,528],{},[516,5359,5360],{"class":518,"line":531},[516,5361,534],{},[11,5363,537,5364,541,5366,545],{},[177,5365,540],{},[66,5367,544],{},[23,5369,549],{"id":548},[11,5371,5372,555],{},[31,5373,554],{},[11,5375,558],{},[23,5377,562],{"id":561},[11,5379,565],{},[11,5381,5382,571,5384,575],{},[31,5383,570],{},[177,5385,574],{},[11,5387,5388,581,5390,585],{},[31,5389,580],{},[177,5391,584],{},[11,5393,5394,591,5396,595,5398,599],{},[31,5395,590],{},[66,5397,594],{},[177,5399,598],{},[36,5401,5402,5412],{},[39,5403,5404],{},[42,5405,5406,5408,5410],{},[45,5407,608],{},[45,5409,611],{},[45,5411,614],{},[58,5413,5414,5422,5430],{},[42,5415,5416,5418,5420],{},[63,5417,570],{},[63,5419,623],{},[63,5421,626],{},[42,5423,5424,5426,5428],{},[63,5425,580],{},[63,5427,623],{},[63,5429,635],{},[42,5431,5432,5434,5436],{},[63,5433,590],{},[63,5435,642],{},[63,5437,645],{},[23,5439,649,5440,652],{"id":648},[66,5441,461],{},[11,5443,5444,658],{},[31,5445,657],{},[11,5447,661,5448,664,5450,668,5452,672],{},[66,5449,461],{},[66,5451,667],{},[66,5453,671],{},[507,5455,5456],{"className":509,"code":675,"language":511,"meta":512,"style":512},[66,5457,5458,5462,5466],{"__ignoreMap":512},[516,5459,5460],{"class":518,"line":519},[516,5461,682],{},[516,5463,5464],{"class":518,"line":525},[516,5465,687],{},[516,5467,5468],{"class":518,"line":531},[516,5469,692],{},[23,5471,696,5472,154,5474,157,5476,706],{"id":695},[66,5473,699],{},[66,5475,702],{},[66,5477,705],{},[11,5479,5480,712],{},[31,5481,711],{},[11,5483,715],{},[717,5485,5486,5490,5494],{},[720,5487,5488,724],{},[66,5489,699],{},[720,5491,5492,729],{},[66,5493,702],{},[720,5495,5496,734,5498,154,5500,741,5502,745],{},[66,5497,705],{},[66,5499,737],{},[66,5501,740],{},[66,5503,744],{},[11,5505,748,5506,154,5508,157,5510,756,5512,759,5514,405],{},[66,5507,699],{},[66,5509,702],{},[66,5511,755],{},[66,5513,737],{},[761,5515,764],{"href":763},[23,5517,768],{"id":767},[11,5519,771,5520,774],{},[31,5521,497],{},[11,5523,777],{},[23,5525,781],{"id":780},[11,5527,784,5528,788],{},[31,5529,787],{},[11,5531,791,5532,795],{},[177,5533,794],{},[18,5535,799],{"id":798},[23,5537,803],{"id":802},[11,5539,5540,809],{},[31,5541,808],{},[11,5543,812],{},[717,5545,5546,5550,5554,5558,5566,5570],{},[720,5547,5548,820],{},[31,5549,819],{},[720,5551,5552,826],{},[31,5553,825],{},[720,5555,5556,832],{},[31,5557,831],{},[720,5559,5560,838,5562,154,5564,843],{},[31,5561,837],{},[66,5563,68],{},[66,5565,84],{},[720,5567,5568,849],{},[31,5569,848],{},[720,5571,5572,855],{},[31,5573,854],{},[11,5575,858,5576,862],{},[177,5577,861],{},[23,5579,866],{"id":865},[11,5581,5582,872,5584,876],{},[31,5583,871],{},[31,5585,875],{},[36,5587,5588,5596],{},[39,5589,5590],{},[42,5591,5592,5594],{},[45,5593,885],{},[45,5595,888],{},[58,5597,5598,5608,5618,5628],{},[42,5599,5600,5604],{},[63,5601,5602],{},[66,5603,897],{},[63,5605,5606],{},[66,5607,902],{},[42,5609,5610,5614],{},[63,5611,5612],{},[66,5613,909],{},[63,5615,5616],{},[66,5617,914],{},[42,5619,5620,5624],{},[63,5621,5622],{},[66,5623,921],{},[63,5625,5626],{},[66,5627,926],{},[42,5629,5630,5634],{},[63,5631,5632],{},[66,5633,933],{},[63,5635,5636],{},[66,5637,938],{},[11,5639,941],{},[23,5641,945],{"id":944},[11,5643,5644,951],{},[31,5645,950],{},[36,5647,5648,5658],{},[39,5649,5650],{},[42,5651,5652,5654,5656],{},[45,5653,960],{},[45,5655,963],{},[45,5657,966],{},[58,5659,5660,5670,5680,5690],{},[42,5661,5662,5664,5668],{},[63,5663,973],{},[63,5665,5666],{},[66,5667,978],{},[63,5669,981],{},[42,5671,5672,5674,5678],{},[63,5673,986],{},[63,5675,5676],{},[66,5677,991],{},[63,5679,994],{},[42,5681,5682,5684,5688],{},[63,5683,999],{},[63,5685,5686],{},[66,5687,1004],{},[63,5689,1007],{},[42,5691,5692,5696,5700],{},[63,5693,1012,5694,1015],{},[66,5695,461],{},[63,5697,5698],{},[66,5699,1020],{},[63,5701,1023],{},[11,5703,1026,5704,1030],{},[177,5705,1029],{},[23,5707,1034],{"id":1033},[11,5709,5710,1040],{},[31,5711,1039],{},[11,5713,5714,1046,5716,1050],{},[31,5715,1045],{},[66,5717,1049],{},[11,5719,5720,1056,5722,1060,5724,1064],{},[31,5721,1055],{},[177,5723,1059],{},[66,5725,1063],{},[23,5727,1068],{"id":1067},[11,5729,5730,1074,5732,405],{},[31,5731,1073],{},[66,5733,1077],{},[11,5735,1080,5736,202,5738,1087],{},[66,5737,1083],{},[66,5739,1086],{},[23,5741,1091],{"id":1090},[11,5743,1094,5744,1098],{},[31,5745,1097],{},[11,5747,1101,5748,1104],{},[66,5749,84],{},[507,5751,5752],{"className":509,"code":1107,"language":511,"meta":512,"style":512},[66,5753,5754,5758,5762,5766,5770],{"__ignoreMap":512},[516,5755,5756],{"class":518,"line":519},[516,5757,1114],{},[516,5759,5760],{"class":518,"line":525},[516,5761,1119],{},[516,5763,5764],{"class":518,"line":531},[516,5765,1124],{},[516,5767,5768],{"class":518,"line":1127},[516,5769,1131],{"emptyLinePlaceholder":1130},[516,5771,5772],{"class":518,"line":1134},[516,5773,1137],{},[23,5775,1141],{"id":1140},[11,5777,5778,1146,5780,1150,5782,1154],{},[31,5779,808],{},[31,5781,1149],{},[177,5783,1153],{},[11,5785,1157,5786,1161,5788,1165],{},[177,5787,1160],{},[177,5789,1164],{},[507,5791,5793],{"className":5792,"code":1170,"language":1171,"meta":512},[1169],[66,5794,1170],{"__ignoreMap":512},[11,5796,1176,5797,1180,5799,1185],{},[31,5798,1179],{},[761,5800,1184],{"href":1183},[23,5802,1189],{"id":1188},[11,5804,5805,1195],{},[31,5806,1194],{},[11,5808,1198,5809,756,5811,1205],{},[66,5810,1201],{},[66,5812,1204],{},[23,5814,1209],{"id":1208},[11,5816,1212],{},[11,5818,1215],{},[507,5820,5821],{"className":1218,"code":1219,"language":1220,"meta":512,"style":512},[66,5822,5823,5827,5833,5843,5853,5859,5879,5883,5887],{"__ignoreMap":512},[516,5824,5825],{"class":518,"line":519},[516,5826,1228],{"class":1227},[516,5828,5829,5831],{"class":518,"line":525},[516,5830,1234],{"class":1233},[516,5832,1237],{"class":1227},[516,5834,5835,5837,5839,5841],{"class":518,"line":531},[516,5836,1242],{"class":1233},[516,5838,1245],{"class":1227},[516,5840,1249],{"class":1248},[516,5842,1252],{"class":1227},[516,5844,5845,5847,5849,5851],{"class":518,"line":1127},[516,5846,1257],{"class":1233},[516,5848,1245],{"class":1227},[516,5850,1262],{"class":1248},[516,5852,1252],{"class":1227},[516,5854,5855,5857],{"class":518,"line":1134},[516,5856,1269],{"class":1233},[516,5858,1272],{"class":1227},[516,5860,5861,5863,5865,5867,5869,5871,5873,5875,5877],{"class":518,"line":1275},[516,5862,1278],{"class":1227},[516,5864,1281],{"class":1233},[516,5866,1245],{"class":1227},[516,5868,1286],{"class":1248},[516,5870,154],{"class":1227},[516,5872,1291],{"class":1233},[516,5874,1245],{"class":1227},[516,5876,1296],{"class":1248},[516,5878,1299],{"class":1227},[516,5880,5881],{"class":518,"line":1302},[516,5882,1305],{"class":1227},[516,5884,5885],{"class":518,"line":1308},[516,5886,1311],{"class":1227},[516,5888,5889],{"class":518,"line":1314},[516,5890,1317],{"class":1227},[11,5892,1320],{},[23,5894,1324],{"id":1323},[11,5896,1094,5897,1330,5899,1334],{},[31,5898,1329],{},[66,5900,1333],{},[11,5902,1337],{},[23,5904,1341],{"id":1340},[11,5906,5907,1347,5909,1351,5911,1355],{},[31,5908,1346],{},[31,5910,1350],{},[177,5912,1354],{},[11,5914,1358],{},[23,5916,1362],{"id":1361},[11,5918,784,5919,1368,5921,1372],{},[31,5920,1367],{},[31,5922,1371],{},[11,5924,1375],{},[11,5926,1378],{},[11,5928,1381],{},[18,5930,1385],{"id":1384},[11,5932,1388,5933,1393],{},[761,5934,1392],{"href":1391},[23,5936,1397],{"id":1396},[11,5938,5939,1403],{},[31,5940,1402],{},[11,5942,1406,5943,1410,5945,1414,5947,1418],{},[66,5944,1409],{},[66,5946,1413],{},[31,5948,1417],{},[23,5950,1422],{"id":1421},[11,5952,1425],{},[11,5954,5955,1431,5957,1435,5959,1439],{},[31,5956,1430],{},[66,5958,1434],{},[66,5960,1438],{},[11,5962,5963,1445,5965,1448,5967,1452,5969,1456,5971,1460,5973,1464,5975,1468],{},[31,5964,1444],{},[177,5966,179],{},[66,5968,1451],{},[66,5970,1455],{},[66,5972,1459],{},[66,5974,1463],{},[66,5976,1467],{},[11,5978,5979,1474,5981,1478,5983,1482,5985,154,5987,157,5989,1492,5991,1495,5993,1498,5995,1501,5997,1504,5999,1508],{},[31,5980,1473],{},[177,5982,1477],{},[66,5984,1481],{},[66,5986,1485],{},[66,5988,1488],{},[66,5990,1491],{},[66,5992,1491],{},[66,5994,1488],{},[66,5996,1485],{},[66,5998,1491],{},[66,6000,1507],{},[11,6002,1511],{},[23,6004,1515],{"id":1514},[11,6006,6007,1521],{},[31,6008,1520],{},[11,6010,1524,6011,1528,6013,1531],{},[66,6012,1527],{},[66,6014,1467],{},[23,6016,1535],{"id":1534},[11,6018,784,6019,1541,6021,1545],{},[31,6020,1540],{},[66,6022,1544],{},[11,6024,784,6025,1551,6027,1555,6029,1559,6031,1563],{},[31,6026,1550],{},[31,6028,1554],{},[66,6030,1558],{},[66,6032,1562],{},[11,6034,784,6035,1569,6037,1572,6039,1575,6041,1579],{},[31,6036,1568],{},[66,6038,1544],{},[66,6040,192],{},[66,6042,1578],{},[23,6044,1583],{"id":1582},[11,6046,1094,6047,1589,6049,1593],{},[31,6048,1588],{},[66,6050,1592],{},[11,6052,1596,6053,1600,6055,1604,6057,1607,6059,1611,6061,1615,6063,1619],{},[66,6054,1599],{},[177,6056,1603],{},[66,6058,192],{},[66,6060,1610],{},[66,6062,1614],{},[66,6064,1618],{},[23,6066,1623],{"id":1622},[11,6068,1626,6069,154,6071,741,6073,1635],{},[66,6070,1629],{},[66,6072,1632],{},[66,6074,130],{},[11,6076,1638,6077,154,6079,741,6081,1645],{},[66,6078,1610],{},[66,6080,1614],{},[66,6082,1618],{},[23,6084,1649],{"id":1648},[11,6086,784,6087,1655,6089,1659],{},[31,6088,1654],{},[177,6090,1658],{},[11,6092,784,6093,1665],{},[31,6094,1664],{},[23,6096,1669],{"id":1668},[11,6098,784,6099,1675],{},[31,6100,1674],{},[36,6102,6103,6111],{},[39,6104,6105],{},[42,6106,6107,6109],{},[45,6108,1684],{},[45,6110,1687],{},[58,6112,6113,6121,6131,6141],{},[42,6114,6115,6119],{},[63,6116,6117],{},[66,6118,1696],{},[63,6120,1699],{},[42,6122,6123,6127],{},[63,6124,6125],{},[66,6126,1706],{},[63,6128,1709,6129,1712],{},[66,6130,1544],{},[42,6132,6133,6137],{},[63,6134,6135],{},[66,6136,1719],{},[63,6138,1722,6139,1712],{},[66,6140,1544],{},[42,6142,6143,6147],{},[63,6144,6145],{},[66,6146,1731],{},[63,6148,1734,6149,1737],{},[66,6150,1544],{},[507,6152,6153],{"className":1740,"code":1741,"language":1742,"meta":512,"style":512},[66,6154,6155,6173,6179],{"__ignoreMap":512},[516,6156,6157,6159,6161,6163,6165,6167,6169,6171],{"class":518,"line":519},[516,6158,1750],{"class":1749},[516,6160,1753],{"class":1233},[516,6162,405],{"class":1227},[516,6164,1578],{"class":1233},[516,6166,154],{"class":1227},[516,6168,1409],{"class":1233},[516,6170,405],{"class":1227},[516,6172,1766],{"class":1233},[516,6174,6175,6177],{"class":518,"line":525},[516,6176,1771],{"class":1749},[516,6178,1774],{"class":1227},[516,6180,6181,6183,6185,6187,6189,6191,6193,6195,6197,6199,6201],{"class":518,"line":531},[516,6182,1706],{"class":1749},[516,6184,1781],{"class":1227},[516,6186,1784],{"class":1749},[516,6188,1753],{"class":1233},[516,6190,405],{"class":1227},[516,6192,1562],{"class":1233},[516,6194,1793],{"class":1749},[516,6196,1796],{"class":1233},[516,6198,405],{"class":1227},[516,6200,1578],{"class":1233},[516,6202,1803],{"class":1227},[11,6204,1806,6205,1809,6207,1813,6209,1816,6211,1819,6213,1822,6215,405],{},[66,6206,1706],{},[66,6208,1812],{},[66,6210,1544],{},[66,6212,1696],{},[66,6214,1719],{},[66,6216,1706],{},[23,6218,1828],{"id":1827},[11,6220,784,6221,1834],{},[31,6222,1833],{},[11,6224,6225,1840],{},[31,6226,1839],{},[717,6228,6229,6233,6237,6241],{},[720,6230,6231,1848],{},[31,6232,1847],{},[720,6234,6235,1854],{},[31,6236,1853],{},[720,6238,6239,1860],{},[31,6240,1859],{},[720,6242,6243,1866],{},[31,6244,1865],{},[507,6246,6247],{"className":1740,"code":1869,"language":1742,"meta":512,"style":512},[66,6248,6249,6255,6283,6311],{"__ignoreMap":512},[516,6250,6251,6253],{"class":518,"line":519},[516,6252,1876],{"class":1749},[516,6254,1803],{"class":1227},[516,6256,6257,6259,6261,6263,6265,6267,6269,6271,6273,6275,6277,6279,6281],{"class":518,"line":525},[516,6258,1632],{"class":1749},[516,6260,1885],{"class":1227},[516,6262,1888],{"class":1749},[516,6264,1891],{"class":1227},[516,6266,1894],{"class":1749},[516,6268,1891],{"class":1227},[516,6270,1899],{"class":1749},[516,6272,1902],{"class":1233},[516,6274,1905],{"class":1749},[516,6276,1908],{"class":1227},[516,6278,1894],{"class":1749},[516,6280,1913],{"class":1233},[516,6282,1803],{"class":1227},[516,6284,6285,6287,6289,6291,6293,6295,6297,6299,6301,6303,6305,6307,6309],{"class":518,"line":531},[516,6286,1632],{"class":1749},[516,6288,1885],{"class":1227},[516,6290,1888],{"class":1749},[516,6292,1891],{"class":1227},[516,6294,1894],{"class":1749},[516,6296,1891],{"class":1227},[516,6298,1932],{"class":1749},[516,6300,1902],{"class":1233},[516,6302,1905],{"class":1749},[516,6304,1908],{"class":1227},[516,6306,1894],{"class":1749},[516,6308,1943],{"class":1233},[516,6310,1803],{"class":1227},[516,6312,6313,6315],{"class":518,"line":1127},[516,6314,1950],{"class":1749},[516,6316,1803],{"class":1227},[11,6318,1955,6319,1958],{},[66,6320,1632],{},[23,6322,1962],{"id":1961},[11,6324,6325,1968],{},[31,6326,1967],{},[36,6328,6329,6339],{},[39,6330,6331],{},[42,6332,6333,6335,6337],{},[45,6334,1977],{},[45,6336,1980],{},[45,6338,1983],{},[58,6340,6341,6349,6357,6365],{},[42,6342,6343,6345,6347],{},[63,6344,1990],{},[63,6346,1993],{},[63,6348,1996],{},[42,6350,6351,6353,6355],{},[63,6352,2001],{},[63,6354,2004],{},[63,6356,2007],{},[42,6358,6359,6361,6363],{},[63,6360,2012],{},[63,6362,2015],{},[63,6364,2018],{},[42,6366,6367,6369,6371],{},[63,6368,2023],{},[63,6370,2026],{},[63,6372,2029],{},[11,6374,2032],{},[717,6376,6377,6381,6385],{},[720,6378,784,6379,2040],{},[31,6380,2039],{},[720,6382,784,6383,2046],{},[31,6384,2045],{},[720,6386,784,6387,2052,6389,2056],{},[31,6388,2051],{},[177,6390,2055],{},[11,6392,6393,2061,6395,2064],{},[66,6394,2001],{},[66,6396,2023],{},[23,6398,2068],{"id":2067},[11,6400,784,6401,2074],{},[31,6402,2073],{},[11,6404,2077],{},[23,6406,2081],{"id":2080},[11,6408,771,6409,2087,6411,2091,6413,2095],{},[31,6410,2086],{},[177,6412,2090],{},[66,6414,2094],{},[507,6416,6418],{"className":6417,"code":2099,"language":1171,"meta":512},[1169],[66,6419,2099],{"__ignoreMap":512},[11,6421,2104,6422,2107,6424,2111],{},[66,6423,1614],{},[66,6425,2110],{},[23,6427,2115],{"id":2114},[11,6429,2118,6430,2122],{},[31,6431,2121],{},[11,6433,2125],{},[23,6435,2129],{"id":2128},[11,6437,6438,2135,6440,2139,6442,2143],{},[31,6439,2134],{},[31,6441,2138],{},[31,6443,2142],{},[11,6445,2146,6446,2150],{},[31,6447,2149],{},[11,6449,2146,6450,2156],{},[31,6451,2155],{},[11,6453,6454],{},[2160,6455],{"alt":2162,"src":2163},[23,6457,2167],{"id":2166},[11,6459,6460,2173,6462,2177,6464,2181,6466,2185],{},[31,6461,2172],{},[31,6463,2176],{},[177,6465,2180],{},[66,6467,2184],{},[11,6469,2188,6470,2192],{},[177,6471,2191],{},[11,6473,2195,6474,2199],{},[31,6475,2198],{},[18,6477,2203],{"id":2202},[23,6479,2207],{"id":2206},[11,6481,6482,2213,6484,2217],{},[31,6483,2212],{},[31,6485,2216],{},[36,6487,6488,6498],{},[39,6489,6490],{},[42,6491,6492,6494,6496],{},[45,6493,2226],{},[45,6495,2212],{},[45,6497,2216],{},[58,6499,6500,6508,6516,6524],{},[42,6501,6502,6504,6506],{},[63,6503,2237],{},[63,6505,2240],{},[63,6507,2243],{},[42,6509,6510,6512,6514],{},[63,6511,2248],{},[63,6513,2251],{},[63,6515,2254],{},[42,6517,6518,6520,6522],{},[63,6519,2259],{},[63,6521,2262],{},[63,6523,2265],{},[42,6525,6526,6528,6530],{},[63,6527,1853],{},[63,6529,2272],{},[63,6531,2275],{},[11,6533,2278],{},[23,6535,2282],{"id":2281},[11,6537,2285],{},[36,6539,6540,6552],{},[39,6541,6542],{},[42,6543,6544,6546,6548,6550],{},[45,6545,2294],{},[45,6547,2297],{},[45,6549,963],{},[45,6551,2302],{},[58,6553,6554,6564,6574,6584],{},[42,6555,6556,6558,6560,6562],{},[63,6557,2309],{},[63,6559,2312],{},[63,6561,2315],{},[63,6563,2318],{},[42,6565,6566,6568,6570,6572],{},[63,6567,2323],{},[63,6569,2326],{},[63,6571,2329],{},[63,6573,2332],{},[42,6575,6576,6578,6580,6582],{},[63,6577,2337],{},[63,6579,2340],{},[63,6581,2343],{},[63,6583,2346],{},[42,6585,6586,6588,6590,6592],{},[63,6587,2351],{},[63,6589,2354],{},[63,6591,2357],{},[63,6593,2360],{},[11,6595,2363],{},[23,6597,2367],{"id":2366},[11,6599,2370,6600,2374],{},[31,6601,2373],{},[11,6603,2377,6604,2381],{},[66,6605,2380],{},[507,6607,6608],{"className":1218,"code":2384,"language":1220,"meta":512,"style":512},[66,6609,6610,6614,6624,6630,6650,6670,6674],{"__ignoreMap":512},[516,6611,6612],{"class":518,"line":519},[516,6613,1228],{"class":1227},[516,6615,6616,6618,6620,6622],{"class":518,"line":525},[516,6617,2395],{"class":1233},[516,6619,1245],{"class":1227},[516,6621,2400],{"class":1248},[516,6623,1252],{"class":1227},[516,6625,6626,6628],{"class":518,"line":531},[516,6627,2407],{"class":1233},[516,6629,1272],{"class":1227},[516,6631,6632,6634,6636,6638,6640,6642,6644,6646,6648],{"class":518,"line":1127},[516,6633,2414],{"class":1227},[516,6635,2417],{"class":1233},[516,6637,1245],{"class":1227},[516,6639,2422],{"class":1248},[516,6641,154],{"class":1227},[516,6643,2427],{"class":1233},[516,6645,1245],{"class":1227},[516,6647,2432],{"class":1248},[516,6649,2435],{"class":1227},[516,6651,6652,6654,6656,6658,6660,6662,6664,6666,6668],{"class":518,"line":1134},[516,6653,2414],{"class":1227},[516,6655,2417],{"class":1233},[516,6657,1245],{"class":1227},[516,6659,2446],{"class":1248},[516,6661,154],{"class":1227},[516,6663,2427],{"class":1233},[516,6665,1245],{"class":1227},[516,6667,2455],{"class":1248},[516,6669,1299],{"class":1227},[516,6671,6672],{"class":518,"line":1275},[516,6673,1305],{"class":1227},[516,6675,6676],{"class":518,"line":1302},[516,6677,1317],{"class":1227},[11,6679,2468],{},[23,6681,2472],{"id":2471},[11,6683,6684,2478,6686,2482],{},[31,6685,2477],{},[177,6687,2481],{},[11,6689,2485],{},[23,6691,2489],{"id":2488},[11,6693,771,6694,2495],{},[31,6695,2494],{},[717,6697,6698,6702,6706],{},[720,6699,6700,2502],{},[31,6701,1853],{},[720,6703,6704,2508],{},[31,6705,2507],{},[720,6707,6708,2514],{},[31,6709,2513],{},[11,6711,2517,6712,2521],{},[177,6713,2520],{},[11,6715,2524,6716,2528],{},[177,6717,2527],{},[23,6719,2532],{"id":2531},[11,6721,784,6722,2538,6724,2541,6726,2545],{},[31,6723,2537],{},[66,6725,1562],{},[66,6727,2544],{},[11,6729,2548],{},[23,6731,2552],{"id":2551},[11,6733,2555,6734,2559,6736,2563],{},[66,6735,2558],{},[66,6737,2562],{},[11,6739,2566,6740,2570],{},[66,6741,2569],{},[23,6743,2574],{"id":2573},[11,6745,2577,6746,2581],{},[177,6747,2580],{},[11,6749,2584,6750,2588],{},[177,6751,2587],{},[18,6753,2592],{"id":2591},[23,6755,2596],{"id":2595},[11,6757,6758,2602,6760,2605],{},[31,6759,2601],{},[31,6761,453],{},[11,6763,2608,6764,2612],{},[177,6765,2611],{},[23,6767,2616],{"id":2615},[11,6769,2146,6770,2622,6772,2626,6774,2630],{},[31,6771,2621],{},[31,6773,2625],{},[66,6775,2629],{},[36,6777,6778,6788],{},[39,6779,6780],{},[42,6781,6782,6784,6786],{},[45,6783,2226],{},[45,6785,2641],{},[45,6787,2644],{},[58,6789,6790,6798,6806,6814],{},[42,6791,6792,6794,6796],{},[63,6793,2651],{},[63,6795,2654],{},[63,6797,2657],{},[42,6799,6800,6802,6804],{},[63,6801,2259],{},[63,6803,2664],{},[63,6805,2667],{},[42,6807,6808,6810,6812],{},[63,6809,2672],{},[63,6811,2675],{},[63,6813,2678],{},[42,6815,6816,6818,6820],{},[63,6817,2683],{},[63,6819,2686],{},[63,6821,2689,6822,2692],{},[66,6823,453],{},[11,6825,2695],{},[23,6827,2699],{"id":2698},[11,6829,784,6830,2704,6832,405],{},[31,6831,2629],{},[66,6833,2707],{},[507,6835,6837],{"className":6836,"code":2711,"language":1171,"meta":512},[1169],[66,6838,2711],{"__ignoreMap":512},[717,6840,6841,6847,6853],{},[720,6842,6843,2721,6845,2725],{},[31,6844,2720],{},[66,6846,2724],{},[720,6848,6849,2731,6851,2735],{},[31,6850,2730],{},[66,6852,2734],{},[720,6854,6855,2741],{},[31,6856,2740],{},[11,6858,2744,6859,405],{},[761,6860,2748],{"href":2747},[23,6862,2752,6863,2756,6865,2760],{"id":2751},[66,6864,2755],{},[66,6866,2759],{},[11,6868,2763,6869,2766,6871,2770,6873,2774,6875,2777],{},[66,6870,2755],{},[177,6872,2769],{},[31,6874,2773],{},[66,6876,2755],{},[11,6878,2780,6879,2783,6881,2787,6883,2791,6885,2794],{},[66,6880,2759],{},[66,6882,2786],{},[31,6884,2790],{},[66,6886,705],{},[36,6888,6889,6899],{},[39,6890,6891],{},[42,6892,6893,6895,6897],{},[45,6894,2803],{},[45,6896,2806],{},[45,6898,2809],{},[58,6900,6901,6911],{},[42,6902,6903,6907,6909],{},[63,6904,6905],{},[66,6906,2755],{},[63,6908,2820],{},[63,6910,2823],{},[42,6912,6913,6917,6919],{},[63,6914,6915,2830],{},[66,6916,2759],{},[63,6918,2833],{},[63,6920,2836],{},[11,6922,2839,6923,2842,6925,2846,6927,2849],{},[66,6924,2759],{},[66,6926,2845],{},[66,6928,740],{},[23,6930,2853],{"id":2852},[11,6932,6933,2859],{},[31,6934,2858],{},[11,6936,2862,6937,2866],{},[177,6938,2865],{},[2868,6940,6941,6943,6945,6949,6953],{},[720,6942,2872],{},[720,6944,2875],{},[720,6946,2878,6947,405],{},[31,6948,2865],{},[720,6950,2883,6951,2887],{},[31,6952,2886],{},[720,6954,2890],{},[11,6956,6957],{},[2160,6958],{"alt":2895,"src":2896},[11,6960,2899],{},[23,6962,2903],{"id":2902},[11,6964,2906,6965,2910,6967,2914],{},[177,6966,2909],{},[177,6968,2913],{},[11,6970,6971,2920,6973,2924],{},[31,6972,2919],{},[31,6974,2923],{},[23,6976,2928],{"id":2927},[11,6978,2931,6979,756,6981,2938,6983,154,6985,741,6987,2948,6989,2952],{},[66,6980,2934],{},[66,6982,2937],{},[66,6984,2941],{},[66,6986,2944],{},[66,6988,2947],{},[31,6990,2951],{},[11,6992,2955,6993,2958,6995,2961,6997,2965,6999,2969],{},[66,6994,2934],{},[66,6996,2937],{},[177,6998,2964],{},[31,7000,2968],{},[507,7002,7004],{"className":7003,"code":2973,"language":1171,"meta":512},[1169],[66,7005,2973],{"__ignoreMap":512},[11,7007,2978],{},[23,7009,2982],{"id":2981},[11,7011,784,7012,2987],{},[31,7013,2951],{},[11,7015,2990,7016,2993],{},[177,7017,493],{},[23,7019,2997],{"id":2996},[11,7021,7022,3002],{},[31,7023,2790],{},[11,7025,3005,7026,3009,7028,3012,7030,756,7032,3017,7034,2958,7036,3024,7038,3027],{},[31,7027,3008],{},[66,7029,705],{},[66,7031,737],{},[66,7033,740],{},[66,7035,3020],{},[66,7037,3023],{},[66,7039,705],{},[23,7041,3031],{"id":3030},[11,7043,7044,3036],{},[31,7045,2773],{},[11,7047,3039,7048,154,7050,154,7052,3049,7054,3053,7056,3056],{},[66,7049,3042],{},[66,7051,3045],{},[66,7053,3048],{},[66,7055,3052],{},[66,7057,2759],{},[23,7059,3060],{"id":3059},[11,7061,7062,3066],{},[31,7063,3065],{},[507,7065,7066],{"className":1740,"code":3069,"language":1742,"meta":512,"style":512},[66,7067,7068,7072,7098,7102,7106,7110,7130],{"__ignoreMap":512},[516,7069,7070],{"class":518,"line":519},[516,7071,3077],{"class":3076},[516,7073,7074,7076,7078,7080,7082,7084,7086,7088,7090,7092,7094,7096],{"class":518,"line":525},[516,7075,1750],{"class":1749},[516,7077,3084],{"class":1749},[516,7079,3087],{"class":1749},[516,7081,3090],{"class":1227},[516,7083,1610],{"class":1749},[516,7085,3095],{"class":1227},[516,7087,1894],{"class":1749},[516,7089,3100],{"class":1248},[516,7091,3103],{"class":1749},[516,7093,3106],{"class":1749},[516,7095,1793],{"class":1749},[516,7097,3111],{"class":1248},[516,7099,7100],{"class":518,"line":531},[516,7101,1131],{"emptyLinePlaceholder":1130},[516,7103,7104],{"class":518,"line":1127},[516,7105,3120],{"class":3076},[516,7107,7108],{"class":518,"line":1134},[516,7109,3125],{"class":3076},[516,7111,7112,7114,7116,7118,7120,7122,7124,7126,7128],{"class":518,"line":1275},[516,7113,1750],{"class":1749},[516,7115,3084],{"class":1749},[516,7117,3087],{"class":1749},[516,7119,3090],{"class":1227},[516,7121,1610],{"class":1749},[516,7123,3095],{"class":1227},[516,7125,1894],{"class":1749},[516,7127,3144],{"class":1248},[516,7129,3147],{"class":3076},[516,7131,7132],{"class":518,"line":1302},[516,7133,3152],{"class":3076},[11,7135,7136,3158],{},[31,7137,3157],{},[507,7139,7140],{"className":1740,"code":3161,"language":1742,"meta":512,"style":512},[66,7141,7142,7146,7172],{"__ignoreMap":512},[516,7143,7144],{"class":518,"line":519},[516,7145,3168],{"class":3076},[516,7147,7148,7150,7152,7154,7156,7158,7160,7162,7164,7166,7168,7170],{"class":518,"line":525},[516,7149,1750],{"class":1749},[516,7151,3084],{"class":1749},[516,7153,3087],{"class":1749},[516,7155,3090],{"class":1227},[516,7157,1610],{"class":1749},[516,7159,3095],{"class":1227},[516,7161,1894],{"class":1749},[516,7163,3187],{"class":1227},[516,7165,3190],{"class":1749},[516,7167,3106],{"class":1749},[516,7169,1793],{"class":1749},[516,7171,3197],{"class":1227},[516,7173,7174],{"class":518,"line":531},[516,7175,3202],{"class":3076},[11,7177,3205],{},[23,7179,3209],{"id":3208},[11,7181,7182,3214],{},[31,7183,1073],{},[11,7185,3217],{},[23,7187,3221],{"id":3220},[11,7189,771,7190,3227],{},[31,7191,3226],{},[11,7193,3230],{},[23,7195,3234],{"id":3233},[11,7197,7198,3240,7200,3244],{},[31,7199,3239],{},[66,7201,3243],{},[11,7203,3247,7204,3251],{},[31,7205,3250],{},[23,7207,3255],{"id":3254},[11,7209,784,7210,3261,7212,3264],{},[31,7211,3260],{},[31,7213,2886],{},[11,7215,3267,7216,3270],{},[66,7217,2759],{},[18,7219,3274],{"id":3273},[23,7221,3278],{"id":3277},[11,7223,7224,3283],{},[31,7225,3274],{},[11,7227,3286,7228,3290],{},[177,7229,3289],{},[23,7231,3294],{"id":3293},[11,7233,3297],{},[36,7235,7236,7248],{},[39,7237,7238],{},[42,7239,7240,7242,7244,7246],{},[45,7241,3306],{},[45,7243,3309],{},[45,7245,3312],{},[45,7247,963],{},[58,7249,7250,7262,7272],{},[42,7251,7252,7254,7256,7258],{},[63,7253,3321],{},[63,7255,3324],{},[63,7257,3327],{},[63,7259,3330,7260],{},[66,7261,2755],{},[42,7263,7264,7266,7268,7270],{},[63,7265,3337],{},[63,7267,3340],{},[63,7269,3343],{},[63,7271,3346],{},[42,7273,7274,7276,7278,7280],{},[63,7275,3351],{},[63,7277,3354],{},[63,7279,3357],{},[63,7281,3360],{},[11,7283,3363,7284,3366],{},[31,7285,3337],{},[23,7287,3370],{"id":3369},[11,7289,7290,3376,7292,3380,7294,3384],{},[31,7291,3375],{},[31,7293,3379],{},[31,7295,3383],{},[507,7297,7299],{"className":7298,"code":3388,"language":1171,"meta":512},[1169],[66,7300,3388],{"__ignoreMap":512},[11,7302,7303],{},[2160,7304],{"alt":3395,"src":3396},[11,7306,3399],{},[23,7308,3403],{"id":3402},[11,7310,3406,7311,3410],{},[177,7312,3409],{},[36,7314,7315,7327],{},[39,7316,7317],{},[42,7318,7319,7321,7323,7325],{},[45,7320,960],{},[45,7322,3421],{},[45,7324,1853],{},[45,7326,3426],{},[58,7328,7329,7339,7349],{},[42,7330,7331,7333,7335,7337],{},[63,7332,3375],{},[63,7334,3435],{},[63,7336,3438],{},[63,7338,3441],{},[42,7340,7341,7343,7345,7347],{},[63,7342,3446],{},[63,7344,3449],{},[63,7346,3452],{},[63,7348,3455],{},[42,7350,7351,7353,7355,7357],{},[63,7352,3460],{},[63,7354,3463],{},[63,7356,3466],{},[63,7358,3469],{},[11,7360,7361,3474,7363,3477,7365,3480],{},[31,7362,3375],{},[31,7364,3446],{},[31,7366,3460],{},[23,7368,3484],{"id":3483},[11,7370,7371,3490,7373,3494,7375,3498,7377,3502],{},[31,7372,3489],{},[177,7374,3493],{},[177,7376,3497],{},[177,7378,3501],{},[11,7380,3505],{},[23,7382,3509],{"id":3508},[11,7384,784,7385,3515],{},[31,7386,3514],{},[11,7388,3518],{},[23,7390,3522],{"id":3521},[11,7392,784,7393,3528],{},[31,7394,3527],{},[11,7396,3531],{},[23,7398,3535],{"id":3534},[11,7400,3538,7401,202,7403,3545],{},[31,7402,3541],{},[31,7404,3544],{},[36,7406,7407,7417],{},[39,7408,7409],{},[42,7410,7411,7413,7415],{},[45,7412,2226],{},[45,7414,3541],{},[45,7416,3544],{},[58,7418,7419,7427,7439,7447],{},[42,7420,7421,7423,7425],{},[63,7422,3564],{},[63,7424,3567],{},[63,7426,3570],{},[42,7428,7429,7431,7437],{},[63,7430,3575],{},[63,7432,3578,7433,2958,7435,3583],{},[66,7434,2558],{},[66,7436,2562],{},[63,7438,3586],{},[42,7440,7441,7443,7445],{},[63,7442,3591],{},[63,7444,3594],{},[63,7446,3597],{},[42,7448,7449,7451,7453],{},[63,7450,3602],{},[63,7452,3605],{},[63,7454,3608],{},[11,7456,3611,7457,3615],{},[177,7458,3614],{},[18,7460,3619],{"id":3618},[23,7462,3623],{"id":3622},[11,7464,784,7465,3629,7467,3633],{},[31,7466,3628],{},[31,7468,3632],{},[11,7470,3636],{},[23,7472,3640],{"id":3639},[11,7474,7475,3646,7477,3650],{},[31,7476,3645],{},[31,7478,3649],{},[11,7480,3653],{},[23,7482,3657],{"id":3656},[11,7484,784,7485,3663],{},[31,7486,3662],{},[507,7488,7490],{"className":7489,"code":3667,"language":1171,"meta":512},[1169],[66,7491,3667],{"__ignoreMap":512},[11,7493,3672,7494,3676],{},[66,7495,3675],{},[23,7497,3680],{"id":3679},[11,7499,784,7500,3685],{},[31,7501,2073],{},[11,7503,3688],{},[2868,7505,7506,7510,7514,7518],{},[720,7507,7508,3696],{},[31,7509,3695],{},[720,7511,7512,3702],{},[31,7513,3701],{},[720,7515,7516,3708],{},[31,7517,3707],{},[720,7519,7520,3714],{},[31,7521,3713],{},[11,7523,3717],{},[23,7525,3721],{"id":3720},[11,7527,3724,7528,3728,7530,3732],{},[31,7529,3727],{},[31,7531,3731],{},[11,7533,3735],{},[23,7535,3739],{"id":3738},[11,7537,1094,7538,3745],{},[31,7539,3744],{},[11,7541,3748],{},[507,7543,7545],{"className":7544,"code":3752,"language":1171,"meta":512},[1169],[66,7546,3752],{"__ignoreMap":512},[11,7548,3757],{},[23,7550,3761],{"id":3760},[11,7552,7553,3767,7555,3771],{},[31,7554,3766],{},[31,7556,3770],{},[11,7558,3774],{},[23,7560,3778],{"id":3777},[11,7562,784,7563,3784,7565,3788],{},[31,7564,3783],{},[177,7566,3787],{},[11,7568,3791],{},[23,7570,3795],{"id":3794},[11,7572,7573,3801],{},[31,7574,3800],{},[11,7576,3804],{},[23,7578,3808],{"id":3807},[11,7580,7581,3814],{},[31,7582,3813],{},[11,7584,3817],{},[18,7586,3821],{"id":3820},[23,7588,3825],{"id":3824},[11,7590,7591,3831,7593,3835],{},[31,7592,3830],{},[31,7594,3834],{},[36,7596,7597,7607],{},[39,7598,7599],{},[42,7600,7601,7603,7605],{},[45,7602,2226],{},[45,7604,3830],{},[45,7606,3834],{},[58,7608,7609,7617,7625,7633],{},[42,7610,7611,7613,7615],{},[63,7612,3854],{},[63,7614,3857],{},[63,7616,3860],{},[42,7618,7619,7621,7623],{},[63,7620,3865],{},[63,7622,3868],{},[63,7624,3871],{},[42,7626,7627,7629,7631],{},[63,7628,3876],{},[63,7630,3879],{},[63,7632,3882],{},[42,7634,7635,7637,7639],{},[63,7636,3887],{},[63,7638,3890],{},[63,7640,3893],{},[11,7642,3896],{},[23,7644,3900],{"id":3899},[11,7646,784,7647,3906],{},[31,7648,3905],{},[11,7650,3909],{},[36,7652,7653,7661],{},[39,7654,7655],{},[42,7656,7657,7659],{},[45,7658,3918],{},[45,7660,3921],{},[58,7662,7663,7669,7675,7681],{},[42,7664,7665,7667],{},[63,7666,3928],{},[63,7668,3931],{},[42,7670,7671,7673],{},[63,7672,3936],{},[63,7674,3939],{},[42,7676,7677,7679],{},[63,7678,3944],{},[63,7680,3947],{},[42,7682,7683,7685],{},[63,7684,3952],{},[63,7686,3955],{},[11,7688,3958],{},[11,7690,7691],{},[2160,7692],{"alt":3963,"src":3964},[23,7694,3968],{"id":3967},[11,7696,784,7697,3974,7699,3977],{},[31,7698,3973],{},[31,7700,3905],{},[11,7702,3980],{},[23,7704,3984],{"id":3983},[11,7706,1094,7707,3990],{},[31,7708,3989],{},[11,7710,3993],{},[23,7712,3997],{"id":3996},[11,7714,784,7715,4003,7717,4007],{},[31,7716,4002],{},[31,7718,4006],{},[36,7720,7721,7731],{},[39,7722,7723],{},[42,7724,7725,7727,7729],{},[45,7726,2226],{},[45,7728,4018],{},[45,7730,4006],{},[58,7732,7733,7741,7749,7757,7765],{},[42,7734,7735,7737,7739],{},[63,7736,4027],{},[63,7738,4030],{},[63,7740,4033],{},[42,7742,7743,7745,7747],{},[63,7744,2259],{},[63,7746,4040],{},[63,7748,4043],{},[42,7750,7751,7753,7755],{},[63,7752,4048],{},[63,7754,4051],{},[63,7756,4054],{},[42,7758,7759,7761,7763],{},[63,7760,4059],{},[63,7762,4062],{},[63,7764,4065],{},[42,7766,7767,7769,7771],{},[63,7768,4070],{},[63,7770,4073],{},[63,7772,4076],{},[11,7774,4079],{},[23,7776,4083],{"id":4082},[11,7778,7779,4089],{},[31,7780,4088],{},[11,7782,4092,7783,4096,7785,4100,7787,4105],{},[31,7784,4095],{},[31,7786,4099],{},[761,7788,4104],{"href":4103},[23,7790,4109],{"id":4108},[11,7792,784,7793,4115],{},[31,7794,4114],{},[11,7796,4118],{},[23,7798,4122],{"id":4121},[11,7800,7801,4128,7803,4132,7805,4136],{},[31,7802,4127],{},[31,7804,4131],{},[31,7806,4135],{},[11,7808,4139,7809,4143],{},[66,7810,4142],{},[23,7812,4147],{"id":4146},[11,7814,3724,7815,4153,7817,4157],{},[31,7816,4152],{},[31,7818,4156],{},[11,7820,4160],{},[11,7822,4163],{},[23,7824,4167],{"id":4166},[11,7826,771,7827,4173],{},[31,7828,4172],{},[11,7830,4176,7831,4180,7833,4184,7835,4188],{},[31,7832,4179],{},[31,7834,4183],{},[31,7836,4187],{},[11,7838,4191],{},[23,7840,4195],{"id":4194},[11,7842,4198,7843,4202],{},[31,7844,4201],{},[11,7846,4205],{},[11,7848,4208,7849,4211],{},[31,7850,1097],{},[507,7852,7853],{"className":1218,"code":4214,"language":1220,"meta":512,"style":512},[66,7854,7855,7859,7869,7879,7887],{"__ignoreMap":512},[516,7856,7857],{"class":518,"line":519},[516,7858,1228],{"class":1227},[516,7860,7861,7863,7865,7867],{"class":518,"line":525},[516,7862,4225],{"class":1233},[516,7864,1245],{"class":1227},[516,7866,4230],{"class":1248},[516,7868,1252],{"class":1227},[516,7870,7871,7873,7875,7877],{"class":518,"line":531},[516,7872,4237],{"class":1233},[516,7874,1245],{"class":1227},[516,7876,4242],{"class":1233},[516,7878,1252],{"class":1227},[516,7880,7881,7883,7885],{"class":518,"line":1127},[516,7882,4249],{"class":1233},[516,7884,1245],{"class":1227},[516,7886,4254],{"class":1248},[516,7888,7889],{"class":518,"line":1134},[516,7890,1317],{"class":1227},[11,7892,4261],{},[23,7894,4265],{"id":4264},[11,7896,7897,4271,7899,4275],{},[31,7898,4270],{},[31,7900,4274],{},[11,7902,4278],{},[18,7904,4282],{"id":4281},[23,7906,4286],{"id":4285},[11,7908,784,7909,4292],{},[31,7910,4291],{},[11,7912,4295,7913,4299],{},[31,7914,4298],{},[11,7916,7917],{},[2160,7918],{"alt":4304,"src":4305},[23,7920,4309],{"id":4308},[11,7922,4312,7923,4315,7925,4319,7927,4323],{},[31,7924,4291],{},[31,7926,4318],{},[177,7928,4322],{},[11,7930,4326],{},[23,7932,4330],{"id":4329},[11,7934,2146,7935,4336,7937,4340],{},[31,7936,4335],{},[31,7938,4339],{},[11,7940,4343],{},[23,7942,4347],{"id":4346},[11,7944,4350],{},[36,7946,7947,7957],{},[39,7948,7949],{},[42,7950,7951,7953,7955],{},[45,7952,4359],{},[45,7954,307],{},[45,7956,4364],{},[58,7958,7959,7967,7975],{},[42,7960,7961,7963,7965],{},[63,7962,4371],{},[63,7964,4374],{},[63,7966,4377],{},[42,7968,7969,7971,7973],{},[63,7970,4382],{},[63,7972,4385],{},[63,7974,4388],{},[42,7976,7977,7979,7981],{},[63,7978,4393],{},[63,7980,4396],{},[63,7982,4399],{},[11,7984,4402],{},[23,7986,4406],{"id":4405},[11,7988,784,7989,4412],{},[31,7990,4411],{},[11,7992,4415],{},[23,7994,4419],{"id":4418},[11,7996,771,7997,4425],{},[31,7998,4424],{},[11,8000,4428,8001,4432],{},[31,8002,4431],{},[23,8004,4436],{"id":4435},[11,8006,8007,4442],{},[31,8008,4441],{},[11,8010,4445],{},[18,8012,4449],{"id":4448},[23,8014,4453],{"id":4452},[11,8016,4456,8017,4460],{},[177,8018,4459],{},[36,8020,8021,8033],{},[39,8022,8023],{},[42,8024,8025,8027,8029,8031],{},[45,8026,4469],{},[45,8028,4472],{},[45,8030,4475],{},[45,8032,963],{},[58,8034,8035,8047,8057],{},[42,8036,8037,8039,8041,8043],{},[63,8038,4484],{},[63,8040,4487],{},[63,8042,4490],{},[63,8044,4493,8045,4497],{},[66,8046,4496],{},[42,8048,8049,8051,8053,8055],{},[63,8050,4502],{},[63,8052,4505],{},[63,8054,4508],{},[63,8056,4511],{},[42,8058,8059,8061,8063,8065],{},[63,8060,4516],{},[63,8062,4519],{},[63,8064,4522],{},[63,8066,4525],{},[11,8068,4528],{},[23,8070,4532],{"id":4531},[11,8072,8073,4538],{},[31,8074,4537],{},[11,8076,4541],{},[23,8078,4545],{"id":4544},[11,8080,8081,4551,8083,202,8085,4558],{},[31,8082,4550],{},[31,8084,4554],{},[31,8086,4557],{},[11,8088,4561],{},[23,8090,4565],{"id":4564},[11,8092,784,8093,4571,8095,4575],{},[31,8094,4570],{},[31,8096,4574],{},[36,8098,8099,8109],{},[39,8100,8101],{},[42,8102,8103,8105,8107],{},[45,8104,2226],{},[45,8106,4586],{},[45,8108,4589],{},[58,8110,8111,8119,8127,8135,8143],{},[42,8112,8113,8115,8117],{},[63,8114,4596],{},[63,8116,4599],{},[63,8118,4602],{},[42,8120,8121,8123,8125],{},[63,8122,4607],{},[63,8124,4610],{},[63,8126,4613],{},[42,8128,8129,8131,8133],{},[63,8130,4618],{},[63,8132,4621],{},[63,8134,4624],{},[42,8136,8137,8139,8141],{},[63,8138,1859],{},[63,8140,4631],{},[63,8142,4634],{},[42,8144,8145,8147,8149],{},[63,8146,4639],{},[63,8148,4642],{},[63,8150,4645],{},[11,8152,4648],{},[23,8154,4652],{"id":4651},[11,8156,771,8157,4658,8159,4662],{},[31,8158,4657],{},[31,8160,4661],{},[11,8162,4665],{},[23,8164,4669],{"id":4668},[11,8166,4672,8167,4676],{},[31,8168,4675],{},[11,8170,8171,4682,8173,4686,8175,4690],{},[31,8172,4681],{},[31,8174,4685],{},[31,8176,4689],{},[11,8178,4693,8179,4697,8181,4701,8183,4704],{},[177,8180,4696],{},[177,8182,4700],{},[177,8184,2587],{},[23,8186,4708],{"id":4707},[11,8188,784,8189,4714,8191,756,8193,4721],{},[31,8190,4713],{},[66,8192,4717],{},[66,8194,4720],{},[507,8196,8197],{"className":4724,"code":4725,"language":4726,"meta":512,"style":512},[66,8198,8199,8207],{"__ignoreMap":512},[516,8200,8201,8203,8205],{"class":518,"line":519},[516,8202,544],{"class":4733},[516,8204,4736],{"class":1233},[516,8206,4739],{"class":1248},[516,8208,8209],{"class":518,"line":525},[516,8210,4744],{"class":3076},[11,8212,4747],{},[23,8214,4751],{"id":4750},[11,8216,784,8217,4757,8219,4761],{},[31,8218,4756],{},[31,8220,4760],{},[36,8222,8223,8233],{},[39,8224,8225],{},[42,8226,8227,8229,8231],{},[45,8228,2226],{},[45,8230,4772],{},[45,8232,4775],{},[58,8234,8235,8243,8251,8259],{},[42,8236,8237,8239,8241],{},[63,8238,4782],{},[63,8240,4785],{},[63,8242,4788],{},[42,8244,8245,8247,8249],{},[63,8246,4793],{},[63,8248,4796],{},[63,8250,4799],{},[42,8252,8253,8255,8257],{},[63,8254,4804],{},[63,8256,4807],{},[63,8258,4810],{},[42,8260,8261,8263,8265],{},[63,8262,4815],{},[63,8264,4818],{},[63,8266,4821],{},[11,8268,4824],{},[23,8270,4828],{"id":4827},[11,8272,8273,4834],{},[31,8274,4833],{},[507,8276,8278],{"className":8277,"code":4838,"language":1171,"meta":512},[1169],[66,8279,4838],{"__ignoreMap":512},[11,8281,4843],{},[23,8283,4847],{"id":4846},[11,8285,4850],{},[11,8287,8288,4856],{},[31,8289,4855],{},[18,8291,4860],{"id":4859},[11,8293,4863],{},[11,8295,4866],{},[4868,8297,4870],{},{"title":512,"searchDepth":525,"depth":525,"links":8299},[8300,8316,8330,8347,8357,8374,8384,8396,8410,8419,8431],{"id":20,"depth":525,"text":21,"children":8301},[8302,8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315],{"id":25,"depth":531,"text":26},{"id":169,"depth":531,"text":170},{"id":226,"depth":531,"text":227},{"id":277,"depth":531,"text":278},{"id":374,"depth":531,"text":375},{"id":408,"depth":531,"text":409},{"id":437,"depth":531,"text":438},{"id":483,"depth":531,"text":484},{"id":548,"depth":531,"text":549},{"id":561,"depth":531,"text":562},{"id":648,"depth":531,"text":4886},{"id":695,"depth":531,"text":4888},{"id":767,"depth":531,"text":768},{"id":780,"depth":531,"text":781},{"id":798,"depth":525,"text":799,"children":8317},[8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329],{"id":802,"depth":531,"text":803},{"id":865,"depth":531,"text":866},{"id":944,"depth":531,"text":945},{"id":1033,"depth":531,"text":1034},{"id":1067,"depth":531,"text":1068},{"id":1090,"depth":531,"text":1091},{"id":1140,"depth":531,"text":1141},{"id":1188,"depth":531,"text":1189},{"id":1208,"depth":531,"text":1209},{"id":1323,"depth":531,"text":1324},{"id":1340,"depth":531,"text":1341},{"id":1361,"depth":531,"text":1362},{"id":1384,"depth":525,"text":1385,"children":8331},[8332,8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346],{"id":1396,"depth":531,"text":1397},{"id":1421,"depth":531,"text":1422},{"id":1514,"depth":531,"text":1515},{"id":1534,"depth":531,"text":1535},{"id":1582,"depth":531,"text":1583},{"id":1622,"depth":531,"text":1623},{"id":1648,"depth":531,"text":1649},{"id":1668,"depth":531,"text":1669},{"id":1827,"depth":531,"text":1828},{"id":1961,"depth":531,"text":1962},{"id":2067,"depth":531,"text":2068},{"id":2080,"depth":531,"text":2081},{"id":2114,"depth":531,"text":2115},{"id":2128,"depth":531,"text":2129},{"id":2166,"depth":531,"text":2167},{"id":2202,"depth":525,"text":2203,"children":8348},[8349,8350,8351,8352,8353,8354,8355,8356],{"id":2206,"depth":531,"text":2207},{"id":2281,"depth":531,"text":2282},{"id":2366,"depth":531,"text":2367},{"id":2471,"depth":531,"text":2472},{"id":2488,"depth":531,"text":2489},{"id":2531,"depth":531,"text":2532},{"id":2551,"depth":531,"text":2552},{"id":2573,"depth":531,"text":2574},{"id":2591,"depth":525,"text":2592,"children":8358},[8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373],{"id":2595,"depth":531,"text":2596},{"id":2615,"depth":531,"text":2616},{"id":2698,"depth":531,"text":2699},{"id":2751,"depth":531,"text":4938},{"id":2852,"depth":531,"text":2853},{"id":2902,"depth":531,"text":2903},{"id":2927,"depth":531,"text":2928},{"id":2981,"depth":531,"text":2982},{"id":2996,"depth":531,"text":2997},{"id":3030,"depth":531,"text":3031},{"id":3059,"depth":531,"text":3060},{"id":3208,"depth":531,"text":3209},{"id":3220,"depth":531,"text":3221},{"id":3233,"depth":531,"text":3234},{"id":3254,"depth":531,"text":3255},{"id":3273,"depth":525,"text":3274,"children":8375},[8376,8377,8378,8379,8380,8381,8382,8383],{"id":3277,"depth":531,"text":3278},{"id":3293,"depth":531,"text":3294},{"id":3369,"depth":531,"text":3370},{"id":3402,"depth":531,"text":3403},{"id":3483,"depth":531,"text":3484},{"id":3508,"depth":531,"text":3509},{"id":3521,"depth":531,"text":3522},{"id":3534,"depth":531,"text":3535},{"id":3618,"depth":525,"text":3619,"children":8385},[8386,8387,8388,8389,8390,8391,8392,8393,8394,8395],{"id":3622,"depth":531,"text":3623},{"id":3639,"depth":531,"text":3640},{"id":3656,"depth":531,"text":3657},{"id":3679,"depth":531,"text":3680},{"id":3720,"depth":531,"text":3721},{"id":3738,"depth":531,"text":3739},{"id":3760,"depth":531,"text":3761},{"id":3777,"depth":531,"text":3778},{"id":3794,"depth":531,"text":3795},{"id":3807,"depth":531,"text":3808},{"id":3820,"depth":525,"text":3821,"children":8397},[8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409],{"id":3824,"depth":531,"text":3825},{"id":3899,"depth":531,"text":3900},{"id":3967,"depth":531,"text":3968},{"id":3983,"depth":531,"text":3984},{"id":3996,"depth":531,"text":3997},{"id":4082,"depth":531,"text":4083},{"id":4108,"depth":531,"text":4109},{"id":4121,"depth":531,"text":4122},{"id":4146,"depth":531,"text":4147},{"id":4166,"depth":531,"text":4167},{"id":4194,"depth":531,"text":4195},{"id":4264,"depth":531,"text":4265},{"id":4281,"depth":525,"text":4282,"children":8411},[8412,8413,8414,8415,8416,8417,8418],{"id":4285,"depth":531,"text":4286},{"id":4308,"depth":531,"text":4309},{"id":4329,"depth":531,"text":4330},{"id":4346,"depth":531,"text":4347},{"id":4405,"depth":531,"text":4406},{"id":4418,"depth":531,"text":4419},{"id":4435,"depth":531,"text":4436},{"id":4448,"depth":525,"text":4449,"children":8420},[8421,8422,8423,8424,8425,8426,8427,8428,8429,8430],{"id":4452,"depth":531,"text":4453},{"id":4531,"depth":531,"text":4532},{"id":4544,"depth":531,"text":4545},{"id":4564,"depth":531,"text":4565},{"id":4651,"depth":531,"text":4652},{"id":4668,"depth":531,"text":4669},{"id":4707,"depth":531,"text":4708},{"id":4750,"depth":531,"text":4751},{"id":4827,"depth":531,"text":4828},{"id":4846,"depth":531,"text":4847},{"id":4859,"depth":525,"text":4860},{},{"title":5,"description":5009},[5019,5020,5021,5022,5023,5024],{"id":8436,"title":8437,"author":6,"body":8438,"date":29854,"description":29855,"draft":5010,"extension":5011,"guide":5012,"image":29856,"meta":29857,"navigation":1130,"path":29858,"seo":29859,"stem":29860,"tags":29861,"__hash__":29864},"blog/Frontend/3.top-150-vuejs-interview-questions.md","Top 150 Vue.js Interview Questions and Answers",{"type":8,"value":8439,"toc":29595},[8440,8443,8455,8459,8463,8466,8469,8476,8480,8528,8535,8541,8544,8739,8764,8772,8780,8853,8867,8871,9001,9014,9021,9027,9061,9064,9110,9113,9117,9120,9129,9139,9146,9154,9346,9367,9371,9378,9395,9446,9454,9458,9464,9467,9470,9476,9480,9488,9491,9538,9555,9566,9574,9630,9696,9718,9729,9745,9809,9818,9827,9838,9843,9920,9928,9938,9953,10015,10029,10035,10088,10091,10099,10108,10211,10234,10241,10246,10343,10365,10387,10399,10477,10544,10551,10568,10577,10677,10702,10710,10716,10864,10879,10888,10891,10910,10984,10989,11111,11123,11189,11192,11200,11205,11243,11246,11253,11261,11298,11309,11317,11322,11405,11414,11423,11427,11431,11434,11440,11455,11546,11555,11563,11575,11644,11647,11722,11731,11744,11758,11773,11887,11903,11910,11935,11941,12041,12057,12067,12079,12101,12148,12163,12174,12180,12267,12279,12363,12374,12383,12392,12477,12501,12509,12514,12590,12593,12674,12681,12692,12704,12717,12838,12841,12848,12856,12945,12955,12968,12971,12983,13004,13096,13114,13196,13204,13207,13212,13345,13363,13367,13370,13382,13385,13389,13401,13422,13505,13514,13522,13535,13546,13687,13701,13705,13708,13725,13740,13758,13797,13810,13835,13857,13861,13865,13868,13871,13999,14005,14009,14012,14015,14050,14060,14064,14072,14075,14276,14291,14299,14307,14380,14395,14403,14406,14411,14416,14489,14497,14508,14525,14531,14597,14614,14623,14633,14668,14674,14685,14697,14700,14831,14841,14845,14849,14852,14861,15004,15010,15014,15017,15087,15090,15180,15190,15198,15226,15404,15420,15427,15430,15440,15561,15564,15593,15600,15604,15619,15750,15756,15763,15780,15874,15877,15986,16001,16008,16018,16062,16078,16209,16218,16228,16243,16315,16330,16333,16400,16411,16421,16441,16452,16470,16577,16588,16592,16601,16649,16655,16706,16712,16722,16730,16821,16939,16961,16965,16971,16981,17043,17110,17113,17117,17124,17221,17227,17236,17258,17308,17324,17328,17332,17335,17338,17400,17437,17459,17463,17477,17484,17587,17655,17658,17662,17665,17678,17778,17830,17839,17843,17849,17904,17944,17947,17951,17961,17996,18003,18020,18036,18039,18080,18083,18121,18143,18147,18150,18165,18175,18190,18356,18372,18376,18387,18394,18405,18477,18537,18540,18548,18562,18593,18637,18684,18698,18702,18715,18787,18881,18891,18895,18898,18904,18983,18991,18995,19007,19071,19203,19215,19223,19235,19241,19389,19411,19415,19419,19422,19428,19562,19594,19602,19614,19767,19776,19784,19793,19910,19923,19931,19939,20044,20060,20067,20083,20179,20203,20210,20234,20330,20333,20343,20348,20511,20535,20544,20565,20641,20660,20664,20668,20690,20693,20697,20706,20793,20802,20809,20819,20842,20941,20960,20971,20994,21010,21014,21021,21195,21255,21264,21275,21279,21345,21349,21353,21356,21363,21501,21567,21578,21582,21591,21611,21631,21634,21638,21655,21684,21690,21803,21823,21827,21897,21907,21911,21921,22005,22134,22147,22151,22157,22190,22214,22227,22281,22309,22312,22325,22328,22334,22337,22373,22438,22527,22530,22591,22595,22607,22663,22732,22738,22742,22749,22837,22840,22850,22857,22867,22886,22890,22900,23007,23024,23036,23044,23105,23118,23135,23139,23143,23151,23154,23158,23161,23167,23182,23316,23323,23327,23344,23347,23524,23527,23531,23541,23669,23682,23808,23811,23815,23818,23828,23835,23838,23842,23845,23848,23898,23912,23916,23919,23922,23932,23936,23948,24050,24062,24077,24081,24088,24174,24184,24188,24195,24284,24302,24306,24323,24378,24446,24453,24555,24558,24562,24570,24573,24577,24584,24589,24688,24719,24726,24735,24879,24888,25037,25043,25047,25066,25072,25213,25219,25223,25240,25363,25373,25383,25391,25430,25450,25457,25462,25662,25685,25689,25696,25701,25707,25790,25797,25804,25818,25824,25894,25917,25924,25932,25977,25980,26049,26059,26063,26089,26095,26098,26102,26105,26111,26174,26184,26188,26198,26212,26215,26219,26222,26269,26273,26276,26279,26289,26293,26299,26471,26484,26488,26491,26494,26497,26600,26607,26611,26618,26623,26636,26763,26773,26784,26789,26804,26902,27007,27026,27030,27036,27039,27099,27112,27120,27124,27127,27133,27136,27139,27143,27152,27164,27176,27185,27211,27221,27295,27309,27316,27327,27418,27425,27443,27447,27460,27642,27649,27731,27744,27748,27759,27762,27772,27928,27986,27989,27993,28006,28110,28118,28121,28125,28134,28154,28168,28238,28246,28250,28263,28270,28355,28518,28527,28531,28544,28628,28728,28746,28750,28764,28857,28871,28994,29007,29011,29018,29110,29113,29117,29121,29128,29131,29135,29145,29148,29152,29155,29161,29181,29259,29268,29275,29280,29368,29374,29384,29397,29411,29417,29568,29582,29584,29590,29592],[11,8441,8442],{},"Vue.js interviews rarely test whether you have memorized the documentation. They test whether you actually understand how the framework thinks: how reactivity tracks what changed, how components talk to each other, and why the Composition API exists in the first place. Get those mental models right, and most questions become easy to reason through even if you have never seen the exact wording before.",[11,8444,8445,8446,8449,8450,8454],{},"This article collects 150 of the most common Vue.js interview questions, from the basics of ",[66,8447,8448],{},"\u003Cscript setup>"," all the way to compiler internals, Vue Router, Pinia, and server-side rendering with Nuxt. It is deliberately framework-specific: you will not find generic JavaScript questions about closures or promises here. If you want that side of the interview covered, the ",[761,8451,8453],{"href":8452},"/post/top-100-frontend-interview-questions","Top 100 Frontend Interview Questions"," article handles HTML, CSS, and JavaScript fundamentals. The answers here are written the way you would actually explain them out loud: a clear definition first, the reasoning behind it, then a short example when it helps the idea stick.",[18,8456,8458],{"id":8457},"vuejs-fundamentals","Vue.js Fundamentals",[23,8460,8462],{"id":8461},"_1-what-is-vuejs-and-what-kind-of-problems-does-it-solve","1. What is Vue.js, and what kind of problems does it solve?",[11,8464,8465],{},"Vue.js is a JavaScript framework for building user interfaces. Instead of writing code that manually finds DOM elements and updates them whenever your data changes, you describe your UI as a template that maps to your data, and Vue takes care of updating the DOM when that data changes.",[11,8467,8468],{},"The core problem it solves is keeping the UI in sync with application state without you having to track every possible change by hand. As an app grows, manually wiring up event listeners and DOM updates becomes error prone and hard to maintain. Vue's reactivity system watches your data, and its component model lets you break a page into small, reusable, self-contained pieces (each with its own template, logic, and styles) that can be composed into full applications.",[11,8470,8471,8472,8475],{},"It scales from a single ",[66,8473,8474],{},"\u003Cscript>"," tag dropped into an HTML page for small interactive widgets, all the way up to full single-page applications built with Vite, Vue Router, and Pinia.",[23,8477,8479],{"id":8478},"_2-what-are-the-key-features-that-make-vuejs-popular","2. What are the key features that make Vue.js popular?",[717,8481,8482,8488,8494,8504,8510,8516,8522],{},[720,8483,8484,8487],{},[31,8485,8486],{},"Reactivity system",": change a piece of state and every part of the UI that depends on it updates automatically, no manual DOM wiring.",[720,8489,8490,8493],{},[31,8491,8492],{},"Approachable templates",": Vue templates are close to plain HTML with a small set of directives added on top, so the learning curve is gentle.",[720,8495,8496,8499,8500,8503],{},[31,8497,8498],{},"Single File Components",": template, logic, and styles live together in one ",[66,8501,8502],{},".vue"," file, which keeps components easy to reason about.",[720,8505,8506,8509],{},[31,8507,8508],{},"Incremental adoptability",": you can use Vue for one widget on a page, or build an entire app with it, there is no all-or-nothing decision.",[720,8511,8512,8515],{},[31,8513,8514],{},"Composition API",": lets you organize and reuse logic by feature instead of by option type, which helps in larger components.",[720,8517,8518,8521],{},[31,8519,8520],{},"Official ecosystem",": Vue Router, Pinia, and Vite are maintained by the same team and designed to work together out of the box.",[720,8523,8524,8527],{},[31,8525,8526],{},"Performance",": Vue 3's compiler and reactivity system are tuned to do less work at runtime through compile-time optimizations.",[23,8529,8531,8532,8534],{"id":8530},"_3-what-is-a-single-file-component-vue-file-and-what-are-its-three-blocks","3. What is a Single File Component (",[66,8533,8502],{}," file), and what are its three blocks?",[11,8536,8537,8538,8540],{},"A Single File Component is a ",[66,8539,8502],{}," file that groups everything a component needs, its markup, its logic, and its styles, into one file instead of spreading them across separate HTML, JS, and CSS files. A build tool (Vite, in modern Vue) compiles this file into a regular JavaScript module.",[11,8542,8543],{},"It's made up of three blocks:",[507,8545,8549],{"className":8546,"code":8547,"language":8548,"meta":512,"style":512},"language-vue shiki shiki-themes github-dark","\u003Ctemplate>\n    \u003Cbutton @click=\"increment\">Count: {{ count }}\u003C/button>\n\u003C/template>\n\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n\nfunction increment() {\n    count.value++\n}\n\u003C/script>\n\n\u003Cstyle scoped>\nbutton {\n    color: #10b981\n}\n\u003C/style>\n","vue",[66,8550,8551,8562,8585,8594,8598,8610,8624,8628,8650,8654,8666,8675,8680,8689,8694,8706,8714,8725,8730],{"__ignoreMap":512},[516,8552,8553,8555,8559],{"class":518,"line":519},[516,8554,3042],{"class":1227},[516,8556,8558],{"class":8557},"s4JwU","template",[516,8560,8561],{"class":1227},">\n",[516,8563,8564,8567,8570,8573,8575,8578,8581,8583],{"class":518,"line":525},[516,8565,8566],{"class":1227},"    \u003C",[516,8568,8569],{"class":8557},"button",[516,8571,8572],{"class":4733}," @click",[516,8574,1894],{"class":1227},[516,8576,8577],{"class":1248},"\"increment\"",[516,8579,8580],{"class":1227},">Count: {{ count }}\u003C/",[516,8582,8569],{"class":8557},[516,8584,8561],{"class":1227},[516,8586,8587,8590,8592],{"class":518,"line":531},[516,8588,8589],{"class":1227},"\u003C/",[516,8591,8558],{"class":8557},[516,8593,8561],{"class":1227},[516,8595,8596],{"class":518,"line":1127},[516,8597,1131],{"emptyLinePlaceholder":1130},[516,8599,8600,8602,8605,8608],{"class":518,"line":1134},[516,8601,3042],{"class":1227},[516,8603,8604],{"class":8557},"script",[516,8606,8607],{"class":4733}," setup",[516,8609,8561],{"class":1227},[516,8611,8612,8615,8618,8621],{"class":518,"line":1275},[516,8613,8614],{"class":1749},"import",[516,8616,8617],{"class":1227}," { ref } ",[516,8619,8620],{"class":1749},"from",[516,8622,8623],{"class":1248}," 'vue'\n",[516,8625,8626],{"class":518,"line":1302},[516,8627,1131],{"emptyLinePlaceholder":1130},[516,8629,8630,8633,8636,8638,8641,8644,8647],{"class":518,"line":1308},[516,8631,8632],{"class":1749},"const",[516,8634,8635],{"class":1233}," count",[516,8637,1793],{"class":1749},[516,8639,8640],{"class":4733}," ref",[516,8642,8643],{"class":1227},"(",[516,8645,8646],{"class":1233},"0",[516,8648,8649],{"class":1227},")\n",[516,8651,8652],{"class":518,"line":1314},[516,8653,1131],{"emptyLinePlaceholder":1130},[516,8655,8657,8660,8663],{"class":518,"line":8656},10,[516,8658,8659],{"class":1749},"function",[516,8661,8662],{"class":4733}," increment",[516,8664,8665],{"class":1227},"() {\n",[516,8667,8669,8672],{"class":518,"line":8668},11,[516,8670,8671],{"class":1227},"    count.value",[516,8673,8674],{"class":1749},"++\n",[516,8676,8678],{"class":518,"line":8677},12,[516,8679,1317],{"class":1227},[516,8681,8683,8685,8687],{"class":518,"line":8682},13,[516,8684,8589],{"class":1227},[516,8686,8604],{"class":8557},[516,8688,8561],{"class":1227},[516,8690,8692],{"class":518,"line":8691},14,[516,8693,1131],{"emptyLinePlaceholder":1130},[516,8695,8697,8699,8701,8704],{"class":518,"line":8696},15,[516,8698,3042],{"class":1227},[516,8700,4868],{"class":8557},[516,8702,8703],{"class":4733}," scoped",[516,8705,8561],{"class":1227},[516,8707,8709,8711],{"class":518,"line":8708},16,[516,8710,8569],{"class":8557},[516,8712,8713],{"class":1227}," {\n",[516,8715,8717,8720,8722],{"class":518,"line":8716},17,[516,8718,8719],{"class":1233},"    color",[516,8721,1245],{"class":1227},[516,8723,8724],{"class":1233},"#10b981\n",[516,8726,8728],{"class":518,"line":8727},18,[516,8729,1317],{"class":1227},[516,8731,8733,8735,8737],{"class":518,"line":8732},19,[516,8734,8589],{"class":1227},[516,8736,4868],{"class":8557},[516,8738,8561],{"class":1227},[717,8740,8741,8747,8754],{},[720,8742,8743,8746],{},[66,8744,8745],{},"\u003Ctemplate>"," holds the HTML-like markup for the component.",[720,8748,8749,2846,8751,8753],{},[66,8750,8474],{},[66,8752,8448],{},") holds the component's logic: state, computed values, methods, lifecycle hooks.",[720,8755,8756,8759,8760,8763],{},[66,8757,8758],{},"\u003Cstyle>"," holds CSS for the component. Adding ",[66,8761,8762],{},"scoped"," limits those styles to this component only, so they won't leak out and affect other parts of the app.",[23,8765,8767,8768,8771],{"id":8766},"_4-how-do-you-create-and-mount-a-vue-application-createapp","4. How do you create and mount a Vue application (",[66,8769,8770],{},"createApp",")?",[11,8773,8774,8776,8777,405],{},[66,8775,8770],{}," is the function that bootstraps a Vue application. You pass it your root component, and it returns an app instance that you then attach to a real DOM element with ",[66,8778,8779],{},".mount()",[507,8781,8785],{"className":8782,"code":8783,"language":8784,"meta":512,"style":512},"language-js shiki shiki-themes github-dark","// main.js\nimport { createApp } from 'vue'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.mount('#app')\n","js",[66,8786,8787,8792,8803,8815,8819,8834,8838],{"__ignoreMap":512},[516,8788,8789],{"class":518,"line":519},[516,8790,8791],{"class":3076},"// main.js\n",[516,8793,8794,8796,8799,8801],{"class":518,"line":525},[516,8795,8614],{"class":1749},[516,8797,8798],{"class":1227}," { createApp } ",[516,8800,8620],{"class":1749},[516,8802,8623],{"class":1248},[516,8804,8805,8807,8810,8812],{"class":518,"line":531},[516,8806,8614],{"class":1749},[516,8808,8809],{"class":1227}," App ",[516,8811,8620],{"class":1749},[516,8813,8814],{"class":1248}," './App.vue'\n",[516,8816,8817],{"class":518,"line":1127},[516,8818,1131],{"emptyLinePlaceholder":1130},[516,8820,8821,8823,8826,8828,8831],{"class":518,"line":1134},[516,8822,8632],{"class":1749},[516,8824,8825],{"class":1233}," app",[516,8827,1793],{"class":1749},[516,8829,8830],{"class":4733}," createApp",[516,8832,8833],{"class":1227},"(App)\n",[516,8835,8836],{"class":518,"line":1275},[516,8837,1131],{"emptyLinePlaceholder":1130},[516,8839,8840,8843,8846,8848,8851],{"class":518,"line":1302},[516,8841,8842],{"class":1227},"app.",[516,8844,8845],{"class":4733},"mount",[516,8847,8643],{"class":1227},[516,8849,8850],{"class":1248},"'#app'",[516,8852,8649],{"class":1227},[11,8854,8855,8858,8859,8862,8863,8866],{},[66,8856,8857],{},"createApp(App)"," creates the app instance, and ",[66,8860,8861],{},".mount('#app')"," tells Vue to render the root component into the DOM element with ",[66,8864,8865],{},"id=\"app\"",", replacing its contents. Everything registered on this app instance, global components, directives, plugins like Vue Router or Pinia, is scoped to this one application, which also makes it possible to run multiple independent Vue apps on the same page without them interfering with each other.",[23,8868,8870],{"id":8869},"_5-what-is-the-difference-between-vue-2-and-vue-3-at-a-high-level","5. What is the difference between Vue 2 and Vue 3 at a high level?",[36,8872,8873,8885],{},[39,8874,8875],{},[42,8876,8877,8879,8882],{},[45,8878,2226],{},[45,8880,8881],{},"Vue 2",[45,8883,8884],{},"Vue 3",[58,8886,8887,8905,8918,8929,8940,8957,8980,8990],{},[42,8888,8889,8892,8898],{},[63,8890,8891],{},"Reactivity",[63,8893,8894,8897],{},[66,8895,8896],{},"Object.defineProperty"," getters/setters",[63,8899,8900,8901,8904],{},"ES ",[66,8902,8903],{},"Proxy",", can detect property addition/deletion and array index changes",[42,8906,8907,8910,8913],{},[63,8908,8909],{},"API style",[63,8911,8912],{},"Options API only",[63,8914,8915,8916],{},"Options API and Composition API, ",[66,8917,8448],{},[42,8919,8920,8923,8926],{},[63,8921,8922],{},"Root template nodes",[63,8924,8925],{},"Exactly one root element required",[63,8927,8928],{},"Multiple root nodes (fragments) allowed",[42,8930,8931,8934,8937],{},[63,8932,8933],{},"TypeScript",[63,8935,8936],{},"Bolted on, weaker inference",[63,8938,8939],{},"Written in TypeScript, first-class inference",[42,8941,8942,8945,8951],{},[63,8943,8944],{},"Global API",[63,8946,8947,8950],{},[66,8948,8949],{},"Vue.component(...)",", mutates a global",[63,8952,8953,8956],{},[66,8954,8955],{},"createApp(...)"," instance, no shared global state",[42,8958,8959,8962,8971],{},[63,8960,8961],{},"Built-in components",[63,8963,8964,154,8967,8970],{},[66,8965,8966],{},"\u003CTransition>",[66,8968,8969],{},"\u003CKeepAlive>"," similar",[63,8972,8973,8974,202,8977],{},"Same, plus ",[66,8975,8976],{},"\u003CTeleport>",[66,8978,8979],{},"\u003CSuspense>",[42,8981,8982,8984,8987],{},[63,8983,8526],{},[63,8985,8986],{},"Good",[63,8988,8989],{},"Faster initial render and updates via compiler optimizations (static hoisting, patch flags)",[42,8991,8992,8995,8998],{},[63,8993,8994],{},"Support",[63,8996,8997],{},"End of life since end of 2023",[63,8999,9000],{},"Actively developed, default for new projects",[11,9002,9003,9004,154,9007,157,9010,9013],{},"Practically, the two biggest changes for day to day development are the Proxy-based reactivity system (which removed a lot of Vue 2's edge cases around adding new object properties or setting array indices) and the Composition API, which gives you a way to organize logic by feature instead of splitting it across ",[66,9005,9006],{},"data",[66,9008,9009],{},"methods",[66,9011,9012],{},"computed",". The Options API still works in Vue 3, so existing Vue 2 knowledge carries over, it's just no longer the default recommendation.",[23,9015,9017,9018,9020],{"id":9016},"_6-what-does-the-vue-template-compiler-do-to-your-template-block","6. What does the Vue template compiler do to your ",[66,9019,8745],{}," block?",[11,9022,9023,9024,9026],{},"Vue's compiler turns your ",[66,9025,8745],{}," block into a JavaScript render function that produces virtual DOM nodes, roughly the same job JSX does in React, except Vue does it for its own HTML-like template syntax instead of requiring JSX.",[507,9028,9030],{"className":8546,"code":9029,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cp>{{ message }}\u003C/p>\n\u003C/template>\n",[66,9031,9032,9040,9053],{"__ignoreMap":512},[516,9033,9034,9036,9038],{"class":518,"line":519},[516,9035,3042],{"class":1227},[516,9037,8558],{"class":8557},[516,9039,8561],{"class":1227},[516,9041,9042,9044,9046,9049,9051],{"class":518,"line":525},[516,9043,8566],{"class":1227},[516,9045,11],{"class":8557},[516,9047,9048],{"class":1227},">{{ message }}\u003C/",[516,9050,11],{"class":8557},[516,9052,8561],{"class":1227},[516,9054,9055,9057,9059],{"class":518,"line":531},[516,9056,8589],{"class":1227},[516,9058,8558],{"class":8557},[516,9060,8561],{"class":1227},[11,9062,9063],{},"compiles down to something conceptually like:",[507,9065,9067],{"className":8782,"code":9066,"language":8784,"meta":512,"style":512},"function render(ctx) {\n    return h('p', null, ctx.message)\n}\n",[66,9068,9069,9085,9106],{"__ignoreMap":512},[516,9070,9071,9073,9076,9078,9082],{"class":518,"line":519},[516,9072,8659],{"class":1749},[516,9074,9075],{"class":4733}," render",[516,9077,8643],{"class":1227},[516,9079,9081],{"class":9080},"s9osk","ctx",[516,9083,9084],{"class":1227},") {\n",[516,9086,9087,9090,9093,9095,9098,9100,9103],{"class":518,"line":525},[516,9088,9089],{"class":1749},"    return",[516,9091,9092],{"class":4733}," h",[516,9094,8643],{"class":1227},[516,9096,9097],{"class":1248},"'p'",[516,9099,154],{"class":1227},[516,9101,9102],{"class":1233},"null",[516,9104,9105],{"class":1227},", ctx.message)\n",[516,9107,9108],{"class":518,"line":531},[516,9109,1317],{"class":1227},[11,9111,9112],{},"The important part is that this doesn't happen by naively re-running that function and diffing everything on every update. Vue 3's compiler analyzes the template ahead of time and adds optimizations: it marks static content (content with no bindings) so it's created once and skipped on every future re-render (static hoisting), and it attaches \"patch flags\" to dynamic nodes that tell the runtime exactly what kind of thing changed (text, a class, a prop), so updates only touch what actually needs touching instead of doing a full diff of the whole tree. This is why Vue 3 templates tend to outperform a hand-written render function for the same UI, the compiler has information a hand-written function doesn't.",[23,9114,9116],{"id":9115},"_7-what-is-the-difference-between-the-runtime-only-build-and-the-runtimecompiler-build-of-vue","7. What is the difference between the runtime-only build and the runtime+compiler build of Vue?",[11,9118,9119],{},"The runtime-only build contains everything needed to create components and update the DOM, but it does not include the template-to-render-function compiler. The runtime+compiler build includes that compiler as well, so it can compile a template string into a render function directly in the browser.",[11,9121,9122,9123,9125,9126,9128],{},"When you build a Vue app with Vite (or Vue CLI before it), your ",[66,9124,8502],{}," files' ",[66,9127,8745],{}," blocks are compiled to render functions ahead of time, during the build step. Because of that, the app only ever needs the smaller, runtime-only build in production, there's nothing left to compile at runtime.",[11,9130,9131,9132,9134,9135,9138],{},"You need the runtime+compiler build only in the rarer case where Vue has to compile a template string that exists at runtime rather than build time, for example mounting straight onto an in-DOM template with no build step, or passing a template string via the ",[66,9133,8558],{}," option. For a normal SFC-based project scaffolded with ",[66,9136,9137],{},"create-vue",", this distinction is handled for you automatically and you'll almost never touch it directly.",[23,9140,9142,9143,9145],{"id":9141},"_8-what-is-script-setup-and-why-is-it-now-the-recommended-way-to-write-components","8. What is ",[66,9144,8448],{},", and why is it now the recommended way to write components?",[11,9147,9148,9150,9151,9153],{},[66,9149,8448],{}," is a compile-time shorthand for using the Composition API inside a Single File Component. Anything you declare at the top level, variables, functions, imports, is automatically available in the ",[66,9152,8745],{}," block, without you needing to explicitly return it.",[507,9155,9157],{"className":8546,"code":9156,"language":8548,"meta":512,"style":512},"\u003C!-- Without \u003Cscript setup> -->\n\u003Cscript>\nimport { ref } from 'vue'\n\nexport default {\n    setup() {\n        const count = ref(0)\n        function increment() {\n            count.value++\n        }\n        return { count, increment }\n    }\n}\n\u003C/script>\n\n\u003C!-- With \u003Cscript setup> -->\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\nfunction increment() {\n    count.value++\n}\n\u003C/script>\n",[66,9158,9159,9164,9172,9182,9186,9196,9203,9220,9229,9236,9241,9249,9254,9258,9266,9270,9275,9285,9295,9299,9316,9325,9332,9337],{"__ignoreMap":512},[516,9160,9161],{"class":518,"line":519},[516,9162,9163],{"class":3076},"\u003C!-- Without \u003Cscript setup> -->\n",[516,9165,9166,9168,9170],{"class":518,"line":525},[516,9167,3042],{"class":1227},[516,9169,8604],{"class":8557},[516,9171,8561],{"class":1227},[516,9173,9174,9176,9178,9180],{"class":518,"line":531},[516,9175,8614],{"class":1749},[516,9177,8617],{"class":1227},[516,9179,8620],{"class":1749},[516,9181,8623],{"class":1248},[516,9183,9184],{"class":518,"line":1127},[516,9185,1131],{"emptyLinePlaceholder":1130},[516,9187,9188,9191,9194],{"class":518,"line":1134},[516,9189,9190],{"class":1749},"export",[516,9192,9193],{"class":1749}," default",[516,9195,8713],{"class":1227},[516,9197,9198,9201],{"class":518,"line":1275},[516,9199,9200],{"class":4733},"    setup",[516,9202,8665],{"class":1227},[516,9204,9205,9208,9210,9212,9214,9216,9218],{"class":518,"line":1302},[516,9206,9207],{"class":1749},"        const",[516,9209,8635],{"class":1233},[516,9211,1793],{"class":1749},[516,9213,8640],{"class":4733},[516,9215,8643],{"class":1227},[516,9217,8646],{"class":1233},[516,9219,8649],{"class":1227},[516,9221,9222,9225,9227],{"class":518,"line":1308},[516,9223,9224],{"class":1749},"        function",[516,9226,8662],{"class":4733},[516,9228,8665],{"class":1227},[516,9230,9231,9234],{"class":518,"line":1314},[516,9232,9233],{"class":1227},"            count.value",[516,9235,8674],{"class":1749},[516,9237,9238],{"class":518,"line":8656},[516,9239,9240],{"class":1227},"        }\n",[516,9242,9243,9246],{"class":518,"line":8668},[516,9244,9245],{"class":1749},"        return",[516,9247,9248],{"class":1227}," { count, increment }\n",[516,9250,9251],{"class":518,"line":8677},[516,9252,9253],{"class":1227},"    }\n",[516,9255,9256],{"class":518,"line":8682},[516,9257,1317],{"class":1227},[516,9259,9260,9262,9264],{"class":518,"line":8691},[516,9261,8589],{"class":1227},[516,9263,8604],{"class":8557},[516,9265,8561],{"class":1227},[516,9267,9268],{"class":518,"line":8696},[516,9269,1131],{"emptyLinePlaceholder":1130},[516,9271,9272],{"class":518,"line":8708},[516,9273,9274],{"class":3076},"\u003C!-- With \u003Cscript setup> -->\n",[516,9276,9277,9279,9281,9283],{"class":518,"line":8716},[516,9278,3042],{"class":1227},[516,9280,8604],{"class":8557},[516,9282,8607],{"class":4733},[516,9284,8561],{"class":1227},[516,9286,9287,9289,9291,9293],{"class":518,"line":8727},[516,9288,8614],{"class":1749},[516,9290,8617],{"class":1227},[516,9292,8620],{"class":1749},[516,9294,8623],{"class":1248},[516,9296,9297],{"class":518,"line":8732},[516,9298,1131],{"emptyLinePlaceholder":1130},[516,9300,9302,9304,9306,9308,9310,9312,9314],{"class":518,"line":9301},20,[516,9303,8632],{"class":1749},[516,9305,8635],{"class":1233},[516,9307,1793],{"class":1749},[516,9309,8640],{"class":4733},[516,9311,8643],{"class":1227},[516,9313,8646],{"class":1233},[516,9315,8649],{"class":1227},[516,9317,9319,9321,9323],{"class":518,"line":9318},21,[516,9320,8659],{"class":1749},[516,9322,8662],{"class":4733},[516,9324,8665],{"class":1227},[516,9326,9328,9330],{"class":518,"line":9327},22,[516,9329,8671],{"class":1227},[516,9331,8674],{"class":1749},[516,9333,9335],{"class":518,"line":9334},23,[516,9336,1317],{"class":1227},[516,9338,9340,9342,9344],{"class":518,"line":9339},24,[516,9341,8589],{"class":1227},[516,9343,8604],{"class":8557},[516,9345,8561],{"class":1227},[11,9347,9348,9349,9352,9353,9356,9357,9360,9361,9363,9364,9366],{},"It's recommended over the plain Composition API syntax and over the Options API for a few concrete reasons. There's much less boilerplate: no wrapping ",[66,9350,9351],{},"setup()"," function, no manual ",[66,9354,9355],{},"return"," statement, no ",[66,9358,9359],{},"components: {}"," registration since imported components are used directly in the template. TypeScript inference works better because everything is a normal top-level binding rather than being funneled through an object literal. It also compiles to more efficient JavaScript than a plain ",[66,9362,8474],{}," component, since the compiler can statically link template usages directly to the setup bindings. The Options API still exists and is fully supported, but for new components ",[66,9365,8448],{}," is what the Vue team and most current documentation lead with.",[23,9368,9370],{"id":9369},"_9-what-is-the-difference-between-a-vue-app-instance-and-a-component-instance","9. What is the difference between a Vue \"app instance\" and a \"component instance\"?",[11,9372,9373,9374,9377],{},"The app instance is created once, at the top of your application, with ",[66,9375,9376],{},"createApp()",". It represents the whole application and is where you register things globally: global components, directives, plugins (Vue Router, Pinia), and app-level configuration. There's typically only one app instance per application.",[11,9379,9380,9381,9384,9385,9388,9389,9391,9392,9394],{},"A component instance exists per component, per place it's used. Every time a ",[66,9382,9383],{},"\u003CUserCard>"," component is rendered on the page, Vue creates a separate component instance for it, holding that specific instance's local state (its ",[66,9386,9387],{},"ref","s, ",[66,9390,9012],{},"s, props, and so on). Two ",[66,9393,9383],{}," components on the same page have two entirely independent component instances, even though they share the same component definition.",[507,9396,9398],{"className":8782,"code":9397,"language":8784,"meta":512,"style":512},"const app = createApp(App)   // one app instance\napp.component('UserCard', UserCard)  // registered globally, on the app\napp.mount('#app')\n",[66,9399,9400,9416,9434],{"__ignoreMap":512},[516,9401,9402,9404,9406,9408,9410,9413],{"class":518,"line":519},[516,9403,8632],{"class":1749},[516,9405,8825],{"class":1233},[516,9407,1793],{"class":1749},[516,9409,8830],{"class":4733},[516,9411,9412],{"class":1227},"(App)   ",[516,9414,9415],{"class":3076},"// one app instance\n",[516,9417,9418,9420,9423,9425,9428,9431],{"class":518,"line":525},[516,9419,8842],{"class":1227},[516,9421,9422],{"class":4733},"component",[516,9424,8643],{"class":1227},[516,9426,9427],{"class":1248},"'UserCard'",[516,9429,9430],{"class":1227},", UserCard)  ",[516,9432,9433],{"class":3076},"// registered globally, on the app\n",[516,9435,9436,9438,9440,9442,9444],{"class":518,"line":531},[516,9437,8842],{"class":1227},[516,9439,8845],{"class":4733},[516,9441,8643],{"class":1227},[516,9443,8850],{"class":1248},[516,9445,8649],{"class":1227},[11,9447,9448,9449,202,9451,9453],{},"With the Composition API you rarely interact with component instances directly, ",[66,9450,9387],{},[66,9452,9012],{}," already give you what you need inside a component. But the distinction still matters conceptually: app-level registration (plugins, global components) happens once on the app instance, while a component's own reactive state is scoped to its own component instance and doesn't leak to other instances of the same component.",[23,9455,9457],{"id":9456},"_10-what-is-vite-and-why-did-the-vue-ecosystem-move-to-it-from-webpack-based-tooling","10. What is Vite, and why did the Vue ecosystem move to it from Webpack-based tooling?",[11,9459,9460,9461,9463],{},"Vite is a build tool created by Evan You, Vue's creator, and it's now the default tooling for new Vue projects (via ",[66,9462,9137],{},"), replacing the older Webpack-based Vue CLI.",[11,9465,9466],{},"The main problem it solves is dev server startup and update speed on larger applications. Webpack-based tools have to bundle your entire dependency graph before the dev server can serve the first page, which gets slower as a project grows. Vite instead serves your source files as native ES modules directly to the browser during development, so there's no upfront bundling step, the dev server starts almost instantly regardless of app size. It pre-bundles heavier dependencies (like Vue itself or large npm packages) once using esbuild, which is written in Go and dramatically faster than JavaScript-based bundlers for that job.",[11,9468,9469],{},"Hot Module Replacement is also faster with Vite, because when you edit a file, Vite only needs to invalidate and re-serve that one module over the existing native ESM graph, instead of re-bundling a chunk of the dependency graph the way Webpack does.",[11,9471,9472,9473,9475],{},"For production builds, Vite switches to Rollup, which produces a well-optimized, tree-shaken bundle. Vue CLI is now in maintenance mode, and Vite, alongside first-class support for ",[66,9474,8448],{}," SFC compilation, is the officially recommended way to scaffold and build Vue applications today.",[18,9477,9479],{"id":9478},"template-syntax-and-directives","Template Syntax and Directives",[23,9481,9483,9484,9487],{"id":9482},"_11-what-is-template-interpolation-the-mustache-syntax","11. What is template interpolation (the mustache ",[66,9485,9486],{},"{{ }}"," syntax)?",[11,9489,9490],{},"Template interpolation is how you insert a JavaScript value into the text content of an element using double curly braces. Vue evaluates the expression inside the braces and inserts the result as text, then keeps it updated automatically whenever the underlying reactive data changes.",[507,9492,9494],{"className":8546,"code":9493,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cp>Hello, {{ user.name }}\u003C/p>\n    \u003Cp>{{ price * quantity }}\u003C/p>\n\u003C/template>\n",[66,9495,9496,9504,9517,9530],{"__ignoreMap":512},[516,9497,9498,9500,9502],{"class":518,"line":519},[516,9499,3042],{"class":1227},[516,9501,8558],{"class":8557},[516,9503,8561],{"class":1227},[516,9505,9506,9508,9510,9513,9515],{"class":518,"line":525},[516,9507,8566],{"class":1227},[516,9509,11],{"class":8557},[516,9511,9512],{"class":1227},">Hello, {{ user.name }}\u003C/",[516,9514,11],{"class":8557},[516,9516,8561],{"class":1227},[516,9518,9519,9521,9523,9526,9528],{"class":518,"line":531},[516,9520,8566],{"class":1227},[516,9522,11],{"class":8557},[516,9524,9525],{"class":1227},">{{ price * quantity }}\u003C/",[516,9527,11],{"class":8557},[516,9529,8561],{"class":1227},[516,9531,9532,9534,9536],{"class":518,"line":1127},[516,9533,8589],{"class":1227},[516,9535,8558],{"class":8557},[516,9537,8561],{"class":1227},[11,9539,9540,9541,9543,9544,202,9547,9550,9551,9554],{},"The content inside ",[66,9542,9486],{}," must be a single JavaScript expression, not a statement, so ",[66,9545,9546],{},"{{ user.name }}",[66,9548,9549],{},"{{ isActive ? 'On' : 'Off' }}"," work, but assignments or ",[66,9552,9553],{},"if"," statements do not. This keeps templates declarative: you say what should be displayed, not the sequence of steps to compute and update it, and Vue's reactivity system handles re-rendering that text whenever the referenced values change.",[23,9556,9558,9559,202,9562,9565],{"id":9557},"_12-what-is-the-difference-between-v-bind-and-v-on-and-what-are-their-shorthand-forms","12. What is the difference between ",[66,9560,9561],{},"v-bind",[66,9563,9564],{},"v-on",", and what are their shorthand forms?",[11,9567,9568,9570,9571,9573],{},[66,9569,9561],{}," connects a piece of reactive data to an HTML attribute or a component prop, keeping it updated when the data changes. ",[66,9572,9564],{}," attaches an event listener to an element or component, running a handler when that event fires.",[36,9575,9576,9590],{},[39,9577,9578],{},[42,9579,9580,9583,9585,9588],{},[45,9581,9582],{},"Directive",[45,9584,50],{},[45,9586,9587],{},"Shorthand",[45,9589,963],{},[58,9591,9592,9611],{},[42,9593,9594,9598,9601,9606],{},[63,9595,9596],{},[66,9597,9561],{},[63,9599,9600],{},"Bind an attribute/prop",[63,9602,9603],{},[66,9604,9605],{},":",[63,9607,9608],{},[66,9609,9610],{},":src=\"imageUrl\"",[42,9612,9613,9617,9620,9625],{},[63,9614,9615],{},[66,9616,9564],{},[63,9618,9619],{},"Listen for an event",[63,9621,9622],{},[66,9623,9624],{},"@",[63,9626,9627],{},[66,9628,9629],{},"@click=\"handleClick\"",[507,9631,9633],{"className":8546,"code":9632,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cimg :src=\"avatarUrl\" :alt=\"user.name\" />\n    \u003Cbutton @click=\"save\">Save\u003C/button>\n\u003C/template>\n",[66,9634,9635,9643,9668,9688],{"__ignoreMap":512},[516,9636,9637,9639,9641],{"class":518,"line":519},[516,9638,3042],{"class":1227},[516,9640,8558],{"class":8557},[516,9642,8561],{"class":1227},[516,9644,9645,9647,9649,9652,9654,9657,9660,9662,9665],{"class":518,"line":525},[516,9646,8566],{"class":1227},[516,9648,2160],{"class":8557},[516,9650,9651],{"class":4733}," :src",[516,9653,1894],{"class":1227},[516,9655,9656],{"class":1248},"\"avatarUrl\"",[516,9658,9659],{"class":4733}," :alt",[516,9661,1894],{"class":1227},[516,9663,9664],{"class":1248},"\"user.name\"",[516,9666,9667],{"class":1227}," />\n",[516,9669,9670,9672,9674,9676,9678,9681,9684,9686],{"class":518,"line":531},[516,9671,8566],{"class":1227},[516,9673,8569],{"class":8557},[516,9675,8572],{"class":4733},[516,9677,1894],{"class":1227},[516,9679,9680],{"class":1248},"\"save\"",[516,9682,9683],{"class":1227},">Save\u003C/",[516,9685,8569],{"class":8557},[516,9687,8561],{"class":1227},[516,9689,9690,9692,9694],{"class":518,"line":1127},[516,9691,8589],{"class":1227},[516,9693,8558],{"class":8557},[516,9695,8561],{"class":1227},[11,9697,9698,9699,202,9701,9703,9704,202,9707,9710,9711,756,9714,9717],{},"In practice, almost everyone uses the shorthand forms (",[66,9700,9605],{},[66,9702,9624],{},") rather than writing out ",[66,9705,9706],{},"v-bind:",[66,9708,9709],{},"v-on:",", they read closer to plain HTML attributes and event handlers. Both directives can also take a dynamic argument, like ",[66,9712,9713],{},":[attributeName]=\"value\"",[66,9715,9716],{},"@[eventName]=\"handler\"",", when the attribute or event name itself needs to be computed rather than fixed in the template.",[23,9719,9721,9722,202,9725,9728],{"id":9720},"_13-what-is-the-difference-between-v-if-and-v-show","13. What is the difference between ",[66,9723,9724],{},"v-if",[66,9726,9727],{},"v-show","?",[11,9730,9731,9733,9734,9736,9737,9740,9741,9744],{},[66,9732,9724],{}," conditionally renders an element: when the condition is false, Vue does not render the element to the DOM at all, and any component inside it is fully unmounted (its lifecycle hooks fire accordingly). ",[66,9735,9727],{}," always renders the element, but toggles its CSS ",[66,9738,9739],{},"display"," property between ",[66,9742,9743],{},"none"," and its normal value.",[507,9746,9748],{"className":8546,"code":9747,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cdiv v-if=\"isLoggedIn\">Welcome back\u003C/div>\n    \u003Cdiv v-show=\"isPanelOpen\">Panel content\u003C/div>\n\u003C/template>\n",[66,9749,9750,9758,9780,9801],{"__ignoreMap":512},[516,9751,9752,9754,9756],{"class":518,"line":519},[516,9753,3042],{"class":1227},[516,9755,8558],{"class":8557},[516,9757,8561],{"class":1227},[516,9759,9760,9762,9765,9768,9770,9773,9776,9778],{"class":518,"line":525},[516,9761,8566],{"class":1227},[516,9763,9764],{"class":8557},"div",[516,9766,9767],{"class":4733}," v-if",[516,9769,1894],{"class":1227},[516,9771,9772],{"class":1248},"\"isLoggedIn\"",[516,9774,9775],{"class":1227},">Welcome back\u003C/",[516,9777,9764],{"class":8557},[516,9779,8561],{"class":1227},[516,9781,9782,9784,9786,9789,9791,9794,9797,9799],{"class":518,"line":531},[516,9783,8566],{"class":1227},[516,9785,9764],{"class":8557},[516,9787,9788],{"class":4733}," v-show",[516,9790,1894],{"class":1227},[516,9792,9793],{"class":1248},"\"isPanelOpen\"",[516,9795,9796],{"class":1227},">Panel content\u003C/",[516,9798,9764],{"class":8557},[516,9800,8561],{"class":1227},[516,9802,9803,9805,9807],{"class":518,"line":1127},[516,9804,8589],{"class":1227},[516,9806,8558],{"class":8557},[516,9808,8561],{"class":1227},[11,9810,9811,9812,9814,9815,9817],{},"This leads to different cost trade-offs. ",[66,9813,9724],{}," has a higher toggle cost (it has to create or destroy DOM nodes and mount or unmount components each time), but a lower initial cost if the condition starts false, since nothing is rendered until it becomes true. ",[66,9816,9727],{}," has a higher initial render cost (it renders the element regardless of the condition), but toggling it later is cheap since it's just a CSS change.",[11,9819,9820,9821,9823,9824,9826],{},"As a rule of thumb, use ",[66,9822,9727],{}," for something that toggles often, like a dropdown or tab panel, and ",[66,9825,9724],{}," for something that rarely changes, or where you specifically want the component to be destroyed and recreated, like a modal that should reset its internal state each time it opens.",[23,9828,9830,9831,9834,9835,9728],{"id":9829},"_14-what-does-v-for-do-and-why-does-it-need-a-key","14. What does ",[66,9832,9833],{},"v-for"," do, and why does it need a ",[66,9836,9837],{},":key",[11,9839,9840,9842],{},[66,9841,9833],{}," renders a list of elements by looping over an array, object, or range, once per item.",[507,9844,9846],{"className":8546,"code":9845,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cul>\n        \u003Cli v-for=\"item in items\" :key=\"item.id\">\n            {{ item.name }}\n        \u003C/li>\n    \u003C/ul>\n\u003C/template>\n",[66,9847,9848,9856,9864,9889,9894,9903,9912],{"__ignoreMap":512},[516,9849,9850,9852,9854],{"class":518,"line":519},[516,9851,3042],{"class":1227},[516,9853,8558],{"class":8557},[516,9855,8561],{"class":1227},[516,9857,9858,9860,9862],{"class":518,"line":525},[516,9859,8566],{"class":1227},[516,9861,717],{"class":8557},[516,9863,8561],{"class":1227},[516,9865,9866,9869,9871,9874,9876,9879,9882,9884,9887],{"class":518,"line":531},[516,9867,9868],{"class":1227},"        \u003C",[516,9870,720],{"class":8557},[516,9872,9873],{"class":4733}," v-for",[516,9875,1894],{"class":1227},[516,9877,9878],{"class":1248},"\"item in items\"",[516,9880,9881],{"class":4733}," :key",[516,9883,1894],{"class":1227},[516,9885,9886],{"class":1248},"\"item.id\"",[516,9888,8561],{"class":1227},[516,9890,9891],{"class":518,"line":1127},[516,9892,9893],{"class":1227},"            {{ item.name }}\n",[516,9895,9896,9899,9901],{"class":518,"line":1134},[516,9897,9898],{"class":1227},"        \u003C/",[516,9900,720],{"class":8557},[516,9902,8561],{"class":1227},[516,9904,9905,9908,9910],{"class":518,"line":1275},[516,9906,9907],{"class":1227},"    \u003C/",[516,9909,717],{"class":8557},[516,9911,8561],{"class":1227},[516,9913,9914,9916,9918],{"class":518,"line":1302},[516,9915,8589],{"class":1227},[516,9917,8558],{"class":8557},[516,9919,8561],{"class":1227},[11,9921,771,9922,9924,9925,9927],{},[66,9923,9837],{}," is how Vue tracks which DOM node corresponds to which piece of data across re-renders. Without a stable key, Vue's default patching strategy tries to reuse and mutate existing DOM elements in place rather than tracking identity, based only on position. If the list gets reordered, filtered, or has items inserted or removed, that in-place patching can update the wrong element's content, or leave stale local state (like text typed into an input, or a child component's own internal state) attached to the wrong logical item. Giving each item a unique, stable ",[66,9926,9837],{},", usually an id from your data rather than the array index, tells Vue exactly which existing element maps to which item, so it can correctly reorder and reuse elements instead of guessing.",[23,9929,9931,9932,9934,9935,9937],{"id":9930},"_15-why-is-using-the-array-index-as-a-key-in-v-for-considered-risky","15. Why is using the array index as a ",[66,9933,9837],{}," in ",[66,9936,9833],{}," considered risky?",[11,9939,9940,9941,154,9943,154,9946,9949,9950,9952],{},"An index-based key ties an item's identity to its position in the array (",[66,9942,8646],{},[66,9944,9945],{},"1",[66,9947,9948],{},"2",", ...) rather than to the actual data it represents. That's fine as long as the list never reorders and items are only ever added at the end. It breaks down the moment items are inserted at the front, removed from the middle, filtered, or sorted, because the item that used to be at index ",[66,9951,9948],{}," is now a completely different item, but Vue still sees \"key 2\" and assumes it's the same element as before.",[507,9954,9956],{"className":8546,"code":9955,"language":8548,"meta":512,"style":512},"\u003C!-- risky -->\n\u003Cli v-for=\"(item, index) in items\" :key=\"index\">\n    \u003Cinput v-model=\"item.text\" />\n\u003C/li>\n",[66,9957,9958,9963,10002,10007],{"__ignoreMap":512},[516,9959,9960],{"class":518,"line":519},[516,9961,9962],{"class":3076},"\u003C!-- risky -->\n",[516,9964,9965,9967,9969,9971,9973,9975,9978,9981,9984,9986,9989,9992,9994,9996,9998,10000],{"class":518,"line":525},[516,9966,3042],{"class":1227},[516,9968,720],{"class":8557},[516,9970,9873],{"class":1749},[516,9972,1894],{"class":1227},[516,9974,3247],{"class":1248},[516,9976,9977],{"class":1227},"(item, index) ",[516,9979,9980],{"class":1749},"in",[516,9982,9983],{"class":1227}," items",[516,9985,3247],{"class":1248},[516,9987,9988],{"class":1227}," :",[516,9990,9991],{"class":4733},"key",[516,9993,1894],{"class":1227},[516,9995,3247],{"class":1248},[516,9997,1588],{"class":1227},[516,9999,3247],{"class":1248},[516,10001,8561],{"class":1227},[516,10003,10004],{"class":518,"line":531},[516,10005,10006],{"class":1227},"    \u003Cinput v-model=\"item.text\" />\n",[516,10008,10009,10011,10013],{"class":518,"line":1127},[516,10010,8589],{"class":1227},[516,10012,720],{"class":8557},[516,10014,8561],{"class":1227},[11,10016,10017,10018,10021,10022,10024,10025,10028],{},"If you remove the first item from ",[66,10019,10020],{},"items"," here, Vue thinks the element previously at index ",[66,10023,9945],{}," is unchanged, and only the last element needs removing, so it reuses the existing ",[66,10026,10027],{},"\u003Cinput>"," DOM nodes and their typed-in values in place rather than tracking which input belonged to which item. The visible result is inputs (or any local component state) appearing to hold onto the wrong row's data after the list changes.",[11,10030,10031,10032,10034],{},"The fix is to key on something stable that actually identifies the item, typically an ",[66,10033,1578],{}," from your data:",[507,10036,10038],{"className":8546,"code":10037,"language":8548,"meta":512,"style":512},"\u003Cli v-for=\"item in items\" :key=\"item.id\">\n    \u003Cinput v-model=\"item.text\" />\n\u003C/li>\n",[66,10039,10040,10076,10080],{"__ignoreMap":512},[516,10041,10042,10044,10046,10048,10050,10052,10055,10057,10059,10061,10063,10065,10067,10069,10072,10074],{"class":518,"line":519},[516,10043,3042],{"class":1227},[516,10045,720],{"class":8557},[516,10047,9873],{"class":1749},[516,10049,1894],{"class":1227},[516,10051,3247],{"class":1248},[516,10053,10054],{"class":1227},"item ",[516,10056,9980],{"class":1749},[516,10058,9983],{"class":1227},[516,10060,3247],{"class":1248},[516,10062,9988],{"class":1227},[516,10064,9991],{"class":4733},[516,10066,1894],{"class":1227},[516,10068,3247],{"class":1248},[516,10070,10071],{"class":1227},"item.id",[516,10073,3247],{"class":1248},[516,10075,8561],{"class":1227},[516,10077,10078],{"class":518,"line":525},[516,10079,10006],{"class":1227},[516,10081,10082,10084,10086],{"class":518,"line":531},[516,10083,8589],{"class":1227},[516,10085,720],{"class":8557},[516,10087,8561],{"class":1227},[11,10089,10090],{},"Index keys are only acceptable for lists that are static and never reordered or filtered.",[23,10092,10094,10095,10098],{"id":10093},"_16-how-do-you-bind-dynamic-classes-with-class-object-and-array-syntax","16. How do you bind dynamic classes with ",[66,10096,10097],{},":class"," (object and array syntax)?",[11,10100,10101,10103,10104,10107],{},[66,10102,10097],{}," lets you toggle CSS classes based on reactive state instead of concatenating class name strings by hand. It accepts an object, an array, or a mix of both, and it can be combined with a plain static ",[66,10105,10106],{},"class"," attribute on the same element.",[507,10109,10111],{"className":8546,"code":10110,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003C!-- object syntax: keys are class names, values are booleans -->\n    \u003Cdiv :class=\"{ active: isActive, 'text-danger': hasError }\">\u003C/div>\n\n    \u003C!-- array syntax: list of class values -->\n    \u003Cdiv :class=\"[baseClass, isActive ? 'active' : '']\">\u003C/div>\n\n    \u003C!-- array with an object inside -->\n    \u003Cdiv :class=\"[baseClass, { active: isActive }]\">\u003C/div>\n\u003C/template>\n",[66,10112,10113,10121,10126,10147,10151,10156,10175,10179,10184,10203],{"__ignoreMap":512},[516,10114,10115,10117,10119],{"class":518,"line":519},[516,10116,3042],{"class":1227},[516,10118,8558],{"class":8557},[516,10120,8561],{"class":1227},[516,10122,10123],{"class":518,"line":525},[516,10124,10125],{"class":3076},"    \u003C!-- object syntax: keys are class names, values are booleans -->\n",[516,10127,10128,10130,10132,10135,10137,10140,10143,10145],{"class":518,"line":531},[516,10129,8566],{"class":1227},[516,10131,9764],{"class":8557},[516,10133,10134],{"class":4733}," :class",[516,10136,1894],{"class":1227},[516,10138,10139],{"class":1248},"\"{ active: isActive, 'text-danger': hasError }\"",[516,10141,10142],{"class":1227},">\u003C/",[516,10144,9764],{"class":8557},[516,10146,8561],{"class":1227},[516,10148,10149],{"class":518,"line":1127},[516,10150,1131],{"emptyLinePlaceholder":1130},[516,10152,10153],{"class":518,"line":1134},[516,10154,10155],{"class":3076},"    \u003C!-- array syntax: list of class values -->\n",[516,10157,10158,10160,10162,10164,10166,10169,10171,10173],{"class":518,"line":1275},[516,10159,8566],{"class":1227},[516,10161,9764],{"class":8557},[516,10163,10134],{"class":4733},[516,10165,1894],{"class":1227},[516,10167,10168],{"class":1248},"\"[baseClass, isActive ? 'active' : '']\"",[516,10170,10142],{"class":1227},[516,10172,9764],{"class":8557},[516,10174,8561],{"class":1227},[516,10176,10177],{"class":518,"line":1302},[516,10178,1131],{"emptyLinePlaceholder":1130},[516,10180,10181],{"class":518,"line":1308},[516,10182,10183],{"class":3076},"    \u003C!-- array with an object inside -->\n",[516,10185,10186,10188,10190,10192,10194,10197,10199,10201],{"class":518,"line":1314},[516,10187,8566],{"class":1227},[516,10189,9764],{"class":8557},[516,10191,10134],{"class":4733},[516,10193,1894],{"class":1227},[516,10195,10196],{"class":1248},"\"[baseClass, { active: isActive }]\"",[516,10198,10142],{"class":1227},[516,10200,9764],{"class":8557},[516,10202,8561],{"class":1227},[516,10204,10205,10207,10209],{"class":518,"line":8656},[516,10206,8589],{"class":1227},[516,10208,8558],{"class":8557},[516,10210,8561],{"class":1227},[11,10212,10213,10214,10217,10218,10221,10222,10225,10226,10229,10230,10233],{},"The object syntax is the most common for conditional classes: each key is a class name, and it's applied only when its value is truthy, so ",[66,10215,10216],{},"{ active: isActive }"," adds the ",[66,10219,10220],{},"active"," class whenever ",[66,10223,10224],{},"isActive"," is ",[66,10227,10228],{},"true",". The array syntax is more useful when you're combining several class expressions together, like a static base class plus a computed one. Both forms are fully reactive, so classes update automatically whenever the underlying state changes, and both can be used alongside a regular static ",[66,10231,10232],{},"class=\"...\""," attribute, Vue merges them.",[23,10235,10237,10238,9728],{"id":10236},"_17-how-do-you-bind-dynamic-inline-styles-with-style","17. How do you bind dynamic inline styles with ",[66,10239,10240],{},":style",[11,10242,10243,10245],{},[66,10244,10240],{}," binds inline CSS styles to an element using a JavaScript object or array of objects, instead of building a style string by hand.",[507,10247,10249],{"className":8546,"code":10248,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cdiv :style=\"{ color: activeColor, fontSize: fontSize + 'px' }\">\u003C/div>\n\n    \u003C!-- camelCase or kebab-case (quoted) keys both work -->\n    \u003Cdiv :style=\"{ 'font-size': fontSize + 'px' }\">\u003C/div>\n\n    \u003C!-- array syntax merges multiple style objects -->\n    \u003Cdiv :style=\"[baseStyles, overrideStyles]\">\u003C/div>\n\u003C/template>\n",[66,10250,10251,10259,10279,10283,10288,10307,10311,10316,10335],{"__ignoreMap":512},[516,10252,10253,10255,10257],{"class":518,"line":519},[516,10254,3042],{"class":1227},[516,10256,8558],{"class":8557},[516,10258,8561],{"class":1227},[516,10260,10261,10263,10265,10268,10270,10273,10275,10277],{"class":518,"line":525},[516,10262,8566],{"class":1227},[516,10264,9764],{"class":8557},[516,10266,10267],{"class":4733}," :style",[516,10269,1894],{"class":1227},[516,10271,10272],{"class":1248},"\"{ color: activeColor, fontSize: fontSize + 'px' }\"",[516,10274,10142],{"class":1227},[516,10276,9764],{"class":8557},[516,10278,8561],{"class":1227},[516,10280,10281],{"class":518,"line":531},[516,10282,1131],{"emptyLinePlaceholder":1130},[516,10284,10285],{"class":518,"line":1127},[516,10286,10287],{"class":3076},"    \u003C!-- camelCase or kebab-case (quoted) keys both work -->\n",[516,10289,10290,10292,10294,10296,10298,10301,10303,10305],{"class":518,"line":1134},[516,10291,8566],{"class":1227},[516,10293,9764],{"class":8557},[516,10295,10267],{"class":4733},[516,10297,1894],{"class":1227},[516,10299,10300],{"class":1248},"\"{ 'font-size': fontSize + 'px' }\"",[516,10302,10142],{"class":1227},[516,10304,9764],{"class":8557},[516,10306,8561],{"class":1227},[516,10308,10309],{"class":518,"line":1275},[516,10310,1131],{"emptyLinePlaceholder":1130},[516,10312,10313],{"class":518,"line":1302},[516,10314,10315],{"class":3076},"    \u003C!-- array syntax merges multiple style objects -->\n",[516,10317,10318,10320,10322,10324,10326,10329,10331,10333],{"class":518,"line":1308},[516,10319,8566],{"class":1227},[516,10321,9764],{"class":8557},[516,10323,10267],{"class":4733},[516,10325,1894],{"class":1227},[516,10327,10328],{"class":1248},"\"[baseStyles, overrideStyles]\"",[516,10330,10142],{"class":1227},[516,10332,9764],{"class":8557},[516,10334,8561],{"class":1227},[516,10336,10337,10339,10341],{"class":518,"line":1314},[516,10338,8589],{"class":1227},[516,10340,8558],{"class":8557},[516,10342,8561],{"class":1227},[11,10344,10345,10346,10349,10350,10353,10354,10357,10358,756,10361,10364],{},"Object keys can be written in camelCase (",[66,10347,10348],{},"fontSize",") or kebab-case with quotes (",[66,10351,10352],{},"'font-size'","), both map to the same CSS property. Values that need units, like pixel sizes, have to include the unit as part of the string, Vue does not automatically append ",[66,10355,10356],{},"px",". The array syntax is useful when you want to merge a base set of styles with conditional overrides, later objects in the array take precedence for any overlapping properties. Vue also automatically adds vendor prefixes for CSS properties that need them, so you generally don't need to write ",[66,10359,10360],{},"-webkit-",[66,10362,10363],{},"-moz-"," variants yourself.",[23,10366,10368,10369,154,10372,154,10375,154,10378,154,10381,154,10384,8771],{"id":10367},"_18-what-are-event-modifiers-in-vue-stop-prevent-once-self-capture-passive","18. What are event modifiers in Vue (",[66,10370,10371],{},".stop",[66,10373,10374],{},".prevent",[66,10376,10377],{},".once",[66,10379,10380],{},".self",[66,10382,10383],{},".capture",[66,10385,10386],{},".passive",[11,10388,10389,10390,2846,10392,10394,10395,10398],{},"Event modifiers are suffixes you attach to ",[66,10391,9564],{},[66,10393,9624],{},") that handle common event-related tasks declaratively in the template, instead of you having to call things like ",[66,10396,10397],{},"event.preventDefault()"," inside the handler function itself.",[36,10400,10401,10411],{},[39,10402,10403],{},[42,10404,10405,10408],{},[45,10406,10407],{},"Modifier",[45,10409,10410],{},"Effect",[58,10412,10413,10426,10437,10446,10455,10464],{},[42,10414,10415,10419],{},[63,10416,10417],{},[66,10418,10371],{},[63,10420,10421,10422,10425],{},"Calls ",[66,10423,10424],{},"event.stopPropagation()",", stops the event from bubbling further",[42,10427,10428,10432],{},[63,10429,10430],{},[66,10431,10374],{},[63,10433,10421,10434,10436],{},[66,10435,10397],{},", stops the browser's default action (e.g. form submit)",[42,10438,10439,10443],{},[63,10440,10441],{},[66,10442,10377],{},[63,10444,10445],{},"The handler fires at most once, then the listener is removed",[42,10447,10448,10452],{},[63,10449,10450],{},[66,10451,10380],{},[63,10453,10454],{},"Only triggers if the event's target is the element itself, not a child",[42,10456,10457,10461],{},[63,10458,10459],{},[66,10460,10383],{},[63,10462,10463],{},"Listens during the capture phase instead of the bubble phase",[42,10465,10466,10470],{},[63,10467,10468],{},[66,10469,10386],{},[63,10471,10472,10473,10476],{},"Tells the browser the handler won't call ",[66,10474,10475],{},"preventDefault()",", improving scroll performance",[507,10478,10480],{"className":8546,"code":10479,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cform @submit.prevent=\"handleSubmit\">\n        \u003Cbutton @click.stop=\"removeItem\">Remove\u003C/button>\n    \u003C/form>\n\u003C/template>\n",[66,10481,10482,10490,10507,10528,10536],{"__ignoreMap":512},[516,10483,10484,10486,10488],{"class":518,"line":519},[516,10485,3042],{"class":1227},[516,10487,8558],{"class":8557},[516,10489,8561],{"class":1227},[516,10491,10492,10494,10497,10500,10502,10505],{"class":518,"line":525},[516,10493,8566],{"class":1227},[516,10495,10496],{"class":8557},"form",[516,10498,10499],{"class":4733}," @submit.prevent",[516,10501,1894],{"class":1227},[516,10503,10504],{"class":1248},"\"handleSubmit\"",[516,10506,8561],{"class":1227},[516,10508,10509,10511,10513,10516,10518,10521,10524,10526],{"class":518,"line":531},[516,10510,9868],{"class":1227},[516,10512,8569],{"class":8557},[516,10514,10515],{"class":4733}," @click.stop",[516,10517,1894],{"class":1227},[516,10519,10520],{"class":1248},"\"removeItem\"",[516,10522,10523],{"class":1227},">Remove\u003C/",[516,10525,8569],{"class":8557},[516,10527,8561],{"class":1227},[516,10529,10530,10532,10534],{"class":518,"line":1127},[516,10531,9907],{"class":1227},[516,10533,10496],{"class":8557},[516,10535,8561],{"class":1227},[516,10537,10538,10540,10542],{"class":518,"line":1134},[516,10539,8589],{"class":1227},[516,10541,8558],{"class":8557},[516,10543,8561],{"class":1227},[11,10545,10546,10547,10550],{},"Modifiers can be chained, like ",[66,10548,10549],{},"@click.stop.prevent",", and Vue applies them in the order they're written. Keeping this logic in the template rather than the handler keeps the handler function focused purely on what it should do, not on generic DOM event plumbing.",[23,10552,10554,10555,10558,10559,154,10562,154,10565,8771],{"id":10553},"_19-what-are-the-built-in-v-model-modifiers-lazy-number-trim","19. What are the built-in ",[66,10556,10557],{},"v-model"," modifiers (",[66,10560,10561],{},".lazy",[66,10563,10564],{},".number",[66,10566,10567],{},".trim",[11,10569,10570,10572,10573,10576],{},[66,10571,10557],{}," normally syncs on the ",[66,10574,10575],{},"input"," event, meaning it updates on every keystroke. The built-in modifiers change that default behavior.",[507,10578,10580],{"className":8546,"code":10579,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003C!-- sync on 'change' instead of 'input' (fires on blur/enter) -->\n    \u003Cinput v-model.lazy=\"message\" />\n\n    \u003C!-- automatically cast the entered value to a Number -->\n    \u003Cinput v-model.number=\"age\" type=\"number\" />\n\n    \u003C!-- automatically trim leading/trailing whitespace -->\n    \u003Cinput v-model.trim=\"username\" />\n\u003C/template>\n",[66,10581,10582,10590,10595,10611,10615,10620,10644,10648,10653,10669],{"__ignoreMap":512},[516,10583,10584,10586,10588],{"class":518,"line":519},[516,10585,3042],{"class":1227},[516,10587,8558],{"class":8557},[516,10589,8561],{"class":1227},[516,10591,10592],{"class":518,"line":525},[516,10593,10594],{"class":3076},"    \u003C!-- sync on 'change' instead of 'input' (fires on blur/enter) -->\n",[516,10596,10597,10599,10601,10604,10606,10609],{"class":518,"line":531},[516,10598,8566],{"class":1227},[516,10600,10575],{"class":8557},[516,10602,10603],{"class":4733}," v-model.lazy",[516,10605,1894],{"class":1227},[516,10607,10608],{"class":1248},"\"message\"",[516,10610,9667],{"class":1227},[516,10612,10613],{"class":518,"line":1127},[516,10614,1131],{"emptyLinePlaceholder":1130},[516,10616,10617],{"class":518,"line":1134},[516,10618,10619],{"class":3076},"    \u003C!-- automatically cast the entered value to a Number -->\n",[516,10621,10622,10624,10626,10629,10631,10634,10637,10639,10642],{"class":518,"line":1275},[516,10623,8566],{"class":1227},[516,10625,10575],{"class":8557},[516,10627,10628],{"class":4733}," v-model.number",[516,10630,1894],{"class":1227},[516,10632,10633],{"class":1248},"\"age\"",[516,10635,10636],{"class":4733}," type",[516,10638,1894],{"class":1227},[516,10640,10641],{"class":1248},"\"number\"",[516,10643,9667],{"class":1227},[516,10645,10646],{"class":518,"line":1302},[516,10647,1131],{"emptyLinePlaceholder":1130},[516,10649,10650],{"class":518,"line":1308},[516,10651,10652],{"class":3076},"    \u003C!-- automatically trim leading/trailing whitespace -->\n",[516,10654,10655,10657,10659,10662,10664,10667],{"class":518,"line":1314},[516,10656,8566],{"class":1227},[516,10658,10575],{"class":8557},[516,10660,10661],{"class":4733}," v-model.trim",[516,10663,1894],{"class":1227},[516,10665,10666],{"class":1248},"\"username\"",[516,10668,9667],{"class":1227},[516,10670,10671,10673,10675],{"class":518,"line":8656},[516,10672,8589],{"class":1227},[516,10674,8558],{"class":8557},[516,10676,8561],{"class":1227},[11,10678,10679,10681,10682,10684,10685,10688,10689,10691,10692,10695,10696,10698,10699,405],{},[66,10680,10561],{}," switches the sync point from the ",[66,10683,10575],{}," event to the ",[66,10686,10687],{},"change"," event, so the bound value updates only after the field loses focus or the user presses Enter, useful if you don't need to react on every keystroke. ",[66,10690,10564],{}," casts the entered string to a number automatically, which is handy since form inputs always produce strings by default, even for ",[66,10693,10694],{},"type=\"number\""," fields. ",[66,10697,10567],{}," strips leading and trailing whitespace from the value automatically. Modifiers can be combined, like ",[66,10700,10701],{},"v-model.lazy.trim=\"username\"",[23,10703,10705,10706,10709],{"id":10704},"_20-what-does-v-bindobject-do-binding-a-whole-object-of-attributes-at-once","20. What does ",[66,10707,10708],{},"v-bind=\"object\""," do (binding a whole object of attributes at once)?",[11,10711,10712,10713,10715],{},"Passing an object directly to ",[66,10714,9561],{},", without an argument, binds every key/value pair in that object as a separate attribute or prop on the element, in one go, instead of writing out each binding individually.",[507,10717,10719],{"className":8546,"code":10718,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst linkAttrs = {\n    href: 'https://devportalnotes.com',\n    target: '_blank',\n    rel: 'noopener'\n}\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Ca v-bind=\"linkAttrs\">Visit site\u003C/a>\n    \u003C!-- equivalent to -->\n    \u003Ca :href=\"linkAttrs.href\" :target=\"linkAttrs.target\" :rel=\"linkAttrs.rel\">Visit site\u003C/a>\n\u003C/template>\n",[66,10720,10721,10731,10742,10752,10762,10770,10774,10782,10786,10794,10815,10820,10856],{"__ignoreMap":512},[516,10722,10723,10725,10727,10729],{"class":518,"line":519},[516,10724,3042],{"class":1227},[516,10726,8604],{"class":8557},[516,10728,8607],{"class":4733},[516,10730,8561],{"class":1227},[516,10732,10733,10735,10738,10740],{"class":518,"line":525},[516,10734,8632],{"class":1749},[516,10736,10737],{"class":1233}," linkAttrs",[516,10739,1793],{"class":1749},[516,10741,8713],{"class":1227},[516,10743,10744,10747,10750],{"class":518,"line":531},[516,10745,10746],{"class":1227},"    href: ",[516,10748,10749],{"class":1248},"'https://devportalnotes.com'",[516,10751,1252],{"class":1227},[516,10753,10754,10757,10760],{"class":518,"line":1127},[516,10755,10756],{"class":1227},"    target: ",[516,10758,10759],{"class":1248},"'_blank'",[516,10761,1252],{"class":1227},[516,10763,10764,10767],{"class":518,"line":1134},[516,10765,10766],{"class":1227},"    rel: ",[516,10768,10769],{"class":1248},"'noopener'\n",[516,10771,10772],{"class":518,"line":1275},[516,10773,1317],{"class":1227},[516,10775,10776,10778,10780],{"class":518,"line":1302},[516,10777,8589],{"class":1227},[516,10779,8604],{"class":8557},[516,10781,8561],{"class":1227},[516,10783,10784],{"class":518,"line":1308},[516,10785,1131],{"emptyLinePlaceholder":1130},[516,10787,10788,10790,10792],{"class":518,"line":1314},[516,10789,3042],{"class":1227},[516,10791,8558],{"class":8557},[516,10793,8561],{"class":1227},[516,10795,10796,10798,10800,10803,10805,10808,10811,10813],{"class":518,"line":8656},[516,10797,8566],{"class":1227},[516,10799,761],{"class":8557},[516,10801,10802],{"class":4733}," v-bind",[516,10804,1894],{"class":1227},[516,10806,10807],{"class":1248},"\"linkAttrs\"",[516,10809,10810],{"class":1227},">Visit site\u003C/",[516,10812,761],{"class":8557},[516,10814,8561],{"class":1227},[516,10816,10817],{"class":518,"line":8668},[516,10818,10819],{"class":3076},"    \u003C!-- equivalent to -->\n",[516,10821,10822,10824,10826,10829,10831,10834,10837,10839,10842,10845,10847,10850,10852,10854],{"class":518,"line":8677},[516,10823,8566],{"class":1227},[516,10825,761],{"class":8557},[516,10827,10828],{"class":4733}," :href",[516,10830,1894],{"class":1227},[516,10832,10833],{"class":1248},"\"linkAttrs.href\"",[516,10835,10836],{"class":4733}," :target",[516,10838,1894],{"class":1227},[516,10840,10841],{"class":1248},"\"linkAttrs.target\"",[516,10843,10844],{"class":4733}," :rel",[516,10846,1894],{"class":1227},[516,10848,10849],{"class":1248},"\"linkAttrs.rel\"",[516,10851,10810],{"class":1227},[516,10853,761],{"class":8557},[516,10855,8561],{"class":1227},[516,10857,10858,10860,10862],{"class":518,"line":8682},[516,10859,8589],{"class":1227},[516,10861,8558],{"class":8557},[516,10863,8561],{"class":1227},[11,10865,10866,10867,10870,10871,10874,10875,10878],{},"This is useful for grouping a set of related attributes into one config object rather than repeating ",[66,10868,10869],{},":attr=\"obj.attr\""," for each one, and it's also commonly used together with ",[66,10872,10873],{},"$attrs",", for example ",[66,10876,10877],{},"v-bind=\"$attrs\""," on a component's root element to forward any attributes the parent passed down that weren't explicitly declared as props. If the same attribute is also set individually on the element, the order in the template decides which one wins, later bindings override earlier ones.",[23,10880,10882,10883,202,10885,10887],{"id":10881},"_21-can-you-use-v-if-and-v-for-on-the-same-element-and-why-is-it-discouraged","21. Can you use ",[66,10884,9724],{},[66,10886,9833],{}," on the same element, and why is it discouraged?",[11,10889,10890],{},"Technically you can put both directives on the same element, but it's discouraged, and in Vue 3 it will actually throw a compile-time error rather than silently doing something confusing.",[11,10892,10893,10894,10896,10897,10899,10900,10902,10903,10906,10907,10909],{},"The reason is precedence. In Vue 3, ",[66,10895,9724],{}," has higher precedence than ",[66,10898,9833],{}," on the same element, meaning it's evaluated first, before the ",[66,10901,9833],{}," variable even exists in scope. So something like this is invalid, because ",[66,10904,10905],{},"todo"," isn't defined yet when ",[66,10908,9724],{}," runs:",[507,10911,10913],{"className":8546,"code":10912,"language":8548,"meta":512,"style":512},"\u003C!-- invalid in Vue 3, todo is not yet defined -->\n\u003Cli v-for=\"todo in todos\" v-if=\"!todo.done\" :key=\"todo.id\">\n    {{ todo.text }}\n\u003C/li>\n",[66,10914,10915,10920,10971,10976],{"__ignoreMap":512},[516,10916,10917],{"class":518,"line":519},[516,10918,10919],{"class":3076},"\u003C!-- invalid in Vue 3, todo is not yet defined -->\n",[516,10921,10922,10924,10926,10928,10930,10932,10935,10937,10940,10942,10944,10946,10948,10951,10954,10956,10958,10960,10962,10964,10967,10969],{"class":518,"line":525},[516,10923,3042],{"class":1227},[516,10925,720],{"class":8557},[516,10927,9873],{"class":1749},[516,10929,1894],{"class":1227},[516,10931,3247],{"class":1248},[516,10933,10934],{"class":1227},"todo ",[516,10936,9980],{"class":1749},[516,10938,10939],{"class":1227}," todos",[516,10941,3247],{"class":1248},[516,10943,9767],{"class":1749},[516,10945,1894],{"class":1227},[516,10947,3247],{"class":1248},[516,10949,10950],{"class":1749},"!",[516,10952,10953],{"class":1227},"todo.done",[516,10955,3247],{"class":1248},[516,10957,9988],{"class":1227},[516,10959,9991],{"class":4733},[516,10961,1894],{"class":1227},[516,10963,3247],{"class":1248},[516,10965,10966],{"class":1227},"todo.id",[516,10968,3247],{"class":1248},[516,10970,8561],{"class":1227},[516,10972,10973],{"class":518,"line":531},[516,10974,10975],{"class":1227},"    {{ todo.text }}\n",[516,10977,10978,10980,10982],{"class":518,"line":1127},[516,10979,8589],{"class":1227},[516,10981,720],{"class":8557},[516,10983,8561],{"class":1227},[11,10985,10986,10987,9605],{},"There are two clean ways to fix it. Filter the list before it reaches the template, with a ",[66,10988,9012],{},[507,10990,10992],{"className":8546,"code":10991,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { computed } from 'vue'\n\nconst activeTodos = computed(() => todos.value.filter(todo => !todo.done))\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cli v-for=\"todo in activeTodos\" :key=\"todo.id\">{{ todo.text }}\u003C/li>\n\u003C/template>\n",[66,10993,10994,11004,11015,11019,11056,11064,11068,11076,11103],{"__ignoreMap":512},[516,10995,10996,10998,11000,11002],{"class":518,"line":519},[516,10997,3042],{"class":1227},[516,10999,8604],{"class":8557},[516,11001,8607],{"class":4733},[516,11003,8561],{"class":1227},[516,11005,11006,11008,11011,11013],{"class":518,"line":525},[516,11007,8614],{"class":1749},[516,11009,11010],{"class":1227}," { computed } ",[516,11012,8620],{"class":1749},[516,11014,8623],{"class":1248},[516,11016,11017],{"class":518,"line":531},[516,11018,1131],{"emptyLinePlaceholder":1130},[516,11020,11021,11023,11026,11028,11031,11034,11037,11040,11043,11045,11047,11050,11053],{"class":518,"line":1127},[516,11022,8632],{"class":1749},[516,11024,11025],{"class":1233}," activeTodos",[516,11027,1793],{"class":1749},[516,11029,11030],{"class":4733}," computed",[516,11032,11033],{"class":1227},"(() ",[516,11035,11036],{"class":1749},"=>",[516,11038,11039],{"class":1227}," todos.value.",[516,11041,11042],{"class":4733},"filter",[516,11044,8643],{"class":1227},[516,11046,10905],{"class":9080},[516,11048,11049],{"class":1749}," =>",[516,11051,11052],{"class":1749}," !",[516,11054,11055],{"class":1227},"todo.done))\n",[516,11057,11058,11060,11062],{"class":518,"line":1134},[516,11059,8589],{"class":1227},[516,11061,8604],{"class":8557},[516,11063,8561],{"class":1227},[516,11065,11066],{"class":518,"line":1275},[516,11067,1131],{"emptyLinePlaceholder":1130},[516,11069,11070,11072,11074],{"class":518,"line":1302},[516,11071,3042],{"class":1227},[516,11073,8558],{"class":8557},[516,11075,8561],{"class":1227},[516,11077,11078,11080,11082,11084,11086,11089,11091,11093,11096,11099,11101],{"class":518,"line":1308},[516,11079,8566],{"class":1227},[516,11081,720],{"class":8557},[516,11083,9873],{"class":4733},[516,11085,1894],{"class":1227},[516,11087,11088],{"class":1248},"\"todo in activeTodos\"",[516,11090,9881],{"class":4733},[516,11092,1894],{"class":1227},[516,11094,11095],{"class":1248},"\"todo.id\"",[516,11097,11098],{"class":1227},">{{ todo.text }}\u003C/",[516,11100,720],{"class":8557},[516,11102,8561],{"class":1227},[516,11104,11105,11107,11109],{"class":518,"line":1314},[516,11106,8589],{"class":1227},[516,11108,8558],{"class":8557},[516,11110,8561],{"class":1227},[11,11112,11113,11114,11116,11117,11119,11120,11122],{},"Or move the ",[66,11115,9724],{}," to a wrapping ",[66,11118,8745],{}," tag around the loop, so it applies per iteration without conflicting with ",[66,11121,9833],{}," on the same element:",[507,11124,11126],{"className":8546,"code":11125,"language":8548,"meta":512,"style":512},"\u003Ctemplate v-for=\"todo in todos\" :key=\"todo.id\">\n    \u003Cli v-if=\"!todo.done\">{{ todo.text }}\u003C/li>\n\u003C/template>\n",[66,11127,11128,11162,11181],{"__ignoreMap":512},[516,11129,11130,11132,11134,11136,11138,11140,11142,11144,11146,11148,11150,11152,11154,11156,11158,11160],{"class":518,"line":519},[516,11131,3042],{"class":1227},[516,11133,8558],{"class":8557},[516,11135,9873],{"class":1749},[516,11137,1894],{"class":1227},[516,11139,3247],{"class":1248},[516,11141,10934],{"class":1227},[516,11143,9980],{"class":1749},[516,11145,10939],{"class":1227},[516,11147,3247],{"class":1248},[516,11149,9988],{"class":1227},[516,11151,9991],{"class":4733},[516,11153,1894],{"class":1227},[516,11155,3247],{"class":1248},[516,11157,10966],{"class":1227},[516,11159,3247],{"class":1248},[516,11161,8561],{"class":1227},[516,11163,11164,11166,11168,11170,11172,11175,11177,11179],{"class":518,"line":525},[516,11165,8566],{"class":1227},[516,11167,720],{"class":8557},[516,11169,9767],{"class":4733},[516,11171,1894],{"class":1227},[516,11173,11174],{"class":1248},"\"!todo.done\"",[516,11176,11098],{"class":1227},[516,11178,720],{"class":8557},[516,11180,8561],{"class":1227},[516,11182,11183,11185,11187],{"class":518,"line":531},[516,11184,8589],{"class":1227},[516,11186,8558],{"class":8557},[516,11188,8561],{"class":1227},[11,11190,11191],{},"The computed approach is usually preferred, since it also avoids re-running the filter check on every single render for items that were already filtered out.",[23,11193,11195,11196,11199],{"id":11194},"_22-what-is-v-once-and-when-would-you-use-it","22. What is ",[66,11197,11198],{},"v-once",", and when would you use it?",[11,11201,11202,11204],{},[66,11203,11198],{}," tells Vue to render an element (and everything inside it) exactly once, and then treat it as static content from then on, skipping it on all future re-renders even if the data it originally displayed changes.",[507,11206,11208],{"className":8546,"code":11207,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Ch1 v-once>{{ title }}\u003C/h1>\n\u003C/template>\n",[66,11209,11210,11218,11235],{"__ignoreMap":512},[516,11211,11212,11214,11216],{"class":518,"line":519},[516,11213,3042],{"class":1227},[516,11215,8558],{"class":8557},[516,11217,8561],{"class":1227},[516,11219,11220,11222,11225,11228,11231,11233],{"class":518,"line":525},[516,11221,8566],{"class":1227},[516,11223,11224],{"class":8557},"h1",[516,11226,11227],{"class":4733}," v-once",[516,11229,11230],{"class":1227},">{{ title }}\u003C/",[516,11232,11224],{"class":8557},[516,11234,8561],{"class":1227},[516,11236,11237,11239,11241],{"class":518,"line":531},[516,11238,8589],{"class":1227},[516,11240,8558],{"class":8557},[516,11242,8561],{"class":1227},[11,11244,11245],{},"It's a performance optimization for content you know will never need to update after the first render, like a heading built from a prop that's set once and never changes, or a large chunk of content where re-evaluating bindings on every render would be wasted work. Because the element is skipped entirely during Vue's update process, it also slightly reduces the amount of work the virtual DOM diffing has to do elsewhere in that render pass. It's a fairly niche optimization though, reach for it only when you've identified a genuinely static piece of an otherwise dynamic template, not as a default habit.",[23,11247,11249,11250,11199],{"id":11248},"_23-what-is-v-pre-and-when-would-you-use-it","23. What is ",[66,11251,11252],{},"v-pre",[11,11254,11255,11257,11258,11260],{},[66,11256,11252],{}," tells the compiler to skip an element and all of its children entirely, no directive processing, no interpolation. Whatever is written in the markup is output as raw, literal HTML, including any ",[66,11259,9486],{}," mustache syntax.",[507,11262,11264],{"className":8546,"code":11263,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cspan v-pre>{{ this will not be evaluated }}\u003C/span>\n\u003C/template>\n",[66,11265,11266,11274,11290],{"__ignoreMap":512},[516,11267,11268,11270,11272],{"class":518,"line":519},[516,11269,3042],{"class":1227},[516,11271,8558],{"class":8557},[516,11273,8561],{"class":1227},[516,11275,11276,11278,11280,11283,11286,11288],{"class":518,"line":525},[516,11277,8566],{"class":1227},[516,11279,516],{"class":8557},[516,11281,11282],{"class":4733}," v-pre",[516,11284,11285],{"class":1227},">{{ this will not be evaluated }}\u003C/",[516,11287,516],{"class":8557},[516,11289,8561],{"class":1227},[516,11291,11292,11294,11296],{"class":518,"line":531},[516,11293,8589],{"class":1227},[516,11295,8558],{"class":8557},[516,11297,8561],{"class":1227},[11,11299,11300,11301,11304,11305,11308],{},"There are two typical uses. One is a small performance gain: for large blocks of markup with no dynamic bindings or directives at all, skipping compilation on them entirely avoids unnecessary compiler work. The other, more common use is displaying literal Vue syntax to a reader, for example a documentation page that wants to show ",[66,11302,11303],{},"{{ message }}"," as text rather than have Vue try to evaluate ",[66,11306,11307],{},"message"," as an expression. Outside of those two cases it's rarely needed in everyday component code.",[23,11310,11312,11313,11316],{"id":11311},"_24-what-is-v-cloak-and-is-it-still-relevant-in-modern-vue","24. What is ",[66,11314,11315],{},"v-cloak",", and is it still relevant in modern Vue?",[11,11318,11319,11321],{},[66,11320,11315],{}," is a directive that stays on an element until Vue has finished compiling and mounting it, and it's normally paired with a small CSS rule to hide the element until that happens:",[507,11323,11327],{"className":11324,"code":11325,"language":11326,"meta":512,"style":512},"language-html shiki shiki-themes github-dark","\u003Cstyle>\n[v-cloak] {\n    display: none\n}\n\u003C/style>\n\n\u003Cdiv id=\"app\" v-cloak>\n    {{ message }}\n\u003C/div>\n","html",[66,11328,11329,11337,11347,11357,11361,11369,11373,11392,11397],{"__ignoreMap":512},[516,11330,11331,11333,11335],{"class":518,"line":519},[516,11332,3042],{"class":1227},[516,11334,4868],{"class":8557},[516,11336,8561],{"class":1227},[516,11338,11339,11342,11344],{"class":518,"line":525},[516,11340,11341],{"class":1227},"[",[516,11343,11315],{"class":4733},[516,11345,11346],{"class":1227},"] {\n",[516,11348,11349,11352,11354],{"class":518,"line":531},[516,11350,11351],{"class":1233},"    display",[516,11353,1245],{"class":1227},[516,11355,11356],{"class":1233},"none\n",[516,11358,11359],{"class":518,"line":1127},[516,11360,1317],{"class":1227},[516,11362,11363,11365,11367],{"class":518,"line":1134},[516,11364,8589],{"class":1227},[516,11366,4868],{"class":8557},[516,11368,8561],{"class":1227},[516,11370,11371],{"class":518,"line":1275},[516,11372,1131],{"emptyLinePlaceholder":1130},[516,11374,11375,11377,11379,11382,11384,11387,11390],{"class":518,"line":1302},[516,11376,3042],{"class":1227},[516,11378,9764],{"class":8557},[516,11380,11381],{"class":4733}," id",[516,11383,1894],{"class":1227},[516,11385,11386],{"class":1248},"\"app\"",[516,11388,11389],{"class":4733}," v-cloak",[516,11391,8561],{"class":1227},[516,11393,11394],{"class":518,"line":1308},[516,11395,11396],{"class":1227},"    {{ message }}\n",[516,11398,11399,11401,11403],{"class":518,"line":1314},[516,11400,8589],{"class":1227},[516,11402,9764],{"class":8557},[516,11404,8561],{"class":1227},[11,11406,11407,11408,11410,11411,11413],{},"Its purpose is to prevent a brief flash of uncompiled mustache syntax, literally seeing ",[66,11409,11303],{}," on screen for a moment, before Vue takes over. That flash can happen when a browser downloads and parses an HTML page (with the raw template already in the DOM) and then has to wait for the Vue script to load and compile it, which is a scenario specific to using Vue directly via a CDN ",[66,11412,8474],{}," tag with an in-DOM template.",[11,11415,11416,11417,11419,11420,11422],{},"In a modern, build-tool-based Vue app (Vite, ",[66,11418,9137],{},", SFCs), it's mostly irrelevant. Your templates are compiled to render functions at build time, and the app only renders into the DOM once Vue is already running, so there's no raw, uncompiled template sitting in the page waiting to be parsed, and therefore nothing for ",[66,11421,11315],{}," to hide. You'd only reach for it today if you're using the no-build, CDN-script approach to Vue rather than a bundled SFC application.",[18,11424,11426],{"id":11425},"reactivity-system","Reactivity System",[23,11428,11430],{"id":11429},"_25-what-is-reactivity-and-how-does-vues-reactivity-system-work-at-a-high-level","25. What is reactivity, and how does Vue's reactivity system work at a high level?",[11,11432,11433],{},"Reactivity is what lets Vue automatically update the DOM when your data changes, without you writing any manual \"update the UI now\" code. You change a variable, and the parts of the page that depend on it just update themselves.",[11,11435,11436],{},[2160,11437],{"alt":11438,"src":11439},"Vue reactivity flow diagram","/post-images/top-150-vuejs-interview-questions/vue-reactivity-flow-diagram.png",[11,11441,11442,11443,11446,11447,11450,11451,11454],{},"Under the hood, Vue 3 wraps your data in a Proxy (through ",[66,11444,11445],{},"reactive()",") or in a special object with a ",[66,11448,11449],{},".value"," property (through ",[66,11452,11453],{},"ref()","). When a component renders, Vue tracks which reactive properties were read during that render, this is called dependency tracking. When one of those properties is later written to, Vue knows exactly which parts of the app depend on it and schedules them to re-run.",[507,11456,11458],{"className":8782,"code":11457,"language":8784,"meta":512,"style":512},"import { reactive, effect } from 'vue'\n\nconst state = reactive({ count: 0 })\n\neffect(() => {\n    console.log('count is', state.count)\n})\n\nstate.count++  // logs \"count is 1\" automatically\n",[66,11459,11460,11471,11475,11495,11499,11510,11526,11531,11535],{"__ignoreMap":512},[516,11461,11462,11464,11467,11469],{"class":518,"line":519},[516,11463,8614],{"class":1749},[516,11465,11466],{"class":1227}," { reactive, effect } ",[516,11468,8620],{"class":1749},[516,11470,8623],{"class":1248},[516,11472,11473],{"class":518,"line":525},[516,11474,1131],{"emptyLinePlaceholder":1130},[516,11476,11477,11479,11482,11484,11487,11490,11492],{"class":518,"line":531},[516,11478,8632],{"class":1749},[516,11480,11481],{"class":1233}," state",[516,11483,1793],{"class":1749},[516,11485,11486],{"class":4733}," reactive",[516,11488,11489],{"class":1227},"({ count: ",[516,11491,8646],{"class":1233},[516,11493,11494],{"class":1227}," })\n",[516,11496,11497],{"class":518,"line":1127},[516,11498,1131],{"emptyLinePlaceholder":1130},[516,11500,11501,11504,11506,11508],{"class":518,"line":1134},[516,11502,11503],{"class":4733},"effect",[516,11505,11033],{"class":1227},[516,11507,11036],{"class":1749},[516,11509,8713],{"class":1227},[516,11511,11512,11515,11518,11520,11523],{"class":518,"line":1275},[516,11513,11514],{"class":1227},"    console.",[516,11516,11517],{"class":4733},"log",[516,11519,8643],{"class":1227},[516,11521,11522],{"class":1248},"'count is'",[516,11524,11525],{"class":1227},", state.count)\n",[516,11527,11528],{"class":518,"line":1302},[516,11529,11530],{"class":1227},"})\n",[516,11532,11533],{"class":518,"line":1308},[516,11534,1131],{"emptyLinePlaceholder":1130},[516,11536,11537,11540,11543],{"class":518,"line":1314},[516,11538,11539],{"class":1227},"state.count",[516,11541,11542],{"class":1749},"++",[516,11544,11545],{"class":3076},"  // logs \"count is 1\" automatically\n",[11,11547,771,11548,11551,11552,11554],{},[66,11549,11550],{},"effect()"," function above is the low-level primitive Vue's reactivity is built on. Component render functions are, at their core, just an ",[66,11553,11503],{}," that Vue creates for you. So the whole system boils down to two steps repeating forever: track what a piece of code reads, and re-run that code when what it read changes.",[23,11556,11558,11559,202,11561,9728],{"id":11557},"_26-what-is-the-difference-between-ref-and-reactive","26. What is the difference between ",[66,11560,11453],{},[66,11562,11445],{},[11,11564,11565,11566,11568,11569,11571,11572,11574],{},"Both are ways to create reactive state, but they wrap values differently. ",[66,11567,11453],{}," takes any value, including primitives like numbers and strings, and wraps it in an object with a single ",[66,11570,11449],{}," property. ",[66,11573,11445],{}," takes an object (or array, Map, Set) and returns a Proxy of it directly, no wrapper needed.",[507,11576,11578],{"className":8782,"code":11577,"language":8784,"meta":512,"style":512},"import { ref, reactive } from 'vue'\n\nconst count = ref(0)\ncount.value++\n\nconst state = reactive({ count: 0 })\nstate.count++\n",[66,11579,11580,11591,11595,11611,11618,11622,11638],{"__ignoreMap":512},[516,11581,11582,11584,11587,11589],{"class":518,"line":519},[516,11583,8614],{"class":1749},[516,11585,11586],{"class":1227}," { ref, reactive } ",[516,11588,8620],{"class":1749},[516,11590,8623],{"class":1248},[516,11592,11593],{"class":518,"line":525},[516,11594,1131],{"emptyLinePlaceholder":1130},[516,11596,11597,11599,11601,11603,11605,11607,11609],{"class":518,"line":531},[516,11598,8632],{"class":1749},[516,11600,8635],{"class":1233},[516,11602,1793],{"class":1749},[516,11604,8640],{"class":4733},[516,11606,8643],{"class":1227},[516,11608,8646],{"class":1233},[516,11610,8649],{"class":1227},[516,11612,11613,11616],{"class":518,"line":1127},[516,11614,11615],{"class":1227},"count.value",[516,11617,8674],{"class":1749},[516,11619,11620],{"class":518,"line":1134},[516,11621,1131],{"emptyLinePlaceholder":1130},[516,11623,11624,11626,11628,11630,11632,11634,11636],{"class":518,"line":1275},[516,11625,8632],{"class":1749},[516,11627,11481],{"class":1233},[516,11629,1793],{"class":1749},[516,11631,11486],{"class":4733},[516,11633,11489],{"class":1227},[516,11635,8646],{"class":1233},[516,11637,11494],{"class":1227},[516,11639,11640,11642],{"class":518,"line":1302},[516,11641,11539],{"class":1227},[516,11643,8674],{"class":1749},[11,11645,11646],{},"The practical differences that matter:",[36,11648,11649,11663],{},[39,11650,11651],{},[42,11652,11653,11655,11659],{},[45,11654],{},[45,11656,11657],{},[66,11658,11453],{},[45,11660,11661],{},[66,11662,11445],{},[58,11664,11665,11675,11687,11697,11711],{},[42,11666,11667,11670,11672],{},[63,11668,11669],{},"Works with primitives",[63,11671,90],{},[63,11673,11674],{},"No, only objects",[42,11676,11677,11680,11684],{},[63,11678,11679],{},"Access syntax in script",[63,11681,11682],{},[66,11683,11449],{},[63,11685,11686],{},"Direct property access",[42,11688,11689,11692,11695],{},[63,11690,11691],{},"Access syntax in template",[63,11693,11694],{},"Auto-unwrapped",[63,11696,11686],{},[42,11698,11699,11702,11708],{},[63,11700,11701],{},"Can be reassigned entirely",[63,11703,11704,11705,3583],{},"Yes (",[66,11706,11707],{},"count.value = newVal",[63,11709,11710],{},"No, reassigning loses reactivity",[42,11712,11713,11716,11719],{},[63,11714,11715],{},"Destructuring",[63,11717,11718],{},"Safe, still reactive",[63,11720,11721],{},"Breaks reactivity",[11,11723,11724,11725,11727,11728,11730],{},"A common convention is to use ",[66,11726,11453],{}," for most state, since it works for everything and reassigning the whole value is common in day to day code, and reach for ",[66,11729,11445],{}," when you have a tightly related group of fields that will always be read and written together, like a form object.",[23,11732,11734,11735,11737,11738,11740,11741,11743],{"id":11733},"_27-why-do-you-need-value-to-read-a-ref-in-a-script-block-but-not-in-the-template","27. Why do you need ",[66,11736,11449],{}," to read a ",[66,11739,9387],{}," in a ",[66,11742,8474],{}," block but not in the template?",[11,11745,784,11746,11748,11749,11751,11752,11754,11755,11757],{},[66,11747,9387],{}," is just a plain JavaScript object with a getter and setter defined on its ",[66,11750,11449],{}," property (using ",[66,11753,8896],{}," internally, or a class with a getter/setter, depending on the version). JavaScript has no way to intercept \"reading a variable\" the way a Proxy can intercept \"reading a property,\" so outside of a template, there is no magic available: you have to explicitly go through ",[66,11756,11449],{}," to trigger the getter that Vue attached.",[11,11759,11760,11761,11763,11764,11766,11767,11769,11770,11772],{},"Templates are different because they are not really JavaScript, they are compiled. Vue's compiler walks the template, and for any top-level variable it knows came from a ",[66,11762,11453],{}," (because it was returned from ",[66,11765,9351],{}," or is a top-level binding in ",[66,11768,8448],{},"), it automatically inserts the ",[66,11771,11449],{}," access for you during compilation. This is called ref unwrapping.",[507,11774,11776],{"className":8546,"code":11775,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref } from 'vue'\nconst count = ref(0)\nfunction increment() {\n    count.value++ // must use .value here\n}\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cbutton @click=\"increment\">{{ count }}\u003C/button>\n    \u003C!-- no .value needed, compiler handles it -->\n\u003C/template>\n",[66,11777,11778,11788,11798,11814,11822,11831,11835,11843,11847,11855,11874,11879],{"__ignoreMap":512},[516,11779,11780,11782,11784,11786],{"class":518,"line":519},[516,11781,3042],{"class":1227},[516,11783,8604],{"class":8557},[516,11785,8607],{"class":4733},[516,11787,8561],{"class":1227},[516,11789,11790,11792,11794,11796],{"class":518,"line":525},[516,11791,8614],{"class":1749},[516,11793,8617],{"class":1227},[516,11795,8620],{"class":1749},[516,11797,8623],{"class":1248},[516,11799,11800,11802,11804,11806,11808,11810,11812],{"class":518,"line":531},[516,11801,8632],{"class":1749},[516,11803,8635],{"class":1233},[516,11805,1793],{"class":1749},[516,11807,8640],{"class":4733},[516,11809,8643],{"class":1227},[516,11811,8646],{"class":1233},[516,11813,8649],{"class":1227},[516,11815,11816,11818,11820],{"class":518,"line":1127},[516,11817,8659],{"class":1749},[516,11819,8662],{"class":4733},[516,11821,8665],{"class":1227},[516,11823,11824,11826,11828],{"class":518,"line":1134},[516,11825,8671],{"class":1227},[516,11827,11542],{"class":1749},[516,11829,11830],{"class":3076}," // must use .value here\n",[516,11832,11833],{"class":518,"line":1275},[516,11834,1317],{"class":1227},[516,11836,11837,11839,11841],{"class":518,"line":1302},[516,11838,8589],{"class":1227},[516,11840,8604],{"class":8557},[516,11842,8561],{"class":1227},[516,11844,11845],{"class":518,"line":1308},[516,11846,1131],{"emptyLinePlaceholder":1130},[516,11848,11849,11851,11853],{"class":518,"line":1314},[516,11850,3042],{"class":1227},[516,11852,8558],{"class":8557},[516,11854,8561],{"class":1227},[516,11856,11857,11859,11861,11863,11865,11867,11870,11872],{"class":518,"line":8656},[516,11858,8566],{"class":1227},[516,11860,8569],{"class":8557},[516,11862,8572],{"class":4733},[516,11864,1894],{"class":1227},[516,11866,8577],{"class":1248},[516,11868,11869],{"class":1227},">{{ count }}\u003C/",[516,11871,8569],{"class":8557},[516,11873,8561],{"class":1227},[516,11875,11876],{"class":518,"line":8668},[516,11877,11878],{"class":3076},"    \u003C!-- no .value needed, compiler handles it -->\n",[516,11880,11881,11883,11885],{"class":518,"line":8677},[516,11882,8589],{"class":1227},[516,11884,8558],{"class":8557},[516,11886,8561],{"class":1227},[11,11888,11889,11890,11893,11894,11896,11897,11899,11900,11902],{},"One gotcha: unwrapping only happens for refs that are top-level in the template's data context. A ref nested inside a plain object, like ",[66,11891,11892],{},"state.myRef"," where ",[66,11895,259],{}," is a reactive object, does get auto-unwrapped because ",[66,11898,11445],{}," unwraps nested refs on property access. But a ref inside a plain array or a non-reactive object does not unwrap automatically, you still need ",[66,11901,11449],{}," there.",[23,11904,11906,11907,11909],{"id":11905},"_28-how-is-vue-3s-proxy-based-reactivity-different-from-vue-2s-objectdefineproperty-based-reactivity","28. How is Vue 3's Proxy-based reactivity different from Vue 2's ",[66,11908,8896],{}," based reactivity?",[11,11911,11912,11913,11915,11916,11919,11920,11923,11924,11927,11928,202,11931,11934],{},"Vue 2 made objects reactive by walking every property on them at creation time and replacing each one with a getter/setter pair using ",[66,11914,8896],{},". This approach had real limitations. Because it worked property by property, Vue 2 could not detect new properties added to an object after creation, ",[66,11917,11918],{},"this.obj.newProp = 'x'"," was silently non-reactive unless you used ",[66,11921,11922],{},"Vue.set()",". It also could not detect array index assignment (",[66,11925,11926],{},"arr[0] = 'x'",") or length changes, so Vue 2 had to override array methods like ",[66,11929,11930],{},"push",[66,11932,11933],{},"splice"," with reactive versions instead.",[11,11936,11937,11938,11940],{},"Vue 3 solves both problems by wrapping the entire object in a ",[66,11939,8903],{}," instead of touching individual properties.",[507,11942,11944],{"className":8782,"code":11943,"language":8784,"meta":512,"style":512},"const state = reactive({ count: 0 })\nstate.newProp = 'hello'   // reactive in Vue 3, was not in Vue 2\n\nconst list = reactive([1, 2, 3])\nlist[0] = 99               // reactive in Vue 3, needed Vue.set in Vue 2\nlist.length = 0            // also tracked correctly\n",[66,11945,11946,11962,11975,11979,12007,12025],{"__ignoreMap":512},[516,11947,11948,11950,11952,11954,11956,11958,11960],{"class":518,"line":519},[516,11949,8632],{"class":1749},[516,11951,11481],{"class":1233},[516,11953,1793],{"class":1749},[516,11955,11486],{"class":4733},[516,11957,11489],{"class":1227},[516,11959,8646],{"class":1233},[516,11961,11494],{"class":1227},[516,11963,11964,11967,11969,11972],{"class":518,"line":525},[516,11965,11966],{"class":1227},"state.newProp ",[516,11968,1894],{"class":1749},[516,11970,11971],{"class":1248}," 'hello'",[516,11973,11974],{"class":3076},"   // reactive in Vue 3, was not in Vue 2\n",[516,11976,11977],{"class":518,"line":531},[516,11978,1131],{"emptyLinePlaceholder":1130},[516,11980,11981,11983,11986,11988,11990,11993,11995,11997,11999,12001,12004],{"class":518,"line":1127},[516,11982,8632],{"class":1749},[516,11984,11985],{"class":1233}," list",[516,11987,1793],{"class":1749},[516,11989,11486],{"class":4733},[516,11991,11992],{"class":1227},"([",[516,11994,9945],{"class":1233},[516,11996,154],{"class":1227},[516,11998,9948],{"class":1233},[516,12000,154],{"class":1227},[516,12002,12003],{"class":1233},"3",[516,12005,12006],{"class":1227},"])\n",[516,12008,12009,12012,12014,12017,12019,12022],{"class":518,"line":1134},[516,12010,12011],{"class":1227},"list[",[516,12013,8646],{"class":1233},[516,12015,12016],{"class":1227},"] ",[516,12018,1894],{"class":1749},[516,12020,12021],{"class":1233}," 99",[516,12023,12024],{"class":3076},"               // reactive in Vue 3, needed Vue.set in Vue 2\n",[516,12026,12027,12030,12033,12035,12038],{"class":518,"line":1275},[516,12028,12029],{"class":1227},"list.",[516,12031,12032],{"class":1233},"length",[516,12034,1793],{"class":1749},[516,12036,12037],{"class":1233}," 0",[516,12039,12040],{"class":3076},"            // also tracked correctly\n",[11,12042,12043,12044,154,12047,154,12050,154,12053,12056],{},"A Proxy intercepts operations at the object level (",[66,12045,12046],{},"get",[66,12048,12049],{},"set",[66,12051,12052],{},"has",[66,12054,12055],{},"deleteProperty",", and so on), so any property, whether it existed at creation time or was added later, and any array operation, goes through the same trap. This also means Vue 3 no longer needs to eagerly walk and instrument every nested property up front; conversion happens lazily, only when a nested object is actually accessed, which is also a performance win for large state trees.",[23,12058,12060,12061,12063,12064,12066],{"id":12059},"_29-what-are-the-limitations-of-reactive-that-make-ref-necessary-for-primitives","29. What are the limitations of ",[66,12062,11445],{}," that make ",[66,12065,11453],{}," necessary for primitives?",[11,12068,12069,12071,12072,12074,12075,12078],{},[66,12070,11445],{}," is built on JavaScript's ",[66,12073,8903],{},", and a Proxy can only wrap objects, it has nothing to intercept on a primitive like a number or a string, since primitives are passed by value, not by reference. If ",[66,12076,12077],{},"reactive(0)"," were allowed, there would be no object identity for Vue to attach a Proxy to, so Vue explicitly disallows it (and warns you in development if you try).",[11,12080,12081,12082,12084,12085,12087,12088,12091,12092,12094,12095,12097,12098,12100],{},"This is exactly the gap ",[66,12083,11453],{}," fills. Instead of trying to make the primitive itself reactive, ",[66,12086,11453],{}," wraps it inside an object (",[66,12089,12090],{},"{ value: 0 }",") and makes that wrapper object's ",[66,12093,11449],{}," property reactive using a getter/setter pair. Now there is an object for Vue to track, and reassigning ",[66,12096,11449],{}," triggers updates just like changing a property on a ",[66,12099,11445],{}," object would.",[507,12102,12104],{"className":8782,"code":12103,"language":8784,"meta":512,"style":512},"import { ref } from 'vue'\n\nconst count = ref(0)        // works, wrapped in an object internally\n// const count = reactive(0)  // invalid, warns and just returns 0\n",[66,12105,12106,12116,12120,12140],{"__ignoreMap":512},[516,12107,12108,12110,12112,12114],{"class":518,"line":519},[516,12109,8614],{"class":1749},[516,12111,8617],{"class":1227},[516,12113,8620],{"class":1749},[516,12115,8623],{"class":1248},[516,12117,12118],{"class":518,"line":525},[516,12119,1131],{"emptyLinePlaceholder":1130},[516,12121,12122,12124,12126,12128,12130,12132,12134,12137],{"class":518,"line":531},[516,12123,8632],{"class":1749},[516,12125,8635],{"class":1233},[516,12127,1793],{"class":1749},[516,12129,8640],{"class":4733},[516,12131,8643],{"class":1227},[516,12133,8646],{"class":1233},[516,12135,12136],{"class":1227},")        ",[516,12138,12139],{"class":3076},"// works, wrapped in an object internally\n",[516,12141,12142,12145],{"class":518,"line":1127},[516,12143,12144],{"class":3076},"// const count = reactive(0)",[516,12146,12147],{"class":3076},"  // invalid, warns and just returns 0\n",[11,12149,12150,12151,12153,12154,12156,12157,12159,12160,12162],{},"This is also why ",[66,12152,11453],{}," is the more general tool: it works for primitives, objects, and everything in between (in fact, if you pass an object to ",[66,12155,11453],{},", it internally calls ",[66,12158,11445],{}," on it), whereas ",[66,12161,11445],{}," is strictly limited to object types.",[23,12164,12166,12167,12169,12170,12173],{"id":12165},"_30-what-happens-if-you-destructure-a-reactive-object-and-how-do-torefs-fix-it","30. What happens if you destructure a ",[66,12168,11445],{}," object, and how do ",[66,12171,12172],{},"toRefs"," fix it?",[11,12175,12176,12177,12179],{},"When you destructure a ",[66,12178,11445],{}," object, you pull out the current value of each property as a plain, disconnected variable. That variable is no longer linked to the Proxy, so changing the original state does not update it, and changing the destructured variable does not update the original state either. Reactivity is lost.",[507,12181,12183],{"className":8782,"code":12182,"language":8784,"meta":512,"style":512},"import { reactive } from 'vue'\n\nconst state = reactive({ count: 0, name: 'Vue' })\nconst { count, name } = state\n\nstate.count++\nconsole.log(count) // still 0, not connected anymore\n",[66,12184,12185,12196,12200,12222,12244,12248,12254],{"__ignoreMap":512},[516,12186,12187,12189,12192,12194],{"class":518,"line":519},[516,12188,8614],{"class":1749},[516,12190,12191],{"class":1227}," { reactive } ",[516,12193,8620],{"class":1749},[516,12195,8623],{"class":1248},[516,12197,12198],{"class":518,"line":525},[516,12199,1131],{"emptyLinePlaceholder":1130},[516,12201,12202,12204,12206,12208,12210,12212,12214,12217,12220],{"class":518,"line":531},[516,12203,8632],{"class":1749},[516,12205,11481],{"class":1233},[516,12207,1793],{"class":1749},[516,12209,11486],{"class":4733},[516,12211,11489],{"class":1227},[516,12213,8646],{"class":1233},[516,12215,12216],{"class":1227},", name: ",[516,12218,12219],{"class":1248},"'Vue'",[516,12221,11494],{"class":1227},[516,12223,12224,12226,12229,12232,12234,12236,12239,12241],{"class":518,"line":1127},[516,12225,8632],{"class":1749},[516,12227,12228],{"class":1227}," { ",[516,12230,12231],{"class":1233},"count",[516,12233,154],{"class":1227},[516,12235,189],{"class":1233},[516,12237,12238],{"class":1227}," } ",[516,12240,1894],{"class":1749},[516,12242,12243],{"class":1227}," state\n",[516,12245,12246],{"class":518,"line":1134},[516,12247,1131],{"emptyLinePlaceholder":1130},[516,12249,12250,12252],{"class":518,"line":1275},[516,12251,11539],{"class":1227},[516,12253,8674],{"class":1749},[516,12255,12256,12259,12261,12264],{"class":518,"line":1302},[516,12257,12258],{"class":1227},"console.",[516,12260,11517],{"class":4733},[516,12262,12263],{"class":1227},"(count) ",[516,12265,12266],{"class":3076},"// still 0, not connected anymore\n",[11,12268,12269,12272,12273,12275,12276,12278],{},[66,12270,12271],{},"toRefs()"," fixes this by converting every property on a reactive object into its own individual ",[66,12274,9387],{},", each one linked back to the original source through a getter/setter. Destructuring the result of ",[66,12277,12271],{}," gives you refs, not disconnected values, so the connection survives.",[507,12280,12282],{"className":8782,"code":12281,"language":8784,"meta":512,"style":512},"import { reactive, toRefs } from 'vue'\n\nconst state = reactive({ count: 0, name: 'Vue' })\nconst { count, name } = toRefs(state)\n\nstate.count++\nconsole.log(count.value) // 1, still connected\n",[66,12283,12284,12295,12299,12319,12341,12345,12351],{"__ignoreMap":512},[516,12285,12286,12288,12291,12293],{"class":518,"line":519},[516,12287,8614],{"class":1749},[516,12289,12290],{"class":1227}," { reactive, toRefs } ",[516,12292,8620],{"class":1749},[516,12294,8623],{"class":1248},[516,12296,12297],{"class":518,"line":525},[516,12298,1131],{"emptyLinePlaceholder":1130},[516,12300,12301,12303,12305,12307,12309,12311,12313,12315,12317],{"class":518,"line":531},[516,12302,8632],{"class":1749},[516,12304,11481],{"class":1233},[516,12306,1793],{"class":1749},[516,12308,11486],{"class":4733},[516,12310,11489],{"class":1227},[516,12312,8646],{"class":1233},[516,12314,12216],{"class":1227},[516,12316,12219],{"class":1248},[516,12318,11494],{"class":1227},[516,12320,12321,12323,12325,12327,12329,12331,12333,12335,12338],{"class":518,"line":1127},[516,12322,8632],{"class":1749},[516,12324,12228],{"class":1227},[516,12326,12231],{"class":1233},[516,12328,154],{"class":1227},[516,12330,189],{"class":1233},[516,12332,12238],{"class":1227},[516,12334,1894],{"class":1749},[516,12336,12337],{"class":4733}," toRefs",[516,12339,12340],{"class":1227},"(state)\n",[516,12342,12343],{"class":518,"line":1134},[516,12344,1131],{"emptyLinePlaceholder":1130},[516,12346,12347,12349],{"class":518,"line":1275},[516,12348,11539],{"class":1227},[516,12350,8674],{"class":1749},[516,12352,12353,12355,12357,12360],{"class":518,"line":1302},[516,12354,12258],{"class":1227},[516,12356,11517],{"class":4733},[516,12358,12359],{"class":1227},"(count.value) ",[516,12361,12362],{"class":3076},"// 1, still connected\n",[11,12364,12365,12366,12369,12370,12373],{},"This pattern shows up constantly in composables. If a composable returns a ",[66,12367,12368],{},"reactive"," object directly and the caller destructures it, reactivity breaks silently with no error. Returning ",[66,12371,12372],{},"toRefs(state)"," (or a plain object of individual refs) instead means the caller can safely destructure without losing the connection to the underlying state.",[23,12375,12377,12378,202,12381,9728],{"id":12376},"_31-what-is-the-difference-between-toref-and-torefs","31. What is the difference between ",[66,12379,12380],{},"toRef",[66,12382,12172],{},[11,12384,12385,12388,12389,12391],{},[66,12386,12387],{},"toRef()"," creates a single ref linked to one property of a reactive object (or a ref linked to any getter/setter pair, or even a plain default value). ",[66,12390,12271],{}," does the same thing but for every property on a reactive object at once, returning a plain object full of refs.",[507,12393,12395],{"className":8782,"code":12394,"language":8784,"meta":512,"style":512},"import { reactive, toRef, toRefs } from 'vue'\n\nconst state = reactive({ count: 0, name: 'Vue' })\n\nconst countRef = toRef(state, 'count')     // just one property\nconst refs = toRefs(state)                  // { count: Ref, name: Ref }\n",[66,12396,12397,12408,12412,12432,12436,12460],{"__ignoreMap":512},[516,12398,12399,12401,12404,12406],{"class":518,"line":519},[516,12400,8614],{"class":1749},[516,12402,12403],{"class":1227}," { reactive, toRef, toRefs } ",[516,12405,8620],{"class":1749},[516,12407,8623],{"class":1248},[516,12409,12410],{"class":518,"line":525},[516,12411,1131],{"emptyLinePlaceholder":1130},[516,12413,12414,12416,12418,12420,12422,12424,12426,12428,12430],{"class":518,"line":531},[516,12415,8632],{"class":1749},[516,12417,11481],{"class":1233},[516,12419,1793],{"class":1749},[516,12421,11486],{"class":4733},[516,12423,11489],{"class":1227},[516,12425,8646],{"class":1233},[516,12427,12216],{"class":1227},[516,12429,12219],{"class":1248},[516,12431,11494],{"class":1227},[516,12433,12434],{"class":518,"line":1127},[516,12435,1131],{"emptyLinePlaceholder":1130},[516,12437,12438,12440,12443,12445,12448,12451,12454,12457],{"class":518,"line":1134},[516,12439,8632],{"class":1749},[516,12441,12442],{"class":1233}," countRef",[516,12444,1793],{"class":1749},[516,12446,12447],{"class":4733}," toRef",[516,12449,12450],{"class":1227},"(state, ",[516,12452,12453],{"class":1248},"'count'",[516,12455,12456],{"class":1227},")     ",[516,12458,12459],{"class":3076},"// just one property\n",[516,12461,12462,12464,12467,12469,12471,12474],{"class":518,"line":1275},[516,12463,8632],{"class":1749},[516,12465,12466],{"class":1233}," refs",[516,12468,1793],{"class":1749},[516,12470,12337],{"class":4733},[516,12472,12473],{"class":1227},"(state)                  ",[516,12475,12476],{"class":3076},"// { count: Ref, name: Ref }\n",[11,12478,12479,12480,12482,12483,12486,12487,12489,12490,12493,12494,12496,12497,12493,12499,405],{},"Use ",[66,12481,12387],{}," when you only need to pass one property of a reactive object down to a child component or a composable while keeping it linked to the source, for example ",[66,12484,12485],{},"toRef(props, 'modelValue')",". Use ",[66,12488,12271],{}," when you want to destructure the whole object at once, most commonly at the end of a composable function so callers can pull out individual pieces with object destructuring without losing reactivity. Both directions stay live: writing to ",[66,12491,12492],{},"countRef.value"," updates ",[66,12495,11539],{},", and writing to ",[66,12498,11539],{},[66,12500,12492],{},[23,12502,12504,12505,12508],{"id":12503},"_32-what-does-readonly-do-and-when-would-you-wrap-a-value-with-it","32. What does ",[66,12506,12507],{},"readonly()"," do, and when would you wrap a value with it?",[11,12510,12511,12513],{},[66,12512,12507],{}," takes a reactive object (or a plain object, or even a ref) and returns a new proxy where every mutation attempt is intercepted and blocked. In development, trying to write to a readonly value logs a warning and the write is silently ignored; in production the warning is stripped but the write still does nothing. Reads still work normally, and the readonly version still tracks dependencies and updates the UI when the underlying source changes.",[507,12515,12517],{"className":8782,"code":12516,"language":8784,"meta":512,"style":512},"import { reactive, readonly } from 'vue'\n\nconst original = reactive({ count: 0 })\nconst copy = readonly(original)\n\ncopy.count++       // warns in dev, does nothing\noriginal.count++   // this still works, and copy.count reflects it too\n",[66,12518,12519,12530,12534,12551,12566,12570,12580],{"__ignoreMap":512},[516,12520,12521,12523,12526,12528],{"class":518,"line":519},[516,12522,8614],{"class":1749},[516,12524,12525],{"class":1227}," { reactive, readonly } ",[516,12527,8620],{"class":1749},[516,12529,8623],{"class":1248},[516,12531,12532],{"class":518,"line":525},[516,12533,1131],{"emptyLinePlaceholder":1130},[516,12535,12536,12538,12541,12543,12545,12547,12549],{"class":518,"line":531},[516,12537,8632],{"class":1749},[516,12539,12540],{"class":1233}," original",[516,12542,1793],{"class":1749},[516,12544,11486],{"class":4733},[516,12546,11489],{"class":1227},[516,12548,8646],{"class":1233},[516,12550,11494],{"class":1227},[516,12552,12553,12555,12558,12560,12563],{"class":518,"line":1127},[516,12554,8632],{"class":1749},[516,12556,12557],{"class":1233}," copy",[516,12559,1793],{"class":1749},[516,12561,12562],{"class":4733}," readonly",[516,12564,12565],{"class":1227},"(original)\n",[516,12567,12568],{"class":518,"line":1134},[516,12569,1131],{"emptyLinePlaceholder":1130},[516,12571,12572,12575,12577],{"class":518,"line":1275},[516,12573,12574],{"class":1227},"copy.count",[516,12576,11542],{"class":1749},[516,12578,12579],{"class":3076},"       // warns in dev, does nothing\n",[516,12581,12582,12585,12587],{"class":518,"line":1302},[516,12583,12584],{"class":1227},"original.count",[516,12586,11542],{"class":1749},[516,12588,12589],{"class":3076},"   // this still works, and copy.count reflects it too\n",[11,12591,12592],{},"The main use case is enforcing one-way data flow. A common pattern is a composable or a store that owns some state internally and wants to expose it to the rest of the app without letting outside code mutate it directly, forcing all changes to go through explicit functions or actions instead.",[507,12594,12596],{"className":8782,"code":12595,"language":8784,"meta":512,"style":512},"function useCounter() {\n    const state = reactive({ count: 0 })\n    function increment() {\n        state.count++\n    }\n    return {\n        state: readonly(state),\n        increment\n    }\n}\n",[66,12597,12598,12607,12624,12633,12640,12644,12650,12661,12666,12670],{"__ignoreMap":512},[516,12599,12600,12602,12605],{"class":518,"line":519},[516,12601,8659],{"class":1749},[516,12603,12604],{"class":4733}," useCounter",[516,12606,8665],{"class":1227},[516,12608,12609,12612,12614,12616,12618,12620,12622],{"class":518,"line":525},[516,12610,12611],{"class":1749},"    const",[516,12613,11481],{"class":1233},[516,12615,1793],{"class":1749},[516,12617,11486],{"class":4733},[516,12619,11489],{"class":1227},[516,12621,8646],{"class":1233},[516,12623,11494],{"class":1227},[516,12625,12626,12629,12631],{"class":518,"line":531},[516,12627,12628],{"class":1749},"    function",[516,12630,8662],{"class":4733},[516,12632,8665],{"class":1227},[516,12634,12635,12638],{"class":518,"line":1127},[516,12636,12637],{"class":1227},"        state.count",[516,12639,8674],{"class":1749},[516,12641,12642],{"class":518,"line":1134},[516,12643,9253],{"class":1227},[516,12645,12646,12648],{"class":518,"line":1275},[516,12647,9089],{"class":1749},[516,12649,8713],{"class":1227},[516,12651,12652,12655,12658],{"class":518,"line":1302},[516,12653,12654],{"class":1227},"        state: ",[516,12656,12657],{"class":4733},"readonly",[516,12659,12660],{"class":1227},"(state),\n",[516,12662,12663],{"class":518,"line":1308},[516,12664,12665],{"class":1227},"        increment\n",[516,12667,12668],{"class":518,"line":1314},[516,12669,9253],{"class":1227},[516,12671,12672],{"class":518,"line":8656},[516,12673,1317],{"class":1227},[11,12675,12676,12677,12680],{},"This is also exactly how ",[66,12678,12679],{},"props"," behave by default in Vue components: a child receives readonly reactive props precisely so it cannot accidentally mutate state that the parent owns.",[23,12682,12684,12685,2958,12688,12691],{"id":12683},"_33-what-is-the-difference-between-shallowrefshallowreactive-and-their-deep-versions","33. What is the difference between ",[66,12686,12687],{},"shallowRef",[66,12689,12690],{},"shallowReactive"," and their deep versions?",[11,12693,12694,12695,202,12697,12699,12700,12703],{},"By default, ",[66,12696,11453],{},[66,12698,11445],{}," are deep: if you give them a nested object, Vue recursively makes every nested property reactive too, so changing ",[66,12701,12702],{},"state.user.address.city"," still triggers updates. That recursive conversion has a cost, especially for large or deeply nested objects.",[11,12705,12706,12709,12710,12712,12713,12716],{},[66,12707,12708],{},"shallowRef()"," only makes the ",[66,12711,11449],{}," assignment itself reactive; it does not touch anything inside the value. ",[66,12714,12715],{},"shallowReactive()"," only makes the top-level properties reactive; nested objects inside it stay as plain, non-reactive objects.",[507,12718,12720],{"className":8782,"code":12719,"language":8784,"meta":512,"style":512},"import { shallowRef, shallowReactive } from 'vue'\n\nconst state = shallowRef({ user: { name: 'Kashyap' } })\nstate.value.user.name = 'Changed' // does NOT trigger an update\nstate.value = { user: { name: 'New' } } // this DOES trigger an update\n\nconst obj = shallowReactive({ nested: { count: 0 } })\nobj.nested.count++  // does NOT trigger an update\nobj.nested = { count: 1 } // this DOES trigger an update\n",[66,12721,12722,12733,12737,12757,12770,12789,12793,12812,12822],{"__ignoreMap":512},[516,12723,12724,12726,12729,12731],{"class":518,"line":519},[516,12725,8614],{"class":1749},[516,12727,12728],{"class":1227}," { shallowRef, shallowReactive } ",[516,12730,8620],{"class":1749},[516,12732,8623],{"class":1248},[516,12734,12735],{"class":518,"line":525},[516,12736,1131],{"emptyLinePlaceholder":1130},[516,12738,12739,12741,12743,12745,12748,12751,12754],{"class":518,"line":531},[516,12740,8632],{"class":1749},[516,12742,11481],{"class":1233},[516,12744,1793],{"class":1749},[516,12746,12747],{"class":4733}," shallowRef",[516,12749,12750],{"class":1227},"({ user: { name: ",[516,12752,12753],{"class":1248},"'Kashyap'",[516,12755,12756],{"class":1227}," } })\n",[516,12758,12759,12762,12764,12767],{"class":518,"line":1127},[516,12760,12761],{"class":1227},"state.value.user.name ",[516,12763,1894],{"class":1749},[516,12765,12766],{"class":1248}," 'Changed'",[516,12768,12769],{"class":3076}," // does NOT trigger an update\n",[516,12771,12772,12775,12777,12780,12783,12786],{"class":518,"line":1134},[516,12773,12774],{"class":1227},"state.value ",[516,12776,1894],{"class":1749},[516,12778,12779],{"class":1227}," { user: { name: ",[516,12781,12782],{"class":1248},"'New'",[516,12784,12785],{"class":1227}," } } ",[516,12787,12788],{"class":3076},"// this DOES trigger an update\n",[516,12790,12791],{"class":518,"line":1275},[516,12792,1131],{"emptyLinePlaceholder":1130},[516,12794,12795,12797,12800,12802,12805,12808,12810],{"class":518,"line":1302},[516,12796,8632],{"class":1749},[516,12798,12799],{"class":1233}," obj",[516,12801,1793],{"class":1749},[516,12803,12804],{"class":4733}," shallowReactive",[516,12806,12807],{"class":1227},"({ nested: { count: ",[516,12809,8646],{"class":1233},[516,12811,12756],{"class":1227},[516,12813,12814,12817,12819],{"class":518,"line":1308},[516,12815,12816],{"class":1227},"obj.nested.count",[516,12818,11542],{"class":1749},[516,12820,12821],{"class":3076},"  // does NOT trigger an update\n",[516,12823,12824,12827,12829,12832,12834,12836],{"class":518,"line":1314},[516,12825,12826],{"class":1227},"obj.nested ",[516,12828,1894],{"class":1749},[516,12830,12831],{"class":1227}," { count: ",[516,12833,9945],{"class":1233},[516,12835,12238],{"class":1227},[516,12837,12788],{"class":3076},[11,12839,12840],{},"The typical use case is performance: large data structures you receive from an API and treat as immutable blobs (only ever replaced wholesale, never mutated piece by piece), or integrating with external state management or non-Vue libraries where you do not want Vue's reactivity conversion overhead applied to every nested field. If you find yourself mutating deep inside a shallow value and expecting the UI to update, that is the tell that you reached for the wrong one.",[23,12842,12844,12845,11199],{"id":12843},"_34-what-is-markraw-and-when-would-you-use-it","34. What is ",[66,12846,12847],{},"markRaw()",[11,12849,12850,12852,12853,12855],{},[66,12851,12847],{}," marks an object so that Vue's reactivity system will never convert it into a reactive Proxy, even if you later pass it into ",[66,12854,11445],{},". It permanently opts that specific object out of tracking.",[507,12857,12859],{"className":8782,"code":12858,"language":8784,"meta":512,"style":512},"import { reactive, markRaw } from 'vue'\n\nclass HeavyThirdPartyInstance {\n    // some large external library instance\n}\n\nconst state = reactive({\n    instance: markRaw(new HeavyThirdPartyInstance())\n})\n\nstate.instance // plain object, never wrapped in a Proxy\n",[66,12860,12861,12872,12876,12885,12890,12894,12898,12911,12929,12933,12937],{"__ignoreMap":512},[516,12862,12863,12865,12868,12870],{"class":518,"line":519},[516,12864,8614],{"class":1749},[516,12866,12867],{"class":1227}," { reactive, markRaw } ",[516,12869,8620],{"class":1749},[516,12871,8623],{"class":1248},[516,12873,12874],{"class":518,"line":525},[516,12875,1131],{"emptyLinePlaceholder":1130},[516,12877,12878,12880,12883],{"class":518,"line":531},[516,12879,10106],{"class":1749},[516,12881,12882],{"class":4733}," HeavyThirdPartyInstance",[516,12884,8713],{"class":1227},[516,12886,12887],{"class":518,"line":1127},[516,12888,12889],{"class":3076},"    // some large external library instance\n",[516,12891,12892],{"class":518,"line":1134},[516,12893,1317],{"class":1227},[516,12895,12896],{"class":518,"line":1275},[516,12897,1131],{"emptyLinePlaceholder":1130},[516,12899,12900,12902,12904,12906,12908],{"class":518,"line":1302},[516,12901,8632],{"class":1749},[516,12903,11481],{"class":1233},[516,12905,1793],{"class":1749},[516,12907,11486],{"class":4733},[516,12909,12910],{"class":1227},"({\n",[516,12912,12913,12916,12919,12921,12924,12926],{"class":518,"line":1308},[516,12914,12915],{"class":1227},"    instance: ",[516,12917,12918],{"class":4733},"markRaw",[516,12920,8643],{"class":1227},[516,12922,12923],{"class":1749},"new",[516,12925,12882],{"class":4733},[516,12927,12928],{"class":1227},"())\n",[516,12930,12931],{"class":518,"line":1314},[516,12932,11530],{"class":1227},[516,12934,12935],{"class":518,"line":8656},[516,12936,1131],{"emptyLinePlaceholder":1130},[516,12938,12939,12942],{"class":518,"line":8668},[516,12940,12941],{"class":1227},"state.instance ",[516,12943,12944],{"class":3076},"// plain object, never wrapped in a Proxy\n",[11,12946,12947,12948,12951,12952,12954],{},"This matters for two reasons. First, performance: wrapping large complex objects (like a charting library instance, a map instance, or a big class hierarchy) in a reactive Proxy adds tracking overhead for no benefit if you never need Vue to react to changes on it. Second, and more importantly, some third party objects genuinely break when wrapped in a Proxy, because the library does internal identity checks (",[66,12949,12950],{},"===",") that fail once the object is a Proxy wrapper rather than the original instance, or because the library's internal methods do not expect to be called through a Proxy. ",[66,12953,12847],{}," is the escape hatch for storing these kinds of objects inside otherwise reactive state without either problem.",[23,12956,12958,12959,154,12962,157,12965,706],{"id":12957},"_35-what-do-isref-unref-and-tovalue-do","35. What do ",[66,12960,12961],{},"isRef",[66,12963,12964],{},"unref",[66,12966,12967],{},"toValue",[11,12969,12970],{},"These are small utility functions for writing code, usually composables, that needs to work with values that might or might not be refs.",[11,12972,12973,12976,12977,756,12979,12982],{},[66,12974,12975],{},"isRef(value)"," is a type guard that tells you whether something is a ref, returning ",[66,12978,10228],{},[66,12980,12981],{},"false",". It is mostly used in composables that accept flexible arguments and need to branch based on what they were given.",[11,12984,12985,12988,12989,12992,12993,12996,12997,12999,13000,13003],{},[66,12986,12987],{},"unref(value)"," returns ",[66,12990,12991],{},"value.value"," if ",[66,12994,12995],{},"value"," is a ref, or returns ",[66,12998,12995],{}," unchanged if it is not. It is shorthand for ",[66,13001,13002],{},"isRef(value) ? value.value : value",", letting you safely read a value without knowing in advance if it was passed as a ref or a plain value.",[507,13005,13007],{"className":8782,"code":13006,"language":8784,"meta":512,"style":512},"import { ref, isRef, unref } from 'vue'\n\nfunction double(x) {\n    return unref(x) * 2\n}\n\ndouble(4)       // 8\ndouble(ref(4))  // 8, unwraps automatically\n",[66,13008,13009,13020,13024,13038,13054,13058,13062,13078],{"__ignoreMap":512},[516,13010,13011,13013,13016,13018],{"class":518,"line":519},[516,13012,8614],{"class":1749},[516,13014,13015],{"class":1227}," { ref, isRef, unref } ",[516,13017,8620],{"class":1749},[516,13019,8623],{"class":1248},[516,13021,13022],{"class":518,"line":525},[516,13023,1131],{"emptyLinePlaceholder":1130},[516,13025,13026,13028,13031,13033,13036],{"class":518,"line":531},[516,13027,8659],{"class":1749},[516,13029,13030],{"class":4733}," double",[516,13032,8643],{"class":1227},[516,13034,13035],{"class":9080},"x",[516,13037,9084],{"class":1227},[516,13039,13040,13042,13045,13048,13051],{"class":518,"line":1127},[516,13041,9089],{"class":1749},[516,13043,13044],{"class":4733}," unref",[516,13046,13047],{"class":1227},"(x) ",[516,13049,13050],{"class":1749},"*",[516,13052,13053],{"class":1233}," 2\n",[516,13055,13056],{"class":518,"line":1134},[516,13057,1317],{"class":1227},[516,13059,13060],{"class":518,"line":1275},[516,13061,1131],{"emptyLinePlaceholder":1130},[516,13063,13064,13067,13069,13072,13075],{"class":518,"line":1302},[516,13065,13066],{"class":4733},"double",[516,13068,8643],{"class":1227},[516,13070,13071],{"class":1233},"4",[516,13073,13074],{"class":1227},")       ",[516,13076,13077],{"class":3076},"// 8\n",[516,13079,13080,13082,13084,13086,13088,13090,13093],{"class":518,"line":1308},[516,13081,13066],{"class":4733},[516,13083,8643],{"class":1227},[516,13085,9387],{"class":4733},[516,13087,8643],{"class":1227},[516,13089,13071],{"class":1233},[516,13091,13092],{"class":1227},"))  ",[516,13094,13095],{"class":3076},"// 8, unwraps automatically\n",[11,13097,13098,13101,13102,13105,13106,756,13108,13110,13111,13113],{},[66,13099,13100],{},"toValue()"," does something similar to ",[66,13103,13104],{},"unref()"," but goes a step further: it also unwraps getter functions, calling them if the input is a function, and it is reactive, meaning if you use it inside an ",[66,13107,11503],{},[66,13109,9012],{},", it will re-track dependencies correctly even as the source changes. This makes ",[66,13112,13100],{}," the recommended way to normalize arguments in composables, since it accepts a plain value, a ref, or a getter function and always gives you the current value back.",[507,13115,13117],{"className":8782,"code":13116,"language":8784,"meta":512,"style":512},"import { toValue } from 'vue'\n\nfunction useFeature(source) {\n    watchEffect(() => {\n        const value = toValue(source) // works whether source is a value, a ref, or () => something\n        console.log(value)\n    })\n}\n",[66,13118,13119,13130,13134,13148,13159,13177,13187,13192],{"__ignoreMap":512},[516,13120,13121,13123,13126,13128],{"class":518,"line":519},[516,13122,8614],{"class":1749},[516,13124,13125],{"class":1227}," { toValue } ",[516,13127,8620],{"class":1749},[516,13129,8623],{"class":1248},[516,13131,13132],{"class":518,"line":525},[516,13133,1131],{"emptyLinePlaceholder":1130},[516,13135,13136,13138,13141,13143,13146],{"class":518,"line":531},[516,13137,8659],{"class":1749},[516,13139,13140],{"class":4733}," useFeature",[516,13142,8643],{"class":1227},[516,13144,13145],{"class":9080},"source",[516,13147,9084],{"class":1227},[516,13149,13150,13153,13155,13157],{"class":518,"line":1127},[516,13151,13152],{"class":4733},"    watchEffect",[516,13154,11033],{"class":1227},[516,13156,11036],{"class":1749},[516,13158,8713],{"class":1227},[516,13160,13161,13163,13166,13168,13171,13174],{"class":518,"line":1134},[516,13162,9207],{"class":1749},[516,13164,13165],{"class":1233}," value",[516,13167,1793],{"class":1749},[516,13169,13170],{"class":4733}," toValue",[516,13172,13173],{"class":1227},"(source) ",[516,13175,13176],{"class":3076},"// works whether source is a value, a ref, or () => something\n",[516,13178,13179,13182,13184],{"class":518,"line":1275},[516,13180,13181],{"class":1227},"        console.",[516,13183,11517],{"class":4733},[516,13185,13186],{"class":1227},"(value)\n",[516,13188,13189],{"class":518,"line":1302},[516,13190,13191],{"class":1227},"    })\n",[516,13193,13194],{"class":518,"line":1308},[516,13195,1317],{"class":1227},[23,13197,13199,13200,13203],{"id":13198},"_36-what-is-nexttick-and-why-do-you-sometimes-need-it-after-changing-reactive-state","36. What is ",[66,13201,13202],{},"nextTick()",", and why do you sometimes need it after changing reactive state?",[11,13205,13206],{},"Vue does not update the DOM the instant you change reactive state. Instead, it batches updates: if you change several reactive properties in the same tick of the event loop, Vue queues a single re-render and flushes it asynchronously, rather than re-rendering after every individual assignment. This is a deliberate performance optimization, since re-rendering the DOM synchronously on every single mutation would be wasteful if you are about to change ten more properties right after.",[11,13208,13209,13211],{},[66,13210,13202],{}," returns a promise that resolves after Vue has finished flushing its update queue and the DOM has actually been patched to reflect the new state. You use it whenever you need to read something from the DOM (like an element's height, or its scroll position) immediately after a state change that affects that element.",[507,13213,13215],{"className":8546,"code":13214,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, nextTick } from 'vue'\n\nconst show = ref(false)\nconst box = ref(null)\n\nasync function reveal() {\n    show.value = true\n    // at this point, the DOM has not updated yet, box.value has no height\n    await nextTick()\n    // now the DOM is updated, safe to measure\n    console.log(box.value.offsetHeight)\n}\n\u003C/script>\n",[66,13216,13217,13227,13238,13242,13259,13276,13280,13293,13303,13308,13319,13324,13333,13337],{"__ignoreMap":512},[516,13218,13219,13221,13223,13225],{"class":518,"line":519},[516,13220,3042],{"class":1227},[516,13222,8604],{"class":8557},[516,13224,8607],{"class":4733},[516,13226,8561],{"class":1227},[516,13228,13229,13231,13234,13236],{"class":518,"line":525},[516,13230,8614],{"class":1749},[516,13232,13233],{"class":1227}," { ref, nextTick } ",[516,13235,8620],{"class":1749},[516,13237,8623],{"class":1248},[516,13239,13240],{"class":518,"line":531},[516,13241,1131],{"emptyLinePlaceholder":1130},[516,13243,13244,13246,13249,13251,13253,13255,13257],{"class":518,"line":1127},[516,13245,8632],{"class":1749},[516,13247,13248],{"class":1233}," show",[516,13250,1793],{"class":1749},[516,13252,8640],{"class":4733},[516,13254,8643],{"class":1227},[516,13256,12981],{"class":1233},[516,13258,8649],{"class":1227},[516,13260,13261,13263,13266,13268,13270,13272,13274],{"class":518,"line":1134},[516,13262,8632],{"class":1749},[516,13264,13265],{"class":1233}," box",[516,13267,1793],{"class":1749},[516,13269,8640],{"class":4733},[516,13271,8643],{"class":1227},[516,13273,9102],{"class":1233},[516,13275,8649],{"class":1227},[516,13277,13278],{"class":518,"line":1275},[516,13279,1131],{"emptyLinePlaceholder":1130},[516,13281,13282,13285,13288,13291],{"class":518,"line":1302},[516,13283,13284],{"class":1749},"async",[516,13286,13287],{"class":1749}," function",[516,13289,13290],{"class":4733}," reveal",[516,13292,8665],{"class":1227},[516,13294,13295,13298,13300],{"class":518,"line":1308},[516,13296,13297],{"class":1227},"    show.value ",[516,13299,1894],{"class":1749},[516,13301,13302],{"class":1233}," true\n",[516,13304,13305],{"class":518,"line":1314},[516,13306,13307],{"class":3076},"    // at this point, the DOM has not updated yet, box.value has no height\n",[516,13309,13310,13313,13316],{"class":518,"line":8656},[516,13311,13312],{"class":1749},"    await",[516,13314,13315],{"class":4733}," nextTick",[516,13317,13318],{"class":1227},"()\n",[516,13320,13321],{"class":518,"line":8668},[516,13322,13323],{"class":3076},"    // now the DOM is updated, safe to measure\n",[516,13325,13326,13328,13330],{"class":518,"line":8677},[516,13327,11514],{"class":1227},[516,13329,11517],{"class":4733},[516,13331,13332],{"class":1227},"(box.value.offsetHeight)\n",[516,13334,13335],{"class":518,"line":8682},[516,13336,1317],{"class":1227},[516,13338,13339,13341,13343],{"class":518,"line":8691},[516,13340,8589],{"class":1227},[516,13342,8604],{"class":8557},[516,13344,8561],{"class":1227},[11,13346,13347,13348,13351,13352,13355,13356,13359,13360,13362],{},"Without ",[66,13349,13350],{},"await nextTick()",", reading ",[66,13353,13354],{},"box.value.offsetHeight"," right after ",[66,13357,13358],{},"show.value = true"," would give you stale measurements, because the ",[66,13361,9724],{}," that reveals the element has not actually run yet in the DOM.",[23,13364,13366],{"id":13365},"_37-how-does-vue-know-which-parts-of-the-dom-to-update-when-reactive-state-changes","37. How does Vue know which parts of the DOM to update when reactive state changes?",[11,13368,13369],{},"Vue does not diff the entire DOM tree blindly on every change. It compiles each component's template into a render function, and when that render function runs, Vue builds a virtual DOM tree, a lightweight JavaScript object representation of what the real DOM should look like. On the next render, Vue compares (diffs) the new virtual DOM tree against the previous one, and only applies the minimal set of real DOM operations needed to make the actual DOM match.",[11,13371,13372,13373,13375,13376,154,13378,13381],{},"Reactivity is what decides when to re-run that render function in the first place. Every component's render function is wrapped in a reactive ",[66,13374,11503],{},". While it runs, Vue records every reactive property it read, ",[66,13377,11615],{},[66,13379,13380],{},"state.name",", and so on, building a dependency map. When one of those exact properties changes later, Vue looks up which effects depend on it and re-runs only those, not every component in the app.",[11,13383,13384],{},"Vue 3's compiler also adds an optimization on top of the raw virtual DOM diff called static analysis: at compile time, it can see which parts of a template are static (never change) and which are dynamic (bound to reactive data), and it marks the dynamic ones with \"patch flags.\" At render time, Vue skips comparing static nodes entirely and jumps straight to patching only the flagged dynamic bindings. This is why Vue 3's rendering is noticeably faster than a naive virtual DOM diff: reactivity narrows down which components re-render, and compiler flags narrow down which parts of those components actually get touched in the DOM.",[23,13386,13388],{"id":13387},"_38-what-is-an-effect-in-vues-reactivity-system","38. What is an \"effect\" in Vue's reactivity system?",[11,13390,13391,13392,154,13394,154,13397,13400],{},"An effect is a piece of code that Vue re-runs automatically whenever a reactive value it depends on changes. It is the core primitive that everything else in Vue's reactivity is built on top of, ",[66,13393,9012],{},[66,13395,13396],{},"watch",[66,13398,13399],{},"watchEffect",", and even component rendering are all effects under the hood.",[11,13402,13403,13404,13406,13407,13410,13411,13414,13415,13418,13419,13421],{},"The low-level function is ",[66,13405,11550],{},", exported from ",[66,13408,13409],{},"@vue/reactivity"," (not typically something you call directly in application code, but useful for understanding the mechanism). When you call ",[66,13412,13413],{},"effect(fn)",", Vue runs ",[66,13416,13417],{},"fn"," immediately, and while it runs, tracks every reactive property that gets read inside it. Vue then subscribes that effect to each of those properties. The next time any of them changes, Vue re-runs ",[66,13420,13417],{}," automatically.",[507,13423,13425],{"className":8782,"code":13424,"language":8784,"meta":512,"style":512},"import { reactive, effect } from 'vue'\n\nconst state = reactive({ count: 0 })\n\neffect(() => {\n    console.log('count changed to', state.count)\n})\n\nstate.count = 5 // effect re-runs, logs \"count changed to 5\"\n",[66,13426,13427,13437,13441,13457,13461,13471,13484,13488,13492],{"__ignoreMap":512},[516,13428,13429,13431,13433,13435],{"class":518,"line":519},[516,13430,8614],{"class":1749},[516,13432,11466],{"class":1227},[516,13434,8620],{"class":1749},[516,13436,8623],{"class":1248},[516,13438,13439],{"class":518,"line":525},[516,13440,1131],{"emptyLinePlaceholder":1130},[516,13442,13443,13445,13447,13449,13451,13453,13455],{"class":518,"line":531},[516,13444,8632],{"class":1749},[516,13446,11481],{"class":1233},[516,13448,1793],{"class":1749},[516,13450,11486],{"class":4733},[516,13452,11489],{"class":1227},[516,13454,8646],{"class":1233},[516,13456,11494],{"class":1227},[516,13458,13459],{"class":518,"line":1127},[516,13460,1131],{"emptyLinePlaceholder":1130},[516,13462,13463,13465,13467,13469],{"class":518,"line":1134},[516,13464,11503],{"class":4733},[516,13466,11033],{"class":1227},[516,13468,11036],{"class":1749},[516,13470,8713],{"class":1227},[516,13472,13473,13475,13477,13479,13482],{"class":518,"line":1275},[516,13474,11514],{"class":1227},[516,13476,11517],{"class":4733},[516,13478,8643],{"class":1227},[516,13480,13481],{"class":1248},"'count changed to'",[516,13483,11525],{"class":1227},[516,13485,13486],{"class":518,"line":1302},[516,13487,11530],{"class":1227},[516,13489,13490],{"class":518,"line":1308},[516,13491,1131],{"emptyLinePlaceholder":1130},[516,13493,13494,13497,13499,13502],{"class":518,"line":1314},[516,13495,13496],{"class":1227},"state.count ",[516,13498,1894],{"class":1749},[516,13500,13501],{"class":1233}," 5",[516,13503,13504],{"class":3076}," // effect re-runs, logs \"count changed to 5\"\n",[11,13506,13507,13510,13511,13513],{},[66,13508,13509],{},"watchEffect()"," is essentially a thin, component-lifecycle-aware wrapper around this same ",[66,13512,11550],{}," mechanism: it runs your function immediately, tracks dependencies automatically, and cleans itself up when the component unmounts. Understanding that render functions, watchers, and computed properties are all \"just effects\" underneath is the key to understanding why Vue's reactivity feels automatic: you never manually subscribe to anything, reading a value inside any of these effect-based APIs is the subscription.",[23,13515,13517,13518,13521],{"id":13516},"_39-what-is-effectscope-and-when-would-you-reach-for-it","39. What is ",[66,13519,13520],{},"effectScope()",", and when would you reach for it?",[11,13523,13524,13526,13527,13529,13530,2958,13532,13534],{},[66,13525,13520],{}," groups multiple reactive effects, ",[66,13528,9012],{}," properties, and ",[66,13531,13396],{},[66,13533,13399],{}," calls together so they can all be stopped, cleaned up, and garbage collected as one unit, instead of you having to track and stop each one individually.",[11,13536,13537,13538,2846,13540,13542,13543,13545],{},"Normally, when effects are created inside a component's ",[66,13539,9351],{},[66,13541,8448],{},"), Vue automatically binds their lifecycle to that component and disposes of them when the component unmounts, so you rarely think about this. But composables that create watchers or computed values outside of a component's setup context, for example inside a plugin, a store, or a standalone utility that is not itself a component, do not get that automatic cleanup. ",[66,13544,13520],{}," is the manual tool for that situation.",[507,13547,13549],{"className":8782,"code":13548,"language":8784,"meta":512,"style":512},"import { effectScope, ref, watch, computed } from 'vue'\n\nconst scope = effectScope()\n\nscope.run(() => {\n    const count = ref(0)\n    const double = computed(() => count.value * 2)\n    watch(count, (val) => console.log('count is', val))\n})\n\n// later, stop everything created inside the scope at once\nscope.stop()\n",[66,13550,13551,13562,13566,13580,13584,13598,13614,13637,13665,13669,13673,13678],{"__ignoreMap":512},[516,13552,13553,13555,13558,13560],{"class":518,"line":519},[516,13554,8614],{"class":1749},[516,13556,13557],{"class":1227}," { effectScope, ref, watch, computed } ",[516,13559,8620],{"class":1749},[516,13561,8623],{"class":1248},[516,13563,13564],{"class":518,"line":525},[516,13565,1131],{"emptyLinePlaceholder":1130},[516,13567,13568,13570,13573,13575,13578],{"class":518,"line":531},[516,13569,8632],{"class":1749},[516,13571,13572],{"class":1233}," scope",[516,13574,1793],{"class":1749},[516,13576,13577],{"class":4733}," effectScope",[516,13579,13318],{"class":1227},[516,13581,13582],{"class":518,"line":1127},[516,13583,1131],{"emptyLinePlaceholder":1130},[516,13585,13586,13589,13592,13594,13596],{"class":518,"line":1134},[516,13587,13588],{"class":1227},"scope.",[516,13590,13591],{"class":4733},"run",[516,13593,11033],{"class":1227},[516,13595,11036],{"class":1749},[516,13597,8713],{"class":1227},[516,13599,13600,13602,13604,13606,13608,13610,13612],{"class":518,"line":1275},[516,13601,12611],{"class":1749},[516,13603,8635],{"class":1233},[516,13605,1793],{"class":1749},[516,13607,8640],{"class":4733},[516,13609,8643],{"class":1227},[516,13611,8646],{"class":1233},[516,13613,8649],{"class":1227},[516,13615,13616,13618,13620,13622,13624,13626,13628,13631,13633,13635],{"class":518,"line":1302},[516,13617,12611],{"class":1749},[516,13619,13030],{"class":1233},[516,13621,1793],{"class":1749},[516,13623,11030],{"class":4733},[516,13625,11033],{"class":1227},[516,13627,11036],{"class":1749},[516,13629,13630],{"class":1227}," count.value ",[516,13632,13050],{"class":1749},[516,13634,1943],{"class":1233},[516,13636,8649],{"class":1227},[516,13638,13639,13642,13645,13648,13651,13653,13656,13658,13660,13662],{"class":518,"line":1308},[516,13640,13641],{"class":4733},"    watch",[516,13643,13644],{"class":1227},"(count, (",[516,13646,13647],{"class":9080},"val",[516,13649,13650],{"class":1227},") ",[516,13652,11036],{"class":1749},[516,13654,13655],{"class":1227}," console.",[516,13657,11517],{"class":4733},[516,13659,8643],{"class":1227},[516,13661,11522],{"class":1248},[516,13663,13664],{"class":1227},", val))\n",[516,13666,13667],{"class":518,"line":1314},[516,13668,11530],{"class":1227},[516,13670,13671],{"class":518,"line":8656},[516,13672,1131],{"emptyLinePlaceholder":1130},[516,13674,13675],{"class":518,"line":8668},[516,13676,13677],{"class":3076},"// later, stop everything created inside the scope at once\n",[516,13679,13680,13682,13685],{"class":518,"line":8677},[516,13681,13588],{"class":1227},[516,13683,13684],{"class":4733},"stop",[516,13686,13318],{"class":1227},[11,13688,13689,13690,13693,13694,13697,13698,13700],{},"Everything created inside ",[66,13691,13692],{},"scope.run(fn)"," gets registered to that scope automatically, so a single ",[66,13695,13696],{},"scope.stop()"," tears down every watcher and computed inside it, preventing memory leaks. This is mostly relevant if you are authoring composables or libraries meant to be used outside typical component setup, most app code never needs to call ",[66,13699,13520],{}," directly because components handle this for you.",[23,13702,13704],{"id":13703},"_40-what-are-common-reactivity-gotchas-that-trip-up-developers-coming-from-vue-2-or-from-react","40. What are common reactivity gotchas that trip up developers coming from Vue 2 or from React?",[11,13706,13707],{},"A handful of mistakes come up constantly, regardless of framework background.",[11,13709,13710,13716,13717,13720,13721,13724],{},[31,13711,13712,13713,13715],{},"Forgetting ",[66,13714,11449],{}," on a ref outside the template."," Since templates auto-unwrap refs but plain script code does not, it is easy to write ",[66,13718,13719],{},"count++"," instead of ",[66,13722,13723],{},"count.value++"," and wonder why nothing updates.",[11,13726,13727,13733,13734,13736,13737,13739],{},[31,13728,13729,13730,13732],{},"Destructuring a ",[66,13731,11445],{}," object."," As covered earlier, this disconnects the destructured variables from the source. The fix is ",[66,13735,12271],{},", or simply preferring ",[66,13738,11453],{}," for values that will need to be passed around individually.",[11,13741,13742,13747,13748,13750,13751,13754,13755,13757],{},[31,13743,13744,13745,13732],{},"Replacing an entire ",[66,13746,11445],{}," Reassigning a ",[66,13749,12368],{}," variable entirely, ",[66,13752,13753],{},"state = { count: 1 }",", breaks the reactive connection, because you have pointed the variable at a brand new plain object instead of mutating the existing Proxy. Mutate properties on the existing object instead, or use ",[66,13756,11453],{}," if whole-value replacement is something you do often.",[507,13759,13761],{"className":8782,"code":13760,"language":8784,"meta":512,"style":512},"let state = reactive({ count: 0 })\nstate = { count: 1 } // breaks reactivity, this is now a plain object\n",[66,13762,13763,13781],{"__ignoreMap":512},[516,13764,13765,13768,13771,13773,13775,13777,13779],{"class":518,"line":519},[516,13766,13767],{"class":1749},"let",[516,13769,13770],{"class":1227}," state ",[516,13772,1894],{"class":1749},[516,13774,11486],{"class":4733},[516,13776,11489],{"class":1227},[516,13778,8646],{"class":1233},[516,13780,11494],{"class":1227},[516,13782,13783,13786,13788,13790,13792,13794],{"class":518,"line":525},[516,13784,13785],{"class":1227},"state ",[516,13787,1894],{"class":1749},[516,13789,12831],{"class":1227},[516,13791,9945],{"class":1233},[516,13793,12238],{"class":1227},[516,13795,13796],{"class":3076},"// breaks reactivity, this is now a plain object\n",[11,13798,13799,13802,13803,13806,13807,13809],{},[31,13800,13801],{},"Expecting synchronous DOM updates."," Coming from imperative DOM code, developers often read ",[66,13804,13805],{},"element.offsetHeight"," or similar right after a state change and get stale results, because Vue batches DOM updates. This is what ",[66,13808,13202],{}," is for.",[11,13811,13812,13815,13816,9934,13818,734,13820,13823,13824,13826,13827,13830,13831,13834],{},[31,13813,13814],{},"Losing reactivity across component boundaries with plain destructured props."," Destructuring ",[66,13817,12679],{},[66,13819,8448],{},[66,13821,13822],{},"const { title } = defineProps(...)",") loses reactivity for that variable in the same way destructuring a ",[66,13825,12368],{}," object does; Vue's compiler has some special-case handling for this in default value expressions, but generally you should access ",[66,13828,13829],{},"props.title"," directly, or wrap it with ",[66,13832,13833],{},"toRef(props, 'title')"," if you need to pass it elsewhere as a standalone reactive reference.",[11,13836,13837,13840,13841,13844,13845,202,13847,13849,13850,154,13853,13856],{},[31,13838,13839],{},"Coming from React and expecting immutability."," React developers are trained to never mutate state directly (",[66,13842,13843],{},"setState"," with a new object/array) because React relies on reference equality checks. Vue is the opposite: ",[66,13846,11445],{},[66,13848,11453],{}," are built specifically so you can mutate in place (",[66,13851,13852],{},"state.items.push(x)",[66,13854,13855],{},"state.count++",") and have Vue detect it automatically. Cloning state defensively before mutating it, out of a React-trained instinct, is unnecessary in Vue and just adds overhead.",[18,13858,13860],{"id":13859},"computed-properties-watchers-and-methods","Computed Properties, Watchers, and Methods",[23,13862,13864],{"id":13863},"_41-what-is-a-computed-property-and-how-is-it-different-from-a-method","41. What is a computed property, and how is it different from a method?",[11,13866,13867],{},"A computed property is a value that's derived from other reactive state and automatically updates when that state changes. A method is just a plain function you call yourself, it doesn't know anything about reactivity on its own.",[11,13869,13870],{},"The practical difference is caching. A computed property tracks the reactive values it reads and only recalculates when one of them actually changes. A method reruns every single time you call it, including every time the component re-renders, even if the result would be identical.",[507,13872,13874],{"className":8546,"code":13873,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, computed } from 'vue'\n\nconst price = ref(100)\nconst quantity = ref(3)\n\nconst total = computed(() => price.value * quantity.value)\n\nfunction getTotal() {\n    return price.value * quantity.value\n}\n\u003C/script>\n",[66,13875,13876,13886,13897,13901,13919,13936,13940,13963,13967,13976,13987,13991],{"__ignoreMap":512},[516,13877,13878,13880,13882,13884],{"class":518,"line":519},[516,13879,3042],{"class":1227},[516,13881,8604],{"class":8557},[516,13883,8607],{"class":4733},[516,13885,8561],{"class":1227},[516,13887,13888,13890,13893,13895],{"class":518,"line":525},[516,13889,8614],{"class":1749},[516,13891,13892],{"class":1227}," { ref, computed } ",[516,13894,8620],{"class":1749},[516,13896,8623],{"class":1248},[516,13898,13899],{"class":518,"line":531},[516,13900,1131],{"emptyLinePlaceholder":1130},[516,13902,13903,13905,13908,13910,13912,13914,13917],{"class":518,"line":1127},[516,13904,8632],{"class":1749},[516,13906,13907],{"class":1233}," price",[516,13909,1793],{"class":1749},[516,13911,8640],{"class":4733},[516,13913,8643],{"class":1227},[516,13915,13916],{"class":1233},"100",[516,13918,8649],{"class":1227},[516,13920,13921,13923,13926,13928,13930,13932,13934],{"class":518,"line":1134},[516,13922,8632],{"class":1749},[516,13924,13925],{"class":1233}," quantity",[516,13927,1793],{"class":1749},[516,13929,8640],{"class":4733},[516,13931,8643],{"class":1227},[516,13933,12003],{"class":1233},[516,13935,8649],{"class":1227},[516,13937,13938],{"class":518,"line":1275},[516,13939,1131],{"emptyLinePlaceholder":1130},[516,13941,13942,13944,13947,13949,13951,13953,13955,13958,13960],{"class":518,"line":1302},[516,13943,8632],{"class":1749},[516,13945,13946],{"class":1233}," total",[516,13948,1793],{"class":1749},[516,13950,11030],{"class":4733},[516,13952,11033],{"class":1227},[516,13954,11036],{"class":1749},[516,13956,13957],{"class":1227}," price.value ",[516,13959,13050],{"class":1749},[516,13961,13962],{"class":1227}," quantity.value)\n",[516,13964,13965],{"class":518,"line":1308},[516,13966,1131],{"emptyLinePlaceholder":1130},[516,13968,13969,13971,13974],{"class":518,"line":1314},[516,13970,8659],{"class":1749},[516,13972,13973],{"class":4733}," getTotal",[516,13975,8665],{"class":1227},[516,13977,13978,13980,13982,13984],{"class":518,"line":8656},[516,13979,9089],{"class":1749},[516,13981,13957],{"class":1227},[516,13983,13050],{"class":1749},[516,13985,13986],{"class":1227}," quantity.value\n",[516,13988,13989],{"class":518,"line":8668},[516,13990,1317],{"class":1227},[516,13992,13993,13995,13997],{"class":518,"line":8677},[516,13994,8589],{"class":1227},[516,13996,8604],{"class":8557},[516,13998,8561],{"class":1227},[11,14000,12479,14001,14004],{},[66,14002,14003],{},"total"," in the template if you're going to reference it more than once, use a method when you need to pass arguments or trigger something on an event like a click.",[23,14006,14008],{"id":14007},"_42-why-are-computed-properties-cached-and-why-does-that-matter-for-performance","42. Why are computed properties cached, and why does that matter for performance?",[11,14010,14011],{},"Vue caches a computed property's return value and only recomputes it when one of its reactive dependencies changes. Until then, reading the computed property anywhere in the template just returns the cached value instantly, it doesn't rerun your function.",[11,14013,14014],{},"This matters because templates can re-render often (any reactive state used in that component changing triggers a re-render), and it's easy to reference the same derived value in several places. If that derived value were a method call instead, an expensive operation like filtering a 10,000-item array would run again on every render, even when the array and filter criteria haven't moved at all.",[507,14016,14018],{"className":8782,"code":14017,"language":8784,"meta":512,"style":512},"const results = computed(() => items.value.filter(i => i.active))\n",[66,14019,14020],{"__ignoreMap":512},[516,14021,14022,14024,14027,14029,14031,14033,14035,14038,14040,14042,14045,14047],{"class":518,"line":519},[516,14023,8632],{"class":1749},[516,14025,14026],{"class":1233}," results",[516,14028,1793],{"class":1749},[516,14030,11030],{"class":4733},[516,14032,11033],{"class":1227},[516,14034,11036],{"class":1749},[516,14036,14037],{"class":1227}," items.value.",[516,14039,11042],{"class":4733},[516,14041,8643],{"class":1227},[516,14043,14044],{"class":9080},"i",[516,14046,11049],{"class":1749},[516,14048,14049],{"class":1227}," i.active))\n",[11,14051,14052,14053,14056,14057,14059],{},"Here ",[66,14054,14055],{},"results"," only re-filters when ",[66,14058,10020],{}," (or something read inside the function) actually changes, no matter how many times it's used in the template or how often the component re-renders for unrelated reasons.",[23,14061,14063],{"id":14062},"_43-what-is-a-computed-setter-and-when-would-you-use-one","43. What is a computed setter, and when would you use one?",[11,14065,14066,14067,202,14069,14071],{},"By default a computed property is read-only, you pass it a getter function and it returns a value. A computed setter lets that same computed property also be written to, by passing an object with ",[66,14068,12046],{},[66,14070,12049],{}," instead of a plain function.",[11,14073,14074],{},"You reach for this when you want a derived value to behave like a normal writable piece of state from the outside, usually to keep two related pieces of data in sync. A classic example is splitting a full name into first and last name:",[507,14076,14078],{"className":8546,"code":14077,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, computed } from 'vue'\n\nconst firstName = ref('Ada')\nconst lastName = ref('Lovelace')\n\nconst fullName = computed({\n    get() {\n        return `${firstName.value} ${lastName.value}`\n    },\n    set(newValue) {\n        const [first, last] = newValue.split(' ')\n        firstName.value = first\n        lastName.value = last\n    }\n})\n\u003C/script>\n",[66,14079,14080,14090,14100,14104,14122,14140,14144,14157,14164,14191,14196,14208,14240,14250,14260,14264,14268],{"__ignoreMap":512},[516,14081,14082,14084,14086,14088],{"class":518,"line":519},[516,14083,3042],{"class":1227},[516,14085,8604],{"class":8557},[516,14087,8607],{"class":4733},[516,14089,8561],{"class":1227},[516,14091,14092,14094,14096,14098],{"class":518,"line":525},[516,14093,8614],{"class":1749},[516,14095,13892],{"class":1227},[516,14097,8620],{"class":1749},[516,14099,8623],{"class":1248},[516,14101,14102],{"class":518,"line":531},[516,14103,1131],{"emptyLinePlaceholder":1130},[516,14105,14106,14108,14111,14113,14115,14117,14120],{"class":518,"line":1127},[516,14107,8632],{"class":1749},[516,14109,14110],{"class":1233}," firstName",[516,14112,1793],{"class":1749},[516,14114,8640],{"class":4733},[516,14116,8643],{"class":1227},[516,14118,14119],{"class":1248},"'Ada'",[516,14121,8649],{"class":1227},[516,14123,14124,14126,14129,14131,14133,14135,14138],{"class":518,"line":1134},[516,14125,8632],{"class":1749},[516,14127,14128],{"class":1233}," lastName",[516,14130,1793],{"class":1749},[516,14132,8640],{"class":4733},[516,14134,8643],{"class":1227},[516,14136,14137],{"class":1248},"'Lovelace'",[516,14139,8649],{"class":1227},[516,14141,14142],{"class":518,"line":1275},[516,14143,1131],{"emptyLinePlaceholder":1130},[516,14145,14146,14148,14151,14153,14155],{"class":518,"line":1302},[516,14147,8632],{"class":1749},[516,14149,14150],{"class":1233}," fullName",[516,14152,1793],{"class":1749},[516,14154,11030],{"class":4733},[516,14156,12910],{"class":1227},[516,14158,14159,14162],{"class":518,"line":1308},[516,14160,14161],{"class":4733},"    get",[516,14163,8665],{"class":1227},[516,14165,14166,14168,14171,14174,14176,14178,14181,14184,14186,14188],{"class":518,"line":1314},[516,14167,9245],{"class":1749},[516,14169,14170],{"class":1248}," `${",[516,14172,14173],{"class":1227},"firstName",[516,14175,405],{"class":1248},[516,14177,12995],{"class":1227},[516,14179,14180],{"class":1248},"} ${",[516,14182,14183],{"class":1227},"lastName",[516,14185,405],{"class":1248},[516,14187,12995],{"class":1227},[516,14189,14190],{"class":1248},"}`\n",[516,14192,14193],{"class":518,"line":8656},[516,14194,14195],{"class":1227},"    },\n",[516,14197,14198,14201,14203,14206],{"class":518,"line":8668},[516,14199,14200],{"class":4733},"    set",[516,14202,8643],{"class":1227},[516,14204,14205],{"class":9080},"newValue",[516,14207,9084],{"class":1227},[516,14209,14210,14212,14215,14218,14220,14223,14225,14227,14230,14233,14235,14238],{"class":518,"line":8677},[516,14211,9207],{"class":1749},[516,14213,14214],{"class":1227}," [",[516,14216,14217],{"class":1233},"first",[516,14219,154],{"class":1227},[516,14221,14222],{"class":1233},"last",[516,14224,12016],{"class":1227},[516,14226,1894],{"class":1749},[516,14228,14229],{"class":1227}," newValue.",[516,14231,14232],{"class":4733},"split",[516,14234,8643],{"class":1227},[516,14236,14237],{"class":1248},"' '",[516,14239,8649],{"class":1227},[516,14241,14242,14245,14247],{"class":518,"line":8682},[516,14243,14244],{"class":1227},"        firstName.value ",[516,14246,1894],{"class":1749},[516,14248,14249],{"class":1227}," first\n",[516,14251,14252,14255,14257],{"class":518,"line":8691},[516,14253,14254],{"class":1227},"        lastName.value ",[516,14256,1894],{"class":1749},[516,14258,14259],{"class":1227}," last\n",[516,14261,14262],{"class":518,"line":8696},[516,14263,9253],{"class":1227},[516,14265,14266],{"class":518,"line":8708},[516,14267,11530],{"class":1227},[516,14269,14270,14272,14274],{"class":518,"line":8716},[516,14271,8589],{"class":1227},[516,14273,8604],{"class":8557},[516,14275,8561],{"class":1227},[11,14277,14278,14279,14282,14283,202,14285,14287,14288,14290],{},"Now ",[66,14280,14281],{},"fullName.value = 'Grace Hopper'"," updates both ",[66,14284,14173],{},[66,14286,14183],{}," behind the scenes. This is also common when binding a computed directly with ",[66,14289,10557],{}," on a form input that needs to transform a value on the way in and out.",[23,14292,14294,14295,202,14297,9728],{"id":14293},"_44-what-is-the-difference-between-computed-and-watch","44. What is the difference between ",[66,14296,9012],{},[66,14298,13396],{},[11,14300,14301,14303,14304,14306],{},[66,14302,9012],{}," is for deriving a value you're going to use somewhere, typically in the template. ",[66,14305,13396],{}," is for running a side effect in response to a change, it doesn't give you a value to render, it gives you a callback to react in.",[36,14308,14309,14323],{},[39,14310,14311],{},[42,14312,14313,14315,14319],{},[45,14314],{},[45,14316,14317],{},[66,14318,9012],{},[45,14320,14321],{},[66,14322,13396],{},[58,14324,14325,14335,14345,14355,14368],{},[42,14326,14327,14329,14332],{},[63,14328,1687],{},[63,14330,14331],{},"A reactive value (ref)",[63,14333,14334],{},"Nothing, runs a callback",[42,14336,14337,14339,14342],{},[63,14338,50],{},[63,14340,14341],{},"Derive/transform data",[63,14343,14344],{},"Run side effects (API calls, logging, DOM work)",[42,14346,14347,14349,14352],{},[63,14348,3274],{},[63,14350,14351],{},"Yes, cached until dependencies change",[63,14353,14354],{},"No caching, just runs the callback",[42,14356,14357,14360,14362],{},[63,14358,14359],{},"Access to old value",[63,14361,74],{},[63,14363,14364,14365],{},"Yes, ",[66,14366,14367],{},"(newVal, oldVal) => {}",[42,14369,14370,14372,14377],{},[63,14371,56],{},[63,14373,14374],{},[66,14375,14376],{},"\u003Cp>{{ fullName }}\u003C/p>",[63,14378,14379],{},"Fetching data when a route param changes",[11,14381,14382,14383,14385,14386,14388,14389,14391,14392,14394],{},"A good rule of thumb: if you're about to write ",[66,14384,13396],{}," just to set another ref to a transformed version of the first one, that's almost always better expressed as a ",[66,14387,9012],{},". Reach for ",[66,14390,13396],{}," when the reaction is something computed can't express, like calling an API, writing to ",[66,14393,2755],{},", or manipulating a non-Vue library.",[23,14396,14398,14399,202,14401,9728],{"id":14397},"_45-what-is-the-difference-between-watch-and-watcheffect","45. What is the difference between ",[66,14400,13396],{},[66,14402,13399],{},[11,14404,14405],{},"Both let you run a function in response to reactive state changing, but they differ in how they figure out what to track and when they first run.",[11,14407,14408,14410],{},[66,14409,13396],{}," is explicit: you tell it exactly which source (or sources) to watch, and it only reruns when that specific source changes. It's lazy by default, meaning it doesn't run on setup, only after the watched source changes, and it gives you both the new and old value.",[11,14412,14413,14415],{},[66,14414,13399],{}," is implicit: it runs your function immediately once, and automatically tracks whatever reactive values you happened to read inside it during that run. It reruns whenever any of those tracked values change. It does not give you the old value.",[507,14417,14419],{"className":8782,"code":14418,"language":8784,"meta":512,"style":512},"// watch: explicit source, lazy, gives old/new value\nwatch(userId, (newId, oldId) => {\n    fetchUser(newId)\n})\n\n// watchEffect: auto-tracks dependencies, runs immediately\nwatchEffect(() => {\n    fetchUser(userId.value)\n})\n",[66,14420,14421,14426,14447,14455,14459,14463,14468,14478,14485],{"__ignoreMap":512},[516,14422,14423],{"class":518,"line":519},[516,14424,14425],{"class":3076},"// watch: explicit source, lazy, gives old/new value\n",[516,14427,14428,14430,14433,14436,14438,14441,14443,14445],{"class":518,"line":525},[516,14429,13396],{"class":4733},[516,14431,14432],{"class":1227},"(userId, (",[516,14434,14435],{"class":9080},"newId",[516,14437,154],{"class":1227},[516,14439,14440],{"class":9080},"oldId",[516,14442,13650],{"class":1227},[516,14444,11036],{"class":1749},[516,14446,8713],{"class":1227},[516,14448,14449,14452],{"class":518,"line":531},[516,14450,14451],{"class":4733},"    fetchUser",[516,14453,14454],{"class":1227},"(newId)\n",[516,14456,14457],{"class":518,"line":1127},[516,14458,11530],{"class":1227},[516,14460,14461],{"class":518,"line":1134},[516,14462,1131],{"emptyLinePlaceholder":1130},[516,14464,14465],{"class":518,"line":1275},[516,14466,14467],{"class":3076},"// watchEffect: auto-tracks dependencies, runs immediately\n",[516,14469,14470,14472,14474,14476],{"class":518,"line":1302},[516,14471,13399],{"class":4733},[516,14473,11033],{"class":1227},[516,14475,11036],{"class":1749},[516,14477,8713],{"class":1227},[516,14479,14480,14482],{"class":518,"line":1308},[516,14481,14451],{"class":4733},[516,14483,14484],{"class":1227},"(userId.value)\n",[516,14486,14487],{"class":518,"line":1314},[516,14488,11530],{"class":1227},[11,14490,12479,14491,14493,14494,14496],{},[66,14492,13396],{}," when you want to watch a specific, narrow source and need the old value, or when you don't want the effect to run immediately. Use ",[66,14495,13399],{}," when the effect naturally reads several reactive values together and you just want \"rerun whenever any of these change\" without listing them out by hand.",[23,14498,14500,14501,14504,14505,14507],{"id":14499},"_46-what-does-the-deep-option-do-on-watch-and-when-do-you-actually-need-it","46. What does the ",[66,14502,14503],{},"deep"," option do on ",[66,14506,13396],{},", and when do you actually need it?",[11,14509,12694,14510,14512,14513,14516,14517,14520,14521,14524],{},[66,14511,13396],{}," on an object or array only fires when the reference itself is replaced, not when a property inside it changes. So ",[66,14514,14515],{},"watch(user, callback)"," won't fire if you do ",[66,14518,14519],{},"user.value.name = 'New Name'",", because ",[66,14522,14523],{},"user.value"," still points to the same object.",[11,14526,771,14527,14530],{},[66,14528,14529],{},"deep: true"," option makes Vue recursively walk into the object and track every nested property, so the callback fires on mutations anywhere inside it, not just on reassignment.",[507,14532,14534],{"className":8782,"code":14533,"language":8784,"meta":512,"style":512},"const user = ref({ name: 'Ada', settings: { theme: 'dark' } })\n\nwatch(user, () => {\n    console.log('something inside user changed')\n}, { deep: true })\n",[66,14535,14536,14560,14564,14575,14588],{"__ignoreMap":512},[516,14537,14538,14540,14543,14545,14547,14550,14552,14555,14558],{"class":518,"line":519},[516,14539,8632],{"class":1749},[516,14541,14542],{"class":1233}," user",[516,14544,1793],{"class":1749},[516,14546,8640],{"class":4733},[516,14548,14549],{"class":1227},"({ name: ",[516,14551,14119],{"class":1248},[516,14553,14554],{"class":1227},", settings: { theme: ",[516,14556,14557],{"class":1248},"'dark'",[516,14559,12756],{"class":1227},[516,14561,14562],{"class":518,"line":525},[516,14563,1131],{"emptyLinePlaceholder":1130},[516,14565,14566,14568,14571,14573],{"class":518,"line":531},[516,14567,13396],{"class":4733},[516,14569,14570],{"class":1227},"(user, () ",[516,14572,11036],{"class":1749},[516,14574,8713],{"class":1227},[516,14576,14577,14579,14581,14583,14586],{"class":518,"line":1127},[516,14578,11514],{"class":1227},[516,14580,11517],{"class":4733},[516,14582,8643],{"class":1227},[516,14584,14585],{"class":1248},"'something inside user changed'",[516,14587,8649],{"class":1227},[516,14589,14590,14593,14595],{"class":518,"line":1134},[516,14591,14592],{"class":1227},"}, { deep: ",[516,14594,10228],{"class":1233},[516,14596,11494],{"class":1227},[11,14598,14599,14600,14602,14603,756,14605,14607,14608,14611,14612,405],{},"You need ",[66,14601,14503],{}," specifically when you're watching a ",[66,14604,9387],{},[66,14606,12368],{}," object/array and care about nested mutations rather than the whole thing being swapped out. Be careful with it though: deep watching a large or deeply nested object walks the entire structure on every change, which can hurt performance. If you only care about one nested field, it's usually cheaper to watch a getter for that specific path, like ",[66,14609,14610],{},"watch(() => user.value.settings.theme, callback)",", instead of turning on ",[66,14613,14503],{},[23,14615,14617,14618,14504,14621,9728],{"id":14616},"_47-what-does-the-immediate-option-do-on-watch","47. What does the ",[66,14619,14620],{},"immediate",[66,14622,13396],{},[11,14624,14625,14626,14628,14629,14632],{},"Normally, ",[66,14627,13396],{}," is lazy: the callback only runs the first time the watched source changes, not when the watcher is first set up. ",[66,14630,14631],{},"immediate: true"," makes Vue also run the callback right away, once, with the current value, before waiting for any change.",[507,14634,14636],{"className":8782,"code":14635,"language":8784,"meta":512,"style":512},"watch(userId, (id) => {\n    fetchUser(id)\n}, { immediate: true })\n",[66,14637,14638,14652,14659],{"__ignoreMap":512},[516,14639,14640,14642,14644,14646,14648,14650],{"class":518,"line":519},[516,14641,13396],{"class":4733},[516,14643,14432],{"class":1227},[516,14645,1578],{"class":9080},[516,14647,13650],{"class":1227},[516,14649,11036],{"class":1749},[516,14651,8713],{"class":1227},[516,14653,14654,14656],{"class":518,"line":525},[516,14655,14451],{"class":4733},[516,14657,14658],{"class":1227},"(id)\n",[516,14660,14661,14664,14666],{"class":518,"line":531},[516,14662,14663],{"class":1227},"}, { immediate: ",[516,14665,10228],{"class":1233},[516,14667,11494],{"class":1227},[11,14669,14670,14671,14673],{},"This is handy any time the side effect should also happen on initial load, not just on subsequent changes, for example fetching data based on a prop that already has a value the moment the component mounts. Without ",[66,14672,14620],{},", you'd have to duplicate the fetch call once outside the watcher and once inside it.",[23,14675,14677,14678,14680,14681,14684],{"id":14676},"_48-how-do-you-clean-up-a-side-effect-inside-watcheffect-using-its-oncleanup-callback","48. How do you clean up a side effect inside ",[66,14679,13399],{}," using its ",[66,14682,14683],{},"onCleanup"," callback?",[11,14686,14687,14689,14690,14692,14693,14696],{},[66,14688,13399],{}," passes an ",[66,14691,14683],{}," function as an argument to the callback you give it. You call ",[66,14694,14695],{},"onCleanup(fn)"," to register a function that Vue will run right before the effect reruns, and also when the watcher is stopped (for example, when the component unmounts). It's how you cancel or undo whatever the previous run of the effect started, so stale work doesn't leak into the next run.",[11,14698,14699],{},"This matters most for async work like fetch requests or timers, where a fast-changing dependency could otherwise fire off several overlapping requests and let an old, slow response overwrite a newer one.",[507,14701,14703],{"className":8782,"code":14702,"language":8784,"meta":512,"style":512},"watchEffect((onCleanup) => {\n    const controller = new AbortController()\n\n    fetch(`/api/users/${userId.value}`, { signal: controller.signal })\n        .then(res => res.json())\n        .then(data => { user.value = data })\n\n    onCleanup(() => controller.abort())\n})\n",[66,14704,14705,14720,14737,14741,14764,14786,14806,14810,14827],{"__ignoreMap":512},[516,14706,14707,14709,14712,14714,14716,14718],{"class":518,"line":519},[516,14708,13399],{"class":4733},[516,14710,14711],{"class":1227},"((",[516,14713,14683],{"class":9080},[516,14715,13650],{"class":1227},[516,14717,11036],{"class":1749},[516,14719,8713],{"class":1227},[516,14721,14722,14724,14727,14729,14732,14735],{"class":518,"line":525},[516,14723,12611],{"class":1749},[516,14725,14726],{"class":1233}," controller",[516,14728,1793],{"class":1749},[516,14730,14731],{"class":1749}," new",[516,14733,14734],{"class":4733}," AbortController",[516,14736,13318],{"class":1227},[516,14738,14739],{"class":518,"line":531},[516,14740,1131],{"emptyLinePlaceholder":1130},[516,14742,14743,14746,14748,14751,14754,14756,14758,14761],{"class":518,"line":1127},[516,14744,14745],{"class":4733},"    fetch",[516,14747,8643],{"class":1227},[516,14749,14750],{"class":1248},"`/api/users/${",[516,14752,14753],{"class":1227},"userId",[516,14755,405],{"class":1248},[516,14757,12995],{"class":1227},[516,14759,14760],{"class":1248},"}`",[516,14762,14763],{"class":1227},", { signal: controller.signal })\n",[516,14765,14766,14769,14772,14774,14777,14779,14782,14784],{"class":518,"line":1134},[516,14767,14768],{"class":1227},"        .",[516,14770,14771],{"class":4733},"then",[516,14773,8643],{"class":1227},[516,14775,14776],{"class":9080},"res",[516,14778,11049],{"class":1749},[516,14780,14781],{"class":1227}," res.",[516,14783,1220],{"class":4733},[516,14785,12928],{"class":1227},[516,14787,14788,14790,14792,14794,14796,14798,14801,14803],{"class":518,"line":1275},[516,14789,14768],{"class":1227},[516,14791,14771],{"class":4733},[516,14793,8643],{"class":1227},[516,14795,9006],{"class":9080},[516,14797,11049],{"class":1749},[516,14799,14800],{"class":1227}," { user.value ",[516,14802,1894],{"class":1749},[516,14804,14805],{"class":1227}," data })\n",[516,14807,14808],{"class":518,"line":1302},[516,14809,1131],{"emptyLinePlaceholder":1130},[516,14811,14812,14815,14817,14819,14822,14825],{"class":518,"line":1308},[516,14813,14814],{"class":4733},"    onCleanup",[516,14816,11033],{"class":1227},[516,14818,11036],{"class":1749},[516,14820,14821],{"class":1227}," controller.",[516,14823,14824],{"class":4733},"abort",[516,14826,12928],{"class":1227},[516,14828,14829],{"class":518,"line":1314},[516,14830,11530],{"class":1227},[11,14832,14833,14834,14836,14837,14840],{},"Every time ",[66,14835,14753],{}," changes, Vue calls the cleanup function first, aborting the in-flight request, before running the effect again with the new id. The same pattern works for clearing a ",[66,14838,14839],{},"setTimeout",", removing an event listener, or unsubscribing from anything you subscribed to inside the effect.",[18,14842,14844],{"id":14843},"components-props-events-and-v-model","Components: Props, Events, and v-model",[23,14846,14848],{"id":14847},"_49-what-are-props-and-how-do-you-declare-and-validate-them","49. What are props, and how do you declare and validate them?",[11,14850,14851],{},"Props are how a parent component passes data down into a child component. They flow one way, from parent to child, and the child treats them as read-only input.",[11,14853,2146,14854,14856,14857,14860],{},[66,14855,8448],{},", you declare props with the ",[66,14858,14859],{},"defineProps"," macro, either as a simple array of names or, more usefully, as an object where each entry describes the type, whether it's required, a default value, and an optional custom validator.",[507,14862,14864],{"className":8546,"code":14863,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst props = defineProps({\n    title: {\n        type: String,\n        required: true\n    },\n    count: {\n        type: Number,\n        default: 0\n    },\n    status: {\n        type: String,\n        default: 'idle',\n        validator: (value) => ['idle', 'loading', 'done'].includes(value)\n    }\n})\n\u003C/script>\n",[66,14865,14866,14876,14890,14895,14900,14908,14912,14917,14922,14930,14934,14939,14943,14952,14988,14992,14996],{"__ignoreMap":512},[516,14867,14868,14870,14872,14874],{"class":518,"line":519},[516,14869,3042],{"class":1227},[516,14871,8604],{"class":8557},[516,14873,8607],{"class":4733},[516,14875,8561],{"class":1227},[516,14877,14878,14880,14883,14885,14888],{"class":518,"line":525},[516,14879,8632],{"class":1749},[516,14881,14882],{"class":1233}," props",[516,14884,1793],{"class":1749},[516,14886,14887],{"class":4733}," defineProps",[516,14889,12910],{"class":1227},[516,14891,14892],{"class":518,"line":531},[516,14893,14894],{"class":1227},"    title: {\n",[516,14896,14897],{"class":518,"line":1127},[516,14898,14899],{"class":1227},"        type: String,\n",[516,14901,14902,14905],{"class":518,"line":1134},[516,14903,14904],{"class":1227},"        required: ",[516,14906,14907],{"class":1233},"true\n",[516,14909,14910],{"class":518,"line":1275},[516,14911,14195],{"class":1227},[516,14913,14914],{"class":518,"line":1302},[516,14915,14916],{"class":1227},"    count: {\n",[516,14918,14919],{"class":518,"line":1308},[516,14920,14921],{"class":1227},"        type: Number,\n",[516,14923,14924,14927],{"class":518,"line":1314},[516,14925,14926],{"class":1227},"        default: ",[516,14928,14929],{"class":1233},"0\n",[516,14931,14932],{"class":518,"line":8656},[516,14933,14195],{"class":1227},[516,14935,14936],{"class":518,"line":8668},[516,14937,14938],{"class":1227},"    status: {\n",[516,14940,14941],{"class":518,"line":8677},[516,14942,14899],{"class":1227},[516,14944,14945,14947,14950],{"class":518,"line":8682},[516,14946,14926],{"class":1227},[516,14948,14949],{"class":1248},"'idle'",[516,14951,1252],{"class":1227},[516,14953,14954,14957,14960,14962,14964,14966,14968,14970,14972,14975,14977,14980,14983,14986],{"class":518,"line":8691},[516,14955,14956],{"class":4733},"        validator",[516,14958,14959],{"class":1227},": (",[516,14961,12995],{"class":9080},[516,14963,13650],{"class":1227},[516,14965,11036],{"class":1749},[516,14967,14214],{"class":1227},[516,14969,14949],{"class":1248},[516,14971,154],{"class":1227},[516,14973,14974],{"class":1248},"'loading'",[516,14976,154],{"class":1227},[516,14978,14979],{"class":1248},"'done'",[516,14981,14982],{"class":1227},"].",[516,14984,14985],{"class":4733},"includes",[516,14987,13186],{"class":1227},[516,14989,14990],{"class":518,"line":8696},[516,14991,9253],{"class":1227},[516,14993,14994],{"class":518,"line":8708},[516,14995,11530],{"class":1227},[516,14997,14998,15000,15002],{"class":518,"line":8716},[516,14999,8589],{"class":1227},[516,15001,8604],{"class":8557},[516,15003,8561],{"class":1227},[11,15005,15006,15007,15009],{},"During development, Vue checks incoming prop values against this declaration and logs a console warning if a required prop is missing, a type doesn't match, or the validator returns ",[66,15008,12981],{},". This validation is stripped out in production builds, it's a development aid, not runtime enforcement, so it doesn't replace proper input handling for anything user-facing.",[23,15011,15013],{"id":15012},"_50-why-shouldnt-you-mutate-a-prop-directly-inside-a-child-component","50. Why shouldn't you mutate a prop directly inside a child component?",[11,15015,15016],{},"Props are meant to flow in one direction, from parent down to child. The parent owns the actual reactive source, the child's prop is just a reference to the current value of that source. If the child reassigns the prop directly, it's fighting the parent for ownership of that state: Vue will log a warning in development, and any local change gets silently overwritten the next time the parent re-renders with its own value.",[507,15018,15020],{"className":8546,"code":15019,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst props = defineProps(['count'])\n\n// Avoid: mutating a prop directly\nfunction increment() {\n    props.count++ // warning, and gets overwritten by parent\n}\n\u003C/script>\n",[66,15021,15022,15032,15048,15052,15057,15065,15075,15079],{"__ignoreMap":512},[516,15023,15024,15026,15028,15030],{"class":518,"line":519},[516,15025,3042],{"class":1227},[516,15027,8604],{"class":8557},[516,15029,8607],{"class":4733},[516,15031,8561],{"class":1227},[516,15033,15034,15036,15038,15040,15042,15044,15046],{"class":518,"line":525},[516,15035,8632],{"class":1749},[516,15037,14882],{"class":1233},[516,15039,1793],{"class":1749},[516,15041,14887],{"class":4733},[516,15043,11992],{"class":1227},[516,15045,12453],{"class":1248},[516,15047,12006],{"class":1227},[516,15049,15050],{"class":518,"line":531},[516,15051,1131],{"emptyLinePlaceholder":1130},[516,15053,15054],{"class":518,"line":1127},[516,15055,15056],{"class":3076},"// Avoid: mutating a prop directly\n",[516,15058,15059,15061,15063],{"class":518,"line":1134},[516,15060,8659],{"class":1749},[516,15062,8662],{"class":4733},[516,15064,8665],{"class":1227},[516,15066,15067,15070,15072],{"class":518,"line":1275},[516,15068,15069],{"class":1227},"    props.count",[516,15071,11542],{"class":1749},[516,15073,15074],{"class":3076}," // warning, and gets overwritten by parent\n",[516,15076,15077],{"class":518,"line":1302},[516,15078,1317],{"class":1227},[516,15080,15081,15083,15085],{"class":518,"line":1308},[516,15082,8589],{"class":1227},[516,15084,8604],{"class":8557},[516,15086,8561],{"class":1227},[11,15088,15089],{},"If you need an editable local version of a prop, initialize your own local state from it instead:",[507,15091,15093],{"className":8546,"code":15092,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst props = defineProps(['count'])\nconst localCount = ref(props.count)\n\nfunction increment() {\n    localCount.value++\n}\n\u003C/script>\n",[66,15094,15095,15105,15115,15119,15135,15149,15153,15161,15168,15172],{"__ignoreMap":512},[516,15096,15097,15099,15101,15103],{"class":518,"line":519},[516,15098,3042],{"class":1227},[516,15100,8604],{"class":8557},[516,15102,8607],{"class":4733},[516,15104,8561],{"class":1227},[516,15106,15107,15109,15111,15113],{"class":518,"line":525},[516,15108,8614],{"class":1749},[516,15110,8617],{"class":1227},[516,15112,8620],{"class":1749},[516,15114,8623],{"class":1248},[516,15116,15117],{"class":518,"line":531},[516,15118,1131],{"emptyLinePlaceholder":1130},[516,15120,15121,15123,15125,15127,15129,15131,15133],{"class":518,"line":1127},[516,15122,8632],{"class":1749},[516,15124,14882],{"class":1233},[516,15126,1793],{"class":1749},[516,15128,14887],{"class":4733},[516,15130,11992],{"class":1227},[516,15132,12453],{"class":1248},[516,15134,12006],{"class":1227},[516,15136,15137,15139,15142,15144,15146],{"class":518,"line":1134},[516,15138,8632],{"class":1749},[516,15140,15141],{"class":1233}," localCount",[516,15143,1793],{"class":1749},[516,15145,8640],{"class":4733},[516,15147,15148],{"class":1227},"(props.count)\n",[516,15150,15151],{"class":518,"line":1275},[516,15152,1131],{"emptyLinePlaceholder":1130},[516,15154,15155,15157,15159],{"class":518,"line":1302},[516,15156,8659],{"class":1749},[516,15158,8662],{"class":4733},[516,15160,8665],{"class":1227},[516,15162,15163,15166],{"class":518,"line":1308},[516,15164,15165],{"class":1227},"    localCount.value",[516,15167,8674],{"class":1749},[516,15169,15170],{"class":518,"line":1314},[516,15171,1317],{"class":1227},[516,15173,15174,15176,15178],{"class":518,"line":8656},[516,15175,8589],{"class":1227},[516,15177,8604],{"class":8557},[516,15179,8561],{"class":1227},[11,15181,15182,15183,15185,15186,15189],{},"If the intent is really for the child to change the parent's data, the correct pattern is to emit an event and let the parent update its own state (or use ",[66,15184,10557],{}," / ",[66,15187,15188],{},"defineModel",", which is exactly this pattern formalized).",[23,15191,15193,15194,15197],{"id":15192},"_51-how-do-you-use-proptype-for-typing-props-in-the-options-api","51. How do you use ",[66,15195,15196],{},"PropType"," for typing props in the Options API?",[11,15199,15200,15202,15203,756,15206,15209,15210,15213,15214,15217,15218,15221,15222,15225],{},[66,15201,15196],{}," is a TypeScript helper Vue exports so you can give a prop a more specific type than what a plain JavaScript constructor (like ",[66,15204,15205],{},"Object",[66,15207,15208],{},"Array",") can express. When you write ",[66,15211,15212],{},"type: Object",", TypeScript only knows the value is some object, it can't tell you it's specifically a ",[66,15215,15216],{},"User"," or an array of ",[66,15219,15220],{},"Todo"," items. Casting the constructor ",[66,15223,15224],{},"as PropType\u003CUser>"," tells TypeScript the real shape without changing anything at runtime, Vue still just checks that it's an object.",[507,15227,15229],{"className":8546,"code":15228,"language":8548,"meta":512,"style":512},"\u003Cscript>\nimport { defineComponent, type PropType } from 'vue'\n\ninterface User {\n    id: number\n    name: string\n}\n\nexport default defineComponent({\n    props: {\n        user: {\n            type: Object as PropType\u003CUser>,\n            required: true\n        },\n        roles: {\n            type: Array as PropType\u003Cstring[]>,\n            default: () => []\n        }\n    }\n})\n\u003C/script>\n",[66,15230,15231,15239,15256,15260,15270,15280,15290,15294,15298,15309,15314,15319,15337,15344,15349,15354,15371,15384,15388,15392,15396],{"__ignoreMap":512},[516,15232,15233,15235,15237],{"class":518,"line":519},[516,15234,3042],{"class":1227},[516,15236,8604],{"class":8557},[516,15238,8561],{"class":1227},[516,15240,15241,15243,15246,15249,15252,15254],{"class":518,"line":525},[516,15242,8614],{"class":1749},[516,15244,15245],{"class":1227}," { defineComponent, ",[516,15247,15248],{"class":1749},"type",[516,15250,15251],{"class":1227}," PropType } ",[516,15253,8620],{"class":1749},[516,15255,8623],{"class":1248},[516,15257,15258],{"class":518,"line":531},[516,15259,1131],{"emptyLinePlaceholder":1130},[516,15261,15262,15265,15268],{"class":518,"line":1127},[516,15263,15264],{"class":1749},"interface",[516,15266,15267],{"class":4733}," User",[516,15269,8713],{"class":1227},[516,15271,15272,15275,15277],{"class":518,"line":1134},[516,15273,15274],{"class":9080},"    id",[516,15276,9605],{"class":1749},[516,15278,15279],{"class":1233}," number\n",[516,15281,15282,15285,15287],{"class":518,"line":1275},[516,15283,15284],{"class":9080},"    name",[516,15286,9605],{"class":1749},[516,15288,15289],{"class":1233}," string\n",[516,15291,15292],{"class":518,"line":1302},[516,15293,1317],{"class":1227},[516,15295,15296],{"class":518,"line":1308},[516,15297,1131],{"emptyLinePlaceholder":1130},[516,15299,15300,15302,15304,15307],{"class":518,"line":1314},[516,15301,9190],{"class":1749},[516,15303,9193],{"class":1749},[516,15305,15306],{"class":4733}," defineComponent",[516,15308,12910],{"class":1227},[516,15310,15311],{"class":518,"line":8656},[516,15312,15313],{"class":1227},"    props: {\n",[516,15315,15316],{"class":518,"line":8668},[516,15317,15318],{"class":1227},"        user: {\n",[516,15320,15321,15324,15327,15330,15332,15334],{"class":518,"line":8677},[516,15322,15323],{"class":1227},"            type: Object ",[516,15325,15326],{"class":1749},"as",[516,15328,15329],{"class":4733}," PropType",[516,15331,3042],{"class":1227},[516,15333,15216],{"class":4733},[516,15335,15336],{"class":1227},">,\n",[516,15338,15339,15342],{"class":518,"line":8682},[516,15340,15341],{"class":1227},"            required: ",[516,15343,14907],{"class":1233},[516,15345,15346],{"class":518,"line":8691},[516,15347,15348],{"class":1227},"        },\n",[516,15350,15351],{"class":518,"line":8696},[516,15352,15353],{"class":1227},"        roles: {\n",[516,15355,15356,15359,15361,15363,15365,15368],{"class":518,"line":8708},[516,15357,15358],{"class":1227},"            type: Array ",[516,15360,15326],{"class":1749},[516,15362,15329],{"class":4733},[516,15364,3042],{"class":1227},[516,15366,15367],{"class":1233},"string",[516,15369,15370],{"class":1227},"[]>,\n",[516,15372,15373,15376,15379,15381],{"class":518,"line":8716},[516,15374,15375],{"class":4733},"            default",[516,15377,15378],{"class":1227},": () ",[516,15380,11036],{"class":1749},[516,15382,15383],{"class":1227}," []\n",[516,15385,15386],{"class":518,"line":8727},[516,15387,9240],{"class":1227},[516,15389,15390],{"class":518,"line":8732},[516,15391,9253],{"class":1227},[516,15393,15394],{"class":518,"line":9301},[516,15395,11530],{"class":1227},[516,15397,15398,15400,15402],{"class":518,"line":9318},[516,15399,8589],{"class":1227},[516,15401,8604],{"class":8557},[516,15403,8561],{"class":1227},[11,15405,15406,15407,15409,15410,15412,15413,15416,15417,15419],{},"This is specifically an Options API concern with TypeScript. In ",[66,15408,8448],{}," with TypeScript, you'd normally skip ",[66,15411,15196],{}," entirely and use the type-only generic syntax instead, ",[66,15414,15415],{},"defineProps\u003C{ user: User }>()",", which is more concise and doesn't need the ",[66,15418,15326],{}," cast.",[23,15421,15423,15424,9728],{"id":15422},"_52-what-are-custom-events-and-how-do-you-emit-one-with-defineemits","52. What are custom events, and how do you emit one with ",[66,15425,15426],{},"defineEmits",[11,15428,15429],{},"Custom events are how a child component talks back up to its parent, the mirror image of props. Since props only flow downward, events are the mechanism for the child to notify the parent that something happened, optionally with a payload.",[11,15431,15432,15433,15435,15436,15439],{},"You declare which events a component can emit with ",[66,15434,15426],{},", which returns an ",[66,15437,15438],{},"emit"," function you call to actually fire the event.",[507,15441,15443],{"className":8546,"code":15442,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst emit = defineEmits(['add-to-cart'])\n\nfunction handleClick() {\n    emit('add-to-cart', { id: 42, quantity: 1 })\n}\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cbutton @click=\"handleClick\">Add to cart\u003C/button>\n\u003C/template>\n",[66,15444,15445,15455,15474,15478,15487,15509,15513,15521,15525,15533,15553],{"__ignoreMap":512},[516,15446,15447,15449,15451,15453],{"class":518,"line":519},[516,15448,3042],{"class":1227},[516,15450,8604],{"class":8557},[516,15452,8607],{"class":4733},[516,15454,8561],{"class":1227},[516,15456,15457,15459,15462,15464,15467,15469,15472],{"class":518,"line":525},[516,15458,8632],{"class":1749},[516,15460,15461],{"class":1233}," emit",[516,15463,1793],{"class":1749},[516,15465,15466],{"class":4733}," defineEmits",[516,15468,11992],{"class":1227},[516,15470,15471],{"class":1248},"'add-to-cart'",[516,15473,12006],{"class":1227},[516,15475,15476],{"class":518,"line":531},[516,15477,1131],{"emptyLinePlaceholder":1130},[516,15479,15480,15482,15485],{"class":518,"line":1127},[516,15481,8659],{"class":1749},[516,15483,15484],{"class":4733}," handleClick",[516,15486,8665],{"class":1227},[516,15488,15489,15492,15494,15496,15499,15502,15505,15507],{"class":518,"line":1134},[516,15490,15491],{"class":4733},"    emit",[516,15493,8643],{"class":1227},[516,15495,15471],{"class":1248},[516,15497,15498],{"class":1227},", { id: ",[516,15500,15501],{"class":1233},"42",[516,15503,15504],{"class":1227},", quantity: ",[516,15506,9945],{"class":1233},[516,15508,11494],{"class":1227},[516,15510,15511],{"class":518,"line":1275},[516,15512,1317],{"class":1227},[516,15514,15515,15517,15519],{"class":518,"line":1302},[516,15516,8589],{"class":1227},[516,15518,8604],{"class":8557},[516,15520,8561],{"class":1227},[516,15522,15523],{"class":518,"line":1308},[516,15524,1131],{"emptyLinePlaceholder":1130},[516,15526,15527,15529,15531],{"class":518,"line":1314},[516,15528,3042],{"class":1227},[516,15530,8558],{"class":8557},[516,15532,8561],{"class":1227},[516,15534,15535,15537,15539,15541,15543,15546,15549,15551],{"class":518,"line":8656},[516,15536,8566],{"class":1227},[516,15538,8569],{"class":8557},[516,15540,8572],{"class":4733},[516,15542,1894],{"class":1227},[516,15544,15545],{"class":1248},"\"handleClick\"",[516,15547,15548],{"class":1227},">Add to cart\u003C/",[516,15550,8569],{"class":8557},[516,15552,8561],{"class":1227},[516,15554,15555,15557,15559],{"class":518,"line":8668},[516,15556,8589],{"class":1227},[516,15558,8558],{"class":8557},[516,15560,8561],{"class":1227},[11,15562,15563],{},"The parent listens the same way it would for a native DOM event:",[507,15565,15567],{"className":8546,"code":15566,"language":8548,"meta":512,"style":512},"\u003CProductCard @add-to-cart=\"onAddToCart\" />\n",[66,15568,15569],{"__ignoreMap":512},[516,15570,15571,15573,15576,15579,15582,15584,15586,15589,15591],{"class":518,"line":519},[516,15572,3042],{"class":1227},[516,15574,15575],{"class":8557},"ProductCard",[516,15577,15578],{"class":1227}," @",[516,15580,15581],{"class":4733},"add-to-cart",[516,15583,1894],{"class":1227},[516,15585,3247],{"class":1248},[516,15587,15588],{"class":1227},"onAddToCart",[516,15590,3247],{"class":1248},[516,15592,9667],{"class":1227},[11,15594,15595,15596,15599],{},"Declaring emitted events isn't just documentation, Vue uses the list to make sure listeners like ",[66,15597,15598],{},"@add-to-cart"," are treated as component events rather than falling through as a plain HTML attribute, and it powers the emits validation and TypeScript typing for the payload.",[23,15601,15603],{"id":15602},"_53-what-is-emits-validation-and-how-does-it-work","53. What is emits validation, and how does it work?",[11,15605,15606,15607,15610,15611,15614,15615,756,15617,405],{},"Emits validation is the event equivalent of prop validation: instead of declaring ",[66,15608,15609],{},"emits"," as a plain array of event names, you declare it as an object where each key is an event name and the value is a validator function. That function receives the arguments passed to ",[66,15612,15613],{},"emit(...)"," and should return ",[66,15616,10228],{},[66,15618,12981],{},[507,15620,15622],{"className":8546,"code":15621,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst emit = defineEmits({\n    'add-to-cart': (payload) => {\n        return typeof payload.id === 'number' && payload.quantity > 0\n    },\n    'close': null // no validation, just declares the event exists\n})\n\nfunction handleClick() {\n    emit('add-to-cart', { id: 42, quantity: 1 })\n}\n\u003C/script>\n",[66,15623,15624,15634,15646,15662,15688,15692,15704,15708,15712,15720,15738,15742],{"__ignoreMap":512},[516,15625,15626,15628,15630,15632],{"class":518,"line":519},[516,15627,3042],{"class":1227},[516,15629,8604],{"class":8557},[516,15631,8607],{"class":4733},[516,15633,8561],{"class":1227},[516,15635,15636,15638,15640,15642,15644],{"class":518,"line":525},[516,15637,8632],{"class":1749},[516,15639,15461],{"class":1233},[516,15641,1793],{"class":1749},[516,15643,15466],{"class":4733},[516,15645,12910],{"class":1227},[516,15647,15648,15651,15653,15656,15658,15660],{"class":518,"line":531},[516,15649,15650],{"class":1248},"    'add-to-cart'",[516,15652,14959],{"class":1227},[516,15654,15655],{"class":9080},"payload",[516,15657,13650],{"class":1227},[516,15659,11036],{"class":1749},[516,15661,8713],{"class":1227},[516,15663,15664,15666,15669,15672,15674,15677,15680,15683,15685],{"class":518,"line":1127},[516,15665,9245],{"class":1749},[516,15667,15668],{"class":1749}," typeof",[516,15670,15671],{"class":1227}," payload.id ",[516,15673,12950],{"class":1749},[516,15675,15676],{"class":1248}," 'number'",[516,15678,15679],{"class":1749}," &&",[516,15681,15682],{"class":1227}," payload.quantity ",[516,15684,3045],{"class":1749},[516,15686,15687],{"class":1233}," 0\n",[516,15689,15690],{"class":518,"line":1134},[516,15691,14195],{"class":1227},[516,15693,15694,15697,15699,15701],{"class":518,"line":1275},[516,15695,15696],{"class":1248},"    'close'",[516,15698,1245],{"class":1227},[516,15700,9102],{"class":1233},[516,15702,15703],{"class":3076}," // no validation, just declares the event exists\n",[516,15705,15706],{"class":518,"line":1302},[516,15707,11530],{"class":1227},[516,15709,15710],{"class":518,"line":1308},[516,15711,1131],{"emptyLinePlaceholder":1130},[516,15713,15714,15716,15718],{"class":518,"line":1314},[516,15715,8659],{"class":1749},[516,15717,15484],{"class":4733},[516,15719,8665],{"class":1227},[516,15721,15722,15724,15726,15728,15730,15732,15734,15736],{"class":518,"line":8656},[516,15723,15491],{"class":4733},[516,15725,8643],{"class":1227},[516,15727,15471],{"class":1248},[516,15729,15498],{"class":1227},[516,15731,15501],{"class":1233},[516,15733,15504],{"class":1227},[516,15735,9945],{"class":1233},[516,15737,11494],{"class":1227},[516,15739,15740],{"class":518,"line":8668},[516,15741,1317],{"class":1227},[516,15743,15744,15746,15748],{"class":518,"line":8677},[516,15745,8589],{"class":1227},[516,15747,8604],{"class":8557},[516,15749,8561],{"class":1227},[11,15751,15752,15753,15755],{},"If the validator returns ",[66,15754,12981],{},", Vue logs a console warning in development pointing at exactly which emitted event had a bad payload. Like prop validation, it's development-only tooling, it doesn't block the event from firing or throw at runtime, it just makes mistakes visible early instead of silently propagating a malformed payload up to the parent.",[23,15757,15759,15760,15762],{"id":15758},"_54-how-does-v-model-on-a-custom-component-work-under-the-hood","54. How does ",[66,15761,10557],{}," on a custom component work under the hood?",[11,15764,15765,15767,15768,15771,15772,15775,15776,15779],{},[66,15766,10557],{}," on a component is syntactic sugar for a prop plus an event listener. When you write ",[66,15769,15770],{},"v-model=\"value\""," on a component, Vue expands that (by default, in Vue 3) into binding a ",[66,15773,15774],{},"modelValue"," prop and listening for an ",[66,15777,15778],{},"update:modelValue"," event:",[507,15781,15783],{"className":8546,"code":15782,"language":8548,"meta":512,"style":512},"\u003CCustomInput v-model=\"searchText\" />\n\n\u003C!-- is shorthand for -->\n\u003CCustomInput\n    :model-value=\"searchText\"\n    @update:model-value=\"newValue => searchText = newValue\"\n/>\n",[66,15784,15785,15806,15810,15815,15822,15839,15869],{"__ignoreMap":512},[516,15786,15787,15789,15792,15795,15797,15799,15802,15804],{"class":518,"line":519},[516,15788,3042],{"class":1227},[516,15790,15791],{"class":8557},"CustomInput",[516,15793,15794],{"class":4733}," v-model",[516,15796,1894],{"class":1227},[516,15798,3247],{"class":1248},[516,15800,15801],{"class":1227},"searchText",[516,15803,3247],{"class":1248},[516,15805,9667],{"class":1227},[516,15807,15808],{"class":518,"line":525},[516,15809,1131],{"emptyLinePlaceholder":1130},[516,15811,15812],{"class":518,"line":531},[516,15813,15814],{"class":3076},"\u003C!-- is shorthand for -->\n",[516,15816,15817,15819],{"class":518,"line":1127},[516,15818,3042],{"class":1227},[516,15820,15821],{"class":8557},"CustomInput\n",[516,15823,15824,15827,15830,15832,15834,15836],{"class":518,"line":1134},[516,15825,15826],{"class":1227},"    :",[516,15828,15829],{"class":4733},"model-value",[516,15831,1894],{"class":1227},[516,15833,3247],{"class":1248},[516,15835,15801],{"class":1227},[516,15837,15838],{"class":1248},"\"\n",[516,15840,15841,15844,15847,15849,15851,15853,15855,15857,15859,15862,15864,15867],{"class":518,"line":1275},[516,15842,15843],{"class":1227},"    @",[516,15845,15846],{"class":4733},"update",[516,15848,9605],{"class":1227},[516,15850,15829],{"class":4733},[516,15852,1894],{"class":1227},[516,15854,3247],{"class":1248},[516,15856,14205],{"class":9080},[516,15858,11049],{"class":1749},[516,15860,15861],{"class":1227}," searchText ",[516,15863,1894],{"class":1749},[516,15865,15866],{"class":1227}," newValue",[516,15868,15838],{"class":1248},[516,15870,15871],{"class":518,"line":1302},[516,15872,15873],{"class":1227},"/>\n",[11,15875,15876],{},"For the component to actually support this, it needs to declare the matching prop and emit the matching event itself:",[507,15878,15880],{"className":8546,"code":15879,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst props = defineProps(['modelValue'])\nconst emit = defineEmits(['update:modelValue'])\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cinput\n        :value=\"modelValue\"\n        @input=\"emit('update:modelValue', $event.target.value)\"\n    />\n\u003C/template>\n",[66,15881,15882,15892,15909,15926,15934,15938,15946,15953,15963,15973,15978],{"__ignoreMap":512},[516,15883,15884,15886,15888,15890],{"class":518,"line":519},[516,15885,3042],{"class":1227},[516,15887,8604],{"class":8557},[516,15889,8607],{"class":4733},[516,15891,8561],{"class":1227},[516,15893,15894,15896,15898,15900,15902,15904,15907],{"class":518,"line":525},[516,15895,8632],{"class":1749},[516,15897,14882],{"class":1233},[516,15899,1793],{"class":1749},[516,15901,14887],{"class":4733},[516,15903,11992],{"class":1227},[516,15905,15906],{"class":1248},"'modelValue'",[516,15908,12006],{"class":1227},[516,15910,15911,15913,15915,15917,15919,15921,15924],{"class":518,"line":531},[516,15912,8632],{"class":1749},[516,15914,15461],{"class":1233},[516,15916,1793],{"class":1749},[516,15918,15466],{"class":4733},[516,15920,11992],{"class":1227},[516,15922,15923],{"class":1248},"'update:modelValue'",[516,15925,12006],{"class":1227},[516,15927,15928,15930,15932],{"class":518,"line":1127},[516,15929,8589],{"class":1227},[516,15931,8604],{"class":8557},[516,15933,8561],{"class":1227},[516,15935,15936],{"class":518,"line":1134},[516,15937,1131],{"emptyLinePlaceholder":1130},[516,15939,15940,15942,15944],{"class":518,"line":1275},[516,15941,3042],{"class":1227},[516,15943,8558],{"class":8557},[516,15945,8561],{"class":1227},[516,15947,15948,15950],{"class":518,"line":1302},[516,15949,8566],{"class":1227},[516,15951,15952],{"class":8557},"input\n",[516,15954,15955,15958,15960],{"class":518,"line":1308},[516,15956,15957],{"class":4733},"        :value",[516,15959,1894],{"class":1227},[516,15961,15962],{"class":1248},"\"modelValue\"\n",[516,15964,15965,15968,15970],{"class":518,"line":1314},[516,15966,15967],{"class":4733},"        @input",[516,15969,1894],{"class":1227},[516,15971,15972],{"class":1248},"\"emit('update:modelValue', $event.target.value)\"\n",[516,15974,15975],{"class":518,"line":8656},[516,15976,15977],{"class":1227},"    />\n",[516,15979,15980,15982,15984],{"class":518,"line":8668},[516,15981,8589],{"class":1227},[516,15983,8558],{"class":8557},[516,15985,8561],{"class":1227},[11,15987,15988,15989,15991,15992,15994,15995,15997,15998,16000],{},"So ",[66,15990,10557],{}," isn't magic tied specifically to form elements, it's just a naming convention (",[66,15993,15774],{}," in, ",[66,15996,15778],{}," out) that any component can implement to get two-way binding syntax for free. ",[66,15999,15188],{}," (Vue 3.4+) generates exactly this prop/emit pair for you automatically.",[23,16002,16004,16005,16007],{"id":16003},"_55-how-do-you-support-multiple-v-model-bindings-on-the-same-component","55. How do you support multiple ",[66,16006,10557],{}," bindings on the same component?",[11,16009,16010,16011,16013,16014,15185,16016,405],{},"A single component isn't limited to one ",[66,16012,10557],{},", you can give each binding a name as an argument, and Vue expands each named binding into its own prop/event pair instead of the default ",[66,16015,15774],{},[66,16017,15778],{},[507,16019,16021],{"className":8546,"code":16020,"language":8548,"meta":512,"style":512},"\u003CUserForm v-model:first-name=\"firstName\" v-model:last-name=\"lastName\" />\n",[66,16022,16023],{"__ignoreMap":512},[516,16024,16025,16027,16030,16032,16034,16037,16039,16041,16043,16045,16047,16049,16052,16054,16056,16058,16060],{"class":518,"line":519},[516,16026,3042],{"class":1227},[516,16028,16029],{"class":8557},"UserForm",[516,16031,15794],{"class":4733},[516,16033,9605],{"class":1227},[516,16035,16036],{"class":4733},"first-name",[516,16038,1894],{"class":1227},[516,16040,3247],{"class":1248},[516,16042,14173],{"class":1227},[516,16044,3247],{"class":1248},[516,16046,15794],{"class":4733},[516,16048,9605],{"class":1227},[516,16050,16051],{"class":4733},"last-name",[516,16053,1894],{"class":1227},[516,16055,3247],{"class":1248},[516,16057,14183],{"class":1227},[516,16059,3247],{"class":1248},[516,16061,9667],{"class":1227},[11,16063,16064,16065,16067,16068,16071,16072,16067,16074,16077],{},"That expands to binding a ",[66,16066,14173],{}," prop with an ",[66,16069,16070],{},"update:firstName"," listener, and separately a ",[66,16073,14183],{},[66,16075,16076],{},"update:lastName"," listener. The component needs to declare and emit each one:",[507,16079,16081],{"className":8546,"code":16080,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\ndefineProps(['firstName', 'lastName'])\ndefineEmits(['update:firstName', 'update:lastName'])\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cinput\n        :value=\"firstName\"\n        @input=\"$emit('update:firstName', $event.target.value)\"\n    />\n    \u003Cinput\n        :value=\"lastName\"\n        @input=\"$emit('update:lastName', $event.target.value)\"\n    />\n\u003C/template>\n",[66,16082,16083,16093,16109,16125,16133,16137,16145,16151,16160,16169,16173,16179,16188,16197,16201],{"__ignoreMap":512},[516,16084,16085,16087,16089,16091],{"class":518,"line":519},[516,16086,3042],{"class":1227},[516,16088,8604],{"class":8557},[516,16090,8607],{"class":4733},[516,16092,8561],{"class":1227},[516,16094,16095,16097,16099,16102,16104,16107],{"class":518,"line":525},[516,16096,14859],{"class":4733},[516,16098,11992],{"class":1227},[516,16100,16101],{"class":1248},"'firstName'",[516,16103,154],{"class":1227},[516,16105,16106],{"class":1248},"'lastName'",[516,16108,12006],{"class":1227},[516,16110,16111,16113,16115,16118,16120,16123],{"class":518,"line":531},[516,16112,15426],{"class":4733},[516,16114,11992],{"class":1227},[516,16116,16117],{"class":1248},"'update:firstName'",[516,16119,154],{"class":1227},[516,16121,16122],{"class":1248},"'update:lastName'",[516,16124,12006],{"class":1227},[516,16126,16127,16129,16131],{"class":518,"line":1127},[516,16128,8589],{"class":1227},[516,16130,8604],{"class":8557},[516,16132,8561],{"class":1227},[516,16134,16135],{"class":518,"line":1134},[516,16136,1131],{"emptyLinePlaceholder":1130},[516,16138,16139,16141,16143],{"class":518,"line":1275},[516,16140,3042],{"class":1227},[516,16142,8558],{"class":8557},[516,16144,8561],{"class":1227},[516,16146,16147,16149],{"class":518,"line":1302},[516,16148,8566],{"class":1227},[516,16150,15952],{"class":8557},[516,16152,16153,16155,16157],{"class":518,"line":1308},[516,16154,15957],{"class":4733},[516,16156,1894],{"class":1227},[516,16158,16159],{"class":1248},"\"firstName\"\n",[516,16161,16162,16164,16166],{"class":518,"line":1314},[516,16163,15967],{"class":4733},[516,16165,1894],{"class":1227},[516,16167,16168],{"class":1248},"\"$emit('update:firstName', $event.target.value)\"\n",[516,16170,16171],{"class":518,"line":8656},[516,16172,15977],{"class":1227},[516,16174,16175,16177],{"class":518,"line":8668},[516,16176,8566],{"class":1227},[516,16178,15952],{"class":8557},[516,16180,16181,16183,16185],{"class":518,"line":8677},[516,16182,15957],{"class":4733},[516,16184,1894],{"class":1227},[516,16186,16187],{"class":1248},"\"lastName\"\n",[516,16189,16190,16192,16194],{"class":518,"line":8682},[516,16191,15967],{"class":4733},[516,16193,1894],{"class":1227},[516,16195,16196],{"class":1248},"\"$emit('update:lastName', $event.target.value)\"\n",[516,16198,16199],{"class":518,"line":8691},[516,16200,15977],{"class":1227},[516,16202,16203,16205,16207],{"class":518,"line":8696},[516,16204,8589],{"class":1227},[516,16206,8558],{"class":8557},[516,16208,8561],{"class":1227},[11,16210,16211,16212,16214,16215,16217],{},"This is the same underlying mechanism as a plain ",[66,16213,10557],{},", just with a name attached instead of relying on the ",[66,16216,15774],{}," default, so a component can expose as many independent two-way bindings as it needs.",[23,16219,16221,16222,16224,16225,16227],{"id":16220},"_56-what-is-definemodel-vue-34-and-how-does-it-simplify-writing-v-model-support","56. What is ",[66,16223,15188],{}," (Vue 3.4+), and how does it simplify writing ",[66,16226,10557],{}," support?",[11,16229,16230,16232,16233,16235,16236,16238,16239,16242],{},[66,16231,15188],{}," is a ",[66,16234,8448],{}," compiler macro, stabilized in Vue 3.4, that collapses the manual \"declare a prop, declare an emit, wire them together\" boilerplate for ",[66,16237,10557],{}," support into a single line. It automatically declares the underlying prop and the matching ",[66,16240,16241],{},"update:"," event for you, and returns a ref you can read and write directly, writing to it automatically emits the update event.",[507,16244,16246],{"className":8546,"code":16245,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst model = defineModel()\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cinput v-model=\"model\" />\n\u003C/template>\n",[66,16247,16248,16258,16272,16280,16284,16292,16307],{"__ignoreMap":512},[516,16249,16250,16252,16254,16256],{"class":518,"line":519},[516,16251,3042],{"class":1227},[516,16253,8604],{"class":8557},[516,16255,8607],{"class":4733},[516,16257,8561],{"class":1227},[516,16259,16260,16262,16265,16267,16270],{"class":518,"line":525},[516,16261,8632],{"class":1749},[516,16263,16264],{"class":1233}," model",[516,16266,1793],{"class":1749},[516,16268,16269],{"class":4733}," defineModel",[516,16271,13318],{"class":1227},[516,16273,16274,16276,16278],{"class":518,"line":531},[516,16275,8589],{"class":1227},[516,16277,8604],{"class":8557},[516,16279,8561],{"class":1227},[516,16281,16282],{"class":518,"line":1127},[516,16283,1131],{"emptyLinePlaceholder":1130},[516,16285,16286,16288,16290],{"class":518,"line":1134},[516,16287,3042],{"class":1227},[516,16289,8558],{"class":8557},[516,16291,8561],{"class":1227},[516,16293,16294,16296,16298,16300,16302,16305],{"class":518,"line":1275},[516,16295,8566],{"class":1227},[516,16297,10575],{"class":8557},[516,16299,15794],{"class":4733},[516,16301,1894],{"class":1227},[516,16303,16304],{"class":1248},"\"model\"",[516,16306,9667],{"class":1227},[516,16308,16309,16311,16313],{"class":518,"line":1302},[516,16310,8589],{"class":1227},[516,16312,8558],{"class":8557},[516,16314,8561],{"class":1227},[11,16316,16317,16318,2958,16320,16322,16323,16326,16327,16329],{},"That's the entire component, no manual ",[66,16319,14859],{},[66,16321,15426],{}," pairing needed, ",[66,16324,16325],{},"model.value = x"," behaves just like updating any other ref, but under the hood it emits ",[66,16328,15778],{}," for the parent.",[11,16331,16332],{},"It also supports named models and options, mirroring what you'd otherwise write by hand:",[507,16334,16336],{"className":8546,"code":16335,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst firstName = defineModel('firstName', { required: true })\nconst disabled = defineModel('disabled', { default: false })\n\u003C/script>\n",[66,16337,16338,16348,16369,16392],{"__ignoreMap":512},[516,16339,16340,16342,16344,16346],{"class":518,"line":519},[516,16341,3042],{"class":1227},[516,16343,8604],{"class":8557},[516,16345,8607],{"class":4733},[516,16347,8561],{"class":1227},[516,16349,16350,16352,16354,16356,16358,16360,16362,16365,16367],{"class":518,"line":525},[516,16351,8632],{"class":1749},[516,16353,14110],{"class":1233},[516,16355,1793],{"class":1749},[516,16357,16269],{"class":4733},[516,16359,8643],{"class":1227},[516,16361,16101],{"class":1248},[516,16363,16364],{"class":1227},", { required: ",[516,16366,10228],{"class":1233},[516,16368,11494],{"class":1227},[516,16370,16371,16373,16376,16378,16380,16382,16385,16388,16390],{"class":518,"line":531},[516,16372,8632],{"class":1749},[516,16374,16375],{"class":1233}," disabled",[516,16377,1793],{"class":1749},[516,16379,16269],{"class":4733},[516,16381,8643],{"class":1227},[516,16383,16384],{"class":1248},"'disabled'",[516,16386,16387],{"class":1227},", { default: ",[516,16389,12981],{"class":1233},[516,16391,11494],{"class":1227},[516,16393,16394,16396,16398],{"class":518,"line":1127},[516,16395,8589],{"class":1227},[516,16397,8604],{"class":8557},[516,16399,8561],{"class":1227},[11,16401,16402,16403,16405,16406,148,16408,16410],{},"Before 3.4, achieving this required a ",[66,16404,9012],{}," with a getter reading the prop and a setter calling ",[66,16407,15438],{},[66,16409,15188],{}," is purely a developer-experience improvement, the compiled output is functionally the same prop/emit pair described in question 54.",[23,16412,16414,16415,16417,16418,706],{"id":16413},"_57-what-is-attrs-and-what-does-setting-inheritattrs-false-do","57. What is ",[66,16416,10873],{},", and what does setting ",[66,16419,16420],{},"inheritAttrs: false",[11,16422,16423,16425,16426,16428,16429,154,16431,154,16433,16436,16437,16440],{},[66,16424,10873],{}," holds all the attributes and event listeners passed to a component from its parent that weren't declared as props (or explicitly listed in ",[66,16427,15609],{},"). Things like ",[66,16430,1578],{},[66,16432,10106],{},[66,16434,16435],{},"data-*"," attributes, or a random ",[66,16438,16439],{},"@click"," handler someone put on your component tend to end up here if you didn't declare them yourself.",[11,16442,16443,16444,16446,16447,756,16449,16451],{},"By default, Vue automatically applies everything in ",[66,16445,10873],{}," to the component's single root element, this is called \"attribute fallthrough\" and is why you can slap a ",[66,16448,10106],{},[66,16450,1578],{}," on a custom component and have it just land on the right DOM element without you writing any code for it.",[11,16453,16454,16456,16457,16460,16461,16463,16464,16466,16467,16469],{},[66,16455,16420],{}," turns that automatic behavior off, which you use when the automatic target (the root element) isn't actually where those attributes should go, for example a component that wraps a ",[66,16458,16459],{},"\u003Clabel>"," and an ",[66,16462,10027],{},", where attrs like ",[66,16465,1578],{}," really belong on the ",[66,16468,10027],{},", not the outer wrapper.",[507,16471,16473],{"className":8546,"code":16472,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\ndefineOptions({ inheritAttrs: false })\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cdiv class=\"field\">\n        \u003Clabel>Name\u003C/label>\n        \u003Cinput v-bind=\"$attrs\" />\n    \u003C/div>\n\u003C/template>\n",[66,16474,16475,16485,16497,16505,16509,16517,16532,16546,16561,16569],{"__ignoreMap":512},[516,16476,16477,16479,16481,16483],{"class":518,"line":519},[516,16478,3042],{"class":1227},[516,16480,8604],{"class":8557},[516,16482,8607],{"class":4733},[516,16484,8561],{"class":1227},[516,16486,16487,16490,16493,16495],{"class":518,"line":525},[516,16488,16489],{"class":4733},"defineOptions",[516,16491,16492],{"class":1227},"({ inheritAttrs: ",[516,16494,12981],{"class":1233},[516,16496,11494],{"class":1227},[516,16498,16499,16501,16503],{"class":518,"line":531},[516,16500,8589],{"class":1227},[516,16502,8604],{"class":8557},[516,16504,8561],{"class":1227},[516,16506,16507],{"class":518,"line":1127},[516,16508,1131],{"emptyLinePlaceholder":1130},[516,16510,16511,16513,16515],{"class":518,"line":1134},[516,16512,3042],{"class":1227},[516,16514,8558],{"class":8557},[516,16516,8561],{"class":1227},[516,16518,16519,16521,16523,16526,16528,16530],{"class":518,"line":1275},[516,16520,8566],{"class":1227},[516,16522,9764],{"class":8557},[516,16524,16525],{"class":4733}," class",[516,16527,1894],{"class":1227},[516,16529,1281],{"class":1248},[516,16531,8561],{"class":1227},[516,16533,16534,16536,16539,16542,16544],{"class":518,"line":1302},[516,16535,9868],{"class":1227},[516,16537,16538],{"class":8557},"label",[516,16540,16541],{"class":1227},">Name\u003C/",[516,16543,16538],{"class":8557},[516,16545,8561],{"class":1227},[516,16547,16548,16550,16552,16554,16556,16559],{"class":518,"line":1308},[516,16549,9868],{"class":1227},[516,16551,10575],{"class":8557},[516,16553,10802],{"class":4733},[516,16555,1894],{"class":1227},[516,16557,16558],{"class":1248},"\"$attrs\"",[516,16560,9667],{"class":1227},[516,16562,16563,16565,16567],{"class":518,"line":1314},[516,16564,9907],{"class":1227},[516,16566,9764],{"class":8557},[516,16568,8561],{"class":1227},[516,16570,16571,16573,16575],{"class":518,"line":8656},[516,16572,8589],{"class":1227},[516,16574,8558],{"class":8557},[516,16576,8561],{"class":1227},[11,16578,14052,16579,16581,16582,16584,16585,405],{},[66,16580,10873],{}," is bound explicitly to the ",[66,16583,10027],{}," instead of being auto-applied to the outer ",[66,16586,16587],{},"\u003Cdiv>",[23,16589,16591],{"id":16590},"_58-how-does-attribute-fallthrough-work-for-components-with-multiple-root-nodes","58. How does attribute fallthrough work for components with multiple root nodes?",[11,16593,16594,16595,16597,16598,16600],{},"Attribute fallthrough (auto-applying ",[66,16596,10873],{}," to the DOM) only works cleanly when a component has a single root element, Vue knows exactly where those leftover attributes should land. When a component template has multiple root nodes (a \"fragment\" component, like a ",[66,16599,8745],{}," with a couple of sibling elements), Vue has no way to guess which of those roots should receive the attributes, so it does not apply them automatically, and in development it logs a warning if there are unresolved attrs.",[507,16602,16604],{"className":8546,"code":16603,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cheader>...\u003C/header>\n    \u003Cmain>...\u003C/main>\n\u003C/template>\n",[66,16605,16606,16614,16628,16641],{"__ignoreMap":512},[516,16607,16608,16610,16612],{"class":518,"line":519},[516,16609,3042],{"class":1227},[516,16611,8558],{"class":8557},[516,16613,8561],{"class":1227},[516,16615,16616,16618,16621,16624,16626],{"class":518,"line":525},[516,16617,8566],{"class":1227},[516,16619,16620],{"class":8557},"header",[516,16622,16623],{"class":1227},">...\u003C/",[516,16625,16620],{"class":8557},[516,16627,8561],{"class":1227},[516,16629,16630,16632,16635,16637,16639],{"class":518,"line":531},[516,16631,8566],{"class":1227},[516,16633,16634],{"class":8557},"main",[516,16636,16623],{"class":1227},[516,16638,16634],{"class":8557},[516,16640,8561],{"class":1227},[516,16642,16643,16645,16647],{"class":518,"line":1127},[516,16644,8589],{"class":1227},[516,16646,8558],{"class":8557},[516,16648,8561],{"class":1227},[11,16650,16651,16652,16654],{},"To fix the warning and actually apply the fallthrough attributes somewhere sensible, you bind ",[66,16653,10873],{}," manually to whichever root element makes sense:",[507,16656,16658],{"className":8546,"code":16657,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cheader v-bind=\"$attrs\">...\u003C/header>\n    \u003Cmain>...\u003C/main>\n\u003C/template>\n",[66,16659,16660,16668,16686,16698],{"__ignoreMap":512},[516,16661,16662,16664,16666],{"class":518,"line":519},[516,16663,3042],{"class":1227},[516,16665,8558],{"class":8557},[516,16667,8561],{"class":1227},[516,16669,16670,16672,16674,16676,16678,16680,16682,16684],{"class":518,"line":525},[516,16671,8566],{"class":1227},[516,16673,16620],{"class":8557},[516,16675,10802],{"class":4733},[516,16677,1894],{"class":1227},[516,16679,16558],{"class":1248},[516,16681,16623],{"class":1227},[516,16683,16620],{"class":8557},[516,16685,8561],{"class":1227},[516,16687,16688,16690,16692,16694,16696],{"class":518,"line":531},[516,16689,8566],{"class":1227},[516,16691,16634],{"class":8557},[516,16693,16623],{"class":1227},[516,16695,16634],{"class":8557},[516,16697,8561],{"class":1227},[516,16699,16700,16702,16704],{"class":518,"line":1127},[516,16701,8589],{"class":1227},[516,16703,8558],{"class":8557},[516,16705,8561],{"class":1227},[11,16707,16708,16709,16711],{},"This is really the same rule as ",[66,16710,16420],{},", Vue only auto-applies attrs when it's unambiguous which element should receive them, and steps back to let you decide explicitly whenever that's not the case.",[23,16713,16715,16716,16719,16720,9728],{"id":16714},"_59-what-is-defineexpose-and-why-do-you-need-it-with-script-setup","59. What is ",[66,16717,16718],{},"defineExpose",", and why do you need it with ",[66,16721,8448],{},[11,16723,16724,16726,16727,16729],{},[66,16725,16718],{}," is a compiler macro that lets a component explicitly choose which of its internal properties and methods a parent is allowed to access through a template ref. By default, components written with ",[66,16728,8448],{}," are \"closed\": everything declared inside the script block is private to that component and invisible from the outside, even if the parent holds a template ref pointing at it.",[507,16731,16733],{"className":8546,"code":16732,"language":8548,"meta":512,"style":512},"\u003C!-- Child.vue -->\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\nfunction reset() {\n    count.value = 0\n}\n\ndefineExpose({ reset })\n\u003C/script>\n",[66,16734,16735,16740,16750,16760,16764,16780,16789,16798,16802,16806,16813],{"__ignoreMap":512},[516,16736,16737],{"class":518,"line":519},[516,16738,16739],{"class":3076},"\u003C!-- Child.vue -->\n",[516,16741,16742,16744,16746,16748],{"class":518,"line":525},[516,16743,3042],{"class":1227},[516,16745,8604],{"class":8557},[516,16747,8607],{"class":4733},[516,16749,8561],{"class":1227},[516,16751,16752,16754,16756,16758],{"class":518,"line":531},[516,16753,8614],{"class":1749},[516,16755,8617],{"class":1227},[516,16757,8620],{"class":1749},[516,16759,8623],{"class":1248},[516,16761,16762],{"class":518,"line":1127},[516,16763,1131],{"emptyLinePlaceholder":1130},[516,16765,16766,16768,16770,16772,16774,16776,16778],{"class":518,"line":1134},[516,16767,8632],{"class":1749},[516,16769,8635],{"class":1233},[516,16771,1793],{"class":1749},[516,16773,8640],{"class":4733},[516,16775,8643],{"class":1227},[516,16777,8646],{"class":1233},[516,16779,8649],{"class":1227},[516,16781,16782,16784,16787],{"class":518,"line":1275},[516,16783,8659],{"class":1749},[516,16785,16786],{"class":4733}," reset",[516,16788,8665],{"class":1227},[516,16790,16791,16794,16796],{"class":518,"line":1302},[516,16792,16793],{"class":1227},"    count.value ",[516,16795,1894],{"class":1749},[516,16797,15687],{"class":1233},[516,16799,16800],{"class":518,"line":1308},[516,16801,1317],{"class":1227},[516,16803,16804],{"class":518,"line":1314},[516,16805,1131],{"emptyLinePlaceholder":1130},[516,16807,16808,16810],{"class":518,"line":8656},[516,16809,16718],{"class":4733},[516,16811,16812],{"class":1227},"({ reset })\n",[516,16814,16815,16817,16819],{"class":518,"line":8668},[516,16816,8589],{"class":1227},[516,16818,8604],{"class":8557},[516,16820,8561],{"class":1227},[507,16822,16824],{"className":8546,"code":16823,"language":8548,"meta":512,"style":512},"\u003C!-- Parent.vue -->\n\u003Cscript setup>\nimport { ref } from 'vue'\nconst childRef = ref(null)\n\nfunction resetChild() {\n    childRef.value.reset()\n}\n\u003C/script>\n\n\u003Ctemplate>\n    \u003CChild ref=\"childRef\" />\n\u003C/template>\n",[66,16825,16826,16831,16841,16851,16868,16872,16881,16891,16895,16903,16907,16915,16931],{"__ignoreMap":512},[516,16827,16828],{"class":518,"line":519},[516,16829,16830],{"class":3076},"\u003C!-- Parent.vue -->\n",[516,16832,16833,16835,16837,16839],{"class":518,"line":525},[516,16834,3042],{"class":1227},[516,16836,8604],{"class":8557},[516,16838,8607],{"class":4733},[516,16840,8561],{"class":1227},[516,16842,16843,16845,16847,16849],{"class":518,"line":531},[516,16844,8614],{"class":1749},[516,16846,8617],{"class":1227},[516,16848,8620],{"class":1749},[516,16850,8623],{"class":1248},[516,16852,16853,16855,16858,16860,16862,16864,16866],{"class":518,"line":1127},[516,16854,8632],{"class":1749},[516,16856,16857],{"class":1233}," childRef",[516,16859,1793],{"class":1749},[516,16861,8640],{"class":4733},[516,16863,8643],{"class":1227},[516,16865,9102],{"class":1233},[516,16867,8649],{"class":1227},[516,16869,16870],{"class":518,"line":1134},[516,16871,1131],{"emptyLinePlaceholder":1130},[516,16873,16874,16876,16879],{"class":518,"line":1275},[516,16875,8659],{"class":1749},[516,16877,16878],{"class":4733}," resetChild",[516,16880,8665],{"class":1227},[516,16882,16883,16886,16889],{"class":518,"line":1302},[516,16884,16885],{"class":1227},"    childRef.value.",[516,16887,16888],{"class":4733},"reset",[516,16890,13318],{"class":1227},[516,16892,16893],{"class":518,"line":1308},[516,16894,1317],{"class":1227},[516,16896,16897,16899,16901],{"class":518,"line":1314},[516,16898,8589],{"class":1227},[516,16900,8604],{"class":8557},[516,16902,8561],{"class":1227},[516,16904,16905],{"class":518,"line":8656},[516,16906,1131],{"emptyLinePlaceholder":1130},[516,16908,16909,16911,16913],{"class":518,"line":8668},[516,16910,3042],{"class":1227},[516,16912,8558],{"class":8557},[516,16914,8561],{"class":1227},[516,16916,16917,16919,16922,16924,16926,16929],{"class":518,"line":8677},[516,16918,8566],{"class":1227},[516,16920,16921],{"class":8557},"Child",[516,16923,8640],{"class":4733},[516,16925,1894],{"class":1227},[516,16927,16928],{"class":1248},"\"childRef\"",[516,16930,9667],{"class":1227},[516,16932,16933,16935,16937],{"class":518,"line":8682},[516,16934,8589],{"class":1227},[516,16936,8558],{"class":8557},[516,16938,8561],{"class":1227},[11,16940,16941,16942,16945,16946,16949,16950,16953,16954,16956,16957,16960],{},"Without the ",[66,16943,16944],{},"defineExpose({ reset })"," call, ",[66,16947,16948],{},"childRef.value.reset"," would be ",[66,16951,16952],{},"undefined",", since ",[66,16955,8448],{}," doesn't expose anything by default (unlike the Options API, where every property on ",[66,16958,16959],{},"this"," is reachable through a template ref automatically). It's an intentional design choice: it keeps a component's internals private unless it explicitly opts in to being controlled imperatively from outside.",[23,16962,16964],{"id":16963},"_60-what-is-the-difference-between-locally-and-globally-registering-a-component","60. What is the difference between locally and globally registering a component?",[11,16966,16967,16968,16970],{},"Local registration makes a component available only within the specific component that registers it. In ",[66,16969,8448],{},", this happens automatically just by importing the component, no separate registration step needed, and it's usable in that file's template right away.",[11,16972,16973,16974,16977,16978,405],{},"Global registration makes a component available in every template in the entire app, with no per-file import required, by calling ",[66,16975,16976],{},"app.component()"," on the app instance during setup, typically in ",[66,16979,16980],{},"main.js",[507,16982,16984],{"className":8782,"code":16983,"language":8784,"meta":512,"style":512},"// Global registration (main.js)\nimport { createApp } from 'vue'\nimport BaseButton from './components/BaseButton.vue'\n\nconst app = createApp(App)\napp.component('BaseButton', BaseButton)\n",[66,16985,16986,16991,17001,17013,17017,17029],{"__ignoreMap":512},[516,16987,16988],{"class":518,"line":519},[516,16989,16990],{"class":3076},"// Global registration (main.js)\n",[516,16992,16993,16995,16997,16999],{"class":518,"line":525},[516,16994,8614],{"class":1749},[516,16996,8798],{"class":1227},[516,16998,8620],{"class":1749},[516,17000,8623],{"class":1248},[516,17002,17003,17005,17008,17010],{"class":518,"line":531},[516,17004,8614],{"class":1749},[516,17006,17007],{"class":1227}," BaseButton ",[516,17009,8620],{"class":1749},[516,17011,17012],{"class":1248}," './components/BaseButton.vue'\n",[516,17014,17015],{"class":518,"line":1127},[516,17016,1131],{"emptyLinePlaceholder":1130},[516,17018,17019,17021,17023,17025,17027],{"class":518,"line":1134},[516,17020,8632],{"class":1749},[516,17022,8825],{"class":1233},[516,17024,1793],{"class":1749},[516,17026,8830],{"class":4733},[516,17028,8833],{"class":1227},[516,17030,17031,17033,17035,17037,17040],{"class":518,"line":1275},[516,17032,8842],{"class":1227},[516,17034,9422],{"class":4733},[516,17036,8643],{"class":1227},[516,17038,17039],{"class":1248},"'BaseButton'",[516,17041,17042],{"class":1227},", BaseButton)\n",[507,17044,17046],{"className":8546,"code":17045,"language":8548,"meta":512,"style":512},"\u003C!-- Local registration -->\n\u003Cscript setup>\nimport BaseButton from './components/BaseButton.vue'\n\u003C/script>\n\n\u003Ctemplate>\n    \u003CBaseButton />\n\u003C/template>\n",[66,17047,17048,17053,17063,17073,17081,17085,17093,17102],{"__ignoreMap":512},[516,17049,17050],{"class":518,"line":519},[516,17051,17052],{"class":3076},"\u003C!-- Local registration -->\n",[516,17054,17055,17057,17059,17061],{"class":518,"line":525},[516,17056,3042],{"class":1227},[516,17058,8604],{"class":8557},[516,17060,8607],{"class":4733},[516,17062,8561],{"class":1227},[516,17064,17065,17067,17069,17071],{"class":518,"line":531},[516,17066,8614],{"class":1749},[516,17068,17007],{"class":1227},[516,17070,8620],{"class":1749},[516,17072,17012],{"class":1248},[516,17074,17075,17077,17079],{"class":518,"line":1127},[516,17076,8589],{"class":1227},[516,17078,8604],{"class":8557},[516,17080,8561],{"class":1227},[516,17082,17083],{"class":518,"line":1134},[516,17084,1131],{"emptyLinePlaceholder":1130},[516,17086,17087,17089,17091],{"class":518,"line":1275},[516,17088,3042],{"class":1227},[516,17090,8558],{"class":8557},[516,17092,8561],{"class":1227},[516,17094,17095,17097,17100],{"class":518,"line":1302},[516,17096,8566],{"class":1227},[516,17098,17099],{"class":8557},"BaseButton",[516,17101,9667],{"class":1227},[516,17103,17104,17106,17108],{"class":518,"line":1308},[516,17105,8589],{"class":1227},[516,17107,8558],{"class":8557},[516,17109,8561],{"class":1227},[11,17111,17112],{},"Global registration is convenient for components you truly use everywhere, like a base button or icon component, but it comes with a real cost: bundlers can't tree-shake globally registered components, they end up in the main bundle whether or not a given page actually uses them. Local registration keeps the dependency explicit and lets unused components be excluded from a page's bundle, which is why it's the recommended default for most components in most apps.",[23,17114,17116],{"id":17115},"_61-what-are-functional-components-and-when-would-you-reach-for-one","61. What are functional components, and when would you reach for one?",[11,17118,17119,17120,17123],{},"A functional component is a component with no internal state, no lifecycle hooks, and no component instance at all, it's just a plain function that takes props and returns a VNode (the same thing a ",[66,17121,17122],{},"render"," function returns). Because there's no instance to create or track, they're cheaper to render than a stateful component.",[507,17125,17127],{"className":8782,"code":17126,"language":8784,"meta":512,"style":512},"import { h } from 'vue'\n\nfunction StatusIcon(props) {\n    return h('span', { class: `icon icon-${props.status}` })\n}\n\nStatusIcon.props = ['status']\n\nexport default StatusIcon\n",[66,17128,17129,17140,17144,17157,17185,17189,17193,17208,17212],{"__ignoreMap":512},[516,17130,17131,17133,17136,17138],{"class":518,"line":519},[516,17132,8614],{"class":1749},[516,17134,17135],{"class":1227}," { h } ",[516,17137,8620],{"class":1749},[516,17139,8623],{"class":1248},[516,17141,17142],{"class":518,"line":525},[516,17143,1131],{"emptyLinePlaceholder":1130},[516,17145,17146,17148,17151,17153,17155],{"class":518,"line":531},[516,17147,8659],{"class":1749},[516,17149,17150],{"class":4733}," StatusIcon",[516,17152,8643],{"class":1227},[516,17154,12679],{"class":9080},[516,17156,9084],{"class":1227},[516,17158,17159,17161,17163,17165,17168,17171,17174,17176,17178,17181,17183],{"class":518,"line":1127},[516,17160,9089],{"class":1749},[516,17162,9092],{"class":4733},[516,17164,8643],{"class":1227},[516,17166,17167],{"class":1248},"'span'",[516,17169,17170],{"class":1227},", { class: ",[516,17172,17173],{"class":1248},"`icon icon-${",[516,17175,12679],{"class":1227},[516,17177,405],{"class":1248},[516,17179,17180],{"class":1227},"status",[516,17182,14760],{"class":1248},[516,17184,11494],{"class":1227},[516,17186,17187],{"class":518,"line":1134},[516,17188,1317],{"class":1227},[516,17190,17191],{"class":518,"line":1275},[516,17192,1131],{"emptyLinePlaceholder":1130},[516,17194,17195,17198,17200,17202,17205],{"class":518,"line":1302},[516,17196,17197],{"class":1227},"StatusIcon.props ",[516,17199,1894],{"class":1749},[516,17201,14214],{"class":1227},[516,17203,17204],{"class":1248},"'status'",[516,17206,17207],{"class":1227},"]\n",[516,17209,17210],{"class":518,"line":1308},[516,17211,1131],{"emptyLinePlaceholder":1130},[516,17213,17214,17216,17218],{"class":518,"line":1314},[516,17215,9190],{"class":1749},[516,17217,9193],{"class":1749},[516,17219,17220],{"class":1227}," StatusIcon\n",[11,17222,17223,17224,17226],{},"In modern Vue 3, this trade-off matters much less than it used to, stateful components are already fast, so functional components aren't a general-purpose performance trick. They're worth reaching for when you have a genuinely simple, purely presentational component that just renders differently based on its props, and you're instantiating a lot of them, for example an icon component rendered hundreds of times in a table, where skipping instance creation adds up. Outside of that fairly narrow case, a normal ",[66,17225,8448],{}," component is simpler to read and maintain.",[23,17228,17230,17231,17233,17234,9728],{"id":17229},"_62-what-does-defineoptions-do-in-script-setup","62. What does ",[66,17232,16489],{}," do in ",[66,17235,8448],{},[11,17237,17238,17240,17241,17243,17244,756,17246,17248,17249,17251,17252,17255,17256,405],{},[66,17239,16489],{}," is a compiler macro that lets you declare plain component options inside ",[66,17242,8448],{}," that don't already have their own dedicated macro (like ",[66,17245,14859],{},[66,17247,15426],{},"). It exists because ",[66,17250,8448],{}," has no ",[66,17253,17254],{},"export default { ... }"," object to attach arbitrary options to, so without it there'd be no way to set things like a component ",[66,17257,189],{},[507,17259,17261],{"className":8546,"code":17260,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\ndefineOptions({\n    name: 'UserCard',\n    inheritAttrs: false\n})\n\u003C/script>\n",[66,17262,17263,17273,17279,17288,17296,17300],{"__ignoreMap":512},[516,17264,17265,17267,17269,17271],{"class":518,"line":519},[516,17266,3042],{"class":1227},[516,17268,8604],{"class":8557},[516,17270,8607],{"class":4733},[516,17272,8561],{"class":1227},[516,17274,17275,17277],{"class":518,"line":525},[516,17276,16489],{"class":4733},[516,17278,12910],{"class":1227},[516,17280,17281,17284,17286],{"class":518,"line":531},[516,17282,17283],{"class":1227},"    name: ",[516,17285,9427],{"class":1248},[516,17287,1252],{"class":1227},[516,17289,17290,17293],{"class":518,"line":1127},[516,17291,17292],{"class":1227},"    inheritAttrs: ",[516,17294,17295],{"class":1233},"false\n",[516,17297,17298],{"class":518,"line":1134},[516,17299,11530],{"class":1227},[516,17301,17302,17304,17306],{"class":518,"line":1275},[516,17303,8589],{"class":1227},[516,17305,8604],{"class":8557},[516,17307,8561],{"class":1227},[11,17309,17310,17311,17313,17314,17316,17317,17320,17321,17323],{},"The most common use is setting ",[66,17312,189],{}," explicitly, which ",[66,17315,8448],{}," can usually infer automatically from the filename during build, but that inference doesn't always work (for example with certain build setups or dynamic imports), and an explicit name is needed for things like Vue devtools display, ",[66,17318,17319],{},"\u003CKeepAlive include=\"UserCard\">"," matching, and recursive self-referencing components. It can also carry any other Options API-style option that isn't covered by a more specific ",[66,17322,8448],{}," macro.",[18,17325,17327],{"id":17326},"slots-and-content-distribution","Slots and Content Distribution",[23,17329,17331],{"id":17330},"_63-what-are-slots-in-vue-and-what-problem-do-they-solve","63. What are slots in Vue, and what problem do they solve?",[11,17333,17334],{},"Slots are how a component lets its parent inject markup into a specific spot in its template, instead of only accepting data through props. Props are great for passing values, but they are awkward for passing chunks of HTML or other components. Slots solve that by giving a component a \"hole\" that the parent fills in.",[11,17336,17337],{},"This is what makes wrapper components like cards, modals, or layout shells reusable: the component owns the structure and styling, and the parent owns the content.",[507,17339,17341],{"className":8546,"code":17340,"language":8548,"meta":512,"style":512},"\u003C!-- Card.vue -->\n\u003Ctemplate>\n    \u003Cdiv class=\"card\">\n        \u003Cslot>\u003C/slot>\n    \u003C/div>\n\u003C/template>\n",[66,17342,17343,17348,17356,17371,17384,17392],{"__ignoreMap":512},[516,17344,17345],{"class":518,"line":519},[516,17346,17347],{"class":3076},"\u003C!-- Card.vue -->\n",[516,17349,17350,17352,17354],{"class":518,"line":525},[516,17351,3042],{"class":1227},[516,17353,8558],{"class":8557},[516,17355,8561],{"class":1227},[516,17357,17358,17360,17362,17364,17366,17369],{"class":518,"line":531},[516,17359,8566],{"class":1227},[516,17361,9764],{"class":8557},[516,17363,16525],{"class":4733},[516,17365,1894],{"class":1227},[516,17367,17368],{"class":1248},"\"card\"",[516,17370,8561],{"class":1227},[516,17372,17373,17375,17378,17380,17382],{"class":518,"line":1127},[516,17374,9868],{"class":1227},[516,17376,17377],{"class":8557},"slot",[516,17379,10142],{"class":1227},[516,17381,17377],{"class":8557},[516,17383,8561],{"class":1227},[516,17385,17386,17388,17390],{"class":518,"line":1134},[516,17387,9907],{"class":1227},[516,17389,9764],{"class":8557},[516,17391,8561],{"class":1227},[516,17393,17394,17396,17398],{"class":518,"line":1275},[516,17395,8589],{"class":1227},[516,17397,8558],{"class":8557},[516,17399,8561],{"class":1227},[507,17401,17403],{"className":8546,"code":17402,"language":8548,"meta":512,"style":512},"\u003C!-- usage -->\n\u003CCard>\n    \u003Ch2>Title\u003C/h2>\n    \u003Cp>Some content passed in from the parent.\u003C/p>\n\u003C/Card>\n",[66,17404,17405,17410,17419,17424,17429],{"__ignoreMap":512},[516,17406,17407],{"class":518,"line":519},[516,17408,17409],{"class":3076},"\u003C!-- usage -->\n",[516,17411,17412,17414,17417],{"class":518,"line":525},[516,17413,3042],{"class":1227},[516,17415,17416],{"class":8557},"Card",[516,17418,8561],{"class":1227},[516,17420,17421],{"class":518,"line":531},[516,17422,17423],{"class":1227},"    \u003Ch2>Title\u003C/h2>\n",[516,17425,17426],{"class":518,"line":1127},[516,17427,17428],{"class":1227},"    \u003Cp>Some content passed in from the parent.\u003C/p>\n",[516,17430,17431,17433,17435],{"class":518,"line":1134},[516,17432,8589],{"class":1227},[516,17434,17416],{"class":8557},[516,17436,8561],{"class":1227},[11,17438,17439,17440,202,17443,17446,17447,17450,17451,17454,17455,17458],{},"Whatever markup you put between ",[66,17441,17442],{},"\u003CCard>",[66,17444,17445],{},"\u003C/Card>"," gets rendered wherever ",[66,17448,17449],{},"\u003Cslot>\u003C/slot>"," sits inside ",[66,17452,17453],{},"Card.vue",". If a component has no ",[66,17456,17457],{},"\u003Cslot>"," tag, anything you place between its tags is simply discarded.",[23,17460,17462],{"id":17461},"_64-what-is-a-named-slot","64. What is a named slot?",[11,17464,17465,17466,17469,17470,17473,17474,2725],{},"A named slot lets a component expose more than one insertion point, each identified by a name, so the parent can send different content to different parts of the child's template. You define one with ",[66,17467,17468],{},"\u003Cslot name=\"header\">\u003C/slot>"," in the child, and fill it from the parent using ",[66,17471,17472],{},"\u003Ctemplate #header>"," (shorthand for ",[66,17475,17476],{},"v-slot:header",[11,17478,17479,17480,17483],{},"Any slot content without a ",[66,17481,17482],{},"#name"," goes to the special \"default\" slot.",[507,17485,17487],{"className":8546,"code":17486,"language":8548,"meta":512,"style":512},"\u003C!-- Layout.vue -->\n\u003Ctemplate>\n    \u003Cheader>\u003Cslot name=\"header\">\u003C/slot>\u003C/header>\n    \u003Cmain>\u003Cslot>\u003C/slot>\u003C/main>\n    \u003Cfooter>\u003Cslot name=\"footer\">\u003C/slot>\u003C/footer>\n\u003C/template>\n",[66,17488,17489,17494,17502,17531,17551,17579],{"__ignoreMap":512},[516,17490,17491],{"class":518,"line":519},[516,17492,17493],{"class":3076},"\u003C!-- Layout.vue -->\n",[516,17495,17496,17498,17500],{"class":518,"line":525},[516,17497,3042],{"class":1227},[516,17499,8558],{"class":8557},[516,17501,8561],{"class":1227},[516,17503,17504,17506,17508,17511,17513,17516,17518,17521,17523,17525,17527,17529],{"class":518,"line":531},[516,17505,8566],{"class":1227},[516,17507,16620],{"class":8557},[516,17509,17510],{"class":1227},">\u003C",[516,17512,17377],{"class":8557},[516,17514,17515],{"class":4733}," name",[516,17517,1894],{"class":1227},[516,17519,17520],{"class":1248},"\"header\"",[516,17522,10142],{"class":1227},[516,17524,17377],{"class":8557},[516,17526,10142],{"class":1227},[516,17528,16620],{"class":8557},[516,17530,8561],{"class":1227},[516,17532,17533,17535,17537,17539,17541,17543,17545,17547,17549],{"class":518,"line":1127},[516,17534,8566],{"class":1227},[516,17536,16634],{"class":8557},[516,17538,17510],{"class":1227},[516,17540,17377],{"class":8557},[516,17542,10142],{"class":1227},[516,17544,17377],{"class":8557},[516,17546,10142],{"class":1227},[516,17548,16634],{"class":8557},[516,17550,8561],{"class":1227},[516,17552,17553,17555,17558,17560,17562,17564,17566,17569,17571,17573,17575,17577],{"class":518,"line":1134},[516,17554,8566],{"class":1227},[516,17556,17557],{"class":8557},"footer",[516,17559,17510],{"class":1227},[516,17561,17377],{"class":8557},[516,17563,17515],{"class":4733},[516,17565,1894],{"class":1227},[516,17567,17568],{"class":1248},"\"footer\"",[516,17570,10142],{"class":1227},[516,17572,17377],{"class":8557},[516,17574,10142],{"class":1227},[516,17576,17557],{"class":8557},[516,17578,8561],{"class":1227},[516,17580,17581,17583,17585],{"class":518,"line":1275},[516,17582,8589],{"class":1227},[516,17584,8558],{"class":8557},[516,17586,8561],{"class":1227},[507,17588,17590],{"className":8546,"code":17589,"language":8548,"meta":512,"style":512},"\u003C!-- usage -->\n\u003CLayout>\n    \u003Ctemplate #header>\n        \u003Ch1>Page Title\u003C/h1>\n    \u003C/template>\n\n    \u003Cp>Main content goes in the default slot.\u003C/p>\n\n    \u003Ctemplate #footer>\n        \u003Csmall>© 2026\u003C/small>\n    \u003C/template>\n\u003C/Layout>\n",[66,17591,17592,17596,17605,17610,17615,17620,17624,17629,17633,17638,17643,17647],{"__ignoreMap":512},[516,17593,17594],{"class":518,"line":519},[516,17595,17409],{"class":3076},[516,17597,17598,17600,17603],{"class":518,"line":525},[516,17599,3042],{"class":1227},[516,17601,17602],{"class":8557},"Layout",[516,17604,8561],{"class":1227},[516,17606,17607],{"class":518,"line":531},[516,17608,17609],{"class":1227},"    \u003Ctemplate #header>\n",[516,17611,17612],{"class":518,"line":1127},[516,17613,17614],{"class":1227},"        \u003Ch1>Page Title\u003C/h1>\n",[516,17616,17617],{"class":518,"line":1134},[516,17618,17619],{"class":1227},"    \u003C/template>\n",[516,17621,17622],{"class":518,"line":1275},[516,17623,1131],{"emptyLinePlaceholder":1130},[516,17625,17626],{"class":518,"line":1302},[516,17627,17628],{"class":1227},"    \u003Cp>Main content goes in the default slot.\u003C/p>\n",[516,17630,17631],{"class":518,"line":1308},[516,17632,1131],{"emptyLinePlaceholder":1130},[516,17634,17635],{"class":518,"line":1314},[516,17636,17637],{"class":1227},"    \u003Ctemplate #footer>\n",[516,17639,17640],{"class":518,"line":8656},[516,17641,17642],{"class":1227},"        \u003Csmall>© 2026\u003C/small>\n",[516,17644,17645],{"class":518,"line":8668},[516,17646,17619],{"class":1227},[516,17648,17649,17651,17653],{"class":518,"line":8677},[516,17650,8589],{"class":1227},[516,17652,17602],{"class":8557},[516,17654,8561],{"class":1227},[11,17656,17657],{},"Named slots are what make multi-region components (page layouts, dialogs with a header/body/footer) possible without hardcoding structure.",[23,17659,17661],{"id":17660},"_65-what-is-a-scoped-slot-and-why-would-a-child-component-pass-data-back-through-its-slot","65. What is a scoped slot, and why would a child component pass data back through its slot?",[11,17663,17664],{},"A scoped slot is a slot that carries data from the child back out to the parent, so the parent's slot content can use information the child owns, such as loop items or internal state. Normally content flows one way: parent to child. A scoped slot flips a small part of that, letting the child hand data to the slot content while still letting the parent decide how to render it.",[11,17666,17667,17668,17670,17671,17674,17675,2725],{},"The child passes data by binding it as attributes on the ",[66,17669,17457],{}," element, and the parent reads it through ",[66,17672,17673],{},"v-slot=\"props\""," (or destructured, ",[66,17676,17677],{},"v-slot=\"{ item }\"",[507,17679,17681],{"className":8546,"code":17680,"language":8548,"meta":512,"style":512},"\u003C!-- UserList.vue -->\n\u003Ctemplate>\n    \u003Cul>\n        \u003Cli v-for=\"user in users\" :key=\"user.id\">\n            \u003Cslot :user=\"user\" :is-active=\"user.active\">\u003C/slot>\n        \u003C/li>\n    \u003C/ul>\n\u003C/template>\n",[66,17682,17683,17688,17696,17704,17726,17754,17762,17770],{"__ignoreMap":512},[516,17684,17685],{"class":518,"line":519},[516,17686,17687],{"class":3076},"\u003C!-- UserList.vue -->\n",[516,17689,17690,17692,17694],{"class":518,"line":525},[516,17691,3042],{"class":1227},[516,17693,8558],{"class":8557},[516,17695,8561],{"class":1227},[516,17697,17698,17700,17702],{"class":518,"line":531},[516,17699,8566],{"class":1227},[516,17701,717],{"class":8557},[516,17703,8561],{"class":1227},[516,17705,17706,17708,17710,17712,17714,17717,17719,17721,17724],{"class":518,"line":1127},[516,17707,9868],{"class":1227},[516,17709,720],{"class":8557},[516,17711,9873],{"class":4733},[516,17713,1894],{"class":1227},[516,17715,17716],{"class":1248},"\"user in users\"",[516,17718,9881],{"class":4733},[516,17720,1894],{"class":1227},[516,17722,17723],{"class":1248},"\"user.id\"",[516,17725,8561],{"class":1227},[516,17727,17728,17731,17733,17736,17738,17740,17743,17745,17748,17750,17752],{"class":518,"line":1134},[516,17729,17730],{"class":1227},"            \u003C",[516,17732,17377],{"class":8557},[516,17734,17735],{"class":4733}," :user",[516,17737,1894],{"class":1227},[516,17739,2417],{"class":1248},[516,17741,17742],{"class":4733}," :is-active",[516,17744,1894],{"class":1227},[516,17746,17747],{"class":1248},"\"user.active\"",[516,17749,10142],{"class":1227},[516,17751,17377],{"class":8557},[516,17753,8561],{"class":1227},[516,17755,17756,17758,17760],{"class":518,"line":1275},[516,17757,9898],{"class":1227},[516,17759,720],{"class":8557},[516,17761,8561],{"class":1227},[516,17763,17764,17766,17768],{"class":518,"line":1302},[516,17765,9907],{"class":1227},[516,17767,717],{"class":8557},[516,17769,8561],{"class":1227},[516,17771,17772,17774,17776],{"class":518,"line":1308},[516,17773,8589],{"class":1227},[516,17775,8558],{"class":8557},[516,17777,8561],{"class":1227},[507,17779,17781],{"className":8546,"code":17780,"language":8548,"meta":512,"style":512},"\u003C!-- usage -->\n\u003CUserList :users=\"users\">\n    \u003Ctemplate #default=\"{ user, isActive }\">\n        \u003Cspan :class=\"{ active: isActive }\">{{ user.name }}\u003C/span>\n    \u003C/template>\n\u003C/UserList>\n",[66,17782,17783,17787,17808,17813,17818,17822],{"__ignoreMap":512},[516,17784,17785],{"class":518,"line":519},[516,17786,17409],{"class":3076},[516,17788,17789,17791,17794,17796,17798,17800,17802,17804,17806],{"class":518,"line":525},[516,17790,3042],{"class":1227},[516,17792,17793],{"class":8557},"UserList",[516,17795,9988],{"class":1227},[516,17797,4142],{"class":4733},[516,17799,1894],{"class":1227},[516,17801,3247],{"class":1248},[516,17803,4142],{"class":1227},[516,17805,3247],{"class":1248},[516,17807,8561],{"class":1227},[516,17809,17810],{"class":518,"line":531},[516,17811,17812],{"class":1227},"    \u003Ctemplate #default=\"{ user, isActive }\">\n",[516,17814,17815],{"class":518,"line":1127},[516,17816,17817],{"class":1227},"        \u003Cspan :class=\"{ active: isActive }\">{{ user.name }}\u003C/span>\n",[516,17819,17820],{"class":518,"line":1134},[516,17821,17619],{"class":1227},[516,17823,17824,17826,17828],{"class":518,"line":1275},[516,17825,8589],{"class":1227},[516,17827,17793],{"class":8557},[516,17829,8561],{"class":1227},[11,17831,17832,17833,17835,17836,17838],{},"This is powerful because ",[66,17834,17793],{}," can own the fetching, looping, and business logic, while the parent decides exactly how each user is displayed, without ",[66,17837,17793],{}," needing to know anything about presentation. It is the pattern behind flexible, reusable list, table, and dropdown components: the child provides data and behaviour, the parent provides markup.",[23,17840,17842],{"id":17841},"_66-how-do-you-provide-fallback-content-for-a-slot","66. How do you provide fallback content for a slot?",[11,17844,17845,17846,17848],{},"You put default content directly between the ",[66,17847,17457],{}," tags in the child component. If the parent does not supply anything for that slot, Vue renders the fallback; if the parent does supply content, it replaces the fallback entirely.",[507,17850,17852],{"className":8546,"code":17851,"language":8548,"meta":512,"style":512},"\u003C!-- Button.vue -->\n\u003Ctemplate>\n    \u003Cbutton>\n        \u003Cslot>Click me\u003C/slot>\n    \u003C/button>\n\u003C/template>\n",[66,17853,17854,17859,17867,17875,17888,17896],{"__ignoreMap":512},[516,17855,17856],{"class":518,"line":519},[516,17857,17858],{"class":3076},"\u003C!-- Button.vue -->\n",[516,17860,17861,17863,17865],{"class":518,"line":525},[516,17862,3042],{"class":1227},[516,17864,8558],{"class":8557},[516,17866,8561],{"class":1227},[516,17868,17869,17871,17873],{"class":518,"line":531},[516,17870,8566],{"class":1227},[516,17872,8569],{"class":8557},[516,17874,8561],{"class":1227},[516,17876,17877,17879,17881,17884,17886],{"class":518,"line":1127},[516,17878,9868],{"class":1227},[516,17880,17377],{"class":8557},[516,17882,17883],{"class":1227},">Click me\u003C/",[516,17885,17377],{"class":8557},[516,17887,8561],{"class":1227},[516,17889,17890,17892,17894],{"class":518,"line":1134},[516,17891,9907],{"class":1227},[516,17893,8569],{"class":8557},[516,17895,8561],{"class":1227},[516,17897,17898,17900,17902],{"class":518,"line":1275},[516,17899,8589],{"class":1227},[516,17901,8558],{"class":8557},[516,17903,8561],{"class":1227},[507,17905,17907],{"className":8546,"code":17906,"language":8548,"meta":512,"style":512},"\u003CButton />\n\u003C!-- renders: \u003Cbutton>Click me\u003C/button> -->\n\n\u003CButton>Save\u003C/Button>\n\u003C!-- renders: \u003Cbutton>Save\u003C/button> -->\n",[66,17908,17909,17918,17923,17927,17939],{"__ignoreMap":512},[516,17910,17911,17913,17916],{"class":518,"line":519},[516,17912,3042],{"class":1227},[516,17914,17915],{"class":8557},"Button",[516,17917,9667],{"class":1227},[516,17919,17920],{"class":518,"line":525},[516,17921,17922],{"class":3076},"\u003C!-- renders: \u003Cbutton>Click me\u003C/button> -->\n",[516,17924,17925],{"class":518,"line":531},[516,17926,1131],{"emptyLinePlaceholder":1130},[516,17928,17929,17931,17933,17935,17937],{"class":518,"line":1127},[516,17930,3042],{"class":1227},[516,17932,17915],{"class":8557},[516,17934,9683],{"class":1227},[516,17936,17915],{"class":8557},[516,17938,8561],{"class":1227},[516,17940,17941],{"class":518,"line":1134},[516,17942,17943],{"class":3076},"\u003C!-- renders: \u003Cbutton>Save\u003C/button> -->\n",[11,17945,17946],{},"This is handy for components that should work with sensible defaults out of the box (buttons, labels, empty states) but still remain fully customizable when the parent needs something different.",[23,17948,17950],{"id":17949},"_67-what-is-a-dynamic-slot-name","67. What is a dynamic slot name?",[11,17952,17953,17954,17957,17958,17960],{},"A dynamic slot name lets you choose which named slot to fill at runtime, using a JavaScript expression instead of a hardcoded name. You write it as ",[66,17955,17956],{},"#[expression]"," on a ",[66,17959,8745],{}," tag.",[507,17962,17964],{"className":8546,"code":17963,"language":8548,"meta":512,"style":512},"\u003Ctemplate #[currentSlotName]>\n    \u003Cp>This fills whichever slot name is currently stored in currentSlotName.\u003C/p>\n\u003C/template>\n",[66,17965,17966,17975,17988],{"__ignoreMap":512},[516,17967,17968,17970,17972],{"class":518,"line":519},[516,17969,3042],{"class":1227},[516,17971,8558],{"class":8557},[516,17973,17974],{"class":1227}," #[currentSlotName]>\n",[516,17976,17977,17979,17981,17984,17986],{"class":518,"line":525},[516,17978,8566],{"class":1227},[516,17980,11],{"class":8557},[516,17982,17983],{"class":1227},">This fills whichever slot name is currently stored in currentSlotName.\u003C/",[516,17985,11],{"class":8557},[516,17987,8561],{"class":1227},[516,17989,17990,17992,17994],{"class":518,"line":531},[516,17991,8589],{"class":1227},[516,17993,8558],{"class":8557},[516,17995,8561],{"class":1227},[11,17997,17998,17999,18002],{},"This is useful for components that render a variable set of regions, such as a tabbed panel where each tab corresponds to a differently-named slot, or a table component where column slots are generated from a columns array. It follows the same rules as dynamic argument syntax used elsewhere in Vue templates, like ",[66,18000,18001],{},":[attrName]"," for dynamic prop binding.",[23,18004,18006,18007,2958,18010,18013,18014,2958,18016,18019],{"id":18005},"_68-what-is-the-difference-between-the-modern-v-slot-syntax-and-the-legacy-slotslot-scope-syntax","68. What is the difference between the modern ",[66,18008,18009],{},"v-slot",[66,18011,18012],{},"#"," syntax and the legacy ",[66,18015,17377],{},[66,18017,18018],{},"slot-scope"," syntax?",[11,18021,771,18022,202,18024,18026,18027,18029,18030,18032,18033,18035],{},[66,18023,17377],{},[66,18025,18018],{}," attributes were the original Vue 2 way of targeting and reading data from a slot. They were deprecated in Vue 2.6 in favor of the unified ",[66,18028,18009],{}," directive, and removed entirely in Vue 3, so any codebase running Vue 3 must use ",[66,18031,18009],{}," (or its ",[66,18034,18012],{}," shorthand).",[11,18037,18038],{},"Old syntax (no longer valid in Vue 3):",[507,18040,18042],{"className":8546,"code":18041,"language":8548,"meta":512,"style":512},"\u003Ctemplate slot=\"header\" slot-scope=\"props\">\n    {{ props.title }}\n\u003C/template>\n",[66,18043,18044,18067,18072],{"__ignoreMap":512},[516,18045,18046,18048,18050,18053,18055,18057,18060,18062,18065],{"class":518,"line":519},[516,18047,3042],{"class":1227},[516,18049,8558],{"class":8557},[516,18051,18052],{"class":4733}," slot",[516,18054,1894],{"class":1227},[516,18056,17520],{"class":1248},[516,18058,18059],{"class":4733}," slot-scope",[516,18061,1894],{"class":1227},[516,18063,18064],{"class":1248},"\"props\"",[516,18066,8561],{"class":1227},[516,18068,18069],{"class":518,"line":525},[516,18070,18071],{"class":1227},"    {{ props.title }}\n",[516,18073,18074,18076,18078],{"class":518,"line":531},[516,18075,8589],{"class":1227},[516,18077,8558],{"class":8557},[516,18079,8561],{"class":1227},[11,18081,18082],{},"Current syntax:",[507,18084,18086],{"className":8546,"code":18085,"language":8548,"meta":512,"style":512},"\u003Ctemplate #header=\"props\">\n    {{ props.title }}\n\u003C/template>\n",[66,18087,18088,18109,18113],{"__ignoreMap":512},[516,18089,18090,18092,18094,18097,18099,18101,18103,18105,18107],{"class":518,"line":519},[516,18091,3042],{"class":1227},[516,18093,8558],{"class":8557},[516,18095,18096],{"class":1227}," #",[516,18098,16620],{"class":4733},[516,18100,1894],{"class":1227},[516,18102,3247],{"class":1248},[516,18104,12679],{"class":1227},[516,18106,3247],{"class":1248},[516,18108,8561],{"class":1227},[516,18110,18111],{"class":518,"line":525},[516,18112,18071],{"class":1227},[516,18114,18115,18117,18119],{"class":518,"line":531},[516,18116,8589],{"class":1227},[516,18118,8558],{"class":8557},[516,18120,8561],{"class":1227},[11,18122,18123,18124,18126,18127,148,18129,18131,18132,18134,18135,2958,18137,18139,18140,18142],{},"The old approach needed two separate attributes, one for the slot name and one for scoped data, and it was easy to misuse since ",[66,18125,18018],{}," could technically be placed on a plain element rather than a ",[66,18128,8745],{},[66,18130,18009],{}," merges both concerns into a single directive that only works on ",[66,18133,8745],{}," (or the component tag itself for the default slot), which is clearer and less error prone. If you are reading a Vue 2 tutorial or maintaining an older codebase, recognizing ",[66,18136,17377],{},[66,18138,18018],{}," as the legacy equivalent of ",[66,18141,18009],{}," is mostly what you need; in new Vue 3 code you should never write it.",[23,18144,18146],{"id":18145},"_69-when-would-you-choose-a-slot-over-a-prop-for-passing-content-into-a-component","69. When would you choose a slot over a prop for passing content into a component?",[11,18148,18149],{},"Use a prop when you are passing a simple value: a string, number, boolean, or a plain object of data. Use a slot when you are passing markup, structure, or something that needs to stay reactive to the DOM, such as icons, custom formatting, nested components, or entire sections of layout.",[11,18151,18152,18153,18156,18157,18160,18161,18164],{},"A quick rule of thumb: if what you are passing could reasonably be typed and validated (a title string, a count, a flag), it is a prop. If what you are passing is \"arbitrary content that only the parent knows how to render,\" it is a slot. For example, a ",[66,18154,18155],{},"Modal"," component takes a ",[66,18158,18159],{},"title"," prop for its heading text, but takes its body as a default slot, since the body's content is entirely up to whoever uses the modal. Mixing them up leads to awkward code, like passing raw HTML strings through a prop and rendering them with ",[66,18162,18163],{},"v-html",", which loses reactivity on nested components and opens the door to XSS if that content is ever user supplied.",[23,18166,18168,18169,18172,18173,9728],{"id":18167},"_70-what-does-useslots-do-and-when-would-you-use-it-in-script-setup","70. What does ",[66,18170,18171],{},"useSlots()"," do, and when would you use it in ",[66,18174,8448],{},[11,18176,18177,18179,18180,18182,18183,18186,18187,18189],{},[66,18178,18171],{}," is a Composition API function that gives you programmatic access to a component's slots inside ",[66,18181,8448],{},", returning the same slots object that ",[66,18184,18185],{},"this.$slots"," exposes in the Options API. You would not need it to simply render a slot in the template (",[66,18188,17449],{}," handles that on its own), but you need it when you have to inspect slots from script logic.",[507,18191,18193],{"className":8546,"code":18192,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { useSlots, computed } from 'vue'\n\nconst slots = useSlots()\n\nconst hasFooter = computed(() => !!slots.footer)\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cdiv>\n        \u003Cslot>\u003C/slot>\n        \u003Cfooter v-if=\"hasFooter\">\n            \u003Cslot name=\"footer\">\u003C/slot>\n        \u003C/footer>\n    \u003C/div>\n\u003C/template>\n",[66,18194,18195,18205,18216,18220,18234,18238,18259,18267,18271,18279,18287,18299,18314,18332,18340,18348],{"__ignoreMap":512},[516,18196,18197,18199,18201,18203],{"class":518,"line":519},[516,18198,3042],{"class":1227},[516,18200,8604],{"class":8557},[516,18202,8607],{"class":4733},[516,18204,8561],{"class":1227},[516,18206,18207,18209,18212,18214],{"class":518,"line":525},[516,18208,8614],{"class":1749},[516,18210,18211],{"class":1227}," { useSlots, computed } ",[516,18213,8620],{"class":1749},[516,18215,8623],{"class":1248},[516,18217,18218],{"class":518,"line":531},[516,18219,1131],{"emptyLinePlaceholder":1130},[516,18221,18222,18224,18227,18229,18232],{"class":518,"line":1127},[516,18223,8632],{"class":1749},[516,18225,18226],{"class":1233}," slots",[516,18228,1793],{"class":1749},[516,18230,18231],{"class":4733}," useSlots",[516,18233,13318],{"class":1227},[516,18235,18236],{"class":518,"line":1134},[516,18237,1131],{"emptyLinePlaceholder":1130},[516,18239,18240,18242,18245,18247,18249,18251,18253,18256],{"class":518,"line":1275},[516,18241,8632],{"class":1749},[516,18243,18244],{"class":1233}," hasFooter",[516,18246,1793],{"class":1749},[516,18248,11030],{"class":4733},[516,18250,11033],{"class":1227},[516,18252,11036],{"class":1749},[516,18254,18255],{"class":1749}," !!",[516,18257,18258],{"class":1227},"slots.footer)\n",[516,18260,18261,18263,18265],{"class":518,"line":1302},[516,18262,8589],{"class":1227},[516,18264,8604],{"class":8557},[516,18266,8561],{"class":1227},[516,18268,18269],{"class":518,"line":1308},[516,18270,1131],{"emptyLinePlaceholder":1130},[516,18272,18273,18275,18277],{"class":518,"line":1314},[516,18274,3042],{"class":1227},[516,18276,8558],{"class":8557},[516,18278,8561],{"class":1227},[516,18280,18281,18283,18285],{"class":518,"line":8656},[516,18282,8566],{"class":1227},[516,18284,9764],{"class":8557},[516,18286,8561],{"class":1227},[516,18288,18289,18291,18293,18295,18297],{"class":518,"line":8668},[516,18290,9868],{"class":1227},[516,18292,17377],{"class":8557},[516,18294,10142],{"class":1227},[516,18296,17377],{"class":8557},[516,18298,8561],{"class":1227},[516,18300,18301,18303,18305,18307,18309,18312],{"class":518,"line":8677},[516,18302,9868],{"class":1227},[516,18304,17557],{"class":8557},[516,18306,9767],{"class":4733},[516,18308,1894],{"class":1227},[516,18310,18311],{"class":1248},"\"hasFooter\"",[516,18313,8561],{"class":1227},[516,18315,18316,18318,18320,18322,18324,18326,18328,18330],{"class":518,"line":8682},[516,18317,17730],{"class":1227},[516,18319,17377],{"class":8557},[516,18321,17515],{"class":4733},[516,18323,1894],{"class":1227},[516,18325,17568],{"class":1248},[516,18327,10142],{"class":1227},[516,18329,17377],{"class":8557},[516,18331,8561],{"class":1227},[516,18333,18334,18336,18338],{"class":518,"line":8691},[516,18335,9898],{"class":1227},[516,18337,17557],{"class":8557},[516,18339,8561],{"class":1227},[516,18341,18342,18344,18346],{"class":518,"line":8696},[516,18343,9907],{"class":1227},[516,18345,9764],{"class":8557},[516,18347,8561],{"class":1227},[516,18349,18350,18352,18354],{"class":518,"line":8708},[516,18351,8589],{"class":1227},[516,18353,8558],{"class":8557},[516,18355,8561],{"class":1227},[11,18357,18358,18359,18362,18363,202,18365,18368,18369,18371],{},"Common cases: conditionally rendering a wrapper element only if a particular slot was passed, or writing a render function/component library helper that needs to loop over ",[66,18360,18361],{},"slots"," manually. For everyday templates, plain ",[66,18364,17457],{},[66,18366,18367],{},"v-if=\"$slots.footer\""," cover most needs; ",[66,18370,18171],{}," matters most when you are working from script logic rather than the template.",[18,18373,18375],{"id":18374},"provideinject-and-component-communication","Provide/Inject and Component Communication",[23,18377,18379,18380,2958,18383,18386],{"id":18378},"_71-what-is-provideinject-and-what-problem-does-it-solve","71. What is ",[66,18381,18382],{},"provide",[66,18384,18385],{},"inject",", and what problem does it solve?",[11,18388,18389,202,18391,18393],{},[66,18390,18382],{},[66,18392,18385],{}," let an ancestor component make a value available to any descendant, no matter how deeply nested, without passing it down manually through every component in between. That manual passing-down problem is often called \"prop drilling\": if a deeply nested component needs a value from a distant ancestor, every intermediate component has to accept and re-pass a prop it does not actually use itself.",[11,18395,18396,18397,18400,18401,18404],{},"An ancestor calls ",[66,18398,18399],{},"provide(key, value)",", and any descendant calls ",[66,18402,18403],{},"inject(key)"," to read it, regardless of how many layers sit between them.",[507,18406,18408],{"className":8546,"code":18407,"language":8548,"meta":512,"style":512},"\u003C!-- App.vue -->\n\u003Cscript setup>\nimport { provide, ref } from 'vue'\n\nconst theme = ref('dark')\nprovide('theme', theme)\n\u003C/script>\n",[66,18409,18410,18415,18425,18436,18440,18457,18469],{"__ignoreMap":512},[516,18411,18412],{"class":518,"line":519},[516,18413,18414],{"class":3076},"\u003C!-- App.vue -->\n",[516,18416,18417,18419,18421,18423],{"class":518,"line":525},[516,18418,3042],{"class":1227},[516,18420,8604],{"class":8557},[516,18422,8607],{"class":4733},[516,18424,8561],{"class":1227},[516,18426,18427,18429,18432,18434],{"class":518,"line":531},[516,18428,8614],{"class":1749},[516,18430,18431],{"class":1227}," { provide, ref } ",[516,18433,8620],{"class":1749},[516,18435,8623],{"class":1248},[516,18437,18438],{"class":518,"line":1127},[516,18439,1131],{"emptyLinePlaceholder":1130},[516,18441,18442,18444,18447,18449,18451,18453,18455],{"class":518,"line":1134},[516,18443,8632],{"class":1749},[516,18445,18446],{"class":1233}," theme",[516,18448,1793],{"class":1749},[516,18450,8640],{"class":4733},[516,18452,8643],{"class":1227},[516,18454,14557],{"class":1248},[516,18456,8649],{"class":1227},[516,18458,18459,18461,18463,18466],{"class":518,"line":1275},[516,18460,18382],{"class":4733},[516,18462,8643],{"class":1227},[516,18464,18465],{"class":1248},"'theme'",[516,18467,18468],{"class":1227},", theme)\n",[516,18470,18471,18473,18475],{"class":518,"line":1302},[516,18472,8589],{"class":1227},[516,18474,8604],{"class":8557},[516,18476,8561],{"class":1227},[507,18478,18480],{"className":8546,"code":18479,"language":8548,"meta":512,"style":512},"\u003C!-- DeeplyNestedButton.vue -->\n\u003Cscript setup>\nimport { inject } from 'vue'\n\nconst theme = inject('theme')\n\u003C/script>\n",[66,18481,18482,18487,18497,18508,18512,18529],{"__ignoreMap":512},[516,18483,18484],{"class":518,"line":519},[516,18485,18486],{"class":3076},"\u003C!-- DeeplyNestedButton.vue -->\n",[516,18488,18489,18491,18493,18495],{"class":518,"line":525},[516,18490,3042],{"class":1227},[516,18492,8604],{"class":8557},[516,18494,8607],{"class":4733},[516,18496,8561],{"class":1227},[516,18498,18499,18501,18504,18506],{"class":518,"line":531},[516,18500,8614],{"class":1749},[516,18502,18503],{"class":1227}," { inject } ",[516,18505,8620],{"class":1749},[516,18507,8623],{"class":1248},[516,18509,18510],{"class":518,"line":1127},[516,18511,1131],{"emptyLinePlaceholder":1130},[516,18513,18514,18516,18518,18520,18523,18525,18527],{"class":518,"line":1134},[516,18515,8632],{"class":1749},[516,18517,18446],{"class":1233},[516,18519,1793],{"class":1749},[516,18521,18522],{"class":4733}," inject",[516,18524,8643],{"class":1227},[516,18526,18465],{"class":1248},[516,18528,8649],{"class":1227},[516,18530,18531,18533,18535],{"class":518,"line":1275},[516,18532,8589],{"class":1227},[516,18534,8604],{"class":8557},[516,18536,8561],{"class":1227},[11,18538,18539],{},"It is commonly used for things like theming, current user/auth state, or app-wide configuration that many unrelated components need to read. It is not meant to replace props for normal parent-to-child data flow, and it is not a substitute for a proper state management library when the shared state needs complex mutation logic across many independent branches of the tree; for that, most teams reach for Pinia instead.",[23,18541,18543,18544,18547],{"id":18542},"_72-why-is-it-a-good-idea-to-use-a-symbol-as-a-provideinject-key-in-larger-applications","72. Why is it a good idea to use a ",[66,18545,18546],{},"Symbol"," as a provide/inject key in larger applications?",[11,18549,18550,2958,18552,18554,18555,18558,18559,18561],{},[66,18551,18382],{},[66,18553,18385],{}," keys can be plain strings, but strings can collide: if two unrelated parts of a large codebase (or two different libraries) both ",[66,18556,18557],{},"provide('config', ...)",", the second one silently overwrites the first for anything injecting below it, and there is no error to warn you. A ",[66,18560,18546],{}," is guaranteed unique, so two Symbols created separately can never accidentally match, even if they have the same description text.",[507,18563,18565],{"className":8782,"code":18564,"language":8784,"meta":512,"style":512},"// keys.js\nexport const themeKey = Symbol('theme')\n",[66,18566,18567,18572],{"__ignoreMap":512},[516,18568,18569],{"class":518,"line":519},[516,18570,18571],{"class":3076},"// keys.js\n",[516,18573,18574,18576,18579,18582,18584,18587,18589,18591],{"class":518,"line":525},[516,18575,9190],{"class":1749},[516,18577,18578],{"class":1749}," const",[516,18580,18581],{"class":1233}," themeKey",[516,18583,1793],{"class":1749},[516,18585,18586],{"class":4733}," Symbol",[516,18588,8643],{"class":1227},[516,18590,18465],{"class":1248},[516,18592,8649],{"class":1227},[507,18594,18596],{"className":8782,"code":18595,"language":8784,"meta":512,"style":512},"// providing component\nimport { provide } from 'vue'\nimport { themeKey } from './keys'\n\nprovide(themeKey, theme)\n",[66,18597,18598,18603,18614,18626,18630],{"__ignoreMap":512},[516,18599,18600],{"class":518,"line":519},[516,18601,18602],{"class":3076},"// providing component\n",[516,18604,18605,18607,18610,18612],{"class":518,"line":525},[516,18606,8614],{"class":1749},[516,18608,18609],{"class":1227}," { provide } ",[516,18611,8620],{"class":1749},[516,18613,8623],{"class":1248},[516,18615,18616,18618,18621,18623],{"class":518,"line":531},[516,18617,8614],{"class":1749},[516,18619,18620],{"class":1227}," { themeKey } ",[516,18622,8620],{"class":1749},[516,18624,18625],{"class":1248}," './keys'\n",[516,18627,18628],{"class":518,"line":1127},[516,18629,1131],{"emptyLinePlaceholder":1130},[516,18631,18632,18634],{"class":518,"line":1134},[516,18633,18382],{"class":4733},[516,18635,18636],{"class":1227},"(themeKey, theme)\n",[507,18638,18640],{"className":8782,"code":18639,"language":8784,"meta":512,"style":512},"// injecting component\nimport { inject } from 'vue'\nimport { themeKey } from './keys'\n\nconst theme = inject(themeKey)\n",[66,18641,18642,18647,18657,18667,18671],{"__ignoreMap":512},[516,18643,18644],{"class":518,"line":519},[516,18645,18646],{"class":3076},"// injecting component\n",[516,18648,18649,18651,18653,18655],{"class":518,"line":525},[516,18650,8614],{"class":1749},[516,18652,18503],{"class":1227},[516,18654,8620],{"class":1749},[516,18656,8623],{"class":1248},[516,18658,18659,18661,18663,18665],{"class":518,"line":531},[516,18660,8614],{"class":1749},[516,18662,18620],{"class":1227},[516,18664,8620],{"class":1749},[516,18666,18625],{"class":1248},[516,18668,18669],{"class":518,"line":1127},[516,18670,1131],{"emptyLinePlaceholder":1130},[516,18672,18673,18675,18677,18679,18681],{"class":518,"line":1134},[516,18674,8632],{"class":1749},[516,18676,18446],{"class":1233},[516,18678,1793],{"class":1749},[516,18680,18522],{"class":4733},[516,18682,18683],{"class":1227},"(themeKey)\n",[11,18685,18686,18687,18690,18691,18694,18695,405],{},"Beyond avoiding naming collisions, centralizing keys in a shared module also gives you a single source of truth to import from, and in TypeScript you can type a Symbol key with ",[66,18688,18689],{},"InjectionKey\u003CT>"," so ",[66,18692,18693],{},"inject()"," automatically infers the correct return type instead of coming back as ",[66,18696,18697],{},"unknown",[23,18699,18701],{"id":18700},"_73-how-do-you-keep-an-injected-value-reactive","73. How do you keep an injected value reactive?",[11,18703,18704,18705,18707,18708,18710,18711,18714],{},"An injected value stays reactive only if what you provided was itself reactive, a ",[66,18706,9387],{}," or a ",[66,18709,12368],{}," object, not a plain destructured value. If you provide a raw value pulled out of a ref (like ",[66,18712,18713],{},"provide('count', count.value)","), you are handing over a frozen snapshot; the injecting component will never see later updates.",[507,18716,18718],{"className":8546,"code":18717,"language":8548,"meta":512,"style":512},"\u003C!-- provider -->\n\u003Cscript setup>\nimport { provide, ref } from 'vue'\n\nconst count = ref(0)\nprovide('count', count)   // provide the ref itself, not count.value\n\u003C/script>\n",[66,18719,18720,18725,18735,18745,18749,18765,18779],{"__ignoreMap":512},[516,18721,18722],{"class":518,"line":519},[516,18723,18724],{"class":3076},"\u003C!-- provider -->\n",[516,18726,18727,18729,18731,18733],{"class":518,"line":525},[516,18728,3042],{"class":1227},[516,18730,8604],{"class":8557},[516,18732,8607],{"class":4733},[516,18734,8561],{"class":1227},[516,18736,18737,18739,18741,18743],{"class":518,"line":531},[516,18738,8614],{"class":1749},[516,18740,18431],{"class":1227},[516,18742,8620],{"class":1749},[516,18744,8623],{"class":1248},[516,18746,18747],{"class":518,"line":1127},[516,18748,1131],{"emptyLinePlaceholder":1130},[516,18750,18751,18753,18755,18757,18759,18761,18763],{"class":518,"line":1134},[516,18752,8632],{"class":1749},[516,18754,8635],{"class":1233},[516,18756,1793],{"class":1749},[516,18758,8640],{"class":4733},[516,18760,8643],{"class":1227},[516,18762,8646],{"class":1233},[516,18764,8649],{"class":1227},[516,18766,18767,18769,18771,18773,18776],{"class":518,"line":1275},[516,18768,18382],{"class":4733},[516,18770,8643],{"class":1227},[516,18772,12453],{"class":1248},[516,18774,18775],{"class":1227},", count)   ",[516,18777,18778],{"class":3076},"// provide the ref itself, not count.value\n",[516,18780,18781,18783,18785],{"class":518,"line":1302},[516,18782,8589],{"class":1227},[516,18784,8604],{"class":8557},[516,18786,8561],{"class":1227},[507,18788,18790],{"className":8546,"code":18789,"language":8548,"meta":512,"style":512},"\u003C!-- consumer -->\n\u003Cscript setup>\nimport { inject } from 'vue'\n\nconst count = inject('count')   // still a ref, stays reactive\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cp>{{ count }}\u003C/p>\n\u003C/template>\n",[66,18791,18792,18797,18807,18817,18821,18841,18849,18853,18861,18873],{"__ignoreMap":512},[516,18793,18794],{"class":518,"line":519},[516,18795,18796],{"class":3076},"\u003C!-- consumer -->\n",[516,18798,18799,18801,18803,18805],{"class":518,"line":525},[516,18800,3042],{"class":1227},[516,18802,8604],{"class":8557},[516,18804,8607],{"class":4733},[516,18806,8561],{"class":1227},[516,18808,18809,18811,18813,18815],{"class":518,"line":531},[516,18810,8614],{"class":1749},[516,18812,18503],{"class":1227},[516,18814,8620],{"class":1749},[516,18816,8623],{"class":1248},[516,18818,18819],{"class":518,"line":1127},[516,18820,1131],{"emptyLinePlaceholder":1130},[516,18822,18823,18825,18827,18829,18831,18833,18835,18838],{"class":518,"line":1134},[516,18824,8632],{"class":1749},[516,18826,8635],{"class":1233},[516,18828,1793],{"class":1749},[516,18830,18522],{"class":4733},[516,18832,8643],{"class":1227},[516,18834,12453],{"class":1248},[516,18836,18837],{"class":1227},")   ",[516,18839,18840],{"class":3076},"// still a ref, stays reactive\n",[516,18842,18843,18845,18847],{"class":518,"line":1275},[516,18844,8589],{"class":1227},[516,18846,8604],{"class":8557},[516,18848,8561],{"class":1227},[516,18850,18851],{"class":518,"line":1302},[516,18852,1131],{"emptyLinePlaceholder":1130},[516,18854,18855,18857,18859],{"class":518,"line":1308},[516,18856,3042],{"class":1227},[516,18858,8558],{"class":8557},[516,18860,8561],{"class":1227},[516,18862,18863,18865,18867,18869,18871],{"class":518,"line":1314},[516,18864,8566],{"class":1227},[516,18866,11],{"class":8557},[516,18868,11869],{"class":1227},[516,18870,11],{"class":8557},[516,18872,8561],{"class":1227},[516,18874,18875,18877,18879],{"class":518,"line":8656},[516,18876,8589],{"class":1227},[516,18878,8558],{"class":8557},[516,18880,8561],{"class":1227},[11,18882,18883,18884,18886,18887,18890],{},"If you want the provider to control mutations and keep the injected value read-only for consumers, wrap it with ",[66,18885,12507],{}," before providing it, and provide an accompanying function (like ",[66,18888,18889],{},"setCount",") for consumers to request changes. This keeps state changes centralized in the provider instead of letting any descendant mutate shared state directly.",[23,18892,18894],{"id":18893},"_74-what-are-the-different-ways-components-can-communicate-with-each-other-in-vue","74. What are the different ways components can communicate with each other in Vue?",[11,18896,18897],{},"The right mechanism depends on the relationship between the two components:",[11,18899,18900],{},[2160,18901],{"alt":18902,"src":18903},"Vue component communication diagram","/post-images/top-150-vuejs-interview-questions/vue-component-communication-diagram.png",[36,18905,18906,18916],{},[39,18907,18908],{},[42,18909,18910,18913],{},[45,18911,18912],{},"Relationship",[45,18914,18915],{},"Mechanism",[58,18917,18918,18926,18936,18946,18957,18967,18975],{},[42,18919,18920,18923],{},[63,18921,18922],{},"Parent to child",[63,18924,18925],{},"Props",[42,18927,18928,18931],{},[63,18929,18930],{},"Child to parent",[63,18932,18933,18934,3583],{},"Custom events (",[66,18935,15438],{},[42,18937,18938,18941],{},[63,18939,18940],{},"Two-way binding",[63,18942,18943,18945],{},[66,18944,10557],{}," (sugar over a prop + an update event)",[42,18947,18948,18951],{},[63,18949,18950],{},"Ancestor to any descendant",[63,18952,18953,15185,18955],{},[66,18954,18382],{},[66,18956,18385],{},[42,18958,18959,18962],{},[63,18960,18961],{},"Parent reading child internals",[63,18963,18964,18965],{},"Template refs + ",[66,18966,16718],{},[42,18968,18969,18972],{},[63,18970,18971],{},"Sibling or unrelated components",[63,18973,18974],{},"Shared state (Pinia/Vuex), or a shared reactive object/composable",[42,18976,18977,18980],{},[63,18978,18979],{},"Passing markup, not data",[63,18981,18982],{},"Slots",[11,18984,18985,18986,2958,18988,18990],{},"Props and events cover the vast majority of everyday communication, and Vue nudges you toward \"props down, events up\" as the default pattern because it keeps data flow predictable and easy to trace. ",[66,18987,18382],{},[66,18989,18385],{}," and refs handle less common cases (deep nesting, imperative access), while a shared store like Pinia is the usual answer once two components that are not directly related need to read or write the same state.",[23,18992,18994],{"id":18993},"_75-what-is-a-template-ref-and-how-do-you-call-a-method-exposed-by-a-child-component-from-its-parent","75. What is a template ref, and how do you call a method exposed by a child component from its parent?",[11,18996,18997,18998,19001,19002,9934,19004,19006],{},"A template ref is a way to get a direct reference to a DOM element or a child component instance from your script code, by putting ",[66,18999,19000],{},"ref=\"someName\""," on a template tag and declaring a matching ",[66,19003,11453],{},[66,19005,8448],{}," with the same name.",[507,19008,19010],{"className":8546,"code":19009,"language":8548,"meta":512,"style":512},"\u003C!-- Child.vue -->\n\u003Cscript setup>\nfunction focusInput() {\n    console.log('child method called')\n}\n\ndefineExpose({ focusInput })\n\u003C/script>\n",[66,19011,19012,19016,19026,19035,19048,19052,19056,19063],{"__ignoreMap":512},[516,19013,19014],{"class":518,"line":519},[516,19015,16739],{"class":3076},[516,19017,19018,19020,19022,19024],{"class":518,"line":525},[516,19019,3042],{"class":1227},[516,19021,8604],{"class":8557},[516,19023,8607],{"class":4733},[516,19025,8561],{"class":1227},[516,19027,19028,19030,19033],{"class":518,"line":531},[516,19029,8659],{"class":1749},[516,19031,19032],{"class":4733}," focusInput",[516,19034,8665],{"class":1227},[516,19036,19037,19039,19041,19043,19046],{"class":518,"line":1127},[516,19038,11514],{"class":1227},[516,19040,11517],{"class":4733},[516,19042,8643],{"class":1227},[516,19044,19045],{"class":1248},"'child method called'",[516,19047,8649],{"class":1227},[516,19049,19050],{"class":518,"line":1134},[516,19051,1317],{"class":1227},[516,19053,19054],{"class":518,"line":1275},[516,19055,1131],{"emptyLinePlaceholder":1130},[516,19057,19058,19060],{"class":518,"line":1302},[516,19059,16718],{"class":4733},[516,19061,19062],{"class":1227},"({ focusInput })\n",[516,19064,19065,19067,19069],{"class":518,"line":1308},[516,19066,8589],{"class":1227},[516,19068,8604],{"class":8557},[516,19070,8561],{"class":1227},[507,19072,19074],{"className":8546,"code":19073,"language":8548,"meta":512,"style":512},"\u003C!-- Parent.vue -->\n\u003Cscript setup>\nimport { ref, onMounted } from 'vue'\nimport Child from './Child.vue'\n\nconst childRef = ref(null)\n\nonMounted(() => {\n    childRef.value.focusInput()\n})\n\u003C/script>\n\n\u003Ctemplate>\n    \u003CChild ref=\"childRef\" />\n\u003C/template>\n",[66,19075,19076,19080,19090,19101,19113,19117,19133,19137,19148,19157,19161,19169,19173,19181,19195],{"__ignoreMap":512},[516,19077,19078],{"class":518,"line":519},[516,19079,16830],{"class":3076},[516,19081,19082,19084,19086,19088],{"class":518,"line":525},[516,19083,3042],{"class":1227},[516,19085,8604],{"class":8557},[516,19087,8607],{"class":4733},[516,19089,8561],{"class":1227},[516,19091,19092,19094,19097,19099],{"class":518,"line":531},[516,19093,8614],{"class":1749},[516,19095,19096],{"class":1227}," { ref, onMounted } ",[516,19098,8620],{"class":1749},[516,19100,8623],{"class":1248},[516,19102,19103,19105,19108,19110],{"class":518,"line":1127},[516,19104,8614],{"class":1749},[516,19106,19107],{"class":1227}," Child ",[516,19109,8620],{"class":1749},[516,19111,19112],{"class":1248}," './Child.vue'\n",[516,19114,19115],{"class":518,"line":1134},[516,19116,1131],{"emptyLinePlaceholder":1130},[516,19118,19119,19121,19123,19125,19127,19129,19131],{"class":518,"line":1275},[516,19120,8632],{"class":1749},[516,19122,16857],{"class":1233},[516,19124,1793],{"class":1749},[516,19126,8640],{"class":4733},[516,19128,8643],{"class":1227},[516,19130,9102],{"class":1233},[516,19132,8649],{"class":1227},[516,19134,19135],{"class":518,"line":1302},[516,19136,1131],{"emptyLinePlaceholder":1130},[516,19138,19139,19142,19144,19146],{"class":518,"line":1308},[516,19140,19141],{"class":4733},"onMounted",[516,19143,11033],{"class":1227},[516,19145,11036],{"class":1749},[516,19147,8713],{"class":1227},[516,19149,19150,19152,19155],{"class":518,"line":1314},[516,19151,16885],{"class":1227},[516,19153,19154],{"class":4733},"focusInput",[516,19156,13318],{"class":1227},[516,19158,19159],{"class":518,"line":8656},[516,19160,11530],{"class":1227},[516,19162,19163,19165,19167],{"class":518,"line":8668},[516,19164,8589],{"class":1227},[516,19166,8604],{"class":8557},[516,19168,8561],{"class":1227},[516,19170,19171],{"class":518,"line":8677},[516,19172,1131],{"emptyLinePlaceholder":1130},[516,19174,19175,19177,19179],{"class":518,"line":8682},[516,19176,3042],{"class":1227},[516,19178,8558],{"class":8557},[516,19180,8561],{"class":1227},[516,19182,19183,19185,19187,19189,19191,19193],{"class":518,"line":8691},[516,19184,8566],{"class":1227},[516,19186,16921],{"class":8557},[516,19188,8640],{"class":4733},[516,19190,1894],{"class":1227},[516,19192,16928],{"class":1248},[516,19194,9667],{"class":1227},[516,19196,19197,19199,19201],{"class":518,"line":8696},[516,19198,8589],{"class":1227},[516,19200,8558],{"class":8557},[516,19202,8561],{"class":1227},[11,19204,19205,19206,19208,19209,19211,19212,19214],{},"As covered in the ",[66,19207,16718],{}," question above, ",[66,19210,8448],{}," components are closed by default, so the parent cannot reach ",[66,19213,19154],{}," through the template ref unless the child explicitly opts in. That opt-in step is the piece that actually makes this pattern work; the template ref itself just gives the parent a handle to call it on.",[23,19216,19218,19219,19222],{"id":19217},"_76-what-does-useattrs-do-and-when-would-you-use-it","76. What does ",[66,19220,19221],{},"useAttrs()"," do, and when would you use it?",[11,19224,19225,19227,19228,154,19230,154,19232,19234],{},[66,19226,19221],{}," gives you access to \"fallthrough attributes\": attributes and listeners passed to a component that are not declared as props (or emits). By default, Vue automatically applies these attributes to the component's root element, which is usually what you want (",[66,19229,10106],{},[66,19231,1578],{},[66,19233,16435],{}," attributes, ARIA attributes all just work without extra effort).",[11,19236,19237,19238,19240],{},"You reach for ",[66,19239,19221],{}," when you need to inspect or manually redirect those attributes yourself, typically because the component has multiple root nodes (no automatic single-root fallthrough) or you want to apply them to a specific inner element rather than the outermost one.",[507,19242,19244],{"className":8546,"code":19243,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { useAttrs } from 'vue'\n\ndefineProps(['label'])\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cdiv class=\"wrapper\">\n        \u003Clabel>{{ label }}\u003C/label>\n        \u003Cinput v-bind=\"attrs\" />\n    \u003C/div>\n\u003C/template>\n",[66,19245,19246,19256,19267,19271,19282,19292,19296,19310,19318,19322,19330,19345,19358,19373,19381],{"__ignoreMap":512},[516,19247,19248,19250,19252,19254],{"class":518,"line":519},[516,19249,3042],{"class":1227},[516,19251,8604],{"class":8557},[516,19253,8607],{"class":4733},[516,19255,8561],{"class":1227},[516,19257,19258,19260,19263,19265],{"class":518,"line":525},[516,19259,8614],{"class":1749},[516,19261,19262],{"class":1227}," { useAttrs } ",[516,19264,8620],{"class":1749},[516,19266,8623],{"class":1248},[516,19268,19269],{"class":518,"line":531},[516,19270,1131],{"emptyLinePlaceholder":1130},[516,19272,19273,19275,19277,19280],{"class":518,"line":1127},[516,19274,14859],{"class":4733},[516,19276,11992],{"class":1227},[516,19278,19279],{"class":1248},"'label'",[516,19281,12006],{"class":1227},[516,19283,19284,19286,19288,19290],{"class":518,"line":1134},[516,19285,16489],{"class":4733},[516,19287,16492],{"class":1227},[516,19289,12981],{"class":1233},[516,19291,11494],{"class":1227},[516,19293,19294],{"class":518,"line":1275},[516,19295,1131],{"emptyLinePlaceholder":1130},[516,19297,19298,19300,19303,19305,19308],{"class":518,"line":1302},[516,19299,8632],{"class":1749},[516,19301,19302],{"class":1233}," attrs",[516,19304,1793],{"class":1749},[516,19306,19307],{"class":4733}," useAttrs",[516,19309,13318],{"class":1227},[516,19311,19312,19314,19316],{"class":518,"line":1308},[516,19313,8589],{"class":1227},[516,19315,8604],{"class":8557},[516,19317,8561],{"class":1227},[516,19319,19320],{"class":518,"line":1314},[516,19321,1131],{"emptyLinePlaceholder":1130},[516,19323,19324,19326,19328],{"class":518,"line":8656},[516,19325,3042],{"class":1227},[516,19327,8558],{"class":8557},[516,19329,8561],{"class":1227},[516,19331,19332,19334,19336,19338,19340,19343],{"class":518,"line":8668},[516,19333,8566],{"class":1227},[516,19335,9764],{"class":8557},[516,19337,16525],{"class":4733},[516,19339,1894],{"class":1227},[516,19341,19342],{"class":1248},"\"wrapper\"",[516,19344,8561],{"class":1227},[516,19346,19347,19349,19351,19354,19356],{"class":518,"line":8677},[516,19348,9868],{"class":1227},[516,19350,16538],{"class":8557},[516,19352,19353],{"class":1227},">{{ label }}\u003C/",[516,19355,16538],{"class":8557},[516,19357,8561],{"class":1227},[516,19359,19360,19362,19364,19366,19368,19371],{"class":518,"line":8682},[516,19361,9868],{"class":1227},[516,19363,10575],{"class":8557},[516,19365,10802],{"class":4733},[516,19367,1894],{"class":1227},[516,19369,19370],{"class":1248},"\"attrs\"",[516,19372,9667],{"class":1227},[516,19374,19375,19377,19379],{"class":518,"line":8691},[516,19376,9907],{"class":1227},[516,19378,9764],{"class":8557},[516,19380,8561],{"class":1227},[516,19382,19383,19385,19387],{"class":518,"line":8696},[516,19384,8589],{"class":1227},[516,19386,8558],{"class":8557},[516,19388,8561],{"class":1227},[11,19390,19391,19392,19394,19395,157,19397,19400,19401,19403,19404,756,19407,19410],{},"Here, ",[66,19393,16420],{}," stops Vue from dumping attributes onto the outer ",[66,19396,16587],{},[66,19398,19399],{},"v-bind=\"attrs\""," forwards them onto the actual ",[66,19402,10027],{}," instead, so something like ",[66,19405,19406],{},"placeholder",[66,19408,19409],{},"maxlength"," passed from the parent lands where it is actually meaningful.",[18,19412,19414],{"id":19413},"lifecycle-hooks","Lifecycle Hooks",[23,19416,19418],{"id":19417},"_77-what-are-the-vue-component-lifecycle-hooks-in-order-from-creation-to-destruction","77. What are the Vue component lifecycle hooks, in order, from creation to destruction?",[11,19420,19421],{},"A Vue component goes through a predictable sequence of stages as it is created, mounted to the DOM, updated, and eventually removed. Here they are in order, with the Options API hook name and its Composition API equivalent:",[11,19423,19424],{},[2160,19425],{"alt":19426,"src":19427},"Vue component lifecycle hooks diagram","/post-images/top-150-vuejs-interview-questions/vue-lifecycle-hooks-diagram.png",[36,19429,19430,19442],{},[39,19431,19432],{},[42,19433,19434,19437,19440],{},[45,19435,19436],{},"Stage",[45,19438,19439],{},"Options API",[45,19441,8514],{},[58,19443,19444,19459,19473,19488,19502,19517,19532,19547],{},[42,19445,19446,19449,19454],{},[63,19447,19448],{},"Before instance setup",[63,19450,19451],{},[66,19452,19453],{},"beforeCreate",[63,19455,19456,19457,3583],{},"(not needed, code runs directly in ",[66,19458,9351],{},[42,19460,19461,19464,19469],{},[63,19462,19463],{},"After state/computed set up",[63,19465,19466],{},[66,19467,19468],{},"created",[63,19470,19456,19471,3583],{},[66,19472,9351],{},[42,19474,19475,19478,19483],{},[63,19476,19477],{},"Before first DOM render",[63,19479,19480],{},[66,19481,19482],{},"beforeMount",[63,19484,19485],{},[66,19486,19487],{},"onBeforeMount",[42,19489,19490,19493,19498],{},[63,19491,19492],{},"After first DOM render",[63,19494,19495],{},[66,19496,19497],{},"mounted",[63,19499,19500],{},[66,19501,19141],{},[42,19503,19504,19507,19512],{},[63,19505,19506],{},"Before re-render on data change",[63,19508,19509],{},[66,19510,19511],{},"beforeUpdate",[63,19513,19514],{},[66,19515,19516],{},"onBeforeUpdate",[42,19518,19519,19522,19527],{},[63,19520,19521],{},"After re-render on data change",[63,19523,19524],{},[66,19525,19526],{},"updated",[63,19528,19529],{},[66,19530,19531],{},"onUpdated",[42,19533,19534,19537,19542],{},[63,19535,19536],{},"Before component teardown",[63,19538,19539],{},[66,19540,19541],{},"beforeUnmount",[63,19543,19544],{},[66,19545,19546],{},"onBeforeUnmount",[42,19548,19549,19552,19557],{},[63,19550,19551],{},"After component teardown",[63,19553,19554],{},[66,19555,19556],{},"unmounted",[63,19558,19559],{},[66,19560,19561],{},"onUnmounted",[11,19563,19564,19565,734,19567,2958,19570,202,19573,2958,19576,19579,19580,2958,19583,19586,19587,19589,19590,2958,19592,405],{},"There are also two extra hooks tied specifically to ",[66,19566,8969],{},[66,19568,19569],{},"activated",[66,19571,19572],{},"onActivated",[66,19574,19575],{},"deactivated",[66,19577,19578],{},"onDeactivated","), and an error-handling hook (",[66,19581,19582],{},"errorCaptured",[66,19584,19585],{},"onErrorCaptured",") that does not fit neatly into the create-to-destroy timeline. The general pattern to remember: setup/fetch data in the \"before mount\" or \"created\" stage, do DOM-dependent work (measuring elements, third-party widget initialization) in ",[66,19588,19497],{},", and clean up timers, subscriptions, and event listeners in ",[66,19591,19541],{},[66,19593,19556],{},[23,19595,19597,19598,202,19600,9728],{"id":19596},"_78-what-is-the-difference-between-beforemount-and-mounted","78. What is the difference between ",[66,19599,19482],{},[66,19601,19497],{},[11,19603,19604,19606,19607,19610,19611,19613],{},[66,19605,19482],{}," fires right before Vue inserts the component's DOM into the page; the template has been compiled and reactive state is ready, but nothing exists in the actual DOM yet, so ",[66,19608,19609],{},"$el"," (or the equivalent template ref) is not usable. ",[66,19612,19497],{}," fires immediately after the DOM has been created and inserted, so at that point you can safely query or manipulate real DOM elements.",[507,19615,19617],{"className":8546,"code":19616,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onBeforeMount, onMounted, ref } from 'vue'\n\nconst box = ref(null)\n\nonBeforeMount(() => {\n    console.log(box.value)   // null, DOM not created yet\n})\n\nonMounted(() => {\n    console.log(box.value)   // the actual \u003Cdiv>, ready to use\n})\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cdiv ref=\"box\">Hello\u003C/div>\n\u003C/template>\n",[66,19618,19619,19629,19640,19644,19660,19664,19674,19686,19690,19694,19704,19715,19719,19727,19731,19739,19759],{"__ignoreMap":512},[516,19620,19621,19623,19625,19627],{"class":518,"line":519},[516,19622,3042],{"class":1227},[516,19624,8604],{"class":8557},[516,19626,8607],{"class":4733},[516,19628,8561],{"class":1227},[516,19630,19631,19633,19636,19638],{"class":518,"line":525},[516,19632,8614],{"class":1749},[516,19634,19635],{"class":1227}," { onBeforeMount, onMounted, ref } ",[516,19637,8620],{"class":1749},[516,19639,8623],{"class":1248},[516,19641,19642],{"class":518,"line":531},[516,19643,1131],{"emptyLinePlaceholder":1130},[516,19645,19646,19648,19650,19652,19654,19656,19658],{"class":518,"line":1127},[516,19647,8632],{"class":1749},[516,19649,13265],{"class":1233},[516,19651,1793],{"class":1749},[516,19653,8640],{"class":4733},[516,19655,8643],{"class":1227},[516,19657,9102],{"class":1233},[516,19659,8649],{"class":1227},[516,19661,19662],{"class":518,"line":1134},[516,19663,1131],{"emptyLinePlaceholder":1130},[516,19665,19666,19668,19670,19672],{"class":518,"line":1275},[516,19667,19487],{"class":4733},[516,19669,11033],{"class":1227},[516,19671,11036],{"class":1749},[516,19673,8713],{"class":1227},[516,19675,19676,19678,19680,19683],{"class":518,"line":1302},[516,19677,11514],{"class":1227},[516,19679,11517],{"class":4733},[516,19681,19682],{"class":1227},"(box.value)   ",[516,19684,19685],{"class":3076},"// null, DOM not created yet\n",[516,19687,19688],{"class":518,"line":1308},[516,19689,11530],{"class":1227},[516,19691,19692],{"class":518,"line":1314},[516,19693,1131],{"emptyLinePlaceholder":1130},[516,19695,19696,19698,19700,19702],{"class":518,"line":8656},[516,19697,19141],{"class":4733},[516,19699,11033],{"class":1227},[516,19701,11036],{"class":1749},[516,19703,8713],{"class":1227},[516,19705,19706,19708,19710,19712],{"class":518,"line":8668},[516,19707,11514],{"class":1227},[516,19709,11517],{"class":4733},[516,19711,19682],{"class":1227},[516,19713,19714],{"class":3076},"// the actual \u003Cdiv>, ready to use\n",[516,19716,19717],{"class":518,"line":8677},[516,19718,11530],{"class":1227},[516,19720,19721,19723,19725],{"class":518,"line":8682},[516,19722,8589],{"class":1227},[516,19724,8604],{"class":8557},[516,19726,8561],{"class":1227},[516,19728,19729],{"class":518,"line":8691},[516,19730,1131],{"emptyLinePlaceholder":1130},[516,19732,19733,19735,19737],{"class":518,"line":8696},[516,19734,3042],{"class":1227},[516,19736,8558],{"class":8557},[516,19738,8561],{"class":1227},[516,19740,19741,19743,19745,19747,19749,19752,19755,19757],{"class":518,"line":8708},[516,19742,8566],{"class":1227},[516,19744,9764],{"class":8557},[516,19746,8640],{"class":4733},[516,19748,1894],{"class":1227},[516,19750,19751],{"class":1248},"\"box\"",[516,19753,19754],{"class":1227},">Hello\u003C/",[516,19756,9764],{"class":8557},[516,19758,8561],{"class":1227},[516,19760,19761,19763,19765],{"class":518,"line":8716},[516,19762,8589],{"class":1227},[516,19764,8558],{"class":8557},[516,19766,8561],{"class":1227},[11,19768,19769,19770,19772,19773,19775],{},"In practice, ",[66,19771,19482],{}," is rarely used for anything meaningful; ",[66,19774,19497],{}," is the hook you reach for when you need to measure an element, integrate a third-party DOM library (like a chart or map widget), or trigger an initial focus/scroll.",[23,19777,19779,19780,202,19782,9728],{"id":19778},"_79-what-is-the-difference-between-beforeupdate-and-updated","79. What is the difference between ",[66,19781,19511],{},[66,19783,19526],{},[11,19785,19786,19787,19789,19790,19792],{},"Both fire in response to a reactive data change that requires a re-render, but at different points relative to the actual DOM patch. ",[66,19788,19511],{}," runs after Vue detects the change but before it touches the DOM, so the DOM still reflects the old state at that point. ",[66,19791,19526],{}," runs after Vue has finished patching the DOM to match the new state.",[507,19794,19796],{"className":8546,"code":19795,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, onBeforeUpdate, onUpdated } from 'vue'\n\nconst count = ref(0)\n\nonBeforeUpdate(() => {\n    console.log('about to patch DOM')\n})\n\nonUpdated(() => {\n    console.log('DOM now reflects', count.value)\n})\n\u003C/script>\n",[66,19797,19798,19808,19819,19823,19839,19843,19853,19866,19870,19874,19884,19898,19902],{"__ignoreMap":512},[516,19799,19800,19802,19804,19806],{"class":518,"line":519},[516,19801,3042],{"class":1227},[516,19803,8604],{"class":8557},[516,19805,8607],{"class":4733},[516,19807,8561],{"class":1227},[516,19809,19810,19812,19815,19817],{"class":518,"line":525},[516,19811,8614],{"class":1749},[516,19813,19814],{"class":1227}," { ref, onBeforeUpdate, onUpdated } ",[516,19816,8620],{"class":1749},[516,19818,8623],{"class":1248},[516,19820,19821],{"class":518,"line":531},[516,19822,1131],{"emptyLinePlaceholder":1130},[516,19824,19825,19827,19829,19831,19833,19835,19837],{"class":518,"line":1127},[516,19826,8632],{"class":1749},[516,19828,8635],{"class":1233},[516,19830,1793],{"class":1749},[516,19832,8640],{"class":4733},[516,19834,8643],{"class":1227},[516,19836,8646],{"class":1233},[516,19838,8649],{"class":1227},[516,19840,19841],{"class":518,"line":1134},[516,19842,1131],{"emptyLinePlaceholder":1130},[516,19844,19845,19847,19849,19851],{"class":518,"line":1275},[516,19846,19516],{"class":4733},[516,19848,11033],{"class":1227},[516,19850,11036],{"class":1749},[516,19852,8713],{"class":1227},[516,19854,19855,19857,19859,19861,19864],{"class":518,"line":1302},[516,19856,11514],{"class":1227},[516,19858,11517],{"class":4733},[516,19860,8643],{"class":1227},[516,19862,19863],{"class":1248},"'about to patch DOM'",[516,19865,8649],{"class":1227},[516,19867,19868],{"class":518,"line":1308},[516,19869,11530],{"class":1227},[516,19871,19872],{"class":518,"line":1314},[516,19873,1131],{"emptyLinePlaceholder":1130},[516,19875,19876,19878,19880,19882],{"class":518,"line":8656},[516,19877,19531],{"class":4733},[516,19879,11033],{"class":1227},[516,19881,11036],{"class":1749},[516,19883,8713],{"class":1227},[516,19885,19886,19888,19890,19892,19895],{"class":518,"line":8668},[516,19887,11514],{"class":1227},[516,19889,11517],{"class":4733},[516,19891,8643],{"class":1227},[516,19893,19894],{"class":1248},"'DOM now reflects'",[516,19896,19897],{"class":1227},", count.value)\n",[516,19899,19900],{"class":518,"line":8677},[516,19901,11530],{"class":1227},[516,19903,19904,19906,19908],{"class":518,"line":8682},[516,19905,8589],{"class":1227},[516,19907,8604],{"class":8557},[516,19909,8561],{"class":1227},[11,19911,19912,19914,19915,19917,19918,756,19920,19922],{},[66,19913,19526],{}," is the one you would use if you need to read the DOM after a change lands, for example checking a scroll position after a list re-renders. Be careful mutating reactive state inside either hook, since changing state in ",[66,19916,19526],{}," can trigger another update cycle and potentially loop; if you need to react to a specific value changing, a ",[66,19919,13396],{},[66,19921,13399],{}," is usually a cleaner and more targeted tool than these hooks.",[23,19924,19926,19927,202,19929,9728],{"id":19925},"_80-what-is-the-difference-between-beforeunmount-and-unmounted","80. What is the difference between ",[66,19928,19541],{},[66,19930,19556],{},[11,19932,19933,19935,19936,19938],{},[66,19934,19541],{}," fires right before a component instance is torn down; at this point the component is still fully functional; event listeners are still attached, and the instance is still reactive, which makes it the right place to clean things up while everything the cleanup code needs is still alive. ",[66,19937,19556],{}," fires after the teardown is complete: child components have been destroyed, DOM event listeners bound by Vue have been removed, and reactive effects tied to the component have been stopped.",[507,19940,19942],{"className":8546,"code":19941,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onBeforeUnmount, onUnmounted } from 'vue'\n\nlet timerId\n\nonBeforeUnmount(() => {\n    clearInterval(timerId)   // instance still active, safe to clean up\n})\n\nonUnmounted(() => {\n    console.log('component fully removed')\n})\n\u003C/script>\n",[66,19943,19944,19954,19965,19969,19976,19980,19990,20001,20005,20009,20019,20032,20036],{"__ignoreMap":512},[516,19945,19946,19948,19950,19952],{"class":518,"line":519},[516,19947,3042],{"class":1227},[516,19949,8604],{"class":8557},[516,19951,8607],{"class":4733},[516,19953,8561],{"class":1227},[516,19955,19956,19958,19961,19963],{"class":518,"line":525},[516,19957,8614],{"class":1749},[516,19959,19960],{"class":1227}," { onBeforeUnmount, onUnmounted } ",[516,19962,8620],{"class":1749},[516,19964,8623],{"class":1248},[516,19966,19967],{"class":518,"line":531},[516,19968,1131],{"emptyLinePlaceholder":1130},[516,19970,19971,19973],{"class":518,"line":1127},[516,19972,13767],{"class":1749},[516,19974,19975],{"class":1227}," timerId\n",[516,19977,19978],{"class":518,"line":1134},[516,19979,1131],{"emptyLinePlaceholder":1130},[516,19981,19982,19984,19986,19988],{"class":518,"line":1275},[516,19983,19546],{"class":4733},[516,19985,11033],{"class":1227},[516,19987,11036],{"class":1749},[516,19989,8713],{"class":1227},[516,19991,19992,19995,19998],{"class":518,"line":1302},[516,19993,19994],{"class":4733},"    clearInterval",[516,19996,19997],{"class":1227},"(timerId)   ",[516,19999,20000],{"class":3076},"// instance still active, safe to clean up\n",[516,20002,20003],{"class":518,"line":1308},[516,20004,11530],{"class":1227},[516,20006,20007],{"class":518,"line":1314},[516,20008,1131],{"emptyLinePlaceholder":1130},[516,20010,20011,20013,20015,20017],{"class":518,"line":8656},[516,20012,19561],{"class":4733},[516,20014,11033],{"class":1227},[516,20016,11036],{"class":1749},[516,20018,8713],{"class":1227},[516,20020,20021,20023,20025,20027,20030],{"class":518,"line":8668},[516,20022,11514],{"class":1227},[516,20024,11517],{"class":4733},[516,20026,8643],{"class":1227},[516,20028,20029],{"class":1248},"'component fully removed'",[516,20031,8649],{"class":1227},[516,20033,20034],{"class":518,"line":8677},[516,20035,11530],{"class":1227},[516,20037,20038,20040,20042],{"class":518,"line":8682},[516,20039,8589],{"class":1227},[516,20041,8604],{"class":8557},[516,20043,8561],{"class":1227},[11,20045,20046,20047,2958,20050,20053,20054,20056,20057,20059],{},"The practical guidance: put cleanup logic (clearing intervals, removing manually added ",[66,20048,20049],{},"window",[66,20051,20052],{},"document"," listeners, closing WebSocket connections, cancelling subscriptions) in ",[66,20055,19541],{},", since it runs while you still have full access to everything you set up. ",[66,20058,19556],{}," is mostly useful for final bookkeeping, like logging that a component was removed, after everything is already gone.",[23,20061,20063,20064,20066],{"id":20062},"_81-how-do-composition-api-lifecycle-hooks-onmounted-etc-differ-from-options-api-lifecycle-hooks","81. How do Composition API lifecycle hooks (",[66,20065,19141],{},", etc.) differ from Options API lifecycle hooks?",[11,20068,20069,20070,20073,20074,20077,20078,756,20080,20082],{},"Options API hooks are object properties (",[66,20071,20072],{},"mounted() { ... }",") tied to a single component definition, and a component can only define each one once. Composition API hooks are plain imported functions (",[66,20075,20076],{},"onMounted(() => { ... })",") that you call from inside ",[66,20079,9351],{},[66,20081,8448],{},", and you can call the same one multiple times in one component; each callback registered that way runs, in the order it was registered.",[507,20084,20086],{"className":8546,"code":20085,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n    console.log('first mounted callback')\n})\n\nonMounted(() => {\n    console.log('second mounted callback')\n})\n\u003C/script>\n",[66,20087,20088,20098,20109,20113,20123,20136,20140,20144,20154,20167,20171],{"__ignoreMap":512},[516,20089,20090,20092,20094,20096],{"class":518,"line":519},[516,20091,3042],{"class":1227},[516,20093,8604],{"class":8557},[516,20095,8607],{"class":4733},[516,20097,8561],{"class":1227},[516,20099,20100,20102,20105,20107],{"class":518,"line":525},[516,20101,8614],{"class":1749},[516,20103,20104],{"class":1227}," { onMounted } ",[516,20106,8620],{"class":1749},[516,20108,8623],{"class":1248},[516,20110,20111],{"class":518,"line":531},[516,20112,1131],{"emptyLinePlaceholder":1130},[516,20114,20115,20117,20119,20121],{"class":518,"line":1127},[516,20116,19141],{"class":4733},[516,20118,11033],{"class":1227},[516,20120,11036],{"class":1749},[516,20122,8713],{"class":1227},[516,20124,20125,20127,20129,20131,20134],{"class":518,"line":1134},[516,20126,11514],{"class":1227},[516,20128,11517],{"class":4733},[516,20130,8643],{"class":1227},[516,20132,20133],{"class":1248},"'first mounted callback'",[516,20135,8649],{"class":1227},[516,20137,20138],{"class":518,"line":1275},[516,20139,11530],{"class":1227},[516,20141,20142],{"class":518,"line":1302},[516,20143,1131],{"emptyLinePlaceholder":1130},[516,20145,20146,20148,20150,20152],{"class":518,"line":1308},[516,20147,19141],{"class":4733},[516,20149,11033],{"class":1227},[516,20151,11036],{"class":1749},[516,20153,8713],{"class":1227},[516,20155,20156,20158,20160,20162,20165],{"class":518,"line":1314},[516,20157,11514],{"class":1227},[516,20159,11517],{"class":4733},[516,20161,8643],{"class":1227},[516,20163,20164],{"class":1248},"'second mounted callback'",[516,20166,8649],{"class":1227},[516,20168,20169],{"class":518,"line":8656},[516,20170,11530],{"class":1227},[516,20172,20173,20175,20177],{"class":518,"line":8668},[516,20174,8589],{"class":1227},[516,20176,8604],{"class":8557},[516,20178,8561],{"class":1227},[11,20180,20181,20182,2958,20184,20186,20187,20189,20190,20192,20193,20195,20196,20198,20199,20202],{},"This matters most for composables: a composable function can register its own ",[66,20183,19141],{},[66,20185,19561],{}," logic internally, and using that composable from multiple components, or multiple times in the same component, does not clash with hooks the component itself defines. Composition API hooks must be called synchronously during ",[66,20188,9351],{}," (or at the top level of ",[66,20191,8448],{},", which compiles into ",[66,20194,9351],{},"); calling one later, inside an ",[66,20197,13284],{}," callback after an ",[66,20200,20201],{},"await",", will not register correctly because Vue loses track of which component instance is \"current\" at that point.",[23,20204,20206,20207,20209],{"id":20205},"_82-what-lifecycle-hooks-does-keepalive-add-and-what-are-they-for","82. What lifecycle hooks does ",[66,20208,8969],{}," add, and what are they for?",[11,20211,20212,20214,20215,2958,20217,20219,20220,20222,20223,20225,20226,20228,20229,15185,20231,20233],{},[66,20213,8969],{}," caches inactive components instead of destroying them when they are toggled out (for example, switching between tabs or routes), preserving their state and DOM so switching back is instant. Because the component is not actually destroyed and recreated, the normal ",[66,20216,19497],{},[66,20218,19556],{}," hooks do not fire again on toggling; instead, ",[66,20221,8969],{}," adds two dedicated hooks: ",[66,20224,19569],{}," (Options API) / ",[66,20227,19572],{}," (Composition API), which fires when a cached component is inserted back into the DOM, and ",[66,20230,19575],{},[66,20232,19578],{},", which fires when it is removed from the DOM but kept in the cache.",[507,20235,20237],{"className":8546,"code":20236,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onActivated, onDeactivated } from 'vue'\n\nonActivated(() => {\n    console.log('component shown again, resume polling')\n})\n\nonDeactivated(() => {\n    console.log('component hidden, pause polling')\n})\n\u003C/script>\n",[66,20238,20239,20249,20260,20264,20274,20287,20291,20295,20305,20318,20322],{"__ignoreMap":512},[516,20240,20241,20243,20245,20247],{"class":518,"line":519},[516,20242,3042],{"class":1227},[516,20244,8604],{"class":8557},[516,20246,8607],{"class":4733},[516,20248,8561],{"class":1227},[516,20250,20251,20253,20256,20258],{"class":518,"line":525},[516,20252,8614],{"class":1749},[516,20254,20255],{"class":1227}," { onActivated, onDeactivated } ",[516,20257,8620],{"class":1749},[516,20259,8623],{"class":1248},[516,20261,20262],{"class":518,"line":531},[516,20263,1131],{"emptyLinePlaceholder":1130},[516,20265,20266,20268,20270,20272],{"class":518,"line":1127},[516,20267,19572],{"class":4733},[516,20269,11033],{"class":1227},[516,20271,11036],{"class":1749},[516,20273,8713],{"class":1227},[516,20275,20276,20278,20280,20282,20285],{"class":518,"line":1134},[516,20277,11514],{"class":1227},[516,20279,11517],{"class":4733},[516,20281,8643],{"class":1227},[516,20283,20284],{"class":1248},"'component shown again, resume polling'",[516,20286,8649],{"class":1227},[516,20288,20289],{"class":518,"line":1275},[516,20290,11530],{"class":1227},[516,20292,20293],{"class":518,"line":1302},[516,20294,1131],{"emptyLinePlaceholder":1130},[516,20296,20297,20299,20301,20303],{"class":518,"line":1308},[516,20298,19578],{"class":4733},[516,20300,11033],{"class":1227},[516,20302,11036],{"class":1749},[516,20304,8713],{"class":1227},[516,20306,20307,20309,20311,20313,20316],{"class":518,"line":1314},[516,20308,11514],{"class":1227},[516,20310,11517],{"class":4733},[516,20312,8643],{"class":1227},[516,20314,20315],{"class":1248},"'component hidden, pause polling'",[516,20317,8649],{"class":1227},[516,20319,20320],{"class":518,"line":8656},[516,20321,11530],{"class":1227},[516,20323,20324,20326,20328],{"class":518,"line":8668},[516,20325,8589],{"class":1227},[516,20327,8604],{"class":8557},[516,20329,8561],{"class":1227},[11,20331,20332],{},"These are useful for pausing and resuming expensive work tied to visibility, like polling intervals, video playback, or subscriptions, that should not keep running while the component is cached out of view but also should not be fully torn down and reinitialized every time the user switches back.",[23,20334,20336,20337,20339,20340,20342],{"id":20335},"_83-what-does-onerrorcaptured-or-the-options-api-errorcaptured-do","83. What does ",[66,20338,19585],{}," (or the Options API ",[66,20341,19582],{},") do?",[11,20344,20345,20347],{},[66,20346,19585],{}," registers a hook on an ancestor component that catches errors thrown anywhere in its descendant component tree, including errors from render functions, watchers, and lifecycle hooks of child components. It works similarly to an error boundary in other frameworks: it lets a parent component gracefully handle failures in its children instead of letting an uncaught error crash the whole app.",[507,20349,20351],{"className":8546,"code":20350,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, onErrorCaptured } from 'vue'\n\nconst error = ref(null)\n\nonErrorCaptured((err, instance, info) => {\n    error.value = err.message\n    return false   // stop the error from propagating further up\n})\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cp v-if=\"error\">Something went wrong: {{ error }}\u003C/p>\n    \u003Cslot v-else>\u003C/slot>\n\u003C/template>\n",[66,20352,20353,20363,20374,20378,20395,20399,20424,20434,20444,20448,20456,20460,20468,20488,20503],{"__ignoreMap":512},[516,20354,20355,20357,20359,20361],{"class":518,"line":519},[516,20356,3042],{"class":1227},[516,20358,8604],{"class":8557},[516,20360,8607],{"class":4733},[516,20362,8561],{"class":1227},[516,20364,20365,20367,20370,20372],{"class":518,"line":525},[516,20366,8614],{"class":1749},[516,20368,20369],{"class":1227}," { ref, onErrorCaptured } ",[516,20371,8620],{"class":1749},[516,20373,8623],{"class":1248},[516,20375,20376],{"class":518,"line":531},[516,20377,1131],{"emptyLinePlaceholder":1130},[516,20379,20380,20382,20385,20387,20389,20391,20393],{"class":518,"line":1127},[516,20381,8632],{"class":1749},[516,20383,20384],{"class":1233}," error",[516,20386,1793],{"class":1749},[516,20388,8640],{"class":4733},[516,20390,8643],{"class":1227},[516,20392,9102],{"class":1233},[516,20394,8649],{"class":1227},[516,20396,20397],{"class":518,"line":1134},[516,20398,1131],{"emptyLinePlaceholder":1130},[516,20400,20401,20403,20405,20408,20410,20413,20415,20418,20420,20422],{"class":518,"line":1275},[516,20402,19585],{"class":4733},[516,20404,14711],{"class":1227},[516,20406,20407],{"class":9080},"err",[516,20409,154],{"class":1227},[516,20411,20412],{"class":9080},"instance",[516,20414,154],{"class":1227},[516,20416,20417],{"class":9080},"info",[516,20419,13650],{"class":1227},[516,20421,11036],{"class":1749},[516,20423,8713],{"class":1227},[516,20425,20426,20429,20431],{"class":518,"line":1302},[516,20427,20428],{"class":1227},"    error.value ",[516,20430,1894],{"class":1749},[516,20432,20433],{"class":1227}," err.message\n",[516,20435,20436,20438,20441],{"class":518,"line":1308},[516,20437,9089],{"class":1749},[516,20439,20440],{"class":1233}," false",[516,20442,20443],{"class":3076},"   // stop the error from propagating further up\n",[516,20445,20446],{"class":518,"line":1314},[516,20447,11530],{"class":1227},[516,20449,20450,20452,20454],{"class":518,"line":8656},[516,20451,8589],{"class":1227},[516,20453,8604],{"class":8557},[516,20455,8561],{"class":1227},[516,20457,20458],{"class":518,"line":8668},[516,20459,1131],{"emptyLinePlaceholder":1130},[516,20461,20462,20464,20466],{"class":518,"line":8677},[516,20463,3042],{"class":1227},[516,20465,8558],{"class":8557},[516,20467,8561],{"class":1227},[516,20469,20470,20472,20474,20476,20478,20481,20484,20486],{"class":518,"line":8682},[516,20471,8566],{"class":1227},[516,20473,11],{"class":8557},[516,20475,9767],{"class":4733},[516,20477,1894],{"class":1227},[516,20479,20480],{"class":1248},"\"error\"",[516,20482,20483],{"class":1227},">Something went wrong: {{ error }}\u003C/",[516,20485,11],{"class":8557},[516,20487,8561],{"class":1227},[516,20489,20490,20492,20494,20497,20499,20501],{"class":518,"line":8691},[516,20491,8566],{"class":1227},[516,20493,17377],{"class":8557},[516,20495,20496],{"class":4733}," v-else",[516,20498,10142],{"class":1227},[516,20500,17377],{"class":8557},[516,20502,8561],{"class":1227},[516,20504,20505,20507,20509],{"class":518,"line":8696},[516,20506,8589],{"class":1227},[516,20508,8558],{"class":8557},[516,20510,8561],{"class":1227},[11,20512,20513,20514,20516,20517,20520,20521,20523,20524,20527,20528,20530,20531,20534],{},"The callback receives the error itself, the component instance where it occurred, and a string describing the source (",[66,20515,20417],{},", such as ",[66,20518,20519],{},"\"render function\""," or a lifecycle hook name). Returning ",[66,20522,12981],{}," from the hook stops the error from bubbling up further and prevents it from also being sent to the app-level ",[66,20525,20526],{},"app.config.errorHandler","; returning nothing (or ",[66,20529,10228],{},") lets it continue propagating. This is the building block for a reusable ",[66,20532,20533],{},"ErrorBoundary","-style wrapper component in Vue.",[23,20536,20538,20539,756,20541,20543],{"id":20537},"_84-why-doesnt-the-composition-api-have-beforecreate-or-created-hooks","84. Why doesn't the Composition API have ",[66,20540,19453],{},[66,20542,19468],{}," hooks?",[11,20545,20546,20547,202,20549,20551,20552,154,20554,157,20556,20558,20559,20561,20562,20564],{},"In the Options API, ",[66,20548,19453],{},[66,20550,19468],{}," exist to mark two points around Vue's internal setup of ",[66,20553,9006],{},[66,20555,9012],{},[66,20557,9009],{},", since those are defined declaratively as object options and Vue has to process them before they exist. The Composition API does not need that distinction, because in ",[66,20560,9351],{}," (or the top level of ",[66,20563,8448],{},"), your code runs immediately and synchronously as the component instance is being created; there is no separate \"options processing\" step to wait for.",[507,20566,20568],{"className":8546,"code":20567,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\n// this code itself runs at the point where\n// beforeCreate/created would have fired\nimport { ref } from 'vue'\n\nconst count = ref(0)\nconsole.log('this runs immediately, no hook needed')\n\u003C/script>\n",[66,20569,20570,20580,20585,20590,20600,20604,20620,20633],{"__ignoreMap":512},[516,20571,20572,20574,20576,20578],{"class":518,"line":519},[516,20573,3042],{"class":1227},[516,20575,8604],{"class":8557},[516,20577,8607],{"class":4733},[516,20579,8561],{"class":1227},[516,20581,20582],{"class":518,"line":525},[516,20583,20584],{"class":3076},"// this code itself runs at the point where\n",[516,20586,20587],{"class":518,"line":531},[516,20588,20589],{"class":3076},"// beforeCreate/created would have fired\n",[516,20591,20592,20594,20596,20598],{"class":518,"line":1127},[516,20593,8614],{"class":1749},[516,20595,8617],{"class":1227},[516,20597,8620],{"class":1749},[516,20599,8623],{"class":1248},[516,20601,20602],{"class":518,"line":1134},[516,20603,1131],{"emptyLinePlaceholder":1130},[516,20605,20606,20608,20610,20612,20614,20616,20618],{"class":518,"line":1275},[516,20607,8632],{"class":1749},[516,20609,8635],{"class":1233},[516,20611,1793],{"class":1749},[516,20613,8640],{"class":4733},[516,20615,8643],{"class":1227},[516,20617,8646],{"class":1233},[516,20619,8649],{"class":1227},[516,20621,20622,20624,20626,20628,20631],{"class":518,"line":1302},[516,20623,12258],{"class":1227},[516,20625,11517],{"class":4733},[516,20627,8643],{"class":1227},[516,20629,20630],{"class":1248},"'this runs immediately, no hook needed'",[516,20632,8649],{"class":1227},[516,20634,20635,20637,20639],{"class":518,"line":1308},[516,20636,8589],{"class":1227},[516,20638,8604],{"class":8557},[516,20640,8561],{"class":1227},[11,20642,20643,20644,756,20646,20648,20649,20651,20652,20654,20655,2958,20657,20659],{},"Anything you would have put in ",[66,20645,19453],{},[66,20647,19468],{}," (initializing reactive state, calling an API on load, setting up computed values) just becomes regular top-level code in ",[66,20650,8448],{},". If you genuinely need to run something after the DOM exists, ",[66,20653,19141],{}," is still there for that; ",[66,20656,19453],{},[66,20658,19468],{}," are simply redundant once your setup code already runs at that exact point in the component's life by default.",[18,20661,20663],{"id":20662},"composition-api-vs-options-api","Composition API vs Options API",[23,20665,20667],{"id":20666},"_85-what-is-the-composition-api-and-why-was-it-introduced-alongside-the-options-api","85. What is the Composition API, and why was it introduced alongside the Options API?",[11,20669,20670,20671,154,20673,154,20675,154,20677,20679,20680,20682,20683,154,20685,157,20687,20689],{},"The Composition API is a set of functions (",[66,20672,9387],{},[66,20674,12368],{},[66,20676,9012],{},[66,20678,13396],{},", lifecycle hooks like ",[66,20681,19141],{},", and so on) that you import and call to build a component's logic, instead of declaring it as fixed options on an object. It was added in Vue 3, alongside the original Options API, to solve two problems that grew as components got bigger: logic that belonged together (a search feature's state, computed values, and watchers) ended up scattered across separate ",[66,20684,9006],{},[66,20686,9012],{},[66,20688,9009],{}," blocks, and reusing that logic across components required mixins, which had their own downsides.",[11,20691,20692],{},"It was kept alongside the Options API rather than replacing it because the Options API is still easier to learn for beginners and is perfectly fine for small, simple components. Vue 3 lets you mix both styles in the same project, and even in the same component in some cases, though most codebases pick one style and stay consistent.",[23,20694,20696],{"id":20695},"_86-what-are-the-main-practical-differences-between-the-composition-api-and-the-options-api","86. What are the main practical differences between the Composition API and the Options API?",[11,20698,20699,20700,20702,20703,20705],{},"The core difference is how you organize code: the Options API organizes by option type (all data together, all methods together, all computed properties together), while the Composition API organizes by logical concern (everything related to one feature lives together, usually inside a ",[66,20701,9351],{}," function or a ",[66,20704,8448],{}," block).",[36,20707,20708,20718],{},[39,20709,20710],{},[42,20711,20712,20714,20716],{},[45,20713],{},[45,20715,19439],{},[45,20717,8514],{},[58,20719,20720,20737,20748,20760,20771,20782],{},[42,20721,20722,20725,20734],{},[63,20723,20724],{},"Organization",[63,20726,20727,20728,154,20730,154,20732,3583],{},"Grouped by option (",[66,20729,9006],{},[66,20731,9009],{},[66,20733,9012],{},[63,20735,20736],{},"Grouped by feature/concern",[42,20738,20739,20742,20745],{},[63,20740,20741],{},"Code reuse",[63,20743,20744],{},"Mixins (implicit, can clash)",[63,20746,20747],{},"Composables (explicit imports)",[42,20749,20750,20754,20757],{},[63,20751,20752],{},[66,20753,16959],{},[63,20755,20756],{},"Central to accessing state and methods",[63,20758,20759],{},"Not used; state accessed via variables/closures",[42,20761,20762,20765,20768],{},[63,20763,20764],{},"TypeScript inference",[63,20766,20767],{},"Weaker, needs extra typing helpers",[63,20769,20770],{},"Strong, works naturally with plain functions",[42,20772,20773,20776,20779],{},[63,20774,20775],{},"Bundle size",[63,20777,20778],{},"Slightly larger for tiny components",[63,20780,20781],{},"Better tree-shaking for larger apps",[42,20783,20784,20787,20790],{},[63,20785,20786],{},"Learning curve",[63,20788,20789],{},"Gentler for beginners",[63,20791,20792],{},"Steeper at first, pays off at scale",[11,20794,20795,20796,20798,20799,20801],{},"In practice, a small form component with a handful of fields reads fine either way. A dashboard component with data fetching, filters, pagination, and websockets gets much easier to follow with the Composition API, because you can read top to bottom and see \"here is everything related to pagination\" instead of jumping between four different option blocks. ",[66,20797,8448],{}," is the recommended way to write the Composition API today; it is compiler sugar over a ",[66,20800,9351],{}," function that removes most of the boilerplate.",[23,20803,20805,20806,20808],{"id":20804},"_87-what-is-the-setup-function-and-what-arguments-does-it-receive","87. What is the ",[66,20807,9351],{}," function, and what arguments does it receive?",[11,20810,20811,20813,20814,154,20816,20818],{},[66,20812,9351],{}," is the entry point for the Composition API. It runs once, before the component instance is fully created, before ",[66,20815,9006],{},[66,20817,9012],{},", and other Options API properties are resolved. Anything you return from it (state, computed values, functions) becomes available to the template.",[11,20820,20821,20822,20824,20825,20827,20828,20831,20832,154,20835,154,20837,157,20839,405],{},"It receives two arguments: ",[66,20823,12679],{},", a reactive object of the resolved props (you should not destructure it directly, since that breaks reactivity, unless you wrap it in ",[66,20826,12172],{},"), and ",[66,20829,20830],{},"context",", a plain object exposing ",[66,20833,20834],{},"attrs",[66,20836,18361],{},[66,20838,15438],{},[66,20840,20841],{},"expose",[507,20843,20845],{"className":8782,"code":20844,"language":8784,"meta":512,"style":512},"export default {\n    props: {\n        title: String\n    },\n    setup(props, { emit, attrs }) {\n        function save() {\n            emit('save', props.title)\n        }\n\n        return {\n            save\n        }\n    }\n}\n",[66,20846,20847,20855,20859,20864,20868,20888,20897,20910,20914,20918,20924,20929,20933,20937],{"__ignoreMap":512},[516,20848,20849,20851,20853],{"class":518,"line":519},[516,20850,9190],{"class":1749},[516,20852,9193],{"class":1749},[516,20854,8713],{"class":1227},[516,20856,20857],{"class":518,"line":525},[516,20858,15313],{"class":1227},[516,20860,20861],{"class":518,"line":531},[516,20862,20863],{"class":1227},"        title: String\n",[516,20865,20866],{"class":518,"line":1127},[516,20867,14195],{"class":1227},[516,20869,20870,20872,20874,20876,20879,20881,20883,20885],{"class":518,"line":1134},[516,20871,9200],{"class":4733},[516,20873,8643],{"class":1227},[516,20875,12679],{"class":9080},[516,20877,20878],{"class":1227},", { ",[516,20880,15438],{"class":9080},[516,20882,154],{"class":1227},[516,20884,20834],{"class":9080},[516,20886,20887],{"class":1227}," }) {\n",[516,20889,20890,20892,20895],{"class":518,"line":1275},[516,20891,9224],{"class":1749},[516,20893,20894],{"class":4733}," save",[516,20896,8665],{"class":1227},[516,20898,20899,20902,20904,20907],{"class":518,"line":1302},[516,20900,20901],{"class":4733},"            emit",[516,20903,8643],{"class":1227},[516,20905,20906],{"class":1248},"'save'",[516,20908,20909],{"class":1227},", props.title)\n",[516,20911,20912],{"class":518,"line":1308},[516,20913,9240],{"class":1227},[516,20915,20916],{"class":518,"line":1314},[516,20917,1131],{"emptyLinePlaceholder":1130},[516,20919,20920,20922],{"class":518,"line":8656},[516,20921,9245],{"class":1749},[516,20923,8713],{"class":1227},[516,20925,20926],{"class":518,"line":8668},[516,20927,20928],{"class":1227},"            save\n",[516,20930,20931],{"class":518,"line":8677},[516,20932,9240],{"class":1227},[516,20934,20935],{"class":518,"line":8682},[516,20936,9253],{"class":1227},[516,20938,20939],{"class":518,"line":8691},[516,20940,1317],{"class":1227},[11,20942,20943,20945,20946,20948,20949,20952,20953,20956,20957,20959],{},[66,20944,8448],{}," is compiled into a ",[66,20947,9351],{}," function like this behind the scenes, with props declared via ",[66,20950,20951],{},"defineProps()"," and emits via ",[66,20954,20955],{},"defineEmits()",", so you rarely write ",[66,20958,9351],{}," by hand in modern Vue code.",[23,20961,20963,20964,20966,20967,756,20969,9728],{"id":20962},"_88-why-is-there-no-this-inside-setup-or-script-setup","88. Why is there no ",[66,20965,16959],{}," inside ",[66,20968,9351],{},[66,20970,8448],{},[11,20972,20973,20975,20976,20978,20979,20981,20982,20984,20985,20987,20988,20990,20991,20993],{},[66,20974,9351],{}," runs before the component instance is fully constructed, so at that point there is no finished instance for ",[66,20977,16959],{}," to point to; Vue calls ",[66,20980,9351],{}," with ",[66,20983,16959],{}," set to ",[66,20986,16952],{}," on purpose so nobody accidentally relies on it. Instead, the Composition API gives you plain variables and closures: a ",[66,20989,9387],{}," you create inside ",[66,20992,9351],{}," is just a JavaScript variable you close over, not a property looked up on an instance at render time.",[11,20995,20996,20997,21000,21001,21003,21004,21006,21007,21009],{},"This also makes composables possible. A composable function like ",[66,20998,20999],{},"useMouse()"," can be called from anywhere, not just inside a component, because it never depends on a ",[66,21002,16959],{}," binding to a specific component instance. It also sidesteps a classic Options API gotcha where ",[66,21005,16959],{}," inside a regular (non-arrow) callback function loses its binding to the component. With no ",[66,21008,16959],{}," to lose, that whole category of bug disappears.",[23,21011,21013],{"id":21012},"_89-what-are-composables-and-how-do-they-solve-problems-that-vue-2-mixins-had","89. What are composables, and how do they solve problems that Vue 2 mixins had?",[11,21015,21016,21017,21020],{},"A composable is a plain JavaScript function, conventionally named ",[66,21018,21019],{},"useSomething",", that uses Composition API functions internally and returns reactive state and behavior for a component to consume. It is the Composition API's answer to \"how do I reuse stateful logic across components.\"",[507,21022,21024],{"className":8782,"code":21023,"language":8784,"meta":512,"style":512},"// useMouse.js\nimport { ref, onMounted, onUnmounted } from 'vue'\n\nexport function useMouse() {\n    const x = ref(0)\n    const y = ref(0)\n\n    function update(event) {\n        x.value = event.pageX\n        y.value = event.pageY\n    }\n\n    onMounted(() => window.addEventListener('mousemove', update))\n    onUnmounted(() => window.removeEventListener('mousemove', update))\n\n    return { x, y }\n}\n",[66,21025,21026,21031,21042,21046,21057,21074,21091,21095,21109,21119,21129,21133,21137,21160,21180,21184,21191],{"__ignoreMap":512},[516,21027,21028],{"class":518,"line":519},[516,21029,21030],{"class":3076},"// useMouse.js\n",[516,21032,21033,21035,21038,21040],{"class":518,"line":525},[516,21034,8614],{"class":1749},[516,21036,21037],{"class":1227}," { ref, onMounted, onUnmounted } ",[516,21039,8620],{"class":1749},[516,21041,8623],{"class":1248},[516,21043,21044],{"class":518,"line":531},[516,21045,1131],{"emptyLinePlaceholder":1130},[516,21047,21048,21050,21052,21055],{"class":518,"line":1127},[516,21049,9190],{"class":1749},[516,21051,13287],{"class":1749},[516,21053,21054],{"class":4733}," useMouse",[516,21056,8665],{"class":1227},[516,21058,21059,21061,21064,21066,21068,21070,21072],{"class":518,"line":1134},[516,21060,12611],{"class":1749},[516,21062,21063],{"class":1233}," x",[516,21065,1793],{"class":1749},[516,21067,8640],{"class":4733},[516,21069,8643],{"class":1227},[516,21071,8646],{"class":1233},[516,21073,8649],{"class":1227},[516,21075,21076,21078,21081,21083,21085,21087,21089],{"class":518,"line":1275},[516,21077,12611],{"class":1749},[516,21079,21080],{"class":1233}," y",[516,21082,1793],{"class":1749},[516,21084,8640],{"class":4733},[516,21086,8643],{"class":1227},[516,21088,8646],{"class":1233},[516,21090,8649],{"class":1227},[516,21092,21093],{"class":518,"line":1302},[516,21094,1131],{"emptyLinePlaceholder":1130},[516,21096,21097,21099,21102,21104,21107],{"class":518,"line":1308},[516,21098,12628],{"class":1749},[516,21100,21101],{"class":4733}," update",[516,21103,8643],{"class":1227},[516,21105,21106],{"class":9080},"event",[516,21108,9084],{"class":1227},[516,21110,21111,21114,21116],{"class":518,"line":1314},[516,21112,21113],{"class":1227},"        x.value ",[516,21115,1894],{"class":1749},[516,21117,21118],{"class":1227}," event.pageX\n",[516,21120,21121,21124,21126],{"class":518,"line":8656},[516,21122,21123],{"class":1227},"        y.value ",[516,21125,1894],{"class":1749},[516,21127,21128],{"class":1227}," event.pageY\n",[516,21130,21131],{"class":518,"line":8668},[516,21132,9253],{"class":1227},[516,21134,21135],{"class":518,"line":8677},[516,21136,1131],{"emptyLinePlaceholder":1130},[516,21138,21139,21142,21144,21146,21149,21152,21154,21157],{"class":518,"line":8682},[516,21140,21141],{"class":4733},"    onMounted",[516,21143,11033],{"class":1227},[516,21145,11036],{"class":1749},[516,21147,21148],{"class":1227}," window.",[516,21150,21151],{"class":4733},"addEventListener",[516,21153,8643],{"class":1227},[516,21155,21156],{"class":1248},"'mousemove'",[516,21158,21159],{"class":1227},", update))\n",[516,21161,21162,21165,21167,21169,21171,21174,21176,21178],{"class":518,"line":8691},[516,21163,21164],{"class":4733},"    onUnmounted",[516,21166,11033],{"class":1227},[516,21168,11036],{"class":1749},[516,21170,21148],{"class":1227},[516,21172,21173],{"class":4733},"removeEventListener",[516,21175,8643],{"class":1227},[516,21177,21156],{"class":1248},[516,21179,21159],{"class":1227},[516,21181,21182],{"class":518,"line":8696},[516,21183,1131],{"emptyLinePlaceholder":1130},[516,21185,21186,21188],{"class":518,"line":8708},[516,21187,9089],{"class":1749},[516,21189,21190],{"class":1227}," { x, y }\n",[516,21192,21193],{"class":518,"line":8716},[516,21194,1317],{"class":1227},[507,21196,21198],{"className":8546,"code":21197,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { useMouse } from './useMouse'\n\nconst { x, y } = useMouse()\n\u003C/script>\n",[66,21199,21200,21210,21222,21226,21247],{"__ignoreMap":512},[516,21201,21202,21204,21206,21208],{"class":518,"line":519},[516,21203,3042],{"class":1227},[516,21205,8604],{"class":8557},[516,21207,8607],{"class":4733},[516,21209,8561],{"class":1227},[516,21211,21212,21214,21217,21219],{"class":518,"line":525},[516,21213,8614],{"class":1749},[516,21215,21216],{"class":1227}," { useMouse } ",[516,21218,8620],{"class":1749},[516,21220,21221],{"class":1248}," './useMouse'\n",[516,21223,21224],{"class":518,"line":531},[516,21225,1131],{"emptyLinePlaceholder":1130},[516,21227,21228,21230,21232,21234,21236,21239,21241,21243,21245],{"class":518,"line":1127},[516,21229,8632],{"class":1749},[516,21231,12228],{"class":1227},[516,21233,13035],{"class":1233},[516,21235,154],{"class":1227},[516,21237,21238],{"class":1233},"y",[516,21240,12238],{"class":1227},[516,21242,1894],{"class":1749},[516,21244,21054],{"class":4733},[516,21246,13318],{"class":1227},[516,21248,21249,21251,21253],{"class":518,"line":1134},[516,21250,8589],{"class":1227},[516,21252,8604],{"class":8557},[516,21254,8561],{"class":1227},[11,21256,21257,21258,21260,21261,21263],{},"Vue 2 mixins had two well-known problems. First, source ambiguity: if a component used two mixins and both defined a ",[66,21259,9006],{}," property called ",[66,21262,17180],{},", it was not obvious at a glance which one \"won\" or where a property in the template actually came from. Second, implicit merging: mixin options got silently merged into the component's options, so adding a second mixin could quietly break the first one if their properties collided.",[11,21265,21266,21267,21270,21271,21274],{},"Composables avoid both. Everything a composable exposes comes back through an explicit return value that you destructure by hand (",[66,21268,21269],{},"const { x, y } = useMouse()","), so there is no merging and no guessing; you can even rename on the way in (",[66,21272,21273],{},"const { x: mouseX } = useMouse()",") if two composables would otherwise clash.",[23,21276,21278],{"id":21277},"_90-what-are-the-rules-of-thumb-for-writing-a-good-composable","90. What are the rules of thumb for writing a good composable?",[717,21280,21281,21290,21302,21311,21322,21332],{},[720,21282,21283,21289],{},[31,21284,21285,21286,405],{},"Name it ",[66,21287,21288],{},"useX"," This is a strong convention in the Vue ecosystem and instantly signals \"this function uses reactivity and probably has lifecycle behavior.\"",[720,21291,21292,21295,21296,21298,21299,21301],{},[31,21293,21294],{},"Return refs, not a single reactive object",", when the caller needs to destructure the result. Destructuring a ",[66,21297,11445],{}," object loses reactivity; returning individual ",[66,21300,9387],{},"s (or an object of refs) keeps it intact.",[720,21303,21304,21307,21308,21310],{},[31,21305,21306],{},"Accept refs or plain values as arguments",", and normalize with ",[66,21309,13104],{}," internally, so callers can pass either a static value or a reactive one without extra ceremony.",[720,21312,21313,21316,21317,21319,21320,405],{},[31,21314,21315],{},"Clean up after yourself."," If a composable adds an event listener, opens a websocket, or starts a timer in ",[66,21318,19141],{},", it should remove it in ",[66,21321,19561],{},[720,21323,21324,21327,21328,21331],{},[31,21325,21326],{},"Keep it focused on one concern."," A ",[66,21329,21330],{},"useFetch"," composable should fetch data; it should not also manage form validation. Small composables compose well together, large ones become mixins in disguise.",[720,21333,21334,21337,21338,21341,21342,21344],{},[31,21335,21336],{},"Avoid relying on being called in a specific component lifecycle phase"," unless documented; some composables (like a simple ",[66,21339,21340],{},"useLocalStorage",") work fine outside ",[66,21343,9351],{},", others need to run during component setup because they register lifecycle hooks.",[18,21346,21348],{"id":21347},"vue-router","Vue Router",[23,21350,21352],{"id":21351},"_91-what-is-vue-router-and-how-do-you-set-it-up-in-an-application","91. What is Vue Router, and how do you set it up in an application?",[11,21354,21355],{},"Vue Router is the official routing library for Vue. It maps URL paths to components so a Vue app can behave like a multi-page site while staying a single-page application: navigating between routes swaps components in and out without a full browser reload.",[11,21357,21358,21359,21362],{},"Setup has three parts: define an array of routes (each one a path paired with a component), create a router instance with ",[66,21360,21361],{},"createRouter",", and install it on the app.",[507,21364,21366],{"className":8782,"code":21365,"language":8784,"meta":512,"style":512},"// router.js\nimport { createRouter, createWebHistory } from 'vue-router'\nimport Home from './views/Home.vue'\nimport About from './views/About.vue'\n\nconst routes = [\n    { path: '/', component: Home },\n    { path: '/about', component: About }\n]\n\nconst router = createRouter({\n    history: createWebHistory(),\n    routes\n})\n\nexport default router\n",[66,21367,21368,21373,21385,21397,21409,21413,21425,21436,21446,21450,21454,21468,21479,21484,21488,21492],{"__ignoreMap":512},[516,21369,21370],{"class":518,"line":519},[516,21371,21372],{"class":3076},"// router.js\n",[516,21374,21375,21377,21380,21382],{"class":518,"line":525},[516,21376,8614],{"class":1749},[516,21378,21379],{"class":1227}," { createRouter, createWebHistory } ",[516,21381,8620],{"class":1749},[516,21383,21384],{"class":1248}," 'vue-router'\n",[516,21386,21387,21389,21392,21394],{"class":518,"line":531},[516,21388,8614],{"class":1749},[516,21390,21391],{"class":1227}," Home ",[516,21393,8620],{"class":1749},[516,21395,21396],{"class":1248}," './views/Home.vue'\n",[516,21398,21399,21401,21404,21406],{"class":518,"line":1127},[516,21400,8614],{"class":1749},[516,21402,21403],{"class":1227}," About ",[516,21405,8620],{"class":1749},[516,21407,21408],{"class":1248}," './views/About.vue'\n",[516,21410,21411],{"class":518,"line":1134},[516,21412,1131],{"emptyLinePlaceholder":1130},[516,21414,21415,21417,21420,21422],{"class":518,"line":1275},[516,21416,8632],{"class":1749},[516,21418,21419],{"class":1233}," routes",[516,21421,1793],{"class":1749},[516,21423,21424],{"class":1227}," [\n",[516,21426,21427,21430,21433],{"class":518,"line":1302},[516,21428,21429],{"class":1227},"    { path: ",[516,21431,21432],{"class":1248},"'/'",[516,21434,21435],{"class":1227},", component: Home },\n",[516,21437,21438,21440,21443],{"class":518,"line":1308},[516,21439,21429],{"class":1227},[516,21441,21442],{"class":1248},"'/about'",[516,21444,21445],{"class":1227},", component: About }\n",[516,21447,21448],{"class":518,"line":1314},[516,21449,17207],{"class":1227},[516,21451,21452],{"class":518,"line":8656},[516,21453,1131],{"emptyLinePlaceholder":1130},[516,21455,21456,21458,21461,21463,21466],{"class":518,"line":8668},[516,21457,8632],{"class":1749},[516,21459,21460],{"class":1233}," router",[516,21462,1793],{"class":1749},[516,21464,21465],{"class":4733}," createRouter",[516,21467,12910],{"class":1227},[516,21469,21470,21473,21476],{"class":518,"line":8677},[516,21471,21472],{"class":1227},"    history: ",[516,21474,21475],{"class":4733},"createWebHistory",[516,21477,21478],{"class":1227},"(),\n",[516,21480,21481],{"class":518,"line":8682},[516,21482,21483],{"class":1227},"    routes\n",[516,21485,21486],{"class":518,"line":8691},[516,21487,11530],{"class":1227},[516,21489,21490],{"class":518,"line":8696},[516,21491,1131],{"emptyLinePlaceholder":1130},[516,21493,21494,21496,21498],{"class":518,"line":8708},[516,21495,9190],{"class":1749},[516,21497,9193],{"class":1749},[516,21499,21500],{"class":1227}," router\n",[507,21502,21504],{"className":8782,"code":21503,"language":8784,"meta":512,"style":512},"// main.js\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport router from './router'\n\ncreateApp(App).use(router).mount('#app')\n",[66,21505,21506,21510,21520,21530,21542,21546],{"__ignoreMap":512},[516,21507,21508],{"class":518,"line":519},[516,21509,8791],{"class":3076},[516,21511,21512,21514,21516,21518],{"class":518,"line":525},[516,21513,8614],{"class":1749},[516,21515,8798],{"class":1227},[516,21517,8620],{"class":1749},[516,21519,8623],{"class":1248},[516,21521,21522,21524,21526,21528],{"class":518,"line":531},[516,21523,8614],{"class":1749},[516,21525,8809],{"class":1227},[516,21527,8620],{"class":1749},[516,21529,8814],{"class":1248},[516,21531,21532,21534,21537,21539],{"class":518,"line":1127},[516,21533,8614],{"class":1749},[516,21535,21536],{"class":1227}," router ",[516,21538,8620],{"class":1749},[516,21540,21541],{"class":1248}," './router'\n",[516,21543,21544],{"class":518,"line":1134},[516,21545,1131],{"emptyLinePlaceholder":1130},[516,21547,21548,21550,21553,21556,21559,21561,21563,21565],{"class":518,"line":1275},[516,21549,8770],{"class":4733},[516,21551,21552],{"class":1227},"(App).",[516,21554,21555],{"class":4733},"use",[516,21557,21558],{"class":1227},"(router).",[516,21560,8845],{"class":4733},[516,21562,8643],{"class":1227},[516,21564,8850],{"class":1248},[516,21566,8649],{"class":1227},[11,21568,21569,21570,21573,21574,21577],{},"Finally, add a ",[66,21571,21572],{},"\u003Crouter-view />"," somewhere in ",[66,21575,21576],{},"App.vue","; that is where the component matching the current route gets rendered.",[23,21579,21581],{"id":21580},"_92-what-is-the-difference-between-hash-mode-and-history-mode-routing","92. What is the difference between hash mode and history mode routing?",[11,21583,21584,21585,21588,21589,405],{},"Both are ways Vue Router keeps the URL in sync with the current view, and both are configured through the ",[66,21586,21587],{},"history"," option passed to ",[66,21590,21361],{},[11,21592,21593,21596,21597,21599,21600,21603,21604,21607,21608,21610],{},[66,21594,21595],{},"createWebHashHistory()"," puts the route after a ",[66,21598,18012],{},", like ",[66,21601,21602],{},"example.com/#/about",". Everything after the hash is never sent to the server, so the server only ever needs to serve one file (",[66,21605,21606],{},"index.html","); the browser handles the rest. This makes it trivial to deploy anywhere, including a plain static file host with no routing config, but the URLs look less clean and the ",[66,21609,18012],{}," historically interfered with anchor-link scrolling and some SEO tooling.",[11,21612,21613,21616,21617,21620,21621,21623,21624,21627,21628,21630],{},[66,21614,21615],{},"createWebHistory()"," uses the browser's native History API to produce clean URLs, like ",[66,21618,21619],{},"example.com/about",". This looks and behaves like a normal server-rendered site, but it requires the server (or CDN/edge config) to be set up to return ",[66,21622,21606],{}," for any unmatched path; otherwise, refreshing the page on ",[66,21625,21626],{},"/about"," sends a real request to ",[66,21629,21626],{},", which returns a 404 because no such file exists on the server.",[11,21632,21633],{},"For most modern deployments (Vercel, Netlify, Cloudflare Pages, etc.) history mode is the default choice since these platforms make the fallback rewrite easy to configure; hash mode is mostly a fallback for hosts where you cannot control server-side routing at all.",[23,21635,21637],{"id":21636},"_93-what-are-dynamic-route-parameters-and-how-do-you-read-them-in-a-component","93. What are dynamic route parameters, and how do you read them in a component?",[11,21639,21640,21641,21644,21645,154,21648,21651,21652,21654],{},"A dynamic route parameter is a named segment of a path, written with a colon, that matches a variable value instead of a fixed string. ",[66,21642,21643],{},"/users/:id"," matches ",[66,21646,21647],{},"/users/1",[66,21649,21650],{},"/users/42",", and so on, with ",[66,21653,1578],{}," captured as a parameter.",[507,21656,21658],{"className":8782,"code":21657,"language":8784,"meta":512,"style":512},"const routes = [\n    { path: '/users/:id', component: UserProfile }\n]\n",[66,21659,21660,21670,21680],{"__ignoreMap":512},[516,21661,21662,21664,21666,21668],{"class":518,"line":519},[516,21663,8632],{"class":1749},[516,21665,21419],{"class":1233},[516,21667,1793],{"class":1749},[516,21669,21424],{"class":1227},[516,21671,21672,21674,21677],{"class":518,"line":525},[516,21673,21429],{"class":1227},[516,21675,21676],{"class":1248},"'/users/:id'",[516,21678,21679],{"class":1227},", component: UserProfile }\n",[516,21681,21682],{"class":518,"line":531},[516,21683,17207],{"class":1227},[11,21685,21686,21687,9605],{},"Inside a component, you read it with ",[66,21688,21689],{},"useRoute()",[507,21691,21693],{"className":8546,"code":21692,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { useRoute } from 'vue-router'\nimport { watch } from 'vue'\n\nconst route = useRoute()\n\nconsole.log(route.params.id)\n\nwatch(() => route.params.id, (newId) => {\n    // re-fetch data because the component instance is reused\n    // when only the param changes, not re-created\n})\n\u003C/script>\n",[66,21694,21695,21705,21716,21727,21731,21745,21749,21758,21762,21781,21786,21791,21795],{"__ignoreMap":512},[516,21696,21697,21699,21701,21703],{"class":518,"line":519},[516,21698,3042],{"class":1227},[516,21700,8604],{"class":8557},[516,21702,8607],{"class":4733},[516,21704,8561],{"class":1227},[516,21706,21707,21709,21712,21714],{"class":518,"line":525},[516,21708,8614],{"class":1749},[516,21710,21711],{"class":1227}," { useRoute } ",[516,21713,8620],{"class":1749},[516,21715,21384],{"class":1248},[516,21717,21718,21720,21723,21725],{"class":518,"line":531},[516,21719,8614],{"class":1749},[516,21721,21722],{"class":1227}," { watch } ",[516,21724,8620],{"class":1749},[516,21726,8623],{"class":1248},[516,21728,21729],{"class":518,"line":1127},[516,21730,1131],{"emptyLinePlaceholder":1130},[516,21732,21733,21735,21738,21740,21743],{"class":518,"line":1134},[516,21734,8632],{"class":1749},[516,21736,21737],{"class":1233}," route",[516,21739,1793],{"class":1749},[516,21741,21742],{"class":4733}," useRoute",[516,21744,13318],{"class":1227},[516,21746,21747],{"class":518,"line":1275},[516,21748,1131],{"emptyLinePlaceholder":1130},[516,21750,21751,21753,21755],{"class":518,"line":1302},[516,21752,12258],{"class":1227},[516,21754,11517],{"class":4733},[516,21756,21757],{"class":1227},"(route.params.id)\n",[516,21759,21760],{"class":518,"line":1308},[516,21761,1131],{"emptyLinePlaceholder":1130},[516,21763,21764,21766,21768,21770,21773,21775,21777,21779],{"class":518,"line":1314},[516,21765,13396],{"class":4733},[516,21767,11033],{"class":1227},[516,21769,11036],{"class":1749},[516,21771,21772],{"class":1227}," route.params.id, (",[516,21774,14435],{"class":9080},[516,21776,13650],{"class":1227},[516,21778,11036],{"class":1749},[516,21780,8713],{"class":1227},[516,21782,21783],{"class":518,"line":8656},[516,21784,21785],{"class":3076},"    // re-fetch data because the component instance is reused\n",[516,21787,21788],{"class":518,"line":8668},[516,21789,21790],{"class":3076},"    // when only the param changes, not re-created\n",[516,21792,21793],{"class":518,"line":8677},[516,21794,11530],{"class":1227},[516,21796,21797,21799,21801],{"class":518,"line":8682},[516,21798,8589],{"class":1227},[516,21800,8604],{"class":8557},[516,21802,8561],{"class":1227},[11,21804,21805,21806,21808,21809,21812,21813,21815,21816,21818,21819,21822],{},"The gotcha here is that navigating from ",[66,21807,21647],{}," to ",[66,21810,21811],{},"/users/2"," reuses the same component instance for efficiency, so plain ",[66,21814,19141],{}," fetch logic will not re-run automatically; you need to ",[66,21817,13396],{}," the param (or use the ",[66,21820,21821],{},"beforeRouteUpdate"," guard) to react to the change.",[23,21824,21826],{"id":21825},"_94-what-is-the-difference-between-route-params-and-query-strings","94. What is the difference between route params and query strings?",[36,21828,21829,21841],{},[39,21830,21831],{},[42,21832,21833,21835,21838],{},[45,21834],{},[45,21836,21837],{},"Route params",[45,21839,21840],{},"Query strings",[58,21842,21843,21861,21872,21887],{},[42,21844,21845,21848,21853],{},[63,21846,21847],{},"Location",[63,21849,21850,21851,3583],{},"Part of the path pattern (",[66,21852,21643],{},[63,21854,21855,21856,734,21858,3583],{},"After the ",[66,21857,9728],{},[66,21859,21860],{},"/users?sort=asc",[42,21862,21863,21866,21869],{},[63,21864,21865],{},"Required to match",[63,21867,21868],{},"Yes, part of the route definition",[63,21870,21871],{},"No, always optional",[42,21873,21874,21877,21882],{},[63,21875,21876],{},"Access",[63,21878,21879],{},[66,21880,21881],{},"route.params.id",[63,21883,21884],{},[66,21885,21886],{},"route.query.sort",[42,21888,21889,21891,21894],{},[63,21890,56],{},[63,21892,21893],{},"Identifying a specific resource",[63,21895,21896],{},"Filters, sorting, pagination, search state",[11,21898,21899,21900,21902,21903,21906],{},"Params define the shape of the route itself: if a route is declared as ",[66,21901,21643],{},", a URL without that segment simply will not match the route at all. Query strings sit on top of whatever route matched and carry optional, often changeable state, like ",[66,21904,21905],{},"?page=2&sort=name",", that does not affect which route/component is used, only how it behaves. A good rule of thumb: use a param for \"which resource,\" and a query string for \"how do you want it filtered or displayed.\"",[23,21908,21910],{"id":21909},"_95-what-are-nested-child-routes-and-when-would-you-use-them","95. What are nested (child) routes, and when would you use them?",[11,21912,21913,21914,21916,21917,21920],{},"Nested routes let a route render its own component while also rendering a child component inside a nested ",[66,21915,21572],{},", mirroring the way a URL like ",[66,21918,21919],{},"/user/1/profile"," is really \"a user page, with a profile section inside it.\"",[507,21922,21924],{"className":8782,"code":21923,"language":8784,"meta":512,"style":512},"const routes = [\n    {\n        path: '/user/:id',\n        component: User,\n        children: [\n            { path: '', component: UserHome },\n            { path: 'profile', component: UserProfile },\n            { path: 'posts', component: UserPosts }\n        ]\n    }\n]\n",[66,21925,21926,21936,21941,21951,21956,21961,21972,21982,21992,21997,22001],{"__ignoreMap":512},[516,21927,21928,21930,21932,21934],{"class":518,"line":519},[516,21929,8632],{"class":1749},[516,21931,21419],{"class":1233},[516,21933,1793],{"class":1749},[516,21935,21424],{"class":1227},[516,21937,21938],{"class":518,"line":525},[516,21939,21940],{"class":1227},"    {\n",[516,21942,21943,21946,21949],{"class":518,"line":531},[516,21944,21945],{"class":1227},"        path: ",[516,21947,21948],{"class":1248},"'/user/:id'",[516,21950,1252],{"class":1227},[516,21952,21953],{"class":518,"line":1127},[516,21954,21955],{"class":1227},"        component: User,\n",[516,21957,21958],{"class":518,"line":1134},[516,21959,21960],{"class":1227},"        children: [\n",[516,21962,21963,21966,21969],{"class":518,"line":1275},[516,21964,21965],{"class":1227},"            { path: ",[516,21967,21968],{"class":1248},"''",[516,21970,21971],{"class":1227},", component: UserHome },\n",[516,21973,21974,21976,21979],{"class":518,"line":1302},[516,21975,21965],{"class":1227},[516,21977,21978],{"class":1248},"'profile'",[516,21980,21981],{"class":1227},", component: UserProfile },\n",[516,21983,21984,21986,21989],{"class":518,"line":1308},[516,21985,21965],{"class":1227},[516,21987,21988],{"class":1248},"'posts'",[516,21990,21991],{"class":1227},", component: UserPosts }\n",[516,21993,21994],{"class":518,"line":1314},[516,21995,21996],{"class":1227},"        ]\n",[516,21998,21999],{"class":518,"line":8656},[516,22000,9253],{"class":1227},[516,22002,22003],{"class":518,"line":8668},[516,22004,17207],{"class":1227},[507,22006,22008],{"className":8546,"code":22007,"language":8548,"meta":512,"style":512},"\u003C!-- User.vue -->\n\u003Ctemplate>\n    \u003Cdiv class=\"user\">\n        \u003Ch2>User {{ $route.params.id }}\u003C/h2>\n        \u003Cnav>\n            \u003Crouter-link :to=\"`/user/${$route.params.id}/profile`\">Profile\u003C/router-link>\n            \u003Crouter-link :to=\"`/user/${$route.params.id}/posts`\">Posts\u003C/router-link>\n        \u003C/nav>\n        \u003Crouter-view />\n    \u003C/div>\n\u003C/template>\n",[66,22009,22010,22015,22023,22037,22050,22059,22081,22101,22109,22118,22126],{"__ignoreMap":512},[516,22011,22012],{"class":518,"line":519},[516,22013,22014],{"class":3076},"\u003C!-- User.vue -->\n",[516,22016,22017,22019,22021],{"class":518,"line":525},[516,22018,3042],{"class":1227},[516,22020,8558],{"class":8557},[516,22022,8561],{"class":1227},[516,22024,22025,22027,22029,22031,22033,22035],{"class":518,"line":531},[516,22026,8566],{"class":1227},[516,22028,9764],{"class":8557},[516,22030,16525],{"class":4733},[516,22032,1894],{"class":1227},[516,22034,2417],{"class":1248},[516,22036,8561],{"class":1227},[516,22038,22039,22041,22043,22046,22048],{"class":518,"line":1127},[516,22040,9868],{"class":1227},[516,22042,18],{"class":8557},[516,22044,22045],{"class":1227},">User {{ $route.params.id }}\u003C/",[516,22047,18],{"class":8557},[516,22049,8561],{"class":1227},[516,22051,22052,22054,22057],{"class":518,"line":1134},[516,22053,9868],{"class":1227},[516,22055,22056],{"class":8557},"nav",[516,22058,8561],{"class":1227},[516,22060,22061,22063,22066,22069,22071,22074,22077,22079],{"class":518,"line":1275},[516,22062,17730],{"class":1227},[516,22064,22065],{"class":8557},"router-link",[516,22067,22068],{"class":4733}," :to",[516,22070,1894],{"class":1227},[516,22072,22073],{"class":1248},"\"`/user/${$route.params.id}/profile`\"",[516,22075,22076],{"class":1227},">Profile\u003C/",[516,22078,22065],{"class":8557},[516,22080,8561],{"class":1227},[516,22082,22083,22085,22087,22089,22091,22094,22097,22099],{"class":518,"line":1302},[516,22084,17730],{"class":1227},[516,22086,22065],{"class":8557},[516,22088,22068],{"class":4733},[516,22090,1894],{"class":1227},[516,22092,22093],{"class":1248},"\"`/user/${$route.params.id}/posts`\"",[516,22095,22096],{"class":1227},">Posts\u003C/",[516,22098,22065],{"class":8557},[516,22100,8561],{"class":1227},[516,22102,22103,22105,22107],{"class":518,"line":1308},[516,22104,9898],{"class":1227},[516,22106,22056],{"class":8557},[516,22108,8561],{"class":1227},[516,22110,22111,22113,22116],{"class":518,"line":1314},[516,22112,9868],{"class":1227},[516,22114,22115],{"class":8557},"router-view",[516,22117,9667],{"class":1227},[516,22119,22120,22122,22124],{"class":518,"line":8656},[516,22121,9907],{"class":1227},[516,22123,9764],{"class":8557},[516,22125,8561],{"class":1227},[516,22127,22128,22130,22132],{"class":518,"line":8668},[516,22129,8589],{"class":1227},[516,22131,8558],{"class":8557},[516,22133,8561],{"class":1227},[11,22135,22136,22137,154,22140,157,22143,22146],{},"This is the right tool whenever a section of the UI (a sidebar, a set of tabs, a shared header) needs to stay on screen while only the inner content changes as the user navigates, like a settings page with ",[66,22138,22139],{},"/settings/account",[66,22141,22142],{},"/settings/billing",[66,22144,22145],{},"/settings/security"," all sharing the same page shell.",[23,22148,22150],{"id":22149},"_96-what-are-named-routes-and-named-views","96. What are named routes and named views?",[11,22152,22153,22154,22156],{},"A named route is a route with a ",[66,22155,189],{}," property, which lets you navigate to it by name instead of hardcoding the path string. This is useful because paths change more often than names do, and it avoids fragile string concatenation for dynamic segments.",[507,22158,22160],{"className":8782,"code":22159,"language":8784,"meta":512,"style":512},"const routes = [\n    { path: '/user/:id', name: 'user', component: User }\n]\n",[66,22161,22162,22172,22186],{"__ignoreMap":512},[516,22163,22164,22166,22168,22170],{"class":518,"line":519},[516,22165,8632],{"class":1749},[516,22167,21419],{"class":1233},[516,22169,1793],{"class":1749},[516,22171,21424],{"class":1227},[516,22173,22174,22176,22178,22180,22183],{"class":518,"line":525},[516,22175,21429],{"class":1227},[516,22177,21948],{"class":1248},[516,22179,12216],{"class":1227},[516,22181,22182],{"class":1248},"'user'",[516,22184,22185],{"class":1227},", component: User }\n",[516,22187,22188],{"class":518,"line":531},[516,22189,17207],{"class":1227},[507,22191,22193],{"className":8782,"code":22192,"language":8784,"meta":512,"style":512},"router.push({ name: 'user', params: { id: 123 } })\n",[66,22194,22195],{"__ignoreMap":512},[516,22196,22197,22200,22202,22204,22206,22209,22212],{"class":518,"line":519},[516,22198,22199],{"class":1227},"router.",[516,22201,11930],{"class":4733},[516,22203,14549],{"class":1227},[516,22205,22182],{"class":1248},[516,22207,22208],{"class":1227},", params: { id: ",[516,22210,22211],{"class":1233},"123",[516,22213,12756],{"class":1227},[11,22215,22216,22217,22220,22221,22224,22225,405],{},"A named view is different: it lets a single route render multiple components at once into multiple ",[66,22218,22219],{},"\u003Crouter-view>"," outlets, by giving the route a ",[66,22222,22223],{},"components"," object (plural) instead of a single ",[66,22226,9422],{},[507,22228,22230],{"className":8782,"code":22229,"language":8784,"meta":512,"style":512},"const routes = [\n    {\n        path: '/',\n        components: {\n            default: Home,\n            sidebar: Sidebar\n        }\n    }\n]\n",[66,22231,22232,22242,22246,22254,22259,22264,22269,22273,22277],{"__ignoreMap":512},[516,22233,22234,22236,22238,22240],{"class":518,"line":519},[516,22235,8632],{"class":1749},[516,22237,21419],{"class":1233},[516,22239,1793],{"class":1749},[516,22241,21424],{"class":1227},[516,22243,22244],{"class":518,"line":525},[516,22245,21940],{"class":1227},[516,22247,22248,22250,22252],{"class":518,"line":531},[516,22249,21945],{"class":1227},[516,22251,21432],{"class":1248},[516,22253,1252],{"class":1227},[516,22255,22256],{"class":518,"line":1127},[516,22257,22258],{"class":1227},"        components: {\n",[516,22260,22261],{"class":518,"line":1134},[516,22262,22263],{"class":1227},"            default: Home,\n",[516,22265,22266],{"class":518,"line":1275},[516,22267,22268],{"class":1227},"            sidebar: Sidebar\n",[516,22270,22271],{"class":518,"line":1302},[516,22272,9240],{"class":1227},[516,22274,22275],{"class":518,"line":1308},[516,22276,9253],{"class":1227},[516,22278,22279],{"class":518,"line":1314},[516,22280,17207],{"class":1227},[507,22282,22284],{"className":8546,"code":22283,"language":8548,"meta":512,"style":512},"\u003Crouter-view />\n\u003Crouter-view name=\"sidebar\" />\n",[66,22285,22286,22294],{"__ignoreMap":512},[516,22287,22288,22290,22292],{"class":518,"line":519},[516,22289,3042],{"class":1227},[516,22291,22115],{"class":8557},[516,22293,9667],{"class":1227},[516,22295,22296,22298,22300,22302,22304,22307],{"class":518,"line":525},[516,22297,3042],{"class":1227},[516,22299,22115],{"class":8557},[516,22301,17515],{"class":4733},[516,22303,1894],{"class":1227},[516,22305,22306],{"class":1248},"\"sidebar\"",[516,22308,9667],{"class":1227},[11,22310,22311],{},"Named views are typically used for layouts where more than one region of the page changes based on the route, like a main content area plus a contextual sidebar that both depend on which page is active.",[23,22313,22315,22316,154,22319,157,22322,9728],{"id":22314},"_97-what-are-navigation-guards-and-what-are-the-differences-between-beforeeach-beforeenter-and-beforerouteleave","97. What are navigation guards, and what are the differences between ",[66,22317,22318],{},"beforeEach",[66,22320,22321],{},"beforeEnter",[66,22323,22324],{},"beforeRouteLeave",[11,22326,22327],{},"Navigation guards are functions Vue Router calls during a navigation that can allow it, redirect it, or cancel it. They exist so you can gate access to routes (auth checks), warn about unsaved changes, or update page metadata before a route actually renders.",[11,22329,22330],{},[2160,22331],{"alt":22332,"src":22333},"Vue Router navigation guards order diagram","/post-images/top-150-vuejs-interview-questions/vue-router-navigation-guards-diagram.png",[11,22335,22336],{},"The three you asked about live at different scopes:",[717,22338,22339,22347,22359],{},[720,22340,22341,22346],{},[31,22342,22343],{},[66,22344,22345],{},"router.beforeEach"," is a global guard, registered once on the router instance. It runs on every single navigation in the app, regardless of which route is involved, which makes it the natural place for app-wide checks like \"is the user logged in.\"",[720,22348,22349,22353,22354,21808,22356,22358],{},[31,22350,22351],{},[66,22352,22321],{}," is a per-route guard, defined directly in that route's config. It only runs when navigating to that specific route, and it does not fire again on in-place param changes (going from ",[66,22355,21647],{},[66,22357,21811],{}," on the same route record does not re-trigger it, since that is an \"update,\" not a fresh \"entry\").",[720,22360,22361,22365,22366,22369,22370,22372],{},[31,22362,22363],{},[66,22364,22324],{}," is an in-component guard, defined inside the component being navigated away from (as a component option in the Options API, or via the ",[66,22367,22368],{},"onBeforeRouteLeave"," composable in ",[66,22371,8448],{},"). It runs when the user is about to leave the route that renders this component, which makes it the right spot for \"you have unsaved changes, are you sure?\" prompts.",[507,22374,22376],{"className":8782,"code":22375,"language":8784,"meta":512,"style":512},"router.beforeEach((to, from) => {\n    if (to.meta.requiresAuth && !isLoggedIn()) {\n        return { name: 'login' }\n    }\n})\n",[66,22377,22378,22399,22418,22430,22434],{"__ignoreMap":512},[516,22379,22380,22382,22384,22386,22389,22391,22393,22395,22397],{"class":518,"line":519},[516,22381,22199],{"class":1227},[516,22383,22318],{"class":4733},[516,22385,14711],{"class":1227},[516,22387,22388],{"class":9080},"to",[516,22390,154],{"class":1227},[516,22392,8620],{"class":9080},[516,22394,13650],{"class":1227},[516,22396,11036],{"class":1749},[516,22398,8713],{"class":1227},[516,22400,22401,22404,22407,22410,22412,22415],{"class":518,"line":525},[516,22402,22403],{"class":1749},"    if",[516,22405,22406],{"class":1227}," (to.meta.requiresAuth ",[516,22408,22409],{"class":1749},"&&",[516,22411,11052],{"class":1749},[516,22413,22414],{"class":4733},"isLoggedIn",[516,22416,22417],{"class":1227},"()) {\n",[516,22419,22420,22422,22425,22428],{"class":518,"line":531},[516,22421,9245],{"class":1749},[516,22423,22424],{"class":1227}," { name: ",[516,22426,22427],{"class":1248},"'login'",[516,22429,1299],{"class":1227},[516,22431,22432],{"class":518,"line":1127},[516,22433,9253],{"class":1227},[516,22435,22436],{"class":518,"line":1134},[516,22437,11530],{"class":1227},[507,22439,22441],{"className":8546,"code":22440,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onBeforeRouteLeave } from 'vue-router'\n\nonBeforeRouteLeave(() => {\n    const confirmed = window.confirm('Leave without saving changes?')\n    if (!confirmed) return false\n})\n\u003C/script>\n",[66,22442,22443,22453,22464,22468,22478,22499,22515,22519],{"__ignoreMap":512},[516,22444,22445,22447,22449,22451],{"class":518,"line":519},[516,22446,3042],{"class":1227},[516,22448,8604],{"class":8557},[516,22450,8607],{"class":4733},[516,22452,8561],{"class":1227},[516,22454,22455,22457,22460,22462],{"class":518,"line":525},[516,22456,8614],{"class":1749},[516,22458,22459],{"class":1227}," { onBeforeRouteLeave } ",[516,22461,8620],{"class":1749},[516,22463,21384],{"class":1248},[516,22465,22466],{"class":518,"line":531},[516,22467,1131],{"emptyLinePlaceholder":1130},[516,22469,22470,22472,22474,22476],{"class":518,"line":1127},[516,22471,22368],{"class":4733},[516,22473,11033],{"class":1227},[516,22475,11036],{"class":1749},[516,22477,8713],{"class":1227},[516,22479,22480,22482,22485,22487,22489,22492,22494,22497],{"class":518,"line":1134},[516,22481,12611],{"class":1749},[516,22483,22484],{"class":1233}," confirmed",[516,22486,1793],{"class":1749},[516,22488,21148],{"class":1227},[516,22490,22491],{"class":4733},"confirm",[516,22493,8643],{"class":1227},[516,22495,22496],{"class":1248},"'Leave without saving changes?'",[516,22498,8649],{"class":1227},[516,22500,22501,22503,22505,22507,22510,22512],{"class":518,"line":1275},[516,22502,22403],{"class":1749},[516,22504,734],{"class":1227},[516,22506,10950],{"class":1749},[516,22508,22509],{"class":1227},"confirmed) ",[516,22511,9355],{"class":1749},[516,22513,22514],{"class":1233}," false\n",[516,22516,22517],{"class":518,"line":1302},[516,22518,11530],{"class":1227},[516,22520,22521,22523,22525],{"class":518,"line":1308},[516,22522,8589],{"class":1227},[516,22524,8604],{"class":8557},[516,22526,8561],{"class":1227},[11,22528,22529],{},"The full resolution order, which is worth memorizing since it is commonly tested, is:",[2868,22531,22532,22535,22540,22546,22551,22556,22559,22565,22570,22573,22579,22582],{},[720,22533,22534],{},"Navigation is triggered.",[720,22536,22537,22539],{},[66,22538,22324],{}," guards run in components being deactivated.",[720,22541,22542,22543,22545],{},"Global ",[66,22544,22318],{}," guards run.",[720,22547,22548,22550],{},[66,22549,21821],{}," guards run in reused components (same component, changed params).",[720,22552,22553,22555],{},[66,22554,22321],{}," guards run for the route(s) being entered.",[720,22557,22558],{},"Async route components are resolved.",[720,22560,22561,22564],{},[66,22562,22563],{},"beforeRouteEnter"," guards run in components being activated.",[720,22566,22542,22567,22545],{},[66,22568,22569],{},"beforeResolve",[720,22571,22572],{},"The navigation is confirmed.",[720,22574,22542,22575,22578],{},[66,22576,22577],{},"afterEach"," hooks run.",[720,22580,22581],{},"The DOM updates.",[720,22583,22584,22585,20966,22588,22590],{},"Callbacks passed to ",[66,22586,22587],{},"next()",[66,22589,22563],{}," run, now with access to the mounted instance.",[23,22592,22594],{"id":22593},"_98-what-is-route-meta-information-used-for","98. What is route meta information used for?",[11,22596,22597,22600,22601,756,22604,405],{},[66,22598,22599],{},"meta"," is an arbitrary object you attach to a route definition to store custom data that has nothing to do with matching the URL, but that guards, components, and navigation logic can read off ",[66,22602,22603],{},"to.meta",[66,22605,22606],{},"route.meta",[507,22608,22610],{"className":8782,"code":22609,"language":8784,"meta":512,"style":512},"const routes = [\n    {\n        path: '/admin',\n        component: Admin,\n        meta: { requiresAuth: true, title: 'Admin Dashboard' }\n    }\n]\n",[66,22611,22612,22622,22626,22635,22640,22655,22659],{"__ignoreMap":512},[516,22613,22614,22616,22618,22620],{"class":518,"line":519},[516,22615,8632],{"class":1749},[516,22617,21419],{"class":1233},[516,22619,1793],{"class":1749},[516,22621,21424],{"class":1227},[516,22623,22624],{"class":518,"line":525},[516,22625,21940],{"class":1227},[516,22627,22628,22630,22633],{"class":518,"line":531},[516,22629,21945],{"class":1227},[516,22631,22632],{"class":1248},"'/admin'",[516,22634,1252],{"class":1227},[516,22636,22637],{"class":518,"line":1127},[516,22638,22639],{"class":1227},"        component: Admin,\n",[516,22641,22642,22645,22647,22650,22653],{"class":518,"line":1134},[516,22643,22644],{"class":1227},"        meta: { requiresAuth: ",[516,22646,10228],{"class":1233},[516,22648,22649],{"class":1227},", title: ",[516,22651,22652],{"class":1248},"'Admin Dashboard'",[516,22654,1299],{"class":1227},[516,22656,22657],{"class":518,"line":1275},[516,22658,9253],{"class":1227},[516,22660,22661],{"class":518,"line":1302},[516,22662,17207],{"class":1227},[507,22664,22666],{"className":8782,"code":22665,"language":8784,"meta":512,"style":512},"router.beforeEach((to) => {\n    document.title = to.meta.title || 'My App'\n    if (to.meta.requiresAuth && !isLoggedIn()) {\n        return { name: 'login' }\n    }\n})\n",[66,22667,22668,22684,22700,22714,22724,22728],{"__ignoreMap":512},[516,22669,22670,22672,22674,22676,22678,22680,22682],{"class":518,"line":519},[516,22671,22199],{"class":1227},[516,22673,22318],{"class":4733},[516,22675,14711],{"class":1227},[516,22677,22388],{"class":9080},[516,22679,13650],{"class":1227},[516,22681,11036],{"class":1749},[516,22683,8713],{"class":1227},[516,22685,22686,22689,22691,22694,22697],{"class":518,"line":525},[516,22687,22688],{"class":1227},"    document.title ",[516,22690,1894],{"class":1749},[516,22692,22693],{"class":1227}," to.meta.title ",[516,22695,22696],{"class":1749},"||",[516,22698,22699],{"class":1248}," 'My App'\n",[516,22701,22702,22704,22706,22708,22710,22712],{"class":518,"line":531},[516,22703,22403],{"class":1749},[516,22705,22406],{"class":1227},[516,22707,22409],{"class":1749},[516,22709,11052],{"class":1749},[516,22711,22414],{"class":4733},[516,22713,22417],{"class":1227},[516,22715,22716,22718,22720,22722],{"class":518,"line":1127},[516,22717,9245],{"class":1749},[516,22719,22424],{"class":1227},[516,22721,22427],{"class":1248},[516,22723,1299],{"class":1227},[516,22725,22726],{"class":518,"line":1134},[516,22727,9253],{"class":1227},[516,22729,22730],{"class":518,"line":1275},[516,22731,11530],{"class":1227},[11,22733,22734,22735,22737],{},"Common uses are marking routes as requiring authentication or a specific role, picking which layout component to wrap a page in, setting the page title or breadcrumb label, and flagging routes that should be excluded from analytics or a sitemap. Because ",[66,22736,22599],{}," is inherited by nested routes (child route meta merges with parent meta), it is also a convenient way to apply a rule, like \"requires auth,\" to an entire section of the app at once by setting it once on the parent route.",[23,22739,22741],{"id":22740},"_99-how-do-you-lazy-load-a-routes-component","99. How do you lazy load a route's component?",[11,22743,22744,22745,22748],{},"Instead of importing a route's component normally at the top of the file, you give the route a function that returns a dynamic ",[66,22746,22747],{},"import()",". Build tools like Vite or webpack recognize this pattern and automatically split that component into its own chunk, which is only downloaded when the user actually navigates to that route.",[507,22750,22752],{"className":8782,"code":22751,"language":8784,"meta":512,"style":512},"const routes = [\n    {\n        path: '/about',\n        component: () => import('./views/About.vue')\n    },\n    {\n        path: '/dashboard',\n        component: () => import('./views/Dashboard.vue')\n    }\n]\n",[66,22753,22754,22764,22768,22776,22795,22799,22803,22812,22829,22833],{"__ignoreMap":512},[516,22755,22756,22758,22760,22762],{"class":518,"line":519},[516,22757,8632],{"class":1749},[516,22759,21419],{"class":1233},[516,22761,1793],{"class":1749},[516,22763,21424],{"class":1227},[516,22765,22766],{"class":518,"line":525},[516,22767,21940],{"class":1227},[516,22769,22770,22772,22774],{"class":518,"line":531},[516,22771,21945],{"class":1227},[516,22773,21442],{"class":1248},[516,22775,1252],{"class":1227},[516,22777,22778,22781,22783,22785,22788,22790,22793],{"class":518,"line":1127},[516,22779,22780],{"class":4733},"        component",[516,22782,15378],{"class":1227},[516,22784,11036],{"class":1749},[516,22786,22787],{"class":1749}," import",[516,22789,8643],{"class":1227},[516,22791,22792],{"class":1248},"'./views/About.vue'",[516,22794,8649],{"class":1227},[516,22796,22797],{"class":518,"line":1134},[516,22798,14195],{"class":1227},[516,22800,22801],{"class":518,"line":1275},[516,22802,21940],{"class":1227},[516,22804,22805,22807,22810],{"class":518,"line":1302},[516,22806,21945],{"class":1227},[516,22808,22809],{"class":1248},"'/dashboard'",[516,22811,1252],{"class":1227},[516,22813,22814,22816,22818,22820,22822,22824,22827],{"class":518,"line":1308},[516,22815,22780],{"class":4733},[516,22817,15378],{"class":1227},[516,22819,11036],{"class":1749},[516,22821,22787],{"class":1749},[516,22823,8643],{"class":1227},[516,22825,22826],{"class":1248},"'./views/Dashboard.vue'",[516,22828,8649],{"class":1227},[516,22830,22831],{"class":518,"line":1314},[516,22832,9253],{"class":1227},[516,22834,22835],{"class":518,"line":8656},[516,22836,17207],{"class":1227},[11,22838,22839],{},"This keeps the initial JavaScript bundle small, since a visitor landing on the home page does not need to download the code for the admin dashboard or a rarely visited settings page until they actually go there. It is one of the easiest performance wins in a Vue app and is recommended for any route that is not part of the critical first-load path.",[23,22841,22843,22844,202,22847,9728],{"id":22842},"_100-what-is-the-difference-between-routerpush-and-routerreplace","100. What is the difference between ",[66,22845,22846],{},"router.push",[66,22848,22849],{},"router.replace",[11,22851,22852,22853,22856],{},"Both methods navigate programmatically to a new route, and both accept the same arguments (a path string or a location object like ",[66,22854,22855],{},"{ name: 'user', params: { id: 1 } }","), but they treat browser history differently.",[11,22858,22859,22862,22863,22866],{},[66,22860,22861],{},"router.push()"," adds a new entry to the history stack, so the browser's back button takes the user to the route they were on before. ",[66,22864,22865],{},"router.replace()"," swaps out the current history entry instead of adding a new one, so the back button skips over it entirely, as if that navigation never happened.",[11,22868,22869,22872,22873,21808,22876,22879,22880,22882,22883,22885],{},[66,22870,22871],{},"replace"," is the right choice for redirects (sending an unauthenticated user from ",[66,22874,22875],{},"/dashboard",[66,22877,22878],{},"/login"," should not leave ",[66,22881,22875],{}," sitting in history for the back button to return to), for login flows, and for any multi-step wizard step you do not want the user landing back on by accident. ",[66,22884,11930],{}," is the default for normal navigation, like clicking a link to a different page, where going back is expected to work.",[23,22887,22889],{"id":22888},"_101-how-does-vue-router-control-scroll-position-when-navigating-between-routes","101. How does Vue Router control scroll position when navigating between routes?",[11,22891,22892,22893,22896,22897,22899],{},"By default, a single-page app does not reset scroll position when the route changes, since there is no real page load. Vue Router exposes a ",[66,22894,22895],{},"scrollBehavior"," function, passed as an option to ",[66,22898,21361],{},", to control this explicitly.",[507,22901,22903],{"className":8782,"code":22902,"language":8784,"meta":512,"style":512},"const router = createRouter({\n    history: createWebHistory(),\n    routes,\n    scrollBehavior(to, from, savedPosition) {\n        if (savedPosition) {\n            return savedPosition\n        }\n        if (to.hash) {\n            return { el: to.hash }\n        }\n        return { top: 0 }\n    }\n})\n",[66,22904,22905,22917,22925,22930,22950,22958,22966,22970,22977,22984,22988,22999,23003],{"__ignoreMap":512},[516,22906,22907,22909,22911,22913,22915],{"class":518,"line":519},[516,22908,8632],{"class":1749},[516,22910,21460],{"class":1233},[516,22912,1793],{"class":1749},[516,22914,21465],{"class":4733},[516,22916,12910],{"class":1227},[516,22918,22919,22921,22923],{"class":518,"line":525},[516,22920,21472],{"class":1227},[516,22922,21475],{"class":4733},[516,22924,21478],{"class":1227},[516,22926,22927],{"class":518,"line":531},[516,22928,22929],{"class":1227},"    routes,\n",[516,22931,22932,22935,22937,22939,22941,22943,22945,22948],{"class":518,"line":1127},[516,22933,22934],{"class":4733},"    scrollBehavior",[516,22936,8643],{"class":1227},[516,22938,22388],{"class":9080},[516,22940,154],{"class":1227},[516,22942,8620],{"class":9080},[516,22944,154],{"class":1227},[516,22946,22947],{"class":9080},"savedPosition",[516,22949,9084],{"class":1227},[516,22951,22952,22955],{"class":518,"line":1134},[516,22953,22954],{"class":1749},"        if",[516,22956,22957],{"class":1227}," (savedPosition) {\n",[516,22959,22960,22963],{"class":518,"line":1275},[516,22961,22962],{"class":1749},"            return",[516,22964,22965],{"class":1227}," savedPosition\n",[516,22967,22968],{"class":518,"line":1302},[516,22969,9240],{"class":1227},[516,22971,22972,22974],{"class":518,"line":1308},[516,22973,22954],{"class":1749},[516,22975,22976],{"class":1227}," (to.hash) {\n",[516,22978,22979,22981],{"class":518,"line":1314},[516,22980,22962],{"class":1749},[516,22982,22983],{"class":1227}," { el: to.hash }\n",[516,22985,22986],{"class":518,"line":8656},[516,22987,9240],{"class":1227},[516,22989,22990,22992,22995,22997],{"class":518,"line":8668},[516,22991,9245],{"class":1749},[516,22993,22994],{"class":1227}," { top: ",[516,22996,8646],{"class":1233},[516,22998,1299],{"class":1227},[516,23000,23001],{"class":518,"line":8677},[516,23002,9253],{"class":1227},[516,23004,23005],{"class":518,"line":8682},[516,23006,11530],{"class":1227},[11,23008,23009,23010,23012,23013,23016,23017,23020,23021,23023],{},"The function receives the target route, the route being left, and ",[66,23011,22947],{},", which is populated only when the navigation was triggered by the browser's back/forward buttons, letting you restore exactly where the user was, similar to native browser scroll restoration. Returning ",[66,23014,23015],{},"{ top: 0 }"," resets scroll to the top for a normal forward navigation, returning ",[66,23018,23019],{},"{ el: '#some-id' }"," scrolls to an anchor (useful for in-page hash links), and returning ",[66,23022,12981],{}," or nothing leaves scroll position untouched. The function can also return a Promise, which is handy for waiting on a page transition to finish before scrolling.",[23,23025,23027,23028,23031,23032,23035],{"id":23026},"_102-what-is-the-difference-between-router-link-and-a-plain-a-tag","102. What is the difference between ",[66,23029,23030],{},"\u003Crouter-link>"," and a plain ",[66,23033,23034],{},"\u003Ca>"," tag?",[11,23037,23038,23040,23041,23043],{},[66,23039,23030],{}," is Vue Router's component for internal navigation. It renders to an ",[66,23042,23034],{}," tag under the hood, but it intercepts the click and performs the route change client-side through the router, instead of letting the browser make a full request for a new document. That means no full page reload, no re-downloading the app's JavaScript, and the component state elsewhere on the page stays intact.",[507,23045,23047],{"className":8546,"code":23046,"language":8548,"meta":512,"style":512},"\u003Crouter-link to=\"/about\">About\u003C/router-link>\n\u003Crouter-link :to=\"{ name: 'user', params: { id: 1 } }\">User\u003C/router-link>\n",[66,23048,23049,23070],{"__ignoreMap":512},[516,23050,23051,23053,23055,23058,23060,23063,23066,23068],{"class":518,"line":519},[516,23052,3042],{"class":1227},[516,23054,22065],{"class":8557},[516,23056,23057],{"class":4733}," to",[516,23059,1894],{"class":1227},[516,23061,23062],{"class":1248},"\"/about\"",[516,23064,23065],{"class":1227},">About\u003C/",[516,23067,22065],{"class":8557},[516,23069,8561],{"class":1227},[516,23071,23072,23074,23076,23078,23080,23082,23084,23087,23089,23091,23093,23096,23098,23101,23103],{"class":518,"line":525},[516,23073,3042],{"class":1227},[516,23075,22065],{"class":8557},[516,23077,9988],{"class":1227},[516,23079,22388],{"class":4733},[516,23081,1894],{"class":1227},[516,23083,3247],{"class":1248},[516,23085,23086],{"class":1227},"{ name: ",[516,23088,22182],{"class":1248},[516,23090,22208],{"class":1227},[516,23092,9945],{"class":1233},[516,23094,23095],{"class":1227}," } }",[516,23097,3247],{"class":1248},[516,23099,23100],{"class":1227},">User\u003C/",[516,23102,22065],{"class":8557},[516,23104,8561],{"class":1227},[11,23106,23107,23108,23110,23111,202,23114,23117],{},"It also adds a few conveniences a plain ",[66,23109,23034],{}," does not have: it automatically applies ",[66,23112,23113],{},"router-link-active",[66,23115,23116],{},"router-link-exact-active"," classes when its target matches the current route, which is handy for styling nav links as \"current page\" without writing that logic yourself, and it still behaves correctly for modifier-key clicks (ctrl/cmd-click still opens the link in a new tab, since router-link does not hijack those).",[11,23119,23120,23121,23124,23125,23128,23129,23131,23132,23134],{},"A plain ",[66,23122,23123],{},"\u003Ca href=\"/about\">"," pointing at an internal route would trigger a real browser navigation, a full document request and reload, unless you manually call ",[66,23126,23127],{},"preventDefault"," and push the route yourself. For internal links within a Vue Router app, ",[66,23130,23030],{}," is the correct choice; a plain ",[66,23133,23034],{}," is still exactly right for external URLs.",[18,23136,23138],{"id":23137},"state-management-pinia-and-vuex","State Management: Pinia and Vuex",[23,23140,23142],{"id":23141},"_103-what-problem-does-a-centralized-state-management-library-solve-that-props-and-provideinject-do-not","103. What problem does a centralized state management library solve that props and provide/inject do not?",[11,23144,23145,23146,2958,23148,23150],{},"Props work well when data flows in one direction from a parent to its direct children, but once a piece of state needs to reach a component many levels down, you end up \"drilling\" it through every component in between, even ones that do not care about it. ",[66,23147,18382],{},[66,23149,18385],{}," fixes the drilling problem: an ancestor can expose a value directly to any descendant. But it does not fix ownership. Anyone with access to the injected value can mutate it, there is no single place that shows every action that changed it, and Vue devtools cannot show you a timeline of what happened and why.",[11,23152,23153],{},"A centralized store (Pinia or Vuex) solves both problems at once. State lives in one place, changes go through named actions (or mutations in Vuex), and every component that needs the data reads from the same source regardless of where it sits in the component tree. This makes state changes traceable, testable in isolation, and visible in devtools, none of which come for free with props or provide/inject.",[23,23155,23157],{"id":23156},"_104-what-is-pinia-and-how-do-you-define-a-store-with-it","104. What is Pinia, and how do you define a store with it?",[11,23159,23160],{},"Pinia is Vue's official state management library. It gives you a single, reactive store you can read from and write to anywhere in your app, with full TypeScript support and Vue devtools integration (time travel, action logging), without the boilerplate Vuex used to require.",[11,23162,23163],{},[2160,23164],{"alt":23165,"src":23166},"Pinia store architecture diagram","/post-images/top-150-vuejs-interview-questions/pinia-store-architecture-diagram.png",[11,23168,23169,23170,23173,23174,1245,23176,23178,23179,23181],{},"You define a store by calling ",[66,23171,23172],{},"defineStore"," with a unique id and either an options object or a setup function. The setup style looks like a component's ",[66,23175,8448],{},[66,23177,9387],{},"s become state, ",[66,23180,9012],{},"s become getters, and plain functions become actions.",[507,23183,23185],{"className":8782,"code":23184,"language":8784,"meta":512,"style":512},"import { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\n\nexport const useCounterStore = defineStore('counter', () => {\n    const count = ref(0)\n    const doubled = computed(() => count.value * 2)\n\n    function increment() {\n        count.value++\n    }\n\n    return { count, doubled, increment }\n})\n",[66,23186,23187,23199,23209,23213,23239,23255,23278,23282,23290,23297,23301,23305,23312],{"__ignoreMap":512},[516,23188,23189,23191,23194,23196],{"class":518,"line":519},[516,23190,8614],{"class":1749},[516,23192,23193],{"class":1227}," { defineStore } ",[516,23195,8620],{"class":1749},[516,23197,23198],{"class":1248}," 'pinia'\n",[516,23200,23201,23203,23205,23207],{"class":518,"line":525},[516,23202,8614],{"class":1749},[516,23204,13892],{"class":1227},[516,23206,8620],{"class":1749},[516,23208,8623],{"class":1248},[516,23210,23211],{"class":518,"line":531},[516,23212,1131],{"emptyLinePlaceholder":1130},[516,23214,23215,23217,23219,23222,23224,23227,23229,23232,23235,23237],{"class":518,"line":1127},[516,23216,9190],{"class":1749},[516,23218,18578],{"class":1749},[516,23220,23221],{"class":1233}," useCounterStore",[516,23223,1793],{"class":1749},[516,23225,23226],{"class":4733}," defineStore",[516,23228,8643],{"class":1227},[516,23230,23231],{"class":1248},"'counter'",[516,23233,23234],{"class":1227},", () ",[516,23236,11036],{"class":1749},[516,23238,8713],{"class":1227},[516,23240,23241,23243,23245,23247,23249,23251,23253],{"class":518,"line":1134},[516,23242,12611],{"class":1749},[516,23244,8635],{"class":1233},[516,23246,1793],{"class":1749},[516,23248,8640],{"class":4733},[516,23250,8643],{"class":1227},[516,23252,8646],{"class":1233},[516,23254,8649],{"class":1227},[516,23256,23257,23259,23262,23264,23266,23268,23270,23272,23274,23276],{"class":518,"line":1275},[516,23258,12611],{"class":1749},[516,23260,23261],{"class":1233}," doubled",[516,23263,1793],{"class":1749},[516,23265,11030],{"class":4733},[516,23267,11033],{"class":1227},[516,23269,11036],{"class":1749},[516,23271,13630],{"class":1227},[516,23273,13050],{"class":1749},[516,23275,1943],{"class":1233},[516,23277,8649],{"class":1227},[516,23279,23280],{"class":518,"line":1302},[516,23281,1131],{"emptyLinePlaceholder":1130},[516,23283,23284,23286,23288],{"class":518,"line":1308},[516,23285,12628],{"class":1749},[516,23287,8662],{"class":4733},[516,23289,8665],{"class":1227},[516,23291,23292,23295],{"class":518,"line":1314},[516,23293,23294],{"class":1227},"        count.value",[516,23296,8674],{"class":1749},[516,23298,23299],{"class":518,"line":8656},[516,23300,9253],{"class":1227},[516,23302,23303],{"class":518,"line":8668},[516,23304,1131],{"emptyLinePlaceholder":1130},[516,23306,23307,23309],{"class":518,"line":8677},[516,23308,9089],{"class":1749},[516,23310,23311],{"class":1227}," { count, doubled, increment }\n",[516,23313,23314],{"class":518,"line":8682},[516,23315,11530],{"class":1227},[11,23317,23318,23319,23322],{},"Any component can then call ",[66,23320,23321],{},"useCounterStore()"," to get a reactive instance of the store.",[23,23324,23326],{"id":23325},"_105-what-are-state-getters-and-actions-in-a-pinia-store","105. What are state, getters, and actions in a Pinia store?",[11,23328,23329,23331,23332,23335,23336,23339,23340,23343],{},[66,23330,259],{}," is the reactive data the store owns, the single source of truth for that store, similar to ",[66,23333,23334],{},"data()"," in a component. ",[66,23337,23338],{},"getters"," are derived values computed from state (and other getters), cached like computed properties and recalculated only when their dependencies change. ",[66,23341,23342],{},"actions"," are functions that read and mutate state, this is where you put business logic, API calls, or anything that changes more than one piece of state at once.",[11,23345,23346],{},"In an options-style store these map directly onto three separate options:",[507,23348,23350],{"className":8782,"code":23349,"language":8784,"meta":512,"style":512},"export const useUserStore = defineStore('user', {\n    state: () => ({\n        firstName: 'Ada',\n        lastName: 'Lovelace'\n    }),\n    getters: {\n        fullName: (state) => `${state.firstName} ${state.lastName}`\n    },\n    actions: {\n        async login(credentials) {\n            const user = await api.login(credentials)\n            this.firstName = user.firstName\n            this.lastName = user.lastName\n        }\n    }\n})\n",[66,23351,23352,23372,23384,23393,23401,23406,23411,23442,23446,23451,23466,23487,23500,23512,23516,23520],{"__ignoreMap":512},[516,23353,23354,23356,23358,23361,23363,23365,23367,23369],{"class":518,"line":519},[516,23355,9190],{"class":1749},[516,23357,18578],{"class":1749},[516,23359,23360],{"class":1233}," useUserStore",[516,23362,1793],{"class":1749},[516,23364,23226],{"class":4733},[516,23366,8643],{"class":1227},[516,23368,22182],{"class":1248},[516,23370,23371],{"class":1227},", {\n",[516,23373,23374,23377,23379,23381],{"class":518,"line":525},[516,23375,23376],{"class":4733},"    state",[516,23378,15378],{"class":1227},[516,23380,11036],{"class":1749},[516,23382,23383],{"class":1227}," ({\n",[516,23385,23386,23389,23391],{"class":518,"line":531},[516,23387,23388],{"class":1227},"        firstName: ",[516,23390,14119],{"class":1248},[516,23392,1252],{"class":1227},[516,23394,23395,23398],{"class":518,"line":1127},[516,23396,23397],{"class":1227},"        lastName: ",[516,23399,23400],{"class":1248},"'Lovelace'\n",[516,23402,23403],{"class":518,"line":1134},[516,23404,23405],{"class":1227},"    }),\n",[516,23407,23408],{"class":518,"line":1275},[516,23409,23410],{"class":1227},"    getters: {\n",[516,23412,23413,23416,23418,23420,23422,23424,23426,23428,23430,23432,23434,23436,23438,23440],{"class":518,"line":1302},[516,23414,23415],{"class":4733},"        fullName",[516,23417,14959],{"class":1227},[516,23419,259],{"class":9080},[516,23421,13650],{"class":1227},[516,23423,11036],{"class":1749},[516,23425,14170],{"class":1248},[516,23427,259],{"class":1227},[516,23429,405],{"class":1248},[516,23431,14173],{"class":1227},[516,23433,14180],{"class":1248},[516,23435,259],{"class":1227},[516,23437,405],{"class":1248},[516,23439,14183],{"class":1227},[516,23441,14190],{"class":1248},[516,23443,23444],{"class":518,"line":1308},[516,23445,14195],{"class":1227},[516,23447,23448],{"class":518,"line":1314},[516,23449,23450],{"class":1227},"    actions: {\n",[516,23452,23453,23456,23459,23461,23464],{"class":518,"line":8656},[516,23454,23455],{"class":1749},"        async",[516,23457,23458],{"class":4733}," login",[516,23460,8643],{"class":1227},[516,23462,23463],{"class":9080},"credentials",[516,23465,9084],{"class":1227},[516,23467,23468,23471,23473,23475,23478,23481,23484],{"class":518,"line":8668},[516,23469,23470],{"class":1749},"            const",[516,23472,14542],{"class":1233},[516,23474,1793],{"class":1749},[516,23476,23477],{"class":1749}," await",[516,23479,23480],{"class":1227}," api.",[516,23482,23483],{"class":4733},"login",[516,23485,23486],{"class":1227},"(credentials)\n",[516,23488,23489,23492,23495,23497],{"class":518,"line":8677},[516,23490,23491],{"class":1233},"            this",[516,23493,23494],{"class":1227},".firstName ",[516,23496,1894],{"class":1749},[516,23498,23499],{"class":1227}," user.firstName\n",[516,23501,23502,23504,23507,23509],{"class":518,"line":8682},[516,23503,23491],{"class":1233},[516,23505,23506],{"class":1227},".lastName ",[516,23508,1894],{"class":1749},[516,23510,23511],{"class":1227}," user.lastName\n",[516,23513,23514],{"class":518,"line":8691},[516,23515,9240],{"class":1227},[516,23517,23518],{"class":518,"line":8696},[516,23519,9253],{"class":1227},[516,23521,23522],{"class":518,"line":8708},[516,23523,11530],{"class":1227},[11,23525,23526],{},"Unlike Vuex, actions can be asynchronous directly, there is no separate \"mutations\" concept, actions are allowed to change state themselves.",[23,23528,23530],{"id":23529},"_106-what-is-the-difference-between-the-options-style-and-the-composition-setup-style-pinia-store","106. What is the difference between the Options-style and the Composition (setup)-style Pinia store?",[11,23532,23533,23534,154,23536,157,23538,23540],{},"Pinia lets you write a store two ways, and both produce the exact same kind of store at runtime. The options store takes an object with ",[66,23535,259],{},[66,23537,23338],{},[66,23539,23342],{}," keys, it should feel familiar if you have used Vuex or the Options API.",[507,23542,23544],{"className":8782,"code":23543,"language":8784,"meta":512,"style":512},"export const useCartStore = defineStore('cart', {\n    state: () => ({ items: [] }),\n    getters: {\n        total: (state) => state.items.reduce((sum, i) => sum + i.price, 0)\n    },\n    actions: {\n        addItem(item) {\n            this.items.push(item)\n        }\n    }\n})\n",[66,23545,23546,23566,23577,23581,23625,23629,23633,23645,23657,23661,23665],{"__ignoreMap":512},[516,23547,23548,23550,23552,23555,23557,23559,23561,23564],{"class":518,"line":519},[516,23549,9190],{"class":1749},[516,23551,18578],{"class":1749},[516,23553,23554],{"class":1233}," useCartStore",[516,23556,1793],{"class":1749},[516,23558,23226],{"class":4733},[516,23560,8643],{"class":1227},[516,23562,23563],{"class":1248},"'cart'",[516,23565,23371],{"class":1227},[516,23567,23568,23570,23572,23574],{"class":518,"line":525},[516,23569,23376],{"class":4733},[516,23571,15378],{"class":1227},[516,23573,11036],{"class":1749},[516,23575,23576],{"class":1227}," ({ items: [] }),\n",[516,23578,23579],{"class":518,"line":531},[516,23580,23410],{"class":1227},[516,23582,23583,23586,23588,23590,23592,23594,23597,23600,23602,23605,23607,23609,23611,23613,23616,23618,23621,23623],{"class":518,"line":1127},[516,23584,23585],{"class":4733},"        total",[516,23587,14959],{"class":1227},[516,23589,259],{"class":9080},[516,23591,13650],{"class":1227},[516,23593,11036],{"class":1749},[516,23595,23596],{"class":1227}," state.items.",[516,23598,23599],{"class":4733},"reduce",[516,23601,14711],{"class":1227},[516,23603,23604],{"class":9080},"sum",[516,23606,154],{"class":1227},[516,23608,14044],{"class":9080},[516,23610,13650],{"class":1227},[516,23612,11036],{"class":1749},[516,23614,23615],{"class":1227}," sum ",[516,23617,1932],{"class":1749},[516,23619,23620],{"class":1227}," i.price, ",[516,23622,8646],{"class":1233},[516,23624,8649],{"class":1227},[516,23626,23627],{"class":518,"line":1134},[516,23628,14195],{"class":1227},[516,23630,23631],{"class":518,"line":1275},[516,23632,23450],{"class":1227},[516,23634,23635,23638,23640,23643],{"class":518,"line":1302},[516,23636,23637],{"class":4733},"        addItem",[516,23639,8643],{"class":1227},[516,23641,23642],{"class":9080},"item",[516,23644,9084],{"class":1227},[516,23646,23647,23649,23652,23654],{"class":518,"line":1308},[516,23648,23491],{"class":1233},[516,23650,23651],{"class":1227},".items.",[516,23653,11930],{"class":4733},[516,23655,23656],{"class":1227},"(item)\n",[516,23658,23659],{"class":518,"line":1314},[516,23660,9240],{"class":1227},[516,23662,23663],{"class":518,"line":8656},[516,23664,9253],{"class":1227},[516,23666,23667],{"class":518,"line":8668},[516,23668,11530],{"class":1227},[11,23670,23671,23672,148,23674,2958,23676,23678,23679,23681],{},"The setup store takes a function, the same shape as ",[66,23673,8448],{},[66,23675,9387],{},[66,23677,12368],{}," values become state, ",[66,23680,9012],{}," values become getters, and regular functions become actions.",[507,23683,23685],{"className":8782,"code":23684,"language":8784,"meta":512,"style":512},"export const useCartStore = defineStore('cart', () => {\n    const items = ref([])\n    const total = computed(() => items.value.reduce((sum, i) => sum + i.price, 0))\n\n    function addItem(item) {\n        items.value.push(item)\n    }\n\n    return { items, total, addItem }\n})\n",[66,23686,23687,23709,23722,23763,23767,23780,23789,23793,23797,23804],{"__ignoreMap":512},[516,23688,23689,23691,23693,23695,23697,23699,23701,23703,23705,23707],{"class":518,"line":519},[516,23690,9190],{"class":1749},[516,23692,18578],{"class":1749},[516,23694,23554],{"class":1233},[516,23696,1793],{"class":1749},[516,23698,23226],{"class":4733},[516,23700,8643],{"class":1227},[516,23702,23563],{"class":1248},[516,23704,23234],{"class":1227},[516,23706,11036],{"class":1749},[516,23708,8713],{"class":1227},[516,23710,23711,23713,23715,23717,23719],{"class":518,"line":525},[516,23712,12611],{"class":1749},[516,23714,9983],{"class":1233},[516,23716,1793],{"class":1749},[516,23718,8640],{"class":4733},[516,23720,23721],{"class":1227},"([])\n",[516,23723,23724,23726,23728,23730,23732,23734,23736,23738,23740,23742,23744,23746,23748,23750,23752,23754,23756,23758,23760],{"class":518,"line":531},[516,23725,12611],{"class":1749},[516,23727,13946],{"class":1233},[516,23729,1793],{"class":1749},[516,23731,11030],{"class":4733},[516,23733,11033],{"class":1227},[516,23735,11036],{"class":1749},[516,23737,14037],{"class":1227},[516,23739,23599],{"class":4733},[516,23741,14711],{"class":1227},[516,23743,23604],{"class":9080},[516,23745,154],{"class":1227},[516,23747,14044],{"class":9080},[516,23749,13650],{"class":1227},[516,23751,11036],{"class":1749},[516,23753,23615],{"class":1227},[516,23755,1932],{"class":1749},[516,23757,23620],{"class":1227},[516,23759,8646],{"class":1233},[516,23761,23762],{"class":1227},"))\n",[516,23764,23765],{"class":518,"line":1127},[516,23766,1131],{"emptyLinePlaceholder":1130},[516,23768,23769,23771,23774,23776,23778],{"class":518,"line":1134},[516,23770,12628],{"class":1749},[516,23772,23773],{"class":4733}," addItem",[516,23775,8643],{"class":1227},[516,23777,23642],{"class":9080},[516,23779,9084],{"class":1227},[516,23781,23782,23785,23787],{"class":518,"line":1275},[516,23783,23784],{"class":1227},"        items.value.",[516,23786,11930],{"class":4733},[516,23788,23656],{"class":1227},[516,23790,23791],{"class":518,"line":1302},[516,23792,9253],{"class":1227},[516,23794,23795],{"class":518,"line":1308},[516,23796,1131],{"emptyLinePlaceholder":1130},[516,23798,23799,23801],{"class":518,"line":1314},[516,23800,9089],{"class":1749},[516,23802,23803],{"class":1227}," { items, total, addItem }\n",[516,23805,23806],{"class":518,"line":8656},[516,23807,11530],{"class":1227},[11,23809,23810],{},"The setup style is more flexible: you can use watchers and other composables inside the store, and it is generally the recommended default once you are comfortable with the Composition API. The options style is easier to read for people coming from Vuex and needs less explanation of what counts as state versus a getter.",[23,23812,23814],{"id":23813},"_107-why-did-pinia-replace-vuex-as-the-officially-recommended-state-management-library","107. Why did Pinia replace Vuex as the officially recommended state management library?",[11,23816,23817],{},"Pinia was built to fix the pain points Vuex had accumulated over the years. Vuex needed a strict split between mutations (synchronous, for state changes) and actions (for anything async), which meant a lot of ceremony for a simple state update. Pinia drops mutations entirely, actions can change state directly and can be sync or async.",[11,23819,23820,23821,2958,23824,23827],{},"TypeScript support was also a big driver: Vuex's typing was awkward, especially around modules and ",[66,23822,23823],{},"mapState",[66,23825,23826],{},"mapActions"," helpers, while Pinia is written with TypeScript first, so types are inferred automatically without extra typing gymnastics.",[11,23829,23830,23831,23834],{},"Pinia stores are also flat, not nested. Vuex leaned on nested, namespaced modules that needed careful string based namespacing (",[66,23832,23833],{},"'cart/addItem'","); Pinia stores are just separate, independently importable store definitions, so there is no nesting or namespace typos to worry about.",[11,23836,23837],{},"Finally, Pinia works outside of components more naturally, has a smaller footprint, and its devtools support (action tracking, time travel) matches or beats Vuex's. Given all this, the Vue core team adopted Pinia as the official recommendation for Vue 3, and it works with Vue 2 as well through a compatibility layer.",[23,23839,23841],{"id":23840},"_108-what-is-vuex-and-what-are-its-four-core-building-blocks","108. What is Vuex, and what are its four core building blocks?",[11,23843,23844],{},"Vuex is the state management library that was the official recommendation for Vue 2, and it is still found in plenty of production codebases even though Pinia has taken over for new projects. Vuex enforces a strict, predictable flow for state changes so that large apps stay debuggable.",[11,23846,23847],{},"It is built around four pieces:",[36,23849,23850,23859],{},[39,23851,23852],{},[42,23853,23854,23857],{},[45,23855,23856],{},"Piece",[45,23858,50],{},[58,23860,23861,23870,23879,23889],{},[42,23862,23863,23867],{},[63,23864,23865],{},[66,23866,259],{},[63,23868,23869],{},"The single, reactive source of truth for the whole store",[42,23871,23872,23876],{},[63,23873,23874],{},[66,23875,23338],{},[63,23877,23878],{},"Computed values derived from state, cached until dependencies change",[42,23880,23881,23886],{},[63,23882,23883],{},[66,23884,23885],{},"mutations",[63,23887,23888],{},"The only way to change state directly, must be synchronous",[42,23890,23891,23895],{},[63,23892,23893],{},[66,23894,23342],{},[63,23896,23897],{},"Business logic, can be async, commit one or more mutations",[11,23899,23900,23901,23904,23905,23908,23909,23911],{},"Components dispatch actions (",[66,23902,23903],{},"store.dispatch('login', creds)","), actions do their async work then commit mutations (",[66,23906,23907],{},"store.commit('setUser', user)","), and mutations are the only code allowed to touch ",[66,23910,259],{}," directly. This one-way flow (dispatch, then action, then commit, then mutation, then state, then view) is what made Vuex apps predictable and easy to trace in devtools.",[23,23913,23915],{"id":23914},"_109-why-does-vuex-require-mutations-to-be-synchronous","109. Why does Vuex require mutations to be synchronous?",[11,23917,23918],{},"Vuex's devtools integration relies on being able to take a snapshot of the state before and after every mutation and log it as a single, discrete step in a timeline. This is what makes \"time travel debugging\" possible, jumping the app back to any previous state by replaying mutations in order.",[11,23920,23921],{},"If a mutation could run asynchronously, the devtools would have no reliable way to know when the state change actually happened relative to other mutations firing around the same time. Two async mutations could interleave, and the snapshot logged for one mutation might actually contain changes from another. That breaks the guarantee that each entry in the timeline corresponds to exactly one state change.",[11,23923,23924,23925,23927,23928,23931],{},"This is why async work belongs in actions, not mutations: an action can ",[66,23926,20201],{}," an API call, then ",[66,23929,23930],{},"commit"," a mutation once the result is ready, and that commit is the synchronous, trackable event Vuex records. It is a debugging and predictability guarantee, not a technical limitation of Vue's reactivity.",[23,23933,23935],{"id":23934},"_110-what-are-vuex-modules-and-why-would-you-split-a-store-into-them","110. What are Vuex modules, and why would you split a store into them?",[11,23937,23938,23939,154,23941,154,23943,157,23945,23947],{},"A Vuex module is a self contained slice of the store, it has its own ",[66,23940,259],{},[66,23942,23338],{},[66,23944,23885],{},[66,23946,23342],{},", and gets registered under a key on the root store.",[507,23949,23951],{"className":8782,"code":23950,"language":8784,"meta":512,"style":512},"const cart = {\n    namespaced: true,\n    state: () => ({ items: [] }),\n    mutations: {\n        addItem(state, item) {\n            state.items.push(item)\n        }\n    }\n}\n\nconst store = createStore({\n    modules: { cart }\n})\n",[66,23952,23953,23964,23973,23983,23988,24002,24011,24015,24019,24023,24027,24041,24046],{"__ignoreMap":512},[516,23954,23955,23957,23960,23962],{"class":518,"line":519},[516,23956,8632],{"class":1749},[516,23958,23959],{"class":1233}," cart",[516,23961,1793],{"class":1749},[516,23963,8713],{"class":1227},[516,23965,23966,23969,23971],{"class":518,"line":525},[516,23967,23968],{"class":1227},"    namespaced: ",[516,23970,10228],{"class":1233},[516,23972,1252],{"class":1227},[516,23974,23975,23977,23979,23981],{"class":518,"line":531},[516,23976,23376],{"class":4733},[516,23978,15378],{"class":1227},[516,23980,11036],{"class":1749},[516,23982,23576],{"class":1227},[516,23984,23985],{"class":518,"line":1127},[516,23986,23987],{"class":1227},"    mutations: {\n",[516,23989,23990,23992,23994,23996,23998,24000],{"class":518,"line":1134},[516,23991,23637],{"class":4733},[516,23993,8643],{"class":1227},[516,23995,259],{"class":9080},[516,23997,154],{"class":1227},[516,23999,23642],{"class":9080},[516,24001,9084],{"class":1227},[516,24003,24004,24007,24009],{"class":518,"line":1275},[516,24005,24006],{"class":1227},"            state.items.",[516,24008,11930],{"class":4733},[516,24010,23656],{"class":1227},[516,24012,24013],{"class":518,"line":1302},[516,24014,9240],{"class":1227},[516,24016,24017],{"class":518,"line":1308},[516,24018,9253],{"class":1227},[516,24020,24021],{"class":518,"line":1314},[516,24022,1317],{"class":1227},[516,24024,24025],{"class":518,"line":8656},[516,24026,1131],{"emptyLinePlaceholder":1130},[516,24028,24029,24031,24034,24036,24039],{"class":518,"line":8668},[516,24030,8632],{"class":1749},[516,24032,24033],{"class":1233}," store",[516,24035,1793],{"class":1749},[516,24037,24038],{"class":4733}," createStore",[516,24040,12910],{"class":1227},[516,24042,24043],{"class":518,"line":8677},[516,24044,24045],{"class":1227},"    modules: { cart }\n",[516,24047,24048],{"class":518,"line":8682},[516,24049,11530],{"class":1227},[11,24051,24052,24053,154,24056,154,24059,24061],{},"As an app grows, keeping everything in one flat store file becomes hard to navigate, unrelated features start colliding on getter or mutation names, and it gets hard to tell which part of the app owns which piece of state. Splitting into modules (one per feature, like ",[66,24054,24055],{},"cart",[66,24057,24058],{},"auth",[66,24060,1467],{},") keeps related state, getters, mutations, and actions together and makes ownership obvious.",[11,24063,24064,24065,24068,24069,24072,24073,24076],{},"Setting ",[66,24066,24067],{},"namespaced: true"," on a module prefixes its getters, mutations, and actions with the module name (",[66,24070,24071],{},"cart/addItem","), which prevents naming collisions between modules and makes it clear, when you read ",[66,24074,24075],{},"dispatch('cart/checkout')"," in a component, exactly where that logic lives.",[23,24078,24080],{"id":24079},"_111-how-do-you-access-a-pinia-store-outside-of-a-component-for-example-inside-a-router-navigation-guard","111. How do you access a Pinia store outside of a component, for example inside a router navigation guard?",[11,24082,24083,24084,24087],{},"Since Pinia stores are just functions you call (",[66,24085,24086],{},"useXStore()","), you can call them from plain JavaScript too, as long as the Pinia instance has already been installed on the app before that code runs. In a router guard this is usually fine because the guard only runs after the app (and Pinia) is set up.",[507,24089,24091],{"className":8782,"code":24090,"language":8784,"meta":512,"style":512},"import { useAuthStore } from '@/stores/auth'\n\nrouter.beforeEach((to) => {\n    const auth = useAuthStore()\n\n    if (to.meta.requiresAuth && !auth.isLoggedIn) {\n        return { name: 'login' }\n    }\n})\n",[66,24092,24093,24105,24109,24125,24139,24143,24156,24166,24170],{"__ignoreMap":512},[516,24094,24095,24097,24100,24102],{"class":518,"line":519},[516,24096,8614],{"class":1749},[516,24098,24099],{"class":1227}," { useAuthStore } ",[516,24101,8620],{"class":1749},[516,24103,24104],{"class":1248}," '@/stores/auth'\n",[516,24106,24107],{"class":518,"line":525},[516,24108,1131],{"emptyLinePlaceholder":1130},[516,24110,24111,24113,24115,24117,24119,24121,24123],{"class":518,"line":531},[516,24112,22199],{"class":1227},[516,24114,22318],{"class":4733},[516,24116,14711],{"class":1227},[516,24118,22388],{"class":9080},[516,24120,13650],{"class":1227},[516,24122,11036],{"class":1749},[516,24124,8713],{"class":1227},[516,24126,24127,24129,24132,24134,24137],{"class":518,"line":1127},[516,24128,12611],{"class":1749},[516,24130,24131],{"class":1233}," auth",[516,24133,1793],{"class":1749},[516,24135,24136],{"class":4733}," useAuthStore",[516,24138,13318],{"class":1227},[516,24140,24141],{"class":518,"line":1134},[516,24142,1131],{"emptyLinePlaceholder":1130},[516,24144,24145,24147,24149,24151,24153],{"class":518,"line":1275},[516,24146,22403],{"class":1749},[516,24148,22406],{"class":1227},[516,24150,22409],{"class":1749},[516,24152,11052],{"class":1749},[516,24154,24155],{"class":1227},"auth.isLoggedIn) {\n",[516,24157,24158,24160,24162,24164],{"class":518,"line":1302},[516,24159,9245],{"class":1749},[516,24161,22424],{"class":1227},[516,24163,22427],{"class":1248},[516,24165,1299],{"class":1227},[516,24167,24168],{"class":518,"line":1308},[516,24169,9253],{"class":1227},[516,24171,24172],{"class":518,"line":1314},[516,24173,11530],{"class":1227},[11,24175,24176,24177,24179,24180,24183],{},"The one thing to be careful about is calling ",[66,24178,24086],{}," at the top of a module, outside any function, before Pinia has been installed via ",[66,24181,24182],{},"app.use(pinia)",". That will fail because there is no active Pinia instance yet. Call the store function lazily, inside the guard callback itself as shown above, rather than storing the result in a module level variable at import time.",[23,24185,24187],{"id":24186},"_112-what-are-pinia-plugins-and-what-can-you-use-them-for","112. What are Pinia plugins, and what can you use them for?",[11,24189,24190,24191,24194],{},"A Pinia plugin is a function you register once, with ",[66,24192,24193],{},"pinia.use(myPlugin)",", that Pinia then runs against every store that gets created. The plugin receives a context object (including the store instance) and can add new properties, wrap actions, or subscribe to state changes on every store, without you having to repeat that logic inside each store definition.",[507,24196,24198],{"className":8782,"code":24197,"language":8784,"meta":512,"style":512},"function loggerPlugin({ store }) {\n    store.$subscribe((mutation, state) => {\n        console.log(`${store.$id} changed:`, mutation)\n    })\n}\n\npinia.use(loggerPlugin)\n",[66,24199,24200,24215,24238,24262,24266,24270,24274],{"__ignoreMap":512},[516,24201,24202,24204,24207,24210,24213],{"class":518,"line":519},[516,24203,8659],{"class":1749},[516,24205,24206],{"class":4733}," loggerPlugin",[516,24208,24209],{"class":1227},"({ ",[516,24211,24212],{"class":9080},"store",[516,24214,20887],{"class":1227},[516,24216,24217,24220,24223,24225,24228,24230,24232,24234,24236],{"class":518,"line":525},[516,24218,24219],{"class":1227},"    store.",[516,24221,24222],{"class":4733},"$subscribe",[516,24224,14711],{"class":1227},[516,24226,24227],{"class":9080},"mutation",[516,24229,154],{"class":1227},[516,24231,259],{"class":9080},[516,24233,13650],{"class":1227},[516,24235,11036],{"class":1749},[516,24237,8713],{"class":1227},[516,24239,24240,24242,24244,24246,24249,24251,24253,24256,24259],{"class":518,"line":531},[516,24241,13181],{"class":1227},[516,24243,11517],{"class":4733},[516,24245,8643],{"class":1227},[516,24247,24248],{"class":1248},"`${",[516,24250,24212],{"class":1227},[516,24252,405],{"class":1248},[516,24254,24255],{"class":1227},"$id",[516,24257,24258],{"class":1248},"} changed:`",[516,24260,24261],{"class":1227},", mutation)\n",[516,24263,24264],{"class":518,"line":1127},[516,24265,13191],{"class":1227},[516,24267,24268],{"class":518,"line":1134},[516,24269,1317],{"class":1227},[516,24271,24272],{"class":518,"line":1275},[516,24273,1131],{"emptyLinePlaceholder":1130},[516,24275,24276,24279,24281],{"class":518,"line":1302},[516,24277,24278],{"class":1227},"pinia.",[516,24280,21555],{"class":4733},[516,24282,24283],{"class":1227},"(loggerPlugin)\n",[11,24285,24286,24287,24289,24290,24293,24294,24297,24298,24301],{},"Common real world uses include: persisting state to ",[66,24288,2755],{}," on every change, resetting all stores on logout, adding a shared property (like a ",[66,24291,24292],{},"router"," or an ",[66,24295,24296],{},"api"," client) to every store so actions can use ",[66,24299,24300],{},"this.router"," without importing it, and logging or sending state changes to an analytics tool. Plugins are the main extension point of Pinia, and most of the community packages you will use (like persistence plugins) are built exactly this way.",[23,24303,24305],{"id":24304},"_113-how-would-you-persist-pinia-state-across-page-reloads","113. How would you persist Pinia state across page reloads?",[11,24307,24308,24309,24312,24313,24316,24317,2846,24319,24322],{},"The simplest option in real projects is the community plugin ",[66,24310,24311],{},"pinia-plugin-persistedstate",". You register it once on the Pinia instance, then opt individual stores in with ",[66,24314,24315],{},"persist: true",", and it automatically saves the store to ",[66,24318,2755],{},[66,24320,24321],{},"sessionStorage",") on change and restores it on load.",[507,24324,24326],{"className":8782,"code":24325,"language":8784,"meta":512,"style":512},"import { createPinia } from 'pinia'\nimport piniaPluginPersistedstate from 'pinia-plugin-persistedstate'\n\nconst pinia = createPinia()\npinia.use(piniaPluginPersistedstate)\n",[66,24327,24328,24339,24351,24355,24369],{"__ignoreMap":512},[516,24329,24330,24332,24335,24337],{"class":518,"line":519},[516,24331,8614],{"class":1749},[516,24333,24334],{"class":1227}," { createPinia } ",[516,24336,8620],{"class":1749},[516,24338,23198],{"class":1248},[516,24340,24341,24343,24346,24348],{"class":518,"line":525},[516,24342,8614],{"class":1749},[516,24344,24345],{"class":1227}," piniaPluginPersistedstate ",[516,24347,8620],{"class":1749},[516,24349,24350],{"class":1248}," 'pinia-plugin-persistedstate'\n",[516,24352,24353],{"class":518,"line":531},[516,24354,1131],{"emptyLinePlaceholder":1130},[516,24356,24357,24359,24362,24364,24367],{"class":518,"line":1127},[516,24358,8632],{"class":1749},[516,24360,24361],{"class":1233}," pinia",[516,24363,1793],{"class":1749},[516,24365,24366],{"class":4733}," createPinia",[516,24368,13318],{"class":1227},[516,24370,24371,24373,24375],{"class":518,"line":1134},[516,24372,24278],{"class":1227},[516,24374,21555],{"class":4733},[516,24376,24377],{"class":1227},"(piniaPluginPersistedstate)\n",[507,24379,24381],{"className":8782,"code":24380,"language":8784,"meta":512,"style":512},"export const useAuthStore = defineStore('auth', () => {\n    const token = ref(null)\n    return { token }\n}, {\n    persist: true\n})\n",[66,24382,24383,24406,24423,24430,24435,24442],{"__ignoreMap":512},[516,24384,24385,24387,24389,24391,24393,24395,24397,24400,24402,24404],{"class":518,"line":519},[516,24386,9190],{"class":1749},[516,24388,18578],{"class":1749},[516,24390,24136],{"class":1233},[516,24392,1793],{"class":1749},[516,24394,23226],{"class":4733},[516,24396,8643],{"class":1227},[516,24398,24399],{"class":1248},"'auth'",[516,24401,23234],{"class":1227},[516,24403,11036],{"class":1749},[516,24405,8713],{"class":1227},[516,24407,24408,24410,24413,24415,24417,24419,24421],{"class":518,"line":525},[516,24409,12611],{"class":1749},[516,24411,24412],{"class":1233}," token",[516,24414,1793],{"class":1749},[516,24416,8640],{"class":4733},[516,24418,8643],{"class":1227},[516,24420,9102],{"class":1233},[516,24422,8649],{"class":1227},[516,24424,24425,24427],{"class":518,"line":531},[516,24426,9089],{"class":1749},[516,24428,24429],{"class":1227}," { token }\n",[516,24431,24432],{"class":518,"line":1127},[516,24433,24434],{"class":1227},"}, {\n",[516,24436,24437,24440],{"class":518,"line":1134},[516,24438,24439],{"class":1227},"    persist: ",[516,24441,14907],{"class":1233},[516,24443,24444],{"class":518,"line":1275},[516,24445,11530],{"class":1227},[11,24447,24448,24449,24452],{},"If you do not want a dependency, you can do it manually with ",[66,24450,24451],{},"store.$subscribe",", which fires whenever any part of the store's state changes, plus a one time read on startup:",[507,24454,24456],{"className":8782,"code":24455,"language":8784,"meta":512,"style":512},"const saved = localStorage.getItem('auth')\nif (saved) authStore.$patch(JSON.parse(saved))\n\nauthStore.$subscribe((mutation, state) => {\n    localStorage.setItem('auth', JSON.stringify(state))\n})\n",[66,24457,24458,24479,24502,24506,24527,24551],{"__ignoreMap":512},[516,24459,24460,24462,24465,24467,24470,24473,24475,24477],{"class":518,"line":519},[516,24461,8632],{"class":1749},[516,24463,24464],{"class":1233}," saved",[516,24466,1793],{"class":1749},[516,24468,24469],{"class":1227}," localStorage.",[516,24471,24472],{"class":4733},"getItem",[516,24474,8643],{"class":1227},[516,24476,24399],{"class":1248},[516,24478,8649],{"class":1227},[516,24480,24481,24483,24486,24489,24491,24494,24496,24499],{"class":518,"line":525},[516,24482,9553],{"class":1749},[516,24484,24485],{"class":1227}," (saved) authStore.",[516,24487,24488],{"class":4733},"$patch",[516,24490,8643],{"class":1227},[516,24492,24493],{"class":1233},"JSON",[516,24495,405],{"class":1227},[516,24497,24498],{"class":4733},"parse",[516,24500,24501],{"class":1227},"(saved))\n",[516,24503,24504],{"class":518,"line":531},[516,24505,1131],{"emptyLinePlaceholder":1130},[516,24507,24508,24511,24513,24515,24517,24519,24521,24523,24525],{"class":518,"line":1127},[516,24509,24510],{"class":1227},"authStore.",[516,24512,24222],{"class":4733},[516,24514,14711],{"class":1227},[516,24516,24227],{"class":9080},[516,24518,154],{"class":1227},[516,24520,259],{"class":9080},[516,24522,13650],{"class":1227},[516,24524,11036],{"class":1749},[516,24526,8713],{"class":1227},[516,24528,24529,24532,24535,24537,24539,24541,24543,24545,24548],{"class":518,"line":1134},[516,24530,24531],{"class":1227},"    localStorage.",[516,24533,24534],{"class":4733},"setItem",[516,24536,8643],{"class":1227},[516,24538,24399],{"class":1248},[516,24540,154],{"class":1227},[516,24542,24493],{"class":1233},[516,24544,405],{"class":1227},[516,24546,24547],{"class":4733},"stringify",[516,24549,24550],{"class":1227},"(state))\n",[516,24552,24553],{"class":518,"line":1275},[516,24554,11530],{"class":1227},[11,24556,24557],{},"Either way, the two moving parts are the same: write state out on every change, and read it back in before the store is first used.",[23,24559,24561],{"id":24560},"_114-when-should-you-reach-for-a-store-instead-of-provideinject-or-lifting-state-up","114. When should you reach for a store instead of provide/inject or lifting state up?",[11,24563,24564,24565,2958,24567,24569],{},"Lifting state up (moving it to a shared parent and passing it down via props) works well when the components that need the state are close together in the tree. ",[66,24566,18382],{},[66,24568,18385],{}," works well when one ancestor needs to expose something to a deep subtree without drilling props through every level in between. Both assume there is a natural, findable \"owner\" component for the state.",[11,24571,24572],{},"Reach for a store instead once that assumption breaks down: when the state needs to be read or written from components that live in completely different, unrelated branches of the tree (like a shopping cart icon in the header and a checkout page); when the state needs to outlive a particular component tree, for example surviving route navigation; or when you want the debugging benefits, action logging and devtools time travel, that come with a real store. A rough rule of thumb: if you catch yourself passing a prop through three or more components that do not use it themselves just to reach a fourth, or if two unrelated routes both need the same live data, that is a strong sign it belongs in a store rather than in props or provide/inject.",[18,24574,24576],{"id":24575},"forms-and-input-handling","Forms and Input Handling",[23,24578,24580,24581,24583],{"id":24579},"_115-how-does-v-model-behave-differently-on-a-text-input-a-checkbox-a-radio-button-and-a-select","115. How does ",[66,24582,10557],{}," behave differently on a text input, a checkbox, a radio button, and a select?",[11,24585,24586,24588],{},[66,24587,10557],{}," is really just sugar over an event listener and a value binding, but which event and which prop it uses changes depending on the element.",[36,24590,24591,24604],{},[39,24592,24593],{},[42,24594,24595,24598,24601],{},[45,24596,24597],{},"Element",[45,24599,24600],{},"Value bound",[45,24602,24603],{},"Event listened",[58,24605,24606,24619,24634,24649,24666],{},[42,24607,24608,24611,24615],{},[63,24609,24610],{},"Text input / textarea",[63,24612,24613],{},[66,24614,12995],{},[63,24616,24617],{},[66,24618,10575],{},[42,24620,24621,24624,24630],{},[63,24622,24623],{},"Checkbox (single)",[63,24625,24626,24629],{},[66,24627,24628],{},"checked",", bound value is a boolean",[63,24631,24632],{},[66,24633,10687],{},[42,24635,24636,24642,24645],{},[63,24637,24638,24639,24641],{},"Checkbox (bound to array, with a ",[66,24640,12995],{}," attr)",[63,24643,24644],{},"pushes or removes the value from the array",[63,24646,24647],{},[66,24648,10687],{},[42,24650,24651,24654,24662],{},[63,24652,24653],{},"Radio button",[63,24655,24656,24658,24659,24661],{},[66,24657,24628],{},", bound variable gets the radio's ",[66,24660,12995],{}," when selected",[63,24663,24664],{},[66,24665,10687],{},[42,24667,24668,24673,24684],{},[63,24669,24670],{},[66,24671,24672],{},"\u003Cselect>",[63,24674,24675,24677,24678,24681,24682],{},[66,24676,12995],{},", matches the selected ",[66,24679,24680],{},"\u003Coption>","'s ",[66,24683,12995],{},[63,24685,24686],{},[66,24687,10687],{},[11,24689,24690,24691,24694,24695,24698,24699,2958,24701,24703,24704,24706,24707,24709,24710,24712,24713,24715,24716,24718],{},"For a text input, ",[66,24692,24693],{},"v-model=\"text\""," is shorthand for ",[66,24696,24697],{},":value=\"text\" @input=\"text = $event.target.value\"",", updating on every keystroke. For a checkbox bound to a plain variable, the variable becomes ",[66,24700,10228],{},[66,24702,12981],{},". For a radio group, every radio shares the same ",[66,24705,10557],{},", and each one sets that variable to its own ",[66,24708,12995],{}," attribute when picked. For a select, the bound variable takes on the ",[66,24711,12995],{}," of whichever ",[66,24714,24680],{}," is currently selected. Vue picks the right prop and event automatically based on the element type, that mapping is what ",[66,24717,10557],{}," abstracts away.",[23,24720,24722,24723,24725],{"id":24721},"_116-how-do-you-bind-v-model-to-a-group-of-checkboxes-or-radio-buttons","116. How do you bind ",[66,24724,10557],{}," to a group of checkboxes or radio buttons?",[11,24727,24728,24729,24731,24732,24734],{},"For a group of checkboxes that should all update the same array, bind the same ",[66,24730,10557],{}," to every checkbox and give each one a ",[66,24733,12995],{}," attribute. Vue automatically pushes the value into the array when the box is checked and removes it when unchecked.",[507,24736,24738],{"className":8546,"code":24737,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Clabel>\u003Cinput type=\"checkbox\" v-model=\"selected\" value=\"apple\" /> Apple\u003C/label>\n    \u003Clabel>\u003Cinput type=\"checkbox\" v-model=\"selected\" value=\"banana\" /> Banana\u003C/label>\n\u003C/template>\n\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst selected = ref([])\n\u003C/script>\n",[66,24739,24740,24748,24786,24822,24830,24834,24844,24854,24858,24871],{"__ignoreMap":512},[516,24741,24742,24744,24746],{"class":518,"line":519},[516,24743,3042],{"class":1227},[516,24745,8558],{"class":8557},[516,24747,8561],{"class":1227},[516,24749,24750,24752,24754,24756,24758,24760,24762,24765,24767,24769,24772,24774,24776,24779,24782,24784],{"class":518,"line":525},[516,24751,8566],{"class":1227},[516,24753,16538],{"class":8557},[516,24755,17510],{"class":1227},[516,24757,10575],{"class":8557},[516,24759,10636],{"class":4733},[516,24761,1894],{"class":1227},[516,24763,24764],{"class":1248},"\"checkbox\"",[516,24766,15794],{"class":4733},[516,24768,1894],{"class":1227},[516,24770,24771],{"class":1248},"\"selected\"",[516,24773,13165],{"class":4733},[516,24775,1894],{"class":1227},[516,24777,24778],{"class":1248},"\"apple\"",[516,24780,24781],{"class":1227}," /> Apple\u003C/",[516,24783,16538],{"class":8557},[516,24785,8561],{"class":1227},[516,24787,24788,24790,24792,24794,24796,24798,24800,24802,24804,24806,24808,24810,24812,24815,24818,24820],{"class":518,"line":531},[516,24789,8566],{"class":1227},[516,24791,16538],{"class":8557},[516,24793,17510],{"class":1227},[516,24795,10575],{"class":8557},[516,24797,10636],{"class":4733},[516,24799,1894],{"class":1227},[516,24801,24764],{"class":1248},[516,24803,15794],{"class":4733},[516,24805,1894],{"class":1227},[516,24807,24771],{"class":1248},[516,24809,13165],{"class":4733},[516,24811,1894],{"class":1227},[516,24813,24814],{"class":1248},"\"banana\"",[516,24816,24817],{"class":1227}," /> Banana\u003C/",[516,24819,16538],{"class":8557},[516,24821,8561],{"class":1227},[516,24823,24824,24826,24828],{"class":518,"line":1127},[516,24825,8589],{"class":1227},[516,24827,8558],{"class":8557},[516,24829,8561],{"class":1227},[516,24831,24832],{"class":518,"line":1134},[516,24833,1131],{"emptyLinePlaceholder":1130},[516,24835,24836,24838,24840,24842],{"class":518,"line":1275},[516,24837,3042],{"class":1227},[516,24839,8604],{"class":8557},[516,24841,8607],{"class":4733},[516,24843,8561],{"class":1227},[516,24845,24846,24848,24850,24852],{"class":518,"line":1302},[516,24847,8614],{"class":1749},[516,24849,8617],{"class":1227},[516,24851,8620],{"class":1749},[516,24853,8623],{"class":1248},[516,24855,24856],{"class":518,"line":1308},[516,24857,1131],{"emptyLinePlaceholder":1130},[516,24859,24860,24862,24865,24867,24869],{"class":518,"line":1314},[516,24861,8632],{"class":1749},[516,24863,24864],{"class":1233}," selected",[516,24866,1793],{"class":1749},[516,24868,8640],{"class":4733},[516,24870,23721],{"class":1227},[516,24872,24873,24875,24877],{"class":518,"line":8656},[516,24874,8589],{"class":1227},[516,24876,8604],{"class":8557},[516,24878,8561],{"class":1227},[11,24880,24881,24882,24884,24885,24887],{},"Radio buttons work the same way conceptually, but since only one can be picked, the bound variable becomes a single value, not an array. Every radio in the group shares the same ",[66,24883,10557],{},", only their ",[66,24886,12995],{}," attributes differ.",[507,24889,24891],{"className":8546,"code":24890,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Clabel>\u003Cinput type=\"radio\" v-model=\"size\" value=\"small\" /> Small\u003C/label>\n    \u003Clabel>\u003Cinput type=\"radio\" v-model=\"size\" value=\"large\" /> Large\u003C/label>\n\u003C/template>\n\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst size = ref('small')\n\u003C/script>\n",[66,24892,24893,24901,24939,24975,24983,24987,24997,25007,25011,25029],{"__ignoreMap":512},[516,24894,24895,24897,24899],{"class":518,"line":519},[516,24896,3042],{"class":1227},[516,24898,8558],{"class":8557},[516,24900,8561],{"class":1227},[516,24902,24903,24905,24907,24909,24911,24913,24915,24918,24920,24922,24925,24927,24929,24932,24935,24937],{"class":518,"line":525},[516,24904,8566],{"class":1227},[516,24906,16538],{"class":8557},[516,24908,17510],{"class":1227},[516,24910,10575],{"class":8557},[516,24912,10636],{"class":4733},[516,24914,1894],{"class":1227},[516,24916,24917],{"class":1248},"\"radio\"",[516,24919,15794],{"class":4733},[516,24921,1894],{"class":1227},[516,24923,24924],{"class":1248},"\"size\"",[516,24926,13165],{"class":4733},[516,24928,1894],{"class":1227},[516,24930,24931],{"class":1248},"\"small\"",[516,24933,24934],{"class":1227}," /> Small\u003C/",[516,24936,16538],{"class":8557},[516,24938,8561],{"class":1227},[516,24940,24941,24943,24945,24947,24949,24951,24953,24955,24957,24959,24961,24963,24965,24968,24971,24973],{"class":518,"line":531},[516,24942,8566],{"class":1227},[516,24944,16538],{"class":8557},[516,24946,17510],{"class":1227},[516,24948,10575],{"class":8557},[516,24950,10636],{"class":4733},[516,24952,1894],{"class":1227},[516,24954,24917],{"class":1248},[516,24956,15794],{"class":4733},[516,24958,1894],{"class":1227},[516,24960,24924],{"class":1248},[516,24962,13165],{"class":4733},[516,24964,1894],{"class":1227},[516,24966,24967],{"class":1248},"\"large\"",[516,24969,24970],{"class":1227}," /> Large\u003C/",[516,24972,16538],{"class":8557},[516,24974,8561],{"class":1227},[516,24976,24977,24979,24981],{"class":518,"line":1127},[516,24978,8589],{"class":1227},[516,24980,8558],{"class":8557},[516,24982,8561],{"class":1227},[516,24984,24985],{"class":518,"line":1134},[516,24986,1131],{"emptyLinePlaceholder":1130},[516,24988,24989,24991,24993,24995],{"class":518,"line":1275},[516,24990,3042],{"class":1227},[516,24992,8604],{"class":8557},[516,24994,8607],{"class":4733},[516,24996,8561],{"class":1227},[516,24998,24999,25001,25003,25005],{"class":518,"line":1302},[516,25000,8614],{"class":1749},[516,25002,8617],{"class":1227},[516,25004,8620],{"class":1749},[516,25006,8623],{"class":1248},[516,25008,25009],{"class":518,"line":1308},[516,25010,1131],{"emptyLinePlaceholder":1130},[516,25012,25013,25015,25018,25020,25022,25024,25027],{"class":518,"line":1314},[516,25014,8632],{"class":1749},[516,25016,25017],{"class":1233}," size",[516,25019,1793],{"class":1749},[516,25021,8640],{"class":4733},[516,25023,8643],{"class":1227},[516,25025,25026],{"class":1248},"'small'",[516,25028,8649],{"class":1227},[516,25030,25031,25033,25035],{"class":518,"line":8656},[516,25032,8589],{"class":1227},[516,25034,8604],{"class":8557},[516,25036,8561],{"class":1227},[11,25038,25039,25040,25042],{},"In both cases, the key detail is that every input in the group points at the exact same reactive variable, only the static ",[66,25041,12995],{}," attribute changes between inputs.",[23,25044,25046],{"id":25045},"_117-what-is-the-difference-between-a-controlled-and-an-uncontrolled-form-input-in-vue","117. What is the difference between a controlled and an uncontrolled form input in Vue?",[11,25048,25049,25050,25052,25053,25055,25056,25058,25059,25061,25062,25065],{},"A controlled input's value is driven entirely by reactive state: the input's ",[66,25051,12995],{}," comes from a ",[66,25054,9387],{},", and every change flows back into that same ",[66,25057,9387],{}," through ",[66,25060,10557],{}," or a manual ",[66,25063,25064],{},"@input"," handler. Vue state is the single source of truth, the DOM element just reflects it.",[11,25067,25068,25069,25071],{},"An uncontrolled input is left to manage its own value internally, in the DOM, and Vue does not bind it to any reactive variable. You would read its value only when needed, typically using a template ref and reading ",[66,25070,11449],{}," off the actual DOM element (for example, when the form is submitted), rather than tracking every keystroke in reactive state.",[507,25073,25075],{"className":8546,"code":25074,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cinput ref=\"nameInput\" type=\"text\" />\n    \u003Cbutton @click=\"submit\">Submit\u003C/button>\n\u003C/template>\n\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst nameInput = ref(null)\n\nfunction submit() {\n    console.log(nameInput.value.value)\n}\n\u003C/script>\n",[66,25076,25077,25085,25106,25126,25134,25138,25148,25158,25162,25179,25183,25192,25201,25205],{"__ignoreMap":512},[516,25078,25079,25081,25083],{"class":518,"line":519},[516,25080,3042],{"class":1227},[516,25082,8558],{"class":8557},[516,25084,8561],{"class":1227},[516,25086,25087,25089,25091,25093,25095,25098,25100,25102,25104],{"class":518,"line":525},[516,25088,8566],{"class":1227},[516,25090,10575],{"class":8557},[516,25092,8640],{"class":4733},[516,25094,1894],{"class":1227},[516,25096,25097],{"class":1248},"\"nameInput\"",[516,25099,10636],{"class":4733},[516,25101,1894],{"class":1227},[516,25103,2427],{"class":1248},[516,25105,9667],{"class":1227},[516,25107,25108,25110,25112,25114,25116,25119,25122,25124],{"class":518,"line":531},[516,25109,8566],{"class":1227},[516,25111,8569],{"class":8557},[516,25113,8572],{"class":4733},[516,25115,1894],{"class":1227},[516,25117,25118],{"class":1248},"\"submit\"",[516,25120,25121],{"class":1227},">Submit\u003C/",[516,25123,8569],{"class":8557},[516,25125,8561],{"class":1227},[516,25127,25128,25130,25132],{"class":518,"line":1127},[516,25129,8589],{"class":1227},[516,25131,8558],{"class":8557},[516,25133,8561],{"class":1227},[516,25135,25136],{"class":518,"line":1134},[516,25137,1131],{"emptyLinePlaceholder":1130},[516,25139,25140,25142,25144,25146],{"class":518,"line":1275},[516,25141,3042],{"class":1227},[516,25143,8604],{"class":8557},[516,25145,8607],{"class":4733},[516,25147,8561],{"class":1227},[516,25149,25150,25152,25154,25156],{"class":518,"line":1302},[516,25151,8614],{"class":1749},[516,25153,8617],{"class":1227},[516,25155,8620],{"class":1749},[516,25157,8623],{"class":1248},[516,25159,25160],{"class":518,"line":1308},[516,25161,1131],{"emptyLinePlaceholder":1130},[516,25163,25164,25166,25169,25171,25173,25175,25177],{"class":518,"line":1314},[516,25165,8632],{"class":1749},[516,25167,25168],{"class":1233}," nameInput",[516,25170,1793],{"class":1749},[516,25172,8640],{"class":4733},[516,25174,8643],{"class":1227},[516,25176,9102],{"class":1233},[516,25178,8649],{"class":1227},[516,25180,25181],{"class":518,"line":8656},[516,25182,1131],{"emptyLinePlaceholder":1130},[516,25184,25185,25187,25190],{"class":518,"line":8668},[516,25186,8659],{"class":1749},[516,25188,25189],{"class":4733}," submit",[516,25191,8665],{"class":1227},[516,25193,25194,25196,25198],{"class":518,"line":8677},[516,25195,11514],{"class":1227},[516,25197,11517],{"class":4733},[516,25199,25200],{"class":1227},"(nameInput.value.value)\n",[516,25202,25203],{"class":518,"line":8682},[516,25204,1317],{"class":1227},[516,25206,25207,25209,25211],{"class":518,"line":8691},[516,25208,8589],{"class":1227},[516,25210,8604],{"class":8557},[516,25212,8561],{"class":1227},[11,25214,25215,25216,25218],{},"Most Vue forms use controlled inputs via ",[66,25217,10557],{}," because it keeps validation, computed values, and conditional UI trivial to write against reactive state. Uncontrolled inputs show up when you genuinely do not need to react to every change, for example a rarely touched field, or when integrating a non-Vue widget that manages its own DOM state.",[23,25220,25222],{"id":25221},"_118-how-do-you-approach-form-validation-in-vue-and-when-would-you-reach-for-a-library-like-veevalidate","118. How do you approach form validation in Vue, and when would you reach for a library like VeeValidate?",[11,25224,25225,25226,25228,25229,25231,25232,25234,25235,2958,25237,25239],{},"For simple forms, you can validate by hand: bind each field with ",[66,25227,10557],{},", keep a ",[66,25230,9387],{}," (or a ",[66,25233,12368],{}," object) for error messages, and run your checks either on submit or with a ",[66,25236,9012],{},[66,25238,13396],{}," on the field. This keeps validation logic fully visible and dependency free.",[507,25241,25243],{"className":8546,"code":25242,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, computed } from 'vue'\n\nconst email = ref('')\nconst error = computed(() => {\n    if (!email.value) return 'Email is required'\n    if (!email.value.includes('@')) return 'Email looks invalid'\n    return ''\n})\n\u003C/script>\n",[66,25244,25245,25255,25265,25269,25286,25302,25318,25344,25351,25355],{"__ignoreMap":512},[516,25246,25247,25249,25251,25253],{"class":518,"line":519},[516,25248,3042],{"class":1227},[516,25250,8604],{"class":8557},[516,25252,8607],{"class":4733},[516,25254,8561],{"class":1227},[516,25256,25257,25259,25261,25263],{"class":518,"line":525},[516,25258,8614],{"class":1749},[516,25260,13892],{"class":1227},[516,25262,8620],{"class":1749},[516,25264,8623],{"class":1248},[516,25266,25267],{"class":518,"line":531},[516,25268,1131],{"emptyLinePlaceholder":1130},[516,25270,25271,25273,25276,25278,25280,25282,25284],{"class":518,"line":1127},[516,25272,8632],{"class":1749},[516,25274,25275],{"class":1233}," email",[516,25277,1793],{"class":1749},[516,25279,8640],{"class":4733},[516,25281,8643],{"class":1227},[516,25283,21968],{"class":1248},[516,25285,8649],{"class":1227},[516,25287,25288,25290,25292,25294,25296,25298,25300],{"class":518,"line":1134},[516,25289,8632],{"class":1749},[516,25291,20384],{"class":1233},[516,25293,1793],{"class":1749},[516,25295,11030],{"class":4733},[516,25297,11033],{"class":1227},[516,25299,11036],{"class":1749},[516,25301,8713],{"class":1227},[516,25303,25304,25306,25308,25310,25313,25315],{"class":518,"line":1275},[516,25305,22403],{"class":1749},[516,25307,734],{"class":1227},[516,25309,10950],{"class":1749},[516,25311,25312],{"class":1227},"email.value) ",[516,25314,9355],{"class":1749},[516,25316,25317],{"class":1248}," 'Email is required'\n",[516,25319,25320,25322,25324,25326,25329,25331,25333,25336,25339,25341],{"class":518,"line":1302},[516,25321,22403],{"class":1749},[516,25323,734],{"class":1227},[516,25325,10950],{"class":1749},[516,25327,25328],{"class":1227},"email.value.",[516,25330,14985],{"class":4733},[516,25332,8643],{"class":1227},[516,25334,25335],{"class":1248},"'@'",[516,25337,25338],{"class":1227},")) ",[516,25340,9355],{"class":1749},[516,25342,25343],{"class":1248}," 'Email looks invalid'\n",[516,25345,25346,25348],{"class":518,"line":1308},[516,25347,9089],{"class":1749},[516,25349,25350],{"class":1248}," ''\n",[516,25352,25353],{"class":518,"line":1314},[516,25354,11530],{"class":1227},[516,25356,25357,25359,25361],{"class":518,"line":8656},[516,25358,8589],{"class":1227},[516,25360,8604],{"class":8557},[516,25362,8561],{"class":1227},[11,25364,25365,25366,154,25369,25372],{},"This works fine for a login form with two fields, but it gets messy fast once you have many fields, cross field rules (like \"confirm password must match password\"), async checks (like \"is this username taken\"), or nested/dynamic form arrays. That is when a library like VeeValidate earns its place: it gives you a schema based way to describe rules (often paired with a validation schema library like Yup or Zod), handles touched/dirty state, error message display, and submit blocking, and provides composables (",[66,25367,25368],{},"useField",[66,25370,25371],{},"useForm",") that plug straight into Vue's reactivity so you are not reinventing that state tracking yourself. The rule of thumb: hand rolled validation for a couple of simple fields, a library once the form has real complexity or you are repeating the same validation patterns across many forms.",[23,25374,25376,25377,202,25379,25382],{"id":25375},"_119-what-is-the-difference-between-listening-to-input-and-change-on-a-text-field","119. What is the difference between listening to ",[66,25378,25064],{},[66,25380,25381],{},"@change"," on a text field?",[11,25384,25385,25387,25388,25390],{},[66,25386,25064],{}," fires on every value change as it happens, for a text field that means every keystroke, paste, or programmatic value change. ",[66,25389,25381],{}," fires only once the value has been committed, for a text field that is when the field loses focus (blurs) after its value changed, not on every keystroke.",[507,25392,25394],{"className":8546,"code":25393,"language":8548,"meta":512,"style":512},"\u003Cinput @input=\"onInput\" @change=\"onChange\" />\n",[66,25395,25396],{"__ignoreMap":512},[516,25397,25398,25400,25402,25404,25406,25408,25410,25413,25415,25417,25419,25421,25423,25426,25428],{"class":518,"line":519},[516,25399,3042],{"class":1227},[516,25401,10575],{"class":8557},[516,25403,15578],{"class":1227},[516,25405,10575],{"class":4733},[516,25407,1894],{"class":1227},[516,25409,3247],{"class":1248},[516,25411,25412],{"class":1227},"onInput",[516,25414,3247],{"class":1248},[516,25416,15578],{"class":1227},[516,25418,10687],{"class":4733},[516,25420,1894],{"class":1227},[516,25422,3247],{"class":1248},[516,25424,25425],{"class":1227},"onChange",[516,25427,3247],{"class":1248},[516,25429,9667],{"class":1227},[11,25431,25432,25434,25435,25437,25438,25440,25441,25443,25444,25446,25447,25449],{},[66,25433,10557],{}," on a plain text input uses ",[66,25436,10575],{}," under the hood, which is why the bound variable updates live as you type. If you want to react to every keystroke (live character count, live search suggestions), listen for ",[66,25439,25064],{}," (or just use ",[66,25442,10557],{}," and a ",[66,25445,13396],{},"). If you only care about the final value once the user is done editing a field (like triggering a validation check or an expensive computation when they tab away), ",[66,25448,25381],{}," avoids running that logic on every single keystroke.",[23,25451,25453,25454,25456],{"id":25452},"_120-how-would-you-debounce-a-v-model-bound-search-input","120. How would you debounce a ",[66,25455,10557],{}," bound search input?",[11,25458,25459,25461],{},[66,25460,10557],{}," itself does not debounce, it updates the bound variable on every keystroke, so if that variable directly triggers a network request, you will fire a request per character typed. The usual fix is to separate the \"what the user is typing\" state from the \"what we actually search for\" state, and only update the second one after typing has paused.",[507,25463,25465],{"className":8546,"code":25464,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cinput v-model=\"query\" placeholder=\"Search...\" />\n\u003C/template>\n\n\u003Cscript setup>\nimport { ref, watch } from 'vue'\n\nconst query = ref('')\nlet timer = null\n\nwatch(query, (value) => {\n    clearTimeout(timer)\n    timer = setTimeout(() => {\n        search(value)\n    }, 300)\n})\n\nfunction search(value) {\n    // fire the actual API call here\n}\n\u003C/script>\n",[66,25466,25467,25475,25498,25506,25510,25520,25531,25535,25552,25564,25568,25583,25591,25607,25614,25624,25628,25632,25645,25650,25654],{"__ignoreMap":512},[516,25468,25469,25471,25473],{"class":518,"line":519},[516,25470,3042],{"class":1227},[516,25472,8558],{"class":8557},[516,25474,8561],{"class":1227},[516,25476,25477,25479,25481,25483,25485,25488,25491,25493,25496],{"class":518,"line":525},[516,25478,8566],{"class":1227},[516,25480,10575],{"class":8557},[516,25482,15794],{"class":4733},[516,25484,1894],{"class":1227},[516,25486,25487],{"class":1248},"\"query\"",[516,25489,25490],{"class":4733}," placeholder",[516,25492,1894],{"class":1227},[516,25494,25495],{"class":1248},"\"Search...\"",[516,25497,9667],{"class":1227},[516,25499,25500,25502,25504],{"class":518,"line":531},[516,25501,8589],{"class":1227},[516,25503,8558],{"class":8557},[516,25505,8561],{"class":1227},[516,25507,25508],{"class":518,"line":1127},[516,25509,1131],{"emptyLinePlaceholder":1130},[516,25511,25512,25514,25516,25518],{"class":518,"line":1134},[516,25513,3042],{"class":1227},[516,25515,8604],{"class":8557},[516,25517,8607],{"class":4733},[516,25519,8561],{"class":1227},[516,25521,25522,25524,25527,25529],{"class":518,"line":1275},[516,25523,8614],{"class":1749},[516,25525,25526],{"class":1227}," { ref, watch } ",[516,25528,8620],{"class":1749},[516,25530,8623],{"class":1248},[516,25532,25533],{"class":518,"line":1302},[516,25534,1131],{"emptyLinePlaceholder":1130},[516,25536,25537,25539,25542,25544,25546,25548,25550],{"class":518,"line":1308},[516,25538,8632],{"class":1749},[516,25540,25541],{"class":1233}," query",[516,25543,1793],{"class":1749},[516,25545,8640],{"class":4733},[516,25547,8643],{"class":1227},[516,25549,21968],{"class":1248},[516,25551,8649],{"class":1227},[516,25553,25554,25556,25559,25561],{"class":518,"line":1314},[516,25555,13767],{"class":1749},[516,25557,25558],{"class":1227}," timer ",[516,25560,1894],{"class":1749},[516,25562,25563],{"class":1233}," null\n",[516,25565,25566],{"class":518,"line":8656},[516,25567,1131],{"emptyLinePlaceholder":1130},[516,25569,25570,25572,25575,25577,25579,25581],{"class":518,"line":8668},[516,25571,13396],{"class":4733},[516,25573,25574],{"class":1227},"(query, (",[516,25576,12995],{"class":9080},[516,25578,13650],{"class":1227},[516,25580,11036],{"class":1749},[516,25582,8713],{"class":1227},[516,25584,25585,25588],{"class":518,"line":8677},[516,25586,25587],{"class":4733},"    clearTimeout",[516,25589,25590],{"class":1227},"(timer)\n",[516,25592,25593,25596,25598,25601,25603,25605],{"class":518,"line":8682},[516,25594,25595],{"class":1227},"    timer ",[516,25597,1894],{"class":1749},[516,25599,25600],{"class":4733}," setTimeout",[516,25602,11033],{"class":1227},[516,25604,11036],{"class":1749},[516,25606,8713],{"class":1227},[516,25608,25609,25612],{"class":518,"line":8691},[516,25610,25611],{"class":4733},"        search",[516,25613,13186],{"class":1227},[516,25615,25616,25619,25622],{"class":518,"line":8696},[516,25617,25618],{"class":1227},"    }, ",[516,25620,25621],{"class":1233},"300",[516,25623,8649],{"class":1227},[516,25625,25626],{"class":518,"line":8708},[516,25627,11530],{"class":1227},[516,25629,25630],{"class":518,"line":8716},[516,25631,1131],{"emptyLinePlaceholder":1130},[516,25633,25634,25636,25639,25641,25643],{"class":518,"line":8727},[516,25635,8659],{"class":1749},[516,25637,25638],{"class":4733}," search",[516,25640,8643],{"class":1227},[516,25642,12995],{"class":9080},[516,25644,9084],{"class":1227},[516,25646,25647],{"class":518,"line":8732},[516,25648,25649],{"class":3076},"    // fire the actual API call here\n",[516,25651,25652],{"class":518,"line":9301},[516,25653,1317],{"class":1227},[516,25655,25656,25658,25660],{"class":518,"line":9318},[516,25657,8589],{"class":1227},[516,25659,8604],{"class":8557},[516,25661,8561],{"class":1227},[11,25663,25664,25666,25667,25670,25671,25674,25675,756,25678,25681,25682,25684],{},[66,25665,10557],{}," stays bound to ",[66,25668,25669],{},"query"," so the input feels instant, but the expensive ",[66,25672,25673],{},"search"," call only runs 300ms after the user stops typing. If you are already using VueUse, ",[66,25676,25677],{},"refDebounced",[66,25679,25680],{},"useDebounceFn"," do the same thing with less boilerplate, but the underlying idea is the same: let ",[66,25683,10557],{}," update local state immediately, and debounce the side effect that reads from it.",[18,25686,25688],{"id":25687},"performance-optimization","Performance Optimization",[23,25690,25692,25693,11199],{"id":25691},"_121-what-is-v-memo-and-when-would-you-use-it","121. What is ",[66,25694,25695],{},"v-memo",[11,25697,25698,25700],{},[66,25699,25695],{}," is a directive that memoizes a chunk of template, telling Vue to skip re-rendering that subtree as long as a list of dependency values hasn't changed. You give it an array of values to watch; if every value in that array is the same as last render, Vue reuses the existing vnode tree instead of re-diffing it.",[11,25702,25703,25704,25706],{},"It exists for edge cases where Vue's default reactivity and compiler optimizations (patch flags, block tree) aren't enough, typically huge ",[66,25705,9833],{}," lists where most rows never change and you've measured an actual bottleneck. It is not something you reach for by default; misusing it can cause stale UI if you forget to include a value the subtree actually depends on.",[507,25708,25710],{"className":8546,"code":25709,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cdiv v-for=\"item in list\" :key=\"item.id\" v-memo=\"[item.id === selectedId]\">\n        \u003CExpensiveRow :item=\"item\" :selected=\"item.id === selectedId\" />\n    \u003C/div>\n\u003C/template>\n",[66,25711,25712,25720,25749,25774,25782],{"__ignoreMap":512},[516,25713,25714,25716,25718],{"class":518,"line":519},[516,25715,3042],{"class":1227},[516,25717,8558],{"class":8557},[516,25719,8561],{"class":1227},[516,25721,25722,25724,25726,25728,25730,25733,25735,25737,25739,25742,25744,25747],{"class":518,"line":525},[516,25723,8566],{"class":1227},[516,25725,9764],{"class":8557},[516,25727,9873],{"class":4733},[516,25729,1894],{"class":1227},[516,25731,25732],{"class":1248},"\"item in list\"",[516,25734,9881],{"class":4733},[516,25736,1894],{"class":1227},[516,25738,9886],{"class":1248},[516,25740,25741],{"class":4733}," v-memo",[516,25743,1894],{"class":1227},[516,25745,25746],{"class":1248},"\"[item.id === selectedId]\"",[516,25748,8561],{"class":1227},[516,25750,25751,25753,25756,25759,25761,25764,25767,25769,25772],{"class":518,"line":531},[516,25752,9868],{"class":1227},[516,25754,25755],{"class":8557},"ExpensiveRow",[516,25757,25758],{"class":4733}," :item",[516,25760,1894],{"class":1227},[516,25762,25763],{"class":1248},"\"item\"",[516,25765,25766],{"class":4733}," :selected",[516,25768,1894],{"class":1227},[516,25770,25771],{"class":1248},"\"item.id === selectedId\"",[516,25773,9667],{"class":1227},[516,25775,25776,25778,25780],{"class":518,"line":1127},[516,25777,9907],{"class":1227},[516,25779,9764],{"class":8557},[516,25781,8561],{"class":1227},[516,25783,25784,25786,25788],{"class":518,"line":1134},[516,25785,8589],{"class":1227},[516,25787,8558],{"class":8557},[516,25789,8561],{"class":1227},[11,25791,25792,25793,25796],{},"Here, a row only re-renders when its selected state flips, not every time ",[66,25794,25795],{},"selectedId"," changes and forces a full list re-render.",[23,25798,25800,25801,25803],{"id":25799},"_122-what-is-keepalive-and-how-does-it-improve-performance","122. What is ",[66,25802,8969],{},", and how does it improve performance?",[11,25805,25806,25808,25809,18707,25812,25814,25815,25817],{},[66,25807,8969],{}," is a built-in component that caches the component instances of its dynamic children instead of destroying and recreating them when they're toggled out and back in. Normally, switching a ",[66,25810,25811],{},"\u003Ccomponent :is>",[66,25813,22219],{}," unmounts the old component and mounts a fresh one, which re-runs ",[66,25816,9351],{},", loses local state, and rebuilds the DOM from scratch.",[11,25819,25820,25821,25823],{},"Wrapping the dynamic content in ",[66,25822,8969],{}," keeps the unmounted instance alive in memory, so switching back to it just reattaches its existing DOM and state. This is useful for things like tabs, forms with unsaved input, or list/detail views where you want scroll position and form state preserved.",[507,25825,25827],{"className":8546,"code":25826,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003CKeepAlive :include=\"['UserForm', 'Settings']\" :max=\"10\">\n        \u003Ccomponent :is=\"activeTab\" />\n    \u003C/KeepAlive>\n\u003C/template>\n",[66,25828,25829,25837,25862,25878,25886],{"__ignoreMap":512},[516,25830,25831,25833,25835],{"class":518,"line":519},[516,25832,3042],{"class":1227},[516,25834,8558],{"class":8557},[516,25836,8561],{"class":1227},[516,25838,25839,25841,25844,25847,25849,25852,25855,25857,25860],{"class":518,"line":525},[516,25840,8566],{"class":1227},[516,25842,25843],{"class":8557},"KeepAlive",[516,25845,25846],{"class":4733}," :include",[516,25848,1894],{"class":1227},[516,25850,25851],{"class":1248},"\"['UserForm', 'Settings']\"",[516,25853,25854],{"class":4733}," :max",[516,25856,1894],{"class":1227},[516,25858,25859],{"class":1248},"\"10\"",[516,25861,8561],{"class":1227},[516,25863,25864,25866,25868,25871,25873,25876],{"class":518,"line":531},[516,25865,9868],{"class":1227},[516,25867,9422],{"class":8557},[516,25869,25870],{"class":4733}," :is",[516,25872,1894],{"class":1227},[516,25874,25875],{"class":1248},"\"activeTab\"",[516,25877,9667],{"class":1227},[516,25879,25880,25882,25884],{"class":518,"line":1127},[516,25881,9907],{"class":1227},[516,25883,25843],{"class":8557},[516,25885,8561],{"class":1227},[516,25887,25888,25890,25892],{"class":518,"line":1134},[516,25889,8589],{"class":1227},[516,25891,8558],{"class":8557},[516,25893,8561],{"class":1227},[11,25895,25896,2958,25899,25902,25903,25906,25907,202,25909,25911,25912,2958,25914,25916],{},[66,25897,25898],{},"include",[66,25900,25901],{},"exclude"," control which components get cached by name, and ",[66,25904,25905],{},"max"," bounds the cache size with an LRU eviction policy. Cached components gain ",[66,25908,19569],{},[66,25910,19575],{}," lifecycle hooks instead of ",[66,25913,19497],{},[66,25915,19556],{}," on every switch.",[23,25918,25920,25921,9728],{"id":25919},"_123-how-do-you-lazy-load-a-component-with-defineasynccomponent","123. How do you lazy load a component with ",[66,25922,25923],{},"defineAsyncComponent",[11,25925,25926,25928,25929,25931],{},[66,25927,25923],{}," wraps a function that returns a dynamic ",[66,25930,22747],{},", so the component's code is only fetched and evaluated when it's actually needed, instead of being bundled into the initial page load. Vue renders a placeholder (nothing, by default) until the import resolves, then swaps in the real component.",[507,25933,25935],{"className":8782,"code":25934,"language":8784,"meta":512,"style":512},"import { defineAsyncComponent } from 'vue'\n\nconst AdminPanel = defineAsyncComponent(() => import('./AdminPanel.vue'))\n",[66,25936,25937,25948,25952],{"__ignoreMap":512},[516,25938,25939,25941,25944,25946],{"class":518,"line":519},[516,25940,8614],{"class":1749},[516,25942,25943],{"class":1227}," { defineAsyncComponent } ",[516,25945,8620],{"class":1749},[516,25947,8623],{"class":1248},[516,25949,25950],{"class":518,"line":525},[516,25951,1131],{"emptyLinePlaceholder":1130},[516,25953,25954,25956,25959,25961,25964,25966,25968,25970,25972,25975],{"class":518,"line":531},[516,25955,8632],{"class":1749},[516,25957,25958],{"class":1233}," AdminPanel",[516,25960,1793],{"class":1749},[516,25962,25963],{"class":4733}," defineAsyncComponent",[516,25965,11033],{"class":1227},[516,25967,11036],{"class":1749},[516,25969,22787],{"class":1749},[516,25971,8643],{"class":1227},[516,25973,25974],{"class":1248},"'./AdminPanel.vue'",[516,25976,23762],{"class":1227},[11,25978,25979],{},"For more control you pass an options object instead of a bare function:",[507,25981,25983],{"className":8782,"code":25982,"language":8784,"meta":512,"style":512},"const AdminPanel = defineAsyncComponent({\n    loader: () => import('./AdminPanel.vue'),\n    loadingComponent: LoadingSpinner,\n    errorComponent: LoadError,\n    delay: 200,\n    timeout: 5000,\n})\n",[66,25984,25985,25997,26015,26020,26025,26035,26045],{"__ignoreMap":512},[516,25986,25987,25989,25991,25993,25995],{"class":518,"line":519},[516,25988,8632],{"class":1749},[516,25990,25958],{"class":1233},[516,25992,1793],{"class":1749},[516,25994,25963],{"class":4733},[516,25996,12910],{"class":1227},[516,25998,25999,26002,26004,26006,26008,26010,26012],{"class":518,"line":525},[516,26000,26001],{"class":4733},"    loader",[516,26003,15378],{"class":1227},[516,26005,11036],{"class":1749},[516,26007,22787],{"class":1749},[516,26009,8643],{"class":1227},[516,26011,25974],{"class":1248},[516,26013,26014],{"class":1227},"),\n",[516,26016,26017],{"class":518,"line":531},[516,26018,26019],{"class":1227},"    loadingComponent: LoadingSpinner,\n",[516,26021,26022],{"class":518,"line":1127},[516,26023,26024],{"class":1227},"    errorComponent: LoadError,\n",[516,26026,26027,26030,26033],{"class":518,"line":1134},[516,26028,26029],{"class":1227},"    delay: ",[516,26031,26032],{"class":1233},"200",[516,26034,1252],{"class":1227},[516,26036,26037,26040,26043],{"class":518,"line":1275},[516,26038,26039],{"class":1227},"    timeout: ",[516,26041,26042],{"class":1233},"5000",[516,26044,1252],{"class":1227},[516,26046,26047],{"class":518,"line":1302},[516,26048,11530],{"class":1227},[11,26050,26051,26054,26055,26058],{},[66,26052,26053],{},"delay"," avoids flashing a spinner for fast loads, and ",[66,26056,26057],{},"timeout"," falls back to the error component if the chunk takes too long. This pairs naturally with route-level code splitting, where each route's component is its own async component so users only download the JavaScript for the page they visit.",[23,26060,26062],{"id":26061},"_124-what-are-patch-flags-and-how-do-they-let-vue-3-skip-unnecessary-diff-work","124. What are patch flags, and how do they let Vue 3 skip unnecessary diff work?",[11,26064,26065,26066,154,26069,154,26072,154,26075,741,26078,26081,26082,154,26085,26088],{},"Patch flags are numeric hints that the Vue 3 compiler attaches to a vnode at compile time, describing exactly what kind of dynamic content that vnode contains, such as ",[66,26067,26068],{},"TEXT",[66,26070,26071],{},"CLASS",[66,26073,26074],{},"STYLE",[66,26076,26077],{},"PROPS",[66,26079,26080],{},"FULL_PROPS",". The compiler can figure this out because it statically analyzes the template and knows which bindings are dynamic (",[66,26083,26084],{},"{{ msg }}",[66,26086,26087],{},":class=\"foo\"",") and which parts are plain static markup.",[11,26090,26091,26092,26094],{},"At render time, the patch function checks a vnode's flag instead of blindly comparing every attribute, child, and prop against the previous vnode. If a vnode is flagged ",[66,26093,26068],{},", Vue knows only the text content can differ and updates just that, skipping class, style, and prop comparisons entirely. A vnode with no dynamic bindings at all gets no patch flag and is skipped from diffing completely.",[11,26096,26097],{},"This is the core reason Vue 3's compiled templates outperform a naive virtual DOM diff: the compiler does the analysis once, ahead of time, so the runtime doesn't have to rediscover \"what changed\" by brute-force comparison on every render.",[23,26099,26101],{"id":26100},"_125-what-is-static-hoisting-in-the-vue-3-compiler","125. What is static hoisting in the Vue 3 compiler?",[11,26103,26104],{},"Static hoisting is a compiler optimization where vnodes that contain no dynamic bindings are created once, outside of the render function, and then reused on every subsequent render instead of being recreated each time.",[11,26106,26107,26108,26110],{},"In a naive virtual DOM implementation, the entire render function runs on every update, including the code that creates vnodes for markup that never changes, like a static heading or a hardcoded icon. Since the Vue 3 compiler can see at compile time that a piece of template has no ",[66,26109,9486],{}," interpolations, directives, or bindings, it \"hoists\" that vnode creation out of the render function so it only runs once, and the render function just references the same cached vnode object on every call.",[507,26112,26114],{"className":8546,"code":26113,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cdiv>\n        \u003Ch1>Static Title\u003C/h1>\n        \u003Cp>{{ dynamicMessage }}\u003C/p>\n    \u003C/div>\n\u003C/template>\n",[66,26115,26116,26124,26132,26145,26158,26166],{"__ignoreMap":512},[516,26117,26118,26120,26122],{"class":518,"line":519},[516,26119,3042],{"class":1227},[516,26121,8558],{"class":8557},[516,26123,8561],{"class":1227},[516,26125,26126,26128,26130],{"class":518,"line":525},[516,26127,8566],{"class":1227},[516,26129,9764],{"class":8557},[516,26131,8561],{"class":1227},[516,26133,26134,26136,26138,26141,26143],{"class":518,"line":531},[516,26135,9868],{"class":1227},[516,26137,11224],{"class":8557},[516,26139,26140],{"class":1227},">Static Title\u003C/",[516,26142,11224],{"class":8557},[516,26144,8561],{"class":1227},[516,26146,26147,26149,26151,26154,26156],{"class":518,"line":1127},[516,26148,9868],{"class":1227},[516,26150,11],{"class":8557},[516,26152,26153],{"class":1227},">{{ dynamicMessage }}\u003C/",[516,26155,11],{"class":8557},[516,26157,8561],{"class":1227},[516,26159,26160,26162,26164],{"class":518,"line":1134},[516,26161,9907],{"class":1227},[516,26163,9764],{"class":8557},[516,26165,8561],{"class":1227},[516,26167,26168,26170,26172],{"class":518,"line":1275},[516,26169,8589],{"class":1227},[516,26171,8558],{"class":8557},[516,26173,8561],{"class":1227},[11,26175,14052,26176,26179,26180,26183],{},[66,26177,26178],{},"\u003Ch1>Static Title\u003C/h1>"," gets hoisted; only the ",[66,26181,26182],{},"\u003Cp>"," vnode is recreated on re-renders. The benefit is fewer object allocations and less garbage collection pressure on every render pass, which adds up in components that re-render frequently.",[23,26185,26187],{"id":26186},"_126-what-is-the-block-tree-optimization-in-the-vue-3-compiler","126. What is the \"block tree\" optimization in the Vue 3 compiler?",[11,26189,26190,26191,26194,26195,26197],{},"A \"block\" is a vnode that also tracks all of its dynamic descendant vnodes in a flat array called ",[66,26192,26193],{},"dynamicChildren",", gathered at compile time. Instead of the runtime having to walk the entire tree recursively to find what changed, Vue can jump straight to the ",[66,26196,26193],{}," array of a block and only diff those specific nodes, skipping every static node in between automatically.",[11,26199,26200,26201,202,26203,26205,26206,26208,26209,26211],{},"Templates compile into a tree of nested blocks, forming the \"block tree.\" The root template is a block, and structural directives like ",[66,26202,9724],{},[66,26204,9833],{}," create their own nested blocks, because the set of dynamic children they produce can change shape between renders (a ",[66,26207,9833],{}," might add or remove items, a ",[66,26210,9724],{}," branch might swap out entirely). Keeping these as separate blocks means the parent block's flat diff doesn't get confused by children whose structure isn't stable.",[11,26213,26214],{},"The combination of patch flags (what changed) and the block tree (where to look) is what lets Vue 3 turn a full tree diff into something closer to \"diff a flat list of known-dynamic nodes,\" which scales much better as templates grow larger.",[23,26216,26218],{"id":26217},"_127-how-do-you-avoid-performance-problems-when-rendering-large-lists","127. How do you avoid performance problems when rendering large lists?",[11,26220,26221],{},"A few practices matter most:",[717,26223,26224,26233,26247,26252,26258,26266],{},[720,26225,26226,26227,26229,26230,26232],{},"Always give ",[66,26228,9833],{}," a stable, unique ",[66,26231,9837],{}," (an id from your data), never the array index for lists that can reorder, insert, or delete, since index keys cause Vue to misattribute state to the wrong DOM node during diffing.",[720,26234,26235,26236,202,26238,26240,26241,26243,26244,26246],{},"Never combine ",[66,26237,9724],{},[66,26239,9833],{}," on the same element; Vue 3 will warn/error since ",[66,26242,9724],{}," has higher precedence, and evaluating a condition per item is wasteful anyway. Filter the list with a ",[66,26245,9012],{}," property first.",[720,26248,12479,26249,26251],{},[66,26250,9012],{}," properties for any derived/filtered/sorted view of the list so the work is cached and only reruns when the source data changes, not on every render.",[720,26253,26254,26255,26257],{},"Reach for ",[66,26256,25695],{}," on expensive rows only when the default diffing is a measured bottleneck.",[720,26259,26260,26261,756,26263,26265],{},"For very large datasets that don't need per-item reactivity, use ",[66,26262,12687],{},[66,26264,12918],{}," to avoid Vue making every nested object deeply reactive, which has real overhead at scale.",[720,26267,26268],{},"Beyond a few hundred rows, consider virtual scrolling instead of rendering the full list at once.",[23,26270,26272],{"id":26271},"_128-what-is-virtual-scrolling-and-when-would-you-need-it","128. What is virtual scrolling, and when would you need it?",[11,26274,26275],{},"Virtual scrolling (or \"windowing\") is a technique where only the list items currently visible in the viewport, plus a small buffer, are actually rendered as real DOM nodes. As the user scrolls, nodes are recycled and repositioned to represent whatever data has scrolled into view, rather than the browser holding thousands of live DOM nodes for the entire dataset.",[11,26277,26278],{},"You need it once a list gets large enough that rendering every item up front becomes the bottleneck, commonly somewhere in the hundreds to thousands of rows. The cost isn't really about Vue's diffing at that point, it's that the browser itself struggles with layout, paint, and memory for that many real DOM nodes, and Vue's reactivity has to track and patch all of them too.",[11,26280,26281,26282,756,26285,26288],{},"In practice you don't hand-roll this; libraries like ",[66,26283,26284],{},"vue-virtual-scroller",[66,26286,26287],{},"@tanstack/vue-virtual"," calculate which slice of the list is visible based on scroll offset and item height, and render only that slice, keeping the DOM node count roughly constant regardless of how many total items exist.",[23,26290,26292],{"id":26291},"_129-how-do-computed-properties-help-performance-compared-to-calling-a-method-directly-in-a-template","129. How do computed properties help performance compared to calling a method directly in a template?",[11,26294,26295,26296,26298],{},"As covered in the computed caching question above, a ",[66,26297,9012],{}," property only recomputes when one of its reactive dependencies changes, while a method called from a template reruns on every single re-render of that component, whether or not its inputs actually changed. The performance angle is what that caching buys you in practice, once the derived value is expensive.",[507,26300,26302],{"className":8546,"code":26301,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { ref, computed } from 'vue'\n\nconst items = ref([/* large array */])\n\n// recalculates only when items.value changes\nconst sortedItems = computed(() => {\n    return [...items.value].sort((a, b) => a.price - b.price)\n})\n\n// reruns this sort on every re-render, regardless of cause\nfunction sortedItemsMethod() {\n    return [...items.value].sort((a, b) => a.price - b.price)\n}\n\u003C/script>\n",[66,26303,26304,26314,26324,26328,26345,26349,26354,26371,26407,26411,26415,26420,26429,26459,26463],{"__ignoreMap":512},[516,26305,26306,26308,26310,26312],{"class":518,"line":519},[516,26307,3042],{"class":1227},[516,26309,8604],{"class":8557},[516,26311,8607],{"class":4733},[516,26313,8561],{"class":1227},[516,26315,26316,26318,26320,26322],{"class":518,"line":525},[516,26317,8614],{"class":1749},[516,26319,13892],{"class":1227},[516,26321,8620],{"class":1749},[516,26323,8623],{"class":1248},[516,26325,26326],{"class":518,"line":531},[516,26327,1131],{"emptyLinePlaceholder":1130},[516,26329,26330,26332,26334,26336,26338,26340,26343],{"class":518,"line":1127},[516,26331,8632],{"class":1749},[516,26333,9983],{"class":1233},[516,26335,1793],{"class":1749},[516,26337,8640],{"class":4733},[516,26339,11992],{"class":1227},[516,26341,26342],{"class":3076},"/* large array */",[516,26344,12006],{"class":1227},[516,26346,26347],{"class":518,"line":1134},[516,26348,1131],{"emptyLinePlaceholder":1130},[516,26350,26351],{"class":518,"line":1275},[516,26352,26353],{"class":3076},"// recalculates only when items.value changes\n",[516,26355,26356,26358,26361,26363,26365,26367,26369],{"class":518,"line":1302},[516,26357,8632],{"class":1749},[516,26359,26360],{"class":1233}," sortedItems",[516,26362,1793],{"class":1749},[516,26364,11030],{"class":4733},[516,26366,11033],{"class":1227},[516,26368,11036],{"class":1749},[516,26370,8713],{"class":1227},[516,26372,26373,26375,26377,26380,26383,26386,26388,26390,26392,26395,26397,26399,26402,26404],{"class":518,"line":1308},[516,26374,9089],{"class":1749},[516,26376,14214],{"class":1227},[516,26378,26379],{"class":1749},"...",[516,26381,26382],{"class":1227},"items.value].",[516,26384,26385],{"class":4733},"sort",[516,26387,14711],{"class":1227},[516,26389,761],{"class":9080},[516,26391,154],{"class":1227},[516,26393,26394],{"class":9080},"b",[516,26396,13650],{"class":1227},[516,26398,11036],{"class":1749},[516,26400,26401],{"class":1227}," a.price ",[516,26403,1899],{"class":1749},[516,26405,26406],{"class":1227}," b.price)\n",[516,26408,26409],{"class":518,"line":1314},[516,26410,11530],{"class":1227},[516,26412,26413],{"class":518,"line":8656},[516,26414,1131],{"emptyLinePlaceholder":1130},[516,26416,26417],{"class":518,"line":8668},[516,26418,26419],{"class":3076},"// reruns this sort on every re-render, regardless of cause\n",[516,26421,26422,26424,26427],{"class":518,"line":8677},[516,26423,8659],{"class":1749},[516,26425,26426],{"class":4733}," sortedItemsMethod",[516,26428,8665],{"class":1227},[516,26430,26431,26433,26435,26437,26439,26441,26443,26445,26447,26449,26451,26453,26455,26457],{"class":518,"line":8682},[516,26432,9089],{"class":1749},[516,26434,14214],{"class":1227},[516,26436,26379],{"class":1749},[516,26438,26382],{"class":1227},[516,26440,26385],{"class":4733},[516,26442,14711],{"class":1227},[516,26444,761],{"class":9080},[516,26446,154],{"class":1227},[516,26448,26394],{"class":9080},[516,26450,13650],{"class":1227},[516,26452,11036],{"class":1749},[516,26454,26401],{"class":1227},[516,26456,1899],{"class":1749},[516,26458,26406],{"class":1227},[516,26460,26461],{"class":518,"line":8691},[516,26462,1317],{"class":1227},[516,26464,26465,26467,26469],{"class":518,"line":8696},[516,26466,8589],{"class":1227},[516,26468,8604],{"class":8557},[516,26470,8561],{"class":1227},[11,26472,26473,26474,26477,26478,26481,26482,405],{},"If this component re-renders for an unrelated reason (a sibling prop changing, a parent re-rendering it), ",[66,26475,26476],{},"sortedItemsMethod()"," redoes the full sort every time, while ",[66,26479,26480],{},"sortedItems"," just returns the cached array. For cheap operations this difference is invisible, but for expensive derived data (sorting, filtering, aggregating large arrays) it can be the difference between a snappy UI and visible jank. The rule of thumb: if a template expression is derived purely from reactive state and doesn't need arguments, make it a ",[66,26483,9012],{},[23,26485,26487],{"id":26486},"_130-what-tools-would-you-use-to-profile-and-debug-performance-problems-in-a-vue-application","130. What tools would you use to profile and debug performance problems in a Vue application?",[11,26489,26490],{},"Vue Devtools is the first stop: its component inspector shows re-render counts and highlights which components updated on a given tick, and its performance tab can visualize component init, render, and patch timings, which quickly points to a component that's re-rendering far more often than expected.",[11,26492,26493],{},"For deeper timing analysis, the browser's own Performance panel (Chrome DevTools) records a flame graph of actual JavaScript execution and layout/paint work, letting you see whether time is going into Vue's render function, into a specific expensive computed/method, or into layout thrashing from DOM changes.",[11,26495,26496],{},"Vue also exposes debug hooks for tracking exactly why a component re-rendered:",[507,26498,26500],{"className":8546,"code":26499,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { onRenderTracked, onRenderTriggered } from 'vue'\n\nonRenderTracked((event) => {\n    console.log('dependency tracked', event)\n})\nonRenderTriggered((event) => {\n    console.log('re-render triggered by', event)\n})\n\u003C/script>\n",[66,26501,26502,26512,26523,26527,26542,26556,26560,26575,26588,26592],{"__ignoreMap":512},[516,26503,26504,26506,26508,26510],{"class":518,"line":519},[516,26505,3042],{"class":1227},[516,26507,8604],{"class":8557},[516,26509,8607],{"class":4733},[516,26511,8561],{"class":1227},[516,26513,26514,26516,26519,26521],{"class":518,"line":525},[516,26515,8614],{"class":1749},[516,26517,26518],{"class":1227}," { onRenderTracked, onRenderTriggered } ",[516,26520,8620],{"class":1749},[516,26522,8623],{"class":1248},[516,26524,26525],{"class":518,"line":531},[516,26526,1131],{"emptyLinePlaceholder":1130},[516,26528,26529,26532,26534,26536,26538,26540],{"class":518,"line":1127},[516,26530,26531],{"class":4733},"onRenderTracked",[516,26533,14711],{"class":1227},[516,26535,21106],{"class":9080},[516,26537,13650],{"class":1227},[516,26539,11036],{"class":1749},[516,26541,8713],{"class":1227},[516,26543,26544,26546,26548,26550,26553],{"class":518,"line":1134},[516,26545,11514],{"class":1227},[516,26547,11517],{"class":4733},[516,26549,8643],{"class":1227},[516,26551,26552],{"class":1248},"'dependency tracked'",[516,26554,26555],{"class":1227},", event)\n",[516,26557,26558],{"class":518,"line":1275},[516,26559,11530],{"class":1227},[516,26561,26562,26565,26567,26569,26571,26573],{"class":518,"line":1302},[516,26563,26564],{"class":4733},"onRenderTriggered",[516,26566,14711],{"class":1227},[516,26568,21106],{"class":9080},[516,26570,13650],{"class":1227},[516,26572,11036],{"class":1749},[516,26574,8713],{"class":1227},[516,26576,26577,26579,26581,26583,26586],{"class":518,"line":1308},[516,26578,11514],{"class":1227},[516,26580,11517],{"class":4733},[516,26582,8643],{"class":1227},[516,26584,26585],{"class":1248},"'re-render triggered by'",[516,26587,26555],{"class":1227},[516,26589,26590],{"class":518,"line":1314},[516,26591,11530],{"class":1227},[516,26593,26594,26596,26598],{"class":518,"line":8656},[516,26595,8589],{"class":1227},[516,26597,8604],{"class":8557},[516,26599,8561],{"class":1227},[11,26601,26602,26603,26606],{},"You can also set ",[66,26604,26605],{},"app.config.performance = true"," in development to have Vue emit performance marks/measures for component init, compile, render, and patch, which then show up in the browser's Performance timeline. For overall page-level metrics (not Vue-specific but relevant when Vue hydration/rendering is the bottleneck), Lighthouse and the Web Vitals extension round out the toolkit.",[18,26608,26610],{"id":26609},"vue-3-specific-features","Vue 3 Specific Features",[23,26612,26614,26615,18386],{"id":26613},"_131-what-is-teleport-and-what-problem-does-it-solve","131. What is ",[66,26616,26617],{},"Teleport",[11,26619,26620,26622],{},[66,26621,26617],{}," is a built-in component that lets you render part of a component's template into a different location in the DOM, anywhere outside the component's own hierarchy, while the content stays logically part of that component (same instance, same props, same events, same reactive scope).",[11,26624,26625,26626,756,26629,26632,26633,26635],{},"The problem it solves: things like modals, tooltips, and dropdown menus need to be positioned relative to the whole viewport and need to sit outside any parent's ",[66,26627,26628],{},"overflow: hidden",[66,26630,26631],{},"z-index"," stacking context to display correctly, but they're conceptually owned by a deeply nested component and need access to that component's local state. Before ",[66,26634,26617],{},", you'd either fight CSS stacking issues or manually manage DOM manipulation outside of Vue's control.",[507,26637,26639],{"className":8546,"code":26638,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cbutton @click=\"open = true\">Open Modal\u003C/button>\n    \u003CTeleport to=\"body\">\n        \u003Cdiv v-if=\"open\" class=\"modal\">\n            \u003Cp>Modal content, rendered at the end of body\u003C/p>\n            \u003Cbutton @click=\"open = false\">Close\u003C/button>\n        \u003C/div>\n    \u003C/Teleport>\n\u003C/template>\n",[66,26640,26641,26649,26669,26684,26706,26719,26739,26747,26755],{"__ignoreMap":512},[516,26642,26643,26645,26647],{"class":518,"line":519},[516,26644,3042],{"class":1227},[516,26646,8558],{"class":8557},[516,26648,8561],{"class":1227},[516,26650,26651,26653,26655,26657,26659,26662,26665,26667],{"class":518,"line":525},[516,26652,8566],{"class":1227},[516,26654,8569],{"class":8557},[516,26656,8572],{"class":4733},[516,26658,1894],{"class":1227},[516,26660,26661],{"class":1248},"\"open = true\"",[516,26663,26664],{"class":1227},">Open Modal\u003C/",[516,26666,8569],{"class":8557},[516,26668,8561],{"class":1227},[516,26670,26671,26673,26675,26677,26679,26682],{"class":518,"line":531},[516,26672,8566],{"class":1227},[516,26674,26617],{"class":8557},[516,26676,23057],{"class":4733},[516,26678,1894],{"class":1227},[516,26680,26681],{"class":1248},"\"body\"",[516,26683,8561],{"class":1227},[516,26685,26686,26688,26690,26692,26694,26697,26699,26701,26704],{"class":518,"line":1127},[516,26687,9868],{"class":1227},[516,26689,9764],{"class":8557},[516,26691,9767],{"class":4733},[516,26693,1894],{"class":1227},[516,26695,26696],{"class":1248},"\"open\"",[516,26698,16525],{"class":4733},[516,26700,1894],{"class":1227},[516,26702,26703],{"class":1248},"\"modal\"",[516,26705,8561],{"class":1227},[516,26707,26708,26710,26712,26715,26717],{"class":518,"line":1134},[516,26709,17730],{"class":1227},[516,26711,11],{"class":8557},[516,26713,26714],{"class":1227},">Modal content, rendered at the end of body\u003C/",[516,26716,11],{"class":8557},[516,26718,8561],{"class":1227},[516,26720,26721,26723,26725,26727,26729,26732,26735,26737],{"class":518,"line":1275},[516,26722,17730],{"class":1227},[516,26724,8569],{"class":8557},[516,26726,8572],{"class":4733},[516,26728,1894],{"class":1227},[516,26730,26731],{"class":1248},"\"open = false\"",[516,26733,26734],{"class":1227},">Close\u003C/",[516,26736,8569],{"class":8557},[516,26738,8561],{"class":1227},[516,26740,26741,26743,26745],{"class":518,"line":1302},[516,26742,9898],{"class":1227},[516,26744,9764],{"class":8557},[516,26746,8561],{"class":1227},[516,26748,26749,26751,26753],{"class":518,"line":1308},[516,26750,9907],{"class":1227},[516,26752,26617],{"class":8557},[516,26754,8561],{"class":1227},[516,26756,26757,26759,26761],{"class":518,"line":1314},[516,26758,8589],{"class":1227},[516,26760,8558],{"class":8557},[516,26762,8561],{"class":1227},[11,26764,26765,26766,26769,26770,26772],{},"The modal's markup physically lives at the end of ",[66,26767,26768],{},"\u003Cbody>"," in the actual DOM, avoiding any ancestor's clipping or stacking issues, but ",[66,26771,4183],{}," and the click handlers still belong to this component exactly as if it weren't teleported.",[23,26774,26776,26777,26780,26781,26783],{"id":26775},"_132-what-is-suspense-and-how-do-you-use-it-with-an-async-setup-or-async-component","132. What is ",[66,26778,26779],{},"Suspense",", and how do you use it with an async ",[66,26782,9351],{}," or async component?",[11,26785,26786,26788],{},[66,26787,26779],{}," is a built-in component that lets you show fallback content while one or more async dependencies in its child tree are still resolving, then automatically swaps to the real content once everything is ready. It's Vue's way of handling \"this part of the tree needs to wait for a promise\" declaratively, instead of manually tracking loading flags in every component.",[11,26790,26791,26792,26794,26795,26797,26798,26800,26801,26803],{},"A component becomes an async dependency either by using ",[66,26793,25923],{},", or by having a ",[66,26796,8448],{}," with a top-level ",[66,26799,20201],{},", which implicitly makes that component's ",[66,26802,9351],{}," async.",[507,26805,26807],{"className":8546,"code":26806,"language":8548,"meta":512,"style":512},"\u003C!-- UserProfile.vue -->\n\u003Cscript setup>\nconst res = await fetch('/api/user')\nconst user = await res.json()\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cp>{{ user.name }}\u003C/p>\n\u003C/template>\n",[66,26808,26809,26814,26824,26845,26861,26869,26873,26881,26894],{"__ignoreMap":512},[516,26810,26811],{"class":518,"line":519},[516,26812,26813],{"class":3076},"\u003C!-- UserProfile.vue -->\n",[516,26815,26816,26818,26820,26822],{"class":518,"line":525},[516,26817,3042],{"class":1227},[516,26819,8604],{"class":8557},[516,26821,8607],{"class":4733},[516,26823,8561],{"class":1227},[516,26825,26826,26828,26831,26833,26835,26838,26840,26843],{"class":518,"line":531},[516,26827,8632],{"class":1749},[516,26829,26830],{"class":1233}," res",[516,26832,1793],{"class":1749},[516,26834,23477],{"class":1749},[516,26836,26837],{"class":4733}," fetch",[516,26839,8643],{"class":1227},[516,26841,26842],{"class":1248},"'/api/user'",[516,26844,8649],{"class":1227},[516,26846,26847,26849,26851,26853,26855,26857,26859],{"class":518,"line":1127},[516,26848,8632],{"class":1749},[516,26850,14542],{"class":1233},[516,26852,1793],{"class":1749},[516,26854,23477],{"class":1749},[516,26856,14781],{"class":1227},[516,26858,1220],{"class":4733},[516,26860,13318],{"class":1227},[516,26862,26863,26865,26867],{"class":518,"line":1134},[516,26864,8589],{"class":1227},[516,26866,8604],{"class":8557},[516,26868,8561],{"class":1227},[516,26870,26871],{"class":518,"line":1275},[516,26872,1131],{"emptyLinePlaceholder":1130},[516,26874,26875,26877,26879],{"class":518,"line":1302},[516,26876,3042],{"class":1227},[516,26878,8558],{"class":8557},[516,26880,8561],{"class":1227},[516,26882,26883,26885,26887,26890,26892],{"class":518,"line":1308},[516,26884,8566],{"class":1227},[516,26886,11],{"class":8557},[516,26888,26889],{"class":1227},">{{ user.name }}\u003C/",[516,26891,11],{"class":8557},[516,26893,8561],{"class":1227},[516,26895,26896,26898,26900],{"class":518,"line":1314},[516,26897,8589],{"class":1227},[516,26899,8558],{"class":8557},[516,26901,8561],{"class":1227},[507,26903,26905],{"className":8546,"code":26904,"language":8548,"meta":512,"style":512},"\u003C!-- Parent.vue -->\n\u003Ctemplate>\n    \u003CSuspense>\n        \u003Ctemplate #default>\n            \u003CUserProfile />\n        \u003C/template>\n        \u003Ctemplate #fallback>\n            \u003Cp>Loading user...\u003C/p>\n        \u003C/template>\n    \u003C/Suspense>\n\u003C/template>\n",[66,26906,26907,26911,26919,26927,26940,26949,26957,26970,26983,26991,26999],{"__ignoreMap":512},[516,26908,26909],{"class":518,"line":519},[516,26910,16830],{"class":3076},[516,26912,26913,26915,26917],{"class":518,"line":525},[516,26914,3042],{"class":1227},[516,26916,8558],{"class":8557},[516,26918,8561],{"class":1227},[516,26920,26921,26923,26925],{"class":518,"line":531},[516,26922,8566],{"class":1227},[516,26924,26779],{"class":8557},[516,26926,8561],{"class":1227},[516,26928,26929,26931,26933,26935,26938],{"class":518,"line":1127},[516,26930,9868],{"class":1227},[516,26932,8558],{"class":8557},[516,26934,18096],{"class":1227},[516,26936,26937],{"class":4733},"default",[516,26939,8561],{"class":1227},[516,26941,26942,26944,26947],{"class":518,"line":1134},[516,26943,17730],{"class":1227},[516,26945,26946],{"class":8557},"UserProfile",[516,26948,9667],{"class":1227},[516,26950,26951,26953,26955],{"class":518,"line":1275},[516,26952,9898],{"class":1227},[516,26954,8558],{"class":8557},[516,26956,8561],{"class":1227},[516,26958,26959,26961,26963,26965,26968],{"class":518,"line":1302},[516,26960,9868],{"class":1227},[516,26962,8558],{"class":8557},[516,26964,18096],{"class":1227},[516,26966,26967],{"class":4733},"fallback",[516,26969,8561],{"class":1227},[516,26971,26972,26974,26976,26979,26981],{"class":518,"line":1308},[516,26973,17730],{"class":1227},[516,26975,11],{"class":8557},[516,26977,26978],{"class":1227},">Loading user...\u003C/",[516,26980,11],{"class":8557},[516,26982,8561],{"class":1227},[516,26984,26985,26987,26989],{"class":518,"line":1314},[516,26986,9898],{"class":1227},[516,26988,8558],{"class":8557},[516,26990,8561],{"class":1227},[516,26992,26993,26995,26997],{"class":518,"line":8656},[516,26994,9907],{"class":1227},[516,26996,26779],{"class":8557},[516,26998,8561],{"class":1227},[516,27000,27001,27003,27005],{"class":518,"line":8668},[516,27002,8589],{"class":1227},[516,27004,8558],{"class":8557},[516,27006,8561],{"class":1227},[11,27008,27009,27011,27012,27014,27015,27018,27019,27022,27023,27025],{},[66,27010,26779],{}," waits for ",[66,27013,26946],{},"'s async setup to resolve before rendering the ",[66,27016,27017],{},"#default"," slot content, showing ",[66,27020,27021],{},"#fallback"," in the meantime. It's worth noting Vue's own docs still label ",[66,27024,26779],{}," an experimental feature, its API could change in a future minor version, so it's common in interviews but worth using cautiously in production apps that need long-term stability guarantees.",[23,27027,27029],{"id":27028},"_133-what-are-fragments-and-how-did-they-remove-the-single-root-node-restriction-from-vue-2","133. What are Fragments, and how did they remove the \"single root node\" restriction from Vue 2?",[11,27031,27032,27033,27035],{},"A Fragment is Vue's internal representation of a component template that has more than one root-level element. In Vue 2, every component template had to be wrapped in a single root element, because Vue 2's virtual DOM model tied one component to exactly one root vnode; if you needed multiple top-level elements you had to add an artificial wrapper ",[66,27034,16587],{}," just to satisfy the compiler.",[11,27037,27038],{},"Vue 3's virtual DOM and compiler support a component returning an array of vnodes as its root, internally treated as a Fragment. This means a template can look like this without any wrapping element:",[507,27040,27042],{"className":8546,"code":27041,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003Cheader>Title\u003C/header>\n    \u003Cmain>Content\u003C/main>\n    \u003Cfooter>Footer\u003C/footer>\n\u003C/template>\n",[66,27043,27044,27052,27065,27078,27091],{"__ignoreMap":512},[516,27045,27046,27048,27050],{"class":518,"line":519},[516,27047,3042],{"class":1227},[516,27049,8558],{"class":8557},[516,27051,8561],{"class":1227},[516,27053,27054,27056,27058,27061,27063],{"class":518,"line":525},[516,27055,8566],{"class":1227},[516,27057,16620],{"class":8557},[516,27059,27060],{"class":1227},">Title\u003C/",[516,27062,16620],{"class":8557},[516,27064,8561],{"class":1227},[516,27066,27067,27069,27071,27074,27076],{"class":518,"line":531},[516,27068,8566],{"class":1227},[516,27070,16634],{"class":8557},[516,27072,27073],{"class":1227},">Content\u003C/",[516,27075,16634],{"class":8557},[516,27077,8561],{"class":1227},[516,27079,27080,27082,27084,27087,27089],{"class":518,"line":1127},[516,27081,8566],{"class":1227},[516,27083,17557],{"class":8557},[516,27085,27086],{"class":1227},">Footer\u003C/",[516,27088,17557],{"class":8557},[516,27090,8561],{"class":1227},[516,27092,27093,27095,27097],{"class":518,"line":1134},[516,27094,8589],{"class":1227},[516,27096,8558],{"class":8557},[516,27098,8561],{"class":1227},[11,27100,27101,27102,27104,27105,27107,27108,27111],{},"This removes a common source of unnecessary wrapper ",[66,27103,16587],{},"s that used to exist purely to satisfy Vue 2's constraint, which is especially useful for layout components, table rows, or list items where an extra wrapper element would break CSS layout (like inserting a ",[66,27106,16587],{}," between ",[66,27109,27110],{},"\u003Ctr>"," elements).",[11,27113,27114,27115,27117,27118,405],{},"One practical side effect: attribute inheritance (\"fallthrough attributes\") is ambiguous with multiple roots, since Vue doesn't know which root element should receive attributes passed from the parent. Vue 3 will warn if you have multiple roots and don't explicitly bind ",[66,27116,10877],{}," to one of them or set ",[66,27119,16420],{},[23,27121,27123],{"id":27122},"_134-what-is-the-virtual-dom-and-how-does-vue-use-it-to-update-the-real-dom-efficiently","134. What is the Virtual DOM, and how does Vue use it to update the real DOM efficiently?",[11,27125,27126],{},"The Virtual DOM is a lightweight, in-memory tree of plain JavaScript objects (vnodes) that mirrors the structure of the real DOM. Instead of a component directly manipulating DOM elements when its data changes, its render function produces a new vnode tree describing what the UI should look like, and Vue compares that tree to the previous one to figure out the minimal set of real DOM operations needed to make the actual page match.",[11,27128,27129],{},[2160,27130],{"alt":27131,"src":27132},"Vue virtual DOM diffing diagram","/post-images/top-150-vuejs-interview-questions/vue-virtual-dom-diffing-diagram.png",[11,27134,27135],{},"The reason this exists at all: real DOM operations (creating elements, inserting nodes, mutating attributes, triggering layout) are relatively expensive because they touch the browser's rendering engine, while creating and comparing JavaScript objects in memory is cheap. By batching and minimizing actual DOM writes, Vue avoids repeated expensive operations like reflow and repaint that would happen if you mutated the DOM directly on every small change.",[11,27137,27138],{},"It's worth knowing that Vue 3 doesn't rely purely on runtime vnode diffing the way a naive virtual DOM implementation would; the compiler adds patch flags and the block tree so the \"diff\" step already knows what's dynamic and what to skip, before the vnodes are even compared at runtime. The virtual DOM is still the underlying model, but Vue 3 uses compile-time information to make working with it much faster than a generic diff algorithm would be on its own.",[23,27140,27142],{"id":27141},"_135-how-does-vues-diffing-patch-algorithm-decide-what-to-update-in-the-real-dom","135. How does Vue's diffing (patch) algorithm decide what to update in the real DOM?",[11,27144,27145,27146,27148,27149,27151],{},"When patching, Vue first compares the new vnode against the old vnode at the same position: if the element type and ",[66,27147,9991],{}," match, Vue reuses the existing DOM node and only updates what actually differs; if the type or ",[66,27150,9991],{}," differs, Vue tears down the old DOM subtree and mounts a new one rather than trying to reconcile mismatched structures.",[11,27153,27154,27155,27157,27158,27160,27161,27163],{},"For a compiled template, this comparison is guided by patch flags: a vnode flagged ",[66,27156,26068],{}," only has its text content re-checked, one flagged ",[66,27159,26071],{}," only has its class re-checked, and so on, rather than Vue comparing every attribute blindly. Within a block, only the nodes present in that block's ",[66,27162,26193],{}," array get visited at all; static nodes are skipped outright because the compiler already proved they can't change.",[11,27165,27166,27167,27169,27170,27172,27173,27175],{},"For keyed lists (",[66,27168,9833],{},"), Vue runs a specialized algorithm that compares old and new children by their ",[66,27171,9991],{},". It first skips matching nodes at the start and end of both lists (the common case of appending/prepending), then for the remaining middle section it computes the longest increasing subsequence of matched indices, that subsequence represents nodes that are already in the correct relative order and can stay untouched, while everything else gets moved, added, or removed with the minimum number of DOM operations. This is why a stable, unique ",[66,27174,9837],{}," matters so much: without it, Vue can't reliably tell which old node corresponds to which new one, and falls back to less efficient in-place patching that can scramble component state.",[23,27177,27179,27180,202,27182,27184],{"id":27178},"_136-what-are-compiler-macros-like-defineprops-and-defineemits-and-why-dont-you-need-to-import-them","136. What are compiler macros like ",[66,27181,14859],{},[66,27183,15426],{},", and why don't you need to import them?",[11,27186,27187,154,27189,154,27191,154,27193,157,27195,27197,27198,27200,27201,27204,27205,27207,27208,27210],{},[66,27188,14859],{},[66,27190,15426],{},[66,27192,16718],{},[66,27194,16489],{},[66,27196,15188],{}," are compiler macros, special identifiers that only have meaning inside ",[66,27199,8448],{}," and are processed entirely at compile time by the Vue single-file component compiler. They aren't real JavaScript functions with a runtime implementation; when the compiler sees ",[66,27202,27203],{},"defineProps({...})"," in your ",[66,27206,8448],{}," block, it strips that call out and rewrites it into the equivalent of the Options API's ",[66,27209,12679],{}," option on the underlying component definition.",[11,27212,27213,27214,27216,27217,27220],{},"That's exactly why you never import them: importing a macro would imply it's a normal function you call at runtime, but there's nothing to call, the compiler recognizes the identifier by name and transforms the surrounding code before any of it executes in the browser. If you did try to import ",[66,27215,14859],{}," from ",[66,27218,27219],{},"'vue'",", you'd find it isn't even exported as a real function for this purpose, since the whole mechanism depends on static, compile-time analysis of your source code.",[507,27222,27224],{"className":8546,"code":27223,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nconst props = defineProps({\n    title: { type: String, required: true },\n})\n\nconst emit = defineEmits(['update', 'close'])\n\u003C/script>\n",[66,27225,27226,27236,27248,27257,27261,27265,27287],{"__ignoreMap":512},[516,27227,27228,27230,27232,27234],{"class":518,"line":519},[516,27229,3042],{"class":1227},[516,27231,8604],{"class":8557},[516,27233,8607],{"class":4733},[516,27235,8561],{"class":1227},[516,27237,27238,27240,27242,27244,27246],{"class":518,"line":525},[516,27239,8632],{"class":1749},[516,27241,14882],{"class":1233},[516,27243,1793],{"class":1749},[516,27245,14887],{"class":4733},[516,27247,12910],{"class":1227},[516,27249,27250,27253,27255],{"class":518,"line":531},[516,27251,27252],{"class":1227},"    title: { type: String, required: ",[516,27254,10228],{"class":1233},[516,27256,2435],{"class":1227},[516,27258,27259],{"class":518,"line":1127},[516,27260,11530],{"class":1227},[516,27262,27263],{"class":518,"line":1134},[516,27264,1131],{"emptyLinePlaceholder":1130},[516,27266,27267,27269,27271,27273,27275,27277,27280,27282,27285],{"class":518,"line":1275},[516,27268,8632],{"class":1749},[516,27270,15461],{"class":1233},[516,27272,1793],{"class":1749},[516,27274,15466],{"class":4733},[516,27276,11992],{"class":1227},[516,27278,27279],{"class":1248},"'update'",[516,27281,154],{"class":1227},[516,27283,27284],{"class":1248},"'close'",[516,27286,12006],{"class":1227},[516,27288,27289,27291,27293],{"class":518,"line":1302},[516,27290,8589],{"class":1227},[516,27292,8604],{"class":8557},[516,27294,8561],{"class":1227},[11,27296,27297,27298,27300,27301,27303,27304,2958,27306,27308],{},"This code compiles down to a component with a ",[66,27299,12679],{}," option and an ",[66,27302,15609],{}," option, and ",[66,27305,12679],{},[66,27307,15438],{}," become locally scoped variables bound to that instance, all without any import statement needed.",[23,27310,27312,27313,11199],{"id":27311},"_137-what-is-appconfigglobalproperties-and-when-would-you-use-it","137. What is ",[66,27314,27315],{},"app.config.globalProperties",[11,27317,27318,27320,27321,27323,27324,405],{},[66,27319,27315],{}," is an object where you can attach properties or methods that become available on every component instance in the app, accessed via ",[66,27322,16959],{}," in Options API components. It's the Vue 3 replacement for Vue 2's pattern of assigning things onto ",[66,27325,27326],{},"Vue.prototype",[507,27328,27330],{"className":8782,"code":27329,"language":8784,"meta":512,"style":512},"// main.js\nconst app = createApp(App)\n\napp.config.globalProperties.$http = axios\napp.config.globalProperties.$formatDate = (date) => new Intl.DateTimeFormat('en-US').format(date)\n\napp.mount('#app')\n",[66,27331,27332,27336,27348,27352,27362,27402,27406],{"__ignoreMap":512},[516,27333,27334],{"class":518,"line":519},[516,27335,8791],{"class":3076},[516,27337,27338,27340,27342,27344,27346],{"class":518,"line":525},[516,27339,8632],{"class":1749},[516,27341,8825],{"class":1233},[516,27343,1793],{"class":1749},[516,27345,8830],{"class":4733},[516,27347,8833],{"class":1227},[516,27349,27350],{"class":518,"line":531},[516,27351,1131],{"emptyLinePlaceholder":1130},[516,27353,27354,27357,27359],{"class":518,"line":1127},[516,27355,27356],{"class":1227},"app.config.globalProperties.$http ",[516,27358,1894],{"class":1749},[516,27360,27361],{"class":1227}," axios\n",[516,27363,27364,27367,27370,27372,27374,27377,27379,27381,27383,27386,27389,27391,27394,27396,27399],{"class":518,"line":1134},[516,27365,27366],{"class":1227},"app.config.globalProperties.",[516,27368,27369],{"class":4733},"$formatDate",[516,27371,1793],{"class":1749},[516,27373,734],{"class":1227},[516,27375,27376],{"class":9080},"date",[516,27378,13650],{"class":1227},[516,27380,11036],{"class":1749},[516,27382,14731],{"class":1749},[516,27384,27385],{"class":1227}," Intl.",[516,27387,27388],{"class":4733},"DateTimeFormat",[516,27390,8643],{"class":1227},[516,27392,27393],{"class":1248},"'en-US'",[516,27395,2725],{"class":1227},[516,27397,27398],{"class":4733},"format",[516,27400,27401],{"class":1227},"(date)\n",[516,27403,27404],{"class":518,"line":1275},[516,27405,1131],{"emptyLinePlaceholder":1130},[516,27407,27408,27410,27412,27414,27416],{"class":518,"line":1302},[516,27409,8842],{"class":1227},[516,27411,8845],{"class":4733},[516,27413,8643],{"class":1227},[516,27415,8850],{"class":1248},[516,27417,8649],{"class":1227},[11,27419,27420,27421,27424],{},"It's mainly meant for plugin authors who need to expose something app-wide, like an HTTP client or a translation function, without every component having to import it individually. In Options API components you'd then call ",[66,27422,27423],{},"this.$http.get(...)"," anywhere.",[11,27426,27427,27428,27430,27431,27433,27434,27437,27438,2958,27440,27442],{},"It's less useful, and a bit awkward, in ",[66,27429,8448],{}," code, since there's no ",[66,27432,16959],{},"; you'd have to reach for ",[66,27435,27436],{},"getCurrentInstance().appContext.config.globalProperties",", which the Vue team explicitly discourages outside of internal/advisory use. For Composition API codebases, ",[66,27439,18382],{},[66,27441,18385],{}," or plain composables (exporting a shared instance from a module) are the preferred way to share app-wide functionality, since they're explicit about where a value comes from and work cleanly with TypeScript, unlike global properties which are essentially untyped ambient state.",[23,27444,27446],{"id":27445},"_138-how-do-you-write-and-register-a-custom-vue-plugin","138. How do you write and register a custom Vue plugin?",[11,27448,27449,27450,27453,27454,27456,27457,27459],{},"A Vue plugin is an object with an ",[66,27451,27452],{},"install(app, options)"," function (or, more rarely, just a function itself) that receives the application instance and can use it to add app-wide functionality: global components, custom directives, global properties, or values provided via ",[66,27455,18382],{}," for ",[66,27458,18385],{}," to pick up anywhere in the tree.",[507,27461,27463],{"className":8782,"code":27462,"language":8784,"meta":512,"style":512},"// plugins/toast.js\nexport default {\n    install(app, options = {}) {\n        const duration = options.duration ?? 3000\n\n        app.config.globalProperties.$toast = (message) => {\n            console.log(`[toast, ${duration}ms]:`, message)\n        }\n\n        app.directive('focus', {\n            mounted(el) {\n                el.focus()\n            },\n        })\n\n        app.provide('toastDuration', duration)\n    },\n}\n",[66,27464,27465,27470,27478,27498,27516,27520,27540,27561,27565,27569,27584,27596,27606,27611,27616,27620,27634,27638],{"__ignoreMap":512},[516,27466,27467],{"class":518,"line":519},[516,27468,27469],{"class":3076},"// plugins/toast.js\n",[516,27471,27472,27474,27476],{"class":518,"line":525},[516,27473,9190],{"class":1749},[516,27475,9193],{"class":1749},[516,27477,8713],{"class":1227},[516,27479,27480,27483,27485,27488,27490,27493,27495],{"class":518,"line":531},[516,27481,27482],{"class":4733},"    install",[516,27484,8643],{"class":1227},[516,27486,27487],{"class":9080},"app",[516,27489,154],{"class":1227},[516,27491,27492],{"class":9080},"options",[516,27494,1793],{"class":1749},[516,27496,27497],{"class":1227}," {}) {\n",[516,27499,27500,27502,27505,27507,27510,27513],{"class":518,"line":1127},[516,27501,9207],{"class":1749},[516,27503,27504],{"class":1233}," duration",[516,27506,1793],{"class":1749},[516,27508,27509],{"class":1227}," options.duration ",[516,27511,27512],{"class":1749},"??",[516,27514,27515],{"class":1233}," 3000\n",[516,27517,27518],{"class":518,"line":1134},[516,27519,1131],{"emptyLinePlaceholder":1130},[516,27521,27522,27525,27528,27530,27532,27534,27536,27538],{"class":518,"line":1275},[516,27523,27524],{"class":1227},"        app.config.globalProperties.",[516,27526,27527],{"class":4733},"$toast",[516,27529,1793],{"class":1749},[516,27531,734],{"class":1227},[516,27533,11307],{"class":9080},[516,27535,13650],{"class":1227},[516,27537,11036],{"class":1749},[516,27539,8713],{"class":1227},[516,27541,27542,27545,27547,27549,27552,27555,27558],{"class":518,"line":1302},[516,27543,27544],{"class":1227},"            console.",[516,27546,11517],{"class":4733},[516,27548,8643],{"class":1227},[516,27550,27551],{"class":1248},"`[toast, ${",[516,27553,27554],{"class":1227},"duration",[516,27556,27557],{"class":1248},"}ms]:`",[516,27559,27560],{"class":1227},", message)\n",[516,27562,27563],{"class":518,"line":1308},[516,27564,9240],{"class":1227},[516,27566,27567],{"class":518,"line":1314},[516,27568,1131],{"emptyLinePlaceholder":1130},[516,27570,27571,27574,27577,27579,27582],{"class":518,"line":8656},[516,27572,27573],{"class":1227},"        app.",[516,27575,27576],{"class":4733},"directive",[516,27578,8643],{"class":1227},[516,27580,27581],{"class":1248},"'focus'",[516,27583,23371],{"class":1227},[516,27585,27586,27589,27591,27594],{"class":518,"line":8668},[516,27587,27588],{"class":4733},"            mounted",[516,27590,8643],{"class":1227},[516,27592,27593],{"class":9080},"el",[516,27595,9084],{"class":1227},[516,27597,27598,27601,27604],{"class":518,"line":8677},[516,27599,27600],{"class":1227},"                el.",[516,27602,27603],{"class":4733},"focus",[516,27605,13318],{"class":1227},[516,27607,27608],{"class":518,"line":8682},[516,27609,27610],{"class":1227},"            },\n",[516,27612,27613],{"class":518,"line":8691},[516,27614,27615],{"class":1227},"        })\n",[516,27617,27618],{"class":518,"line":8696},[516,27619,1131],{"emptyLinePlaceholder":1130},[516,27621,27622,27624,27626,27628,27631],{"class":518,"line":8708},[516,27623,27573],{"class":1227},[516,27625,18382],{"class":4733},[516,27627,8643],{"class":1227},[516,27629,27630],{"class":1248},"'toastDuration'",[516,27632,27633],{"class":1227},", duration)\n",[516,27635,27636],{"class":518,"line":8716},[516,27637,14195],{"class":1227},[516,27639,27640],{"class":518,"line":8727},[516,27641,1317],{"class":1227},[11,27643,27644,27645,27648],{},"You register it by calling ",[66,27646,27647],{},"app.use()"," before mounting:",[507,27650,27652],{"className":8782,"code":27651,"language":8784,"meta":512,"style":512},"// main.js\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport ToastPlugin from './plugins/toast'\n\nconst app = createApp(App)\napp.use(ToastPlugin, { duration: 5000 })\napp.mount('#app')\n",[66,27653,27654,27658,27668,27678,27690,27694,27706,27719],{"__ignoreMap":512},[516,27655,27656],{"class":518,"line":519},[516,27657,8791],{"class":3076},[516,27659,27660,27662,27664,27666],{"class":518,"line":525},[516,27661,8614],{"class":1749},[516,27663,8798],{"class":1227},[516,27665,8620],{"class":1749},[516,27667,8623],{"class":1248},[516,27669,27670,27672,27674,27676],{"class":518,"line":531},[516,27671,8614],{"class":1749},[516,27673,8809],{"class":1227},[516,27675,8620],{"class":1749},[516,27677,8814],{"class":1248},[516,27679,27680,27682,27685,27687],{"class":518,"line":1127},[516,27681,8614],{"class":1749},[516,27683,27684],{"class":1227}," ToastPlugin ",[516,27686,8620],{"class":1749},[516,27688,27689],{"class":1248}," './plugins/toast'\n",[516,27691,27692],{"class":518,"line":1134},[516,27693,1131],{"emptyLinePlaceholder":1130},[516,27695,27696,27698,27700,27702,27704],{"class":518,"line":1275},[516,27697,8632],{"class":1749},[516,27699,8825],{"class":1233},[516,27701,1793],{"class":1749},[516,27703,8830],{"class":4733},[516,27705,8833],{"class":1227},[516,27707,27708,27710,27712,27715,27717],{"class":518,"line":1302},[516,27709,8842],{"class":1227},[516,27711,21555],{"class":4733},[516,27713,27714],{"class":1227},"(ToastPlugin, { duration: ",[516,27716,26042],{"class":1233},[516,27718,11494],{"class":1227},[516,27720,27721,27723,27725,27727,27729],{"class":518,"line":1308},[516,27722,8842],{"class":1227},[516,27724,8845],{"class":4733},[516,27726,8643],{"class":1227},[516,27728,8850],{"class":1248},[516,27730,8649],{"class":1227},[11,27732,27733,27735,27736,27739,27740,27743],{},[66,27734,27647],{}," calls the plugin's ",[66,27737,27738],{},"install"," method once, passing the app instance and any options you supply, and Vue tracks which plugins are already installed so calling ",[66,27741,27742],{},"use()"," twice with the same plugin is a no-op.",[23,27745,27747],{"id":27746},"_139-what-is-the-difference-between-a-mixin-and-a-plugin-and-why-are-composables-usually-preferred-over-both-today","139. What is the difference between a mixin and a plugin, and why are composables usually preferred over both today?",[11,27749,27750,27751,27754,27755,27758],{},"A mixin is a plain object of component options (data, methods, lifecycle hooks) that gets merged into a component's own options when you add it to the component's ",[66,27752,27753],{},"mixins"," array. It's meant for sharing logic between individual components. The problem is the merge is implicit: once merged, you can't easily tell whether ",[66,27756,27757],{},"this.someMethod"," came from the component itself or from one of its mixins, and if two mixins define a property with the same name, Vue has to apply merge rules that aren't always obvious. This makes mixins hard to trace and refactor, especially as a codebase grows.",[11,27760,27761],{},"A plugin operates at the app level, not the component level. It's for installing cross-cutting functionality once (global components, directives, global properties, provided values), not for injecting reusable stateful logic into many individual components' internals.",[11,27763,27764,27765,154,27767,20679,27769,27771],{},"A composable is just a plain function that uses Composition API primitives (",[66,27766,9387],{},[66,27768,9012],{},[66,27770,19141],{},") internally and returns whatever reactive state and functions the consuming component needs.",[507,27773,27775],{"className":8782,"code":27774,"language":8784,"meta":512,"style":512},"// composables/useMouse.js\nimport { ref, onMounted, onUnmounted } from 'vue'\n\nexport function useMouse() {\n    const x = ref(0)\n    const y = ref(0)\n\n    function update(event) {\n        x.value = event.pageX\n        y.value = event.pageY\n    }\n\n    onMounted(() => window.addEventListener('mousemove', update))\n    onUnmounted(() => window.removeEventListener('mousemove', update))\n\n    return { x, y }\n}\n",[66,27776,27777,27782,27792,27796,27806,27822,27838,27842,27854,27862,27870,27874,27878,27896,27914,27918,27924],{"__ignoreMap":512},[516,27778,27779],{"class":518,"line":519},[516,27780,27781],{"class":3076},"// composables/useMouse.js\n",[516,27783,27784,27786,27788,27790],{"class":518,"line":525},[516,27785,8614],{"class":1749},[516,27787,21037],{"class":1227},[516,27789,8620],{"class":1749},[516,27791,8623],{"class":1248},[516,27793,27794],{"class":518,"line":531},[516,27795,1131],{"emptyLinePlaceholder":1130},[516,27797,27798,27800,27802,27804],{"class":518,"line":1127},[516,27799,9190],{"class":1749},[516,27801,13287],{"class":1749},[516,27803,21054],{"class":4733},[516,27805,8665],{"class":1227},[516,27807,27808,27810,27812,27814,27816,27818,27820],{"class":518,"line":1134},[516,27809,12611],{"class":1749},[516,27811,21063],{"class":1233},[516,27813,1793],{"class":1749},[516,27815,8640],{"class":4733},[516,27817,8643],{"class":1227},[516,27819,8646],{"class":1233},[516,27821,8649],{"class":1227},[516,27823,27824,27826,27828,27830,27832,27834,27836],{"class":518,"line":1275},[516,27825,12611],{"class":1749},[516,27827,21080],{"class":1233},[516,27829,1793],{"class":1749},[516,27831,8640],{"class":4733},[516,27833,8643],{"class":1227},[516,27835,8646],{"class":1233},[516,27837,8649],{"class":1227},[516,27839,27840],{"class":518,"line":1302},[516,27841,1131],{"emptyLinePlaceholder":1130},[516,27843,27844,27846,27848,27850,27852],{"class":518,"line":1308},[516,27845,12628],{"class":1749},[516,27847,21101],{"class":4733},[516,27849,8643],{"class":1227},[516,27851,21106],{"class":9080},[516,27853,9084],{"class":1227},[516,27855,27856,27858,27860],{"class":518,"line":1314},[516,27857,21113],{"class":1227},[516,27859,1894],{"class":1749},[516,27861,21118],{"class":1227},[516,27863,27864,27866,27868],{"class":518,"line":8656},[516,27865,21123],{"class":1227},[516,27867,1894],{"class":1749},[516,27869,21128],{"class":1227},[516,27871,27872],{"class":518,"line":8668},[516,27873,9253],{"class":1227},[516,27875,27876],{"class":518,"line":8677},[516,27877,1131],{"emptyLinePlaceholder":1130},[516,27879,27880,27882,27884,27886,27888,27890,27892,27894],{"class":518,"line":8682},[516,27881,21141],{"class":4733},[516,27883,11033],{"class":1227},[516,27885,11036],{"class":1749},[516,27887,21148],{"class":1227},[516,27889,21151],{"class":4733},[516,27891,8643],{"class":1227},[516,27893,21156],{"class":1248},[516,27895,21159],{"class":1227},[516,27897,27898,27900,27902,27904,27906,27908,27910,27912],{"class":518,"line":8691},[516,27899,21164],{"class":4733},[516,27901,11033],{"class":1227},[516,27903,11036],{"class":1749},[516,27905,21148],{"class":1227},[516,27907,21173],{"class":4733},[516,27909,8643],{"class":1227},[516,27911,21156],{"class":1248},[516,27913,21159],{"class":1227},[516,27915,27916],{"class":518,"line":8696},[516,27917,1131],{"emptyLinePlaceholder":1130},[516,27919,27920,27922],{"class":518,"line":8708},[516,27921,9089],{"class":1749},[516,27923,21190],{"class":1227},[516,27925,27926],{"class":518,"line":8716},[516,27927,1317],{"class":1227},[507,27929,27931],{"className":8546,"code":27930,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\nimport { useMouse } from './composables/useMouse'\n\nconst { x, y } = useMouse()\n\u003C/script>\n",[66,27932,27933,27943,27954,27958,27978],{"__ignoreMap":512},[516,27934,27935,27937,27939,27941],{"class":518,"line":519},[516,27936,3042],{"class":1227},[516,27938,8604],{"class":8557},[516,27940,8607],{"class":4733},[516,27942,8561],{"class":1227},[516,27944,27945,27947,27949,27951],{"class":518,"line":525},[516,27946,8614],{"class":1749},[516,27948,21216],{"class":1227},[516,27950,8620],{"class":1749},[516,27952,27953],{"class":1248}," './composables/useMouse'\n",[516,27955,27956],{"class":518,"line":531},[516,27957,1131],{"emptyLinePlaceholder":1130},[516,27959,27960,27962,27964,27966,27968,27970,27972,27974,27976],{"class":518,"line":1127},[516,27961,8632],{"class":1749},[516,27963,12228],{"class":1227},[516,27965,13035],{"class":1233},[516,27967,154],{"class":1227},[516,27969,21238],{"class":1233},[516,27971,12238],{"class":1227},[516,27973,1894],{"class":1749},[516,27975,21054],{"class":4733},[516,27977,13318],{"class":1227},[516,27979,27980,27982,27984],{"class":518,"line":1134},[516,27981,8589],{"class":1227},[516,27983,8604],{"class":8557},[516,27985,8561],{"class":1227},[11,27987,27988],{},"Composables are preferred because everything is explicit: you can see exactly which values and functions a component pulls in and from where, there's no implicit merging or naming collision since you choose the local variable names yourself (including renaming with destructuring), and TypeScript can infer proper types for the returned values, none of which mixins offer.",[23,27990,27992],{"id":27991},"_140-what-is-a-render-function-and-when-would-you-write-one-instead-of-a-template","140. What is a render function, and when would you write one instead of a template?",[11,27994,27995,27996,27999,28000,28002,28003,28005],{},"A render function is a plain JavaScript (or TypeScript/JSX) function that returns a vnode tree directly, typically using the ",[66,27997,27998],{},"h()"," helper, instead of writing a ",[66,28001,8745],{}," block that Vue's compiler turns into a render function for you automatically. Templates and render functions produce the same underlying thing; a template is just a more constrained, more optimizable syntax that compiles down to calls like ",[66,28004,27998],{}," under the hood.",[507,28007,28009],{"className":8782,"code":28008,"language":8784,"meta":512,"style":512},"import { h, ref } from 'vue'\n\nexport default {\n    setup() {\n        const count = ref(0)\n        return () => h('button', { onClick: () => count.value++ }, `Count: ${count.value}`)\n    },\n}\n",[66,28010,28011,28022,28026,28034,28040,28056,28102,28106],{"__ignoreMap":512},[516,28012,28013,28015,28018,28020],{"class":518,"line":519},[516,28014,8614],{"class":1749},[516,28016,28017],{"class":1227}," { h, ref } ",[516,28019,8620],{"class":1749},[516,28021,8623],{"class":1248},[516,28023,28024],{"class":518,"line":525},[516,28025,1131],{"emptyLinePlaceholder":1130},[516,28027,28028,28030,28032],{"class":518,"line":531},[516,28029,9190],{"class":1749},[516,28031,9193],{"class":1749},[516,28033,8713],{"class":1227},[516,28035,28036,28038],{"class":518,"line":1127},[516,28037,9200],{"class":4733},[516,28039,8665],{"class":1227},[516,28041,28042,28044,28046,28048,28050,28052,28054],{"class":518,"line":1134},[516,28043,9207],{"class":1749},[516,28045,8635],{"class":1233},[516,28047,1793],{"class":1749},[516,28049,8640],{"class":4733},[516,28051,8643],{"class":1227},[516,28053,8646],{"class":1233},[516,28055,8649],{"class":1227},[516,28057,28058,28060,28063,28065,28067,28069,28072,28074,28077,28079,28081,28084,28086,28089,28092,28094,28096,28098,28100],{"class":518,"line":1275},[516,28059,9245],{"class":1749},[516,28061,28062],{"class":1227}," () ",[516,28064,11036],{"class":1749},[516,28066,9092],{"class":4733},[516,28068,8643],{"class":1227},[516,28070,28071],{"class":1248},"'button'",[516,28073,20878],{"class":1227},[516,28075,28076],{"class":4733},"onClick",[516,28078,15378],{"class":1227},[516,28080,11036],{"class":1749},[516,28082,28083],{"class":1227}," count.value",[516,28085,11542],{"class":1749},[516,28087,28088],{"class":1227}," }, ",[516,28090,28091],{"class":1248},"`Count: ${",[516,28093,12231],{"class":1227},[516,28095,405],{"class":1248},[516,28097,12995],{"class":1227},[516,28099,14760],{"class":1248},[516,28101,8649],{"class":1227},[516,28103,28104],{"class":518,"line":1302},[516,28105,14195],{"class":1227},[516,28107,28108],{"class":518,"line":1308},[516,28109,1317],{"class":1227},[11,28111,28112,28113,2958,28115,28117],{},"You'd reach for a render function when the logic you need to express doesn't map cleanly onto template directives, for example: a component that recursively renders itself with structure determined by deeply dynamic data, a component library helper that needs to generate arbitrary combinations of elements based on runtime configuration, or functional/renderless components where a template would need awkward, deeply nested ",[66,28114,9724],{},[66,28116,9833],{}," chains that are clearer as plain JavaScript control flow (loops, conditionals, array methods).",[11,28119,28120],{},"The trade-off is that render functions lose the compiler-level optimizations templates get for free, static hoisting and patch flags rely on the compiler statically analyzing a template's structure, which it can't do for arbitrary hand-written JavaScript. For the vast majority of components, templates are more readable and already fast enough, so render functions stay a tool for specific, more advanced cases rather than a default approach.",[18,28122,28124],{"id":28123},"testing-vue-applications","Testing Vue Applications",[23,28126,28128,28129,202,28131,9728],{"id":28127},"_141-what-is-vue-test-utils-and-what-is-the-difference-between-mount-and-shallowmount","141. What is Vue Test Utils, and what is the difference between ",[66,28130,8845],{},[66,28132,28133],{},"shallowMount",[11,28135,28136,28137,28140,28141,154,28144,157,28147,28150,28151,28153],{},"Vue Test Utils is the official low level library for testing Vue components. It renders a component outside of a real browser and gives you a ",[66,28138,28139],{},"wrapper"," object with helpers like ",[66,28142,28143],{},"wrapper.find()",[66,28145,28146],{},"wrapper.text()",[66,28148,28149],{},"wrapper.trigger()"," to inspect and interact with it. It's almost always paired with Vitest as the test runner, since Vitest reuses your Vite config and already knows how to process ",[66,28152,8502],{}," files.",[11,28155,28156,28157,202,28159,28161,28162,28164,28165,28167],{},"The difference between ",[66,28158,8845],{},[66,28160,28133],{}," is how child components are handled. ",[66,28163,8845],{}," renders the component and every child component fully, so you get a real, complete DOM tree. ",[66,28166,28133],{}," renders only the component under test and replaces every child component with a simple stub element, so a bug in a child never breaks a test for the parent.",[507,28169,28171],{"className":8782,"code":28170,"language":8784,"meta":512,"style":512},"import { mount, shallowMount } from '@vue/test-utils'\nimport UserCard from './UserCard.vue'\n\nconst full = mount(UserCard, { props: { name: 'Ada' } })\nconst shallow = shallowMount(UserCard, { props: { name: 'Ada' } })\n",[66,28172,28173,28185,28197,28201,28220],{"__ignoreMap":512},[516,28174,28175,28177,28180,28182],{"class":518,"line":519},[516,28176,8614],{"class":1749},[516,28178,28179],{"class":1227}," { mount, shallowMount } ",[516,28181,8620],{"class":1749},[516,28183,28184],{"class":1248}," '@vue/test-utils'\n",[516,28186,28187,28189,28192,28194],{"class":518,"line":525},[516,28188,8614],{"class":1749},[516,28190,28191],{"class":1227}," UserCard ",[516,28193,8620],{"class":1749},[516,28195,28196],{"class":1248}," './UserCard.vue'\n",[516,28198,28199],{"class":518,"line":531},[516,28200,1131],{"emptyLinePlaceholder":1130},[516,28202,28203,28205,28208,28210,28213,28216,28218],{"class":518,"line":1127},[516,28204,8632],{"class":1749},[516,28206,28207],{"class":1233}," full",[516,28209,1793],{"class":1749},[516,28211,28212],{"class":4733}," mount",[516,28214,28215],{"class":1227},"(UserCard, { props: { name: ",[516,28217,14119],{"class":1248},[516,28219,12756],{"class":1227},[516,28221,28222,28224,28227,28229,28232,28234,28236],{"class":518,"line":1134},[516,28223,8632],{"class":1749},[516,28225,28226],{"class":1233}," shallow",[516,28228,1793],{"class":1749},[516,28230,28231],{"class":4733}," shallowMount",[516,28233,28215],{"class":1227},[516,28235,14119],{"class":1248},[516,28237,12756],{"class":1227},[11,28239,28240,28242,28243,28245],{},[66,28241,8845],{}," is the better default for most tests because it verifies real parent-child integration. ",[66,28244,28133],{}," is worth reaching for when a child is heavy, slow, or genuinely irrelevant to what you're testing, such as a chart library or a rich text editor.",[23,28247,28249],{"id":28248},"_142-how-do-you-simulate-a-user-interaction-in-a-test-and-assert-that-a-component-emitted-an-event","142. How do you simulate a user interaction in a test and assert that a component emitted an event?",[11,28251,28252,28253,28256,28257,28259,28260,28262],{},"Vue Test Utils simulates interactions with ",[66,28254,28255],{},"wrapper.trigger(eventName)",", which fires a native DOM event (click, input, submit, and so on) on an element you've already found with ",[66,28258,28143],{},". Because Vue batches DOM updates, you should ",[66,28261,20201],{}," the trigger call so the component has a chance to react before your assertions run.",[11,28264,28265,28266,28269],{},"To check what a component emitted, use ",[66,28267,28268],{},"wrapper.emitted()",". It returns an object keyed by event name, where each value is an array of the arguments passed to every emit of that event.",[507,28271,28273],{"className":8546,"code":28272,"language":8548,"meta":512,"style":512},"\u003C!-- LikeButton.vue -->\n\u003Cscript setup>\nconst emit = defineEmits(['like'])\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cbutton @click=\"emit('like')\">Like\u003C/button>\n\u003C/template>\n",[66,28274,28275,28280,28290,28307,28315,28319,28327,28347],{"__ignoreMap":512},[516,28276,28277],{"class":518,"line":519},[516,28278,28279],{"class":3076},"\u003C!-- LikeButton.vue -->\n",[516,28281,28282,28284,28286,28288],{"class":518,"line":525},[516,28283,3042],{"class":1227},[516,28285,8604],{"class":8557},[516,28287,8607],{"class":4733},[516,28289,8561],{"class":1227},[516,28291,28292,28294,28296,28298,28300,28302,28305],{"class":518,"line":531},[516,28293,8632],{"class":1749},[516,28295,15461],{"class":1233},[516,28297,1793],{"class":1749},[516,28299,15466],{"class":4733},[516,28301,11992],{"class":1227},[516,28303,28304],{"class":1248},"'like'",[516,28306,12006],{"class":1227},[516,28308,28309,28311,28313],{"class":518,"line":1127},[516,28310,8589],{"class":1227},[516,28312,8604],{"class":8557},[516,28314,8561],{"class":1227},[516,28316,28317],{"class":518,"line":1134},[516,28318,1131],{"emptyLinePlaceholder":1130},[516,28320,28321,28323,28325],{"class":518,"line":1275},[516,28322,3042],{"class":1227},[516,28324,8558],{"class":8557},[516,28326,8561],{"class":1227},[516,28328,28329,28331,28333,28335,28337,28340,28343,28345],{"class":518,"line":1302},[516,28330,8566],{"class":1227},[516,28332,8569],{"class":8557},[516,28334,8572],{"class":4733},[516,28336,1894],{"class":1227},[516,28338,28339],{"class":1248},"\"emit('like')\"",[516,28341,28342],{"class":1227},">Like\u003C/",[516,28344,8569],{"class":8557},[516,28346,8561],{"class":1227},[516,28348,28349,28351,28353],{"class":518,"line":1308},[516,28350,8589],{"class":1227},[516,28352,8558],{"class":8557},[516,28354,8561],{"class":1227},[507,28356,28358],{"className":8782,"code":28357,"language":8784,"meta":512,"style":512},"import { mount } from '@vue/test-utils'\nimport { it, expect } from 'vitest'\nimport LikeButton from './LikeButton.vue'\n\nit('emits like when clicked', async () => {\n    const wrapper = mount(LikeButton)\n\n    await wrapper.find('button').trigger('click')\n\n    expect(wrapper.emitted()).toHaveProperty('like')\n    expect(wrapper.emitted('like')).toHaveLength(1)\n})\n",[66,28359,28360,28371,28383,28395,28399,28419,28433,28437,28463,28467,28490,28514],{"__ignoreMap":512},[516,28361,28362,28364,28367,28369],{"class":518,"line":519},[516,28363,8614],{"class":1749},[516,28365,28366],{"class":1227}," { mount } ",[516,28368,8620],{"class":1749},[516,28370,28184],{"class":1248},[516,28372,28373,28375,28378,28380],{"class":518,"line":525},[516,28374,8614],{"class":1749},[516,28376,28377],{"class":1227}," { it, expect } ",[516,28379,8620],{"class":1749},[516,28381,28382],{"class":1248}," 'vitest'\n",[516,28384,28385,28387,28390,28392],{"class":518,"line":531},[516,28386,8614],{"class":1749},[516,28388,28389],{"class":1227}," LikeButton ",[516,28391,8620],{"class":1749},[516,28393,28394],{"class":1248}," './LikeButton.vue'\n",[516,28396,28397],{"class":518,"line":1127},[516,28398,1131],{"emptyLinePlaceholder":1130},[516,28400,28401,28404,28406,28409,28411,28413,28415,28417],{"class":518,"line":1134},[516,28402,28403],{"class":4733},"it",[516,28405,8643],{"class":1227},[516,28407,28408],{"class":1248},"'emits like when clicked'",[516,28410,154],{"class":1227},[516,28412,13284],{"class":1749},[516,28414,28062],{"class":1227},[516,28416,11036],{"class":1749},[516,28418,8713],{"class":1227},[516,28420,28421,28423,28426,28428,28430],{"class":518,"line":1275},[516,28422,12611],{"class":1749},[516,28424,28425],{"class":1233}," wrapper",[516,28427,1793],{"class":1749},[516,28429,28212],{"class":4733},[516,28431,28432],{"class":1227},"(LikeButton)\n",[516,28434,28435],{"class":518,"line":1302},[516,28436,1131],{"emptyLinePlaceholder":1130},[516,28438,28439,28441,28444,28447,28449,28451,28453,28456,28458,28461],{"class":518,"line":1308},[516,28440,13312],{"class":1749},[516,28442,28443],{"class":1227}," wrapper.",[516,28445,28446],{"class":4733},"find",[516,28448,8643],{"class":1227},[516,28450,28071],{"class":1248},[516,28452,2725],{"class":1227},[516,28454,28455],{"class":4733},"trigger",[516,28457,8643],{"class":1227},[516,28459,28460],{"class":1248},"'click'",[516,28462,8649],{"class":1227},[516,28464,28465],{"class":518,"line":1314},[516,28466,1131],{"emptyLinePlaceholder":1130},[516,28468,28469,28472,28475,28478,28481,28484,28486,28488],{"class":518,"line":8656},[516,28470,28471],{"class":4733},"    expect",[516,28473,28474],{"class":1227},"(wrapper.",[516,28476,28477],{"class":4733},"emitted",[516,28479,28480],{"class":1227},"()).",[516,28482,28483],{"class":4733},"toHaveProperty",[516,28485,8643],{"class":1227},[516,28487,28304],{"class":1248},[516,28489,8649],{"class":1227},[516,28491,28492,28494,28496,28498,28500,28502,28505,28508,28510,28512],{"class":518,"line":8668},[516,28493,28471],{"class":4733},[516,28495,28474],{"class":1227},[516,28497,28477],{"class":4733},[516,28499,8643],{"class":1227},[516,28501,28304],{"class":1248},[516,28503,28504],{"class":1227},")).",[516,28506,28507],{"class":4733},"toHaveLength",[516,28509,8643],{"class":1227},[516,28511,9945],{"class":1233},[516,28513,8649],{"class":1227},[516,28515,28516],{"class":518,"line":8677},[516,28517,11530],{"class":1227},[11,28519,28520,28521,28523,28524,28526],{},"A common gotcha is forgetting the ",[66,28522,20201],{}," before ",[66,28525,28455],{},", which can lead to assertions running before Vue has finished processing the event.",[23,28528,28530],{"id":28529},"_143-how-do-you-unit-test-a-composable-in-isolation-from-any-component","143. How do you unit test a composable in isolation from any component?",[11,28532,28533,28534,154,28536,154,28538,28540,28541,28543],{},"A composable is just a function built on top of Vue's reactivity primitives (",[66,28535,9387],{},[66,28537,9012],{},[66,28539,13396],{},", and so on), so if it doesn't rely on lifecycle hooks or ",[66,28542,18385],{},", you can call it directly in a test like any other function, no component or mounting required.",[507,28545,28547],{"className":8782,"code":28546,"language":8784,"meta":512,"style":512},"// useCounter.js\nimport { ref } from 'vue'\n\nexport function useCounter(initial = 0) {\n    const count = ref(initial)\n    function increment() {\n        count.value++\n    }\n    return { count, increment }\n}\n",[66,28548,28549,28554,28564,28568,28587,28600,28608,28614,28618,28624],{"__ignoreMap":512},[516,28550,28551],{"class":518,"line":519},[516,28552,28553],{"class":3076},"// useCounter.js\n",[516,28555,28556,28558,28560,28562],{"class":518,"line":525},[516,28557,8614],{"class":1749},[516,28559,8617],{"class":1227},[516,28561,8620],{"class":1749},[516,28563,8623],{"class":1248},[516,28565,28566],{"class":518,"line":531},[516,28567,1131],{"emptyLinePlaceholder":1130},[516,28569,28570,28572,28574,28576,28578,28581,28583,28585],{"class":518,"line":1127},[516,28571,9190],{"class":1749},[516,28573,13287],{"class":1749},[516,28575,12604],{"class":4733},[516,28577,8643],{"class":1227},[516,28579,28580],{"class":9080},"initial",[516,28582,1793],{"class":1749},[516,28584,12037],{"class":1233},[516,28586,9084],{"class":1227},[516,28588,28589,28591,28593,28595,28597],{"class":518,"line":1134},[516,28590,12611],{"class":1749},[516,28592,8635],{"class":1233},[516,28594,1793],{"class":1749},[516,28596,8640],{"class":4733},[516,28598,28599],{"class":1227},"(initial)\n",[516,28601,28602,28604,28606],{"class":518,"line":1275},[516,28603,12628],{"class":1749},[516,28605,8662],{"class":4733},[516,28607,8665],{"class":1227},[516,28609,28610,28612],{"class":518,"line":1302},[516,28611,23294],{"class":1227},[516,28613,8674],{"class":1749},[516,28615,28616],{"class":518,"line":1308},[516,28617,9253],{"class":1227},[516,28619,28620,28622],{"class":518,"line":1314},[516,28621,9089],{"class":1749},[516,28623,9248],{"class":1227},[516,28625,28626],{"class":518,"line":8656},[516,28627,1317],{"class":1227},[507,28629,28631],{"className":8782,"code":28630,"language":8784,"meta":512,"style":512},"import { it, expect } from 'vitest'\nimport { useCounter } from './useCounter'\n\nit('increments count', () => {\n    const { count, increment } = useCounter(5)\n    increment()\n    expect(count.value).toBe(6)\n})\n",[66,28632,28633,28643,28655,28659,28674,28700,28707,28724],{"__ignoreMap":512},[516,28634,28635,28637,28639,28641],{"class":518,"line":519},[516,28636,8614],{"class":1749},[516,28638,28377],{"class":1227},[516,28640,8620],{"class":1749},[516,28642,28382],{"class":1248},[516,28644,28645,28647,28650,28652],{"class":518,"line":525},[516,28646,8614],{"class":1749},[516,28648,28649],{"class":1227}," { useCounter } ",[516,28651,8620],{"class":1749},[516,28653,28654],{"class":1248}," './useCounter'\n",[516,28656,28657],{"class":518,"line":531},[516,28658,1131],{"emptyLinePlaceholder":1130},[516,28660,28661,28663,28665,28668,28670,28672],{"class":518,"line":1127},[516,28662,28403],{"class":4733},[516,28664,8643],{"class":1227},[516,28666,28667],{"class":1248},"'increments count'",[516,28669,23234],{"class":1227},[516,28671,11036],{"class":1749},[516,28673,8713],{"class":1227},[516,28675,28676,28678,28680,28682,28684,28687,28689,28691,28693,28695,28698],{"class":518,"line":1134},[516,28677,12611],{"class":1749},[516,28679,12228],{"class":1227},[516,28681,12231],{"class":1233},[516,28683,154],{"class":1227},[516,28685,28686],{"class":1233},"increment",[516,28688,12238],{"class":1227},[516,28690,1894],{"class":1749},[516,28692,12604],{"class":4733},[516,28694,8643],{"class":1227},[516,28696,28697],{"class":1233},"5",[516,28699,8649],{"class":1227},[516,28701,28702,28705],{"class":518,"line":1275},[516,28703,28704],{"class":4733},"    increment",[516,28706,13318],{"class":1227},[516,28708,28709,28711,28714,28717,28719,28722],{"class":518,"line":1302},[516,28710,28471],{"class":4733},[516,28712,28713],{"class":1227},"(count.value).",[516,28715,28716],{"class":4733},"toBe",[516,28718,8643],{"class":1227},[516,28720,28721],{"class":1233},"6",[516,28723,8649],{"class":1227},[516,28725,28726],{"class":518,"line":1308},[516,28727,11530],{"class":1227},[11,28729,28730,28731,28733,28734,2958,28736,28738,28739,28741,28742,28745],{},"If a composable does depend on lifecycle hooks like ",[66,28732,19141],{},", or on ",[66,28735,18382],{},[66,28737,18385],{},", it needs a component instance to run inside. The usual approach is to mount a small throwaway component whose ",[66,28740,9351],{}," just calls the composable, then assert against what it exposes, either through the returned template refs or by exposing values via ",[66,28743,28744],{},"expose()",". This keeps the test focused on the composable's logic while still giving Vue a valid instance to attach the lifecycle hooks to.",[23,28747,28749],{"id":28748},"_144-how-do-you-mock-vue-router-or-a-pinia-store-inside-a-component-test","144. How do you mock Vue Router or a Pinia store inside a component test?",[11,28751,28752,28753,27216,28756,28759,28760,28763],{},"For Pinia, the recommended approach is ",[66,28754,28755],{},"createTestingPinia",[66,28757,28758],{},"@pinia/testing",". It creates a real Pinia instance but automatically replaces every store action with a spy (so no real logic or network calls run) and lets you seed ",[66,28761,28762],{},"initialState"," directly, so a component reading from a store doesn't need the store's actual implementation to be correct.",[507,28765,28767],{"className":8782,"code":28766,"language":8784,"meta":512,"style":512},"import { mount } from '@vue/test-utils'\nimport { createTestingPinia } from '@pinia/testing'\nimport UserProfile from './UserProfile.vue'\n\nconst wrapper = mount(UserProfile, {\n    global: {\n        plugins: [createTestingPinia({\n            initialState: { user: { name: 'Ada' } },\n        })],\n    },\n})\n",[66,28768,28769,28779,28791,28803,28807,28820,28825,28834,28844,28849,28853],{"__ignoreMap":512},[516,28770,28771,28773,28775,28777],{"class":518,"line":519},[516,28772,8614],{"class":1749},[516,28774,28366],{"class":1227},[516,28776,8620],{"class":1749},[516,28778,28184],{"class":1248},[516,28780,28781,28783,28786,28788],{"class":518,"line":525},[516,28782,8614],{"class":1749},[516,28784,28785],{"class":1227}," { createTestingPinia } ",[516,28787,8620],{"class":1749},[516,28789,28790],{"class":1248}," '@pinia/testing'\n",[516,28792,28793,28795,28798,28800],{"class":518,"line":531},[516,28794,8614],{"class":1749},[516,28796,28797],{"class":1227}," UserProfile ",[516,28799,8620],{"class":1749},[516,28801,28802],{"class":1248}," './UserProfile.vue'\n",[516,28804,28805],{"class":518,"line":1127},[516,28806,1131],{"emptyLinePlaceholder":1130},[516,28808,28809,28811,28813,28815,28817],{"class":518,"line":1134},[516,28810,8632],{"class":1749},[516,28812,28425],{"class":1233},[516,28814,1793],{"class":1749},[516,28816,28212],{"class":4733},[516,28818,28819],{"class":1227},"(UserProfile, {\n",[516,28821,28822],{"class":518,"line":1275},[516,28823,28824],{"class":1227},"    global: {\n",[516,28826,28827,28830,28832],{"class":518,"line":1302},[516,28828,28829],{"class":1227},"        plugins: [",[516,28831,28755],{"class":4733},[516,28833,12910],{"class":1227},[516,28835,28836,28839,28841],{"class":518,"line":1308},[516,28837,28838],{"class":1227},"            initialState: { user: { name: ",[516,28840,14119],{"class":1248},[516,28842,28843],{"class":1227}," } },\n",[516,28845,28846],{"class":518,"line":1314},[516,28847,28848],{"class":1227},"        })],\n",[516,28850,28851],{"class":518,"line":8656},[516,28852,14195],{"class":1227},[516,28854,28855],{"class":518,"line":8668},[516,28856,11530],{"class":1227},[11,28858,28859,28860,28863,28864,2958,28867,28870],{},"For Vue Router, the cleanest option is to install a real router built with ",[66,28861,28862],{},"createMemoryHistory"," (rather than a browser history), pushed to whatever route the test needs, then passed in as a global plugin. This gives you real ",[66,28865,28866],{},"$route",[66,28868,28869],{},"$router"," behavior without a browser.",[507,28872,28874],{"className":8782,"code":28873,"language":8784,"meta":512,"style":512},"import { createRouter, createMemoryHistory } from 'vue-router'\nimport { mount } from '@vue/test-utils'\n\nconst router = createRouter({\n    history: createMemoryHistory(),\n    routes: [{ path: '/', component: Home }, { path: '/about', component: About }],\n})\n\nrouter.push('/about')\nawait router.isReady()\n\nconst wrapper = mount(App, {\n    global: { plugins: [router] },\n})\n",[66,28875,28876,28887,28897,28901,28913,28921,28936,28940,28944,28956,28968,28972,28985,28990],{"__ignoreMap":512},[516,28877,28878,28880,28883,28885],{"class":518,"line":519},[516,28879,8614],{"class":1749},[516,28881,28882],{"class":1227}," { createRouter, createMemoryHistory } ",[516,28884,8620],{"class":1749},[516,28886,21384],{"class":1248},[516,28888,28889,28891,28893,28895],{"class":518,"line":525},[516,28890,8614],{"class":1749},[516,28892,28366],{"class":1227},[516,28894,8620],{"class":1749},[516,28896,28184],{"class":1248},[516,28898,28899],{"class":518,"line":531},[516,28900,1131],{"emptyLinePlaceholder":1130},[516,28902,28903,28905,28907,28909,28911],{"class":518,"line":1127},[516,28904,8632],{"class":1749},[516,28906,21460],{"class":1233},[516,28908,1793],{"class":1749},[516,28910,21465],{"class":4733},[516,28912,12910],{"class":1227},[516,28914,28915,28917,28919],{"class":518,"line":1134},[516,28916,21472],{"class":1227},[516,28918,28862],{"class":4733},[516,28920,21478],{"class":1227},[516,28922,28923,28926,28928,28931,28933],{"class":518,"line":1275},[516,28924,28925],{"class":1227},"    routes: [{ path: ",[516,28927,21432],{"class":1248},[516,28929,28930],{"class":1227},", component: Home }, { path: ",[516,28932,21442],{"class":1248},[516,28934,28935],{"class":1227},", component: About }],\n",[516,28937,28938],{"class":518,"line":1302},[516,28939,11530],{"class":1227},[516,28941,28942],{"class":518,"line":1308},[516,28943,1131],{"emptyLinePlaceholder":1130},[516,28945,28946,28948,28950,28952,28954],{"class":518,"line":1314},[516,28947,22199],{"class":1227},[516,28949,11930],{"class":4733},[516,28951,8643],{"class":1227},[516,28953,21442],{"class":1248},[516,28955,8649],{"class":1227},[516,28957,28958,28960,28963,28966],{"class":518,"line":8656},[516,28959,20201],{"class":1749},[516,28961,28962],{"class":1227}," router.",[516,28964,28965],{"class":4733},"isReady",[516,28967,13318],{"class":1227},[516,28969,28970],{"class":518,"line":8668},[516,28971,1131],{"emptyLinePlaceholder":1130},[516,28973,28974,28976,28978,28980,28982],{"class":518,"line":8677},[516,28975,8632],{"class":1749},[516,28977,28425],{"class":1233},[516,28979,1793],{"class":1749},[516,28981,28212],{"class":4733},[516,28983,28984],{"class":1227},"(App, {\n",[516,28986,28987],{"class":518,"line":8682},[516,28988,28989],{"class":1227},"    global: { plugins: [router] },\n",[516,28991,28992],{"class":518,"line":8691},[516,28993,11530],{"class":1227},[11,28995,28996,28997,29000,29001,29003,29004,405],{},"For simpler cases where a component just reads ",[66,28998,28999],{},"route.params"," or calls ",[66,29002,22846],{},", you can skip a real router entirely and provide lightweight mocks through ",[66,29005,29006],{},"global.mocks",[23,29008,29010],{"id":29009},"_145-what-is-snapshot-testing-and-what-are-its-tradeoffs-for-vue-components","145. What is snapshot testing, and what are its tradeoffs for Vue components?",[11,29012,29013,29014,29017],{},"Snapshot testing renders a component, serializes its output (usually with ",[66,29015,29016],{},"wrapper.html()","), and saves that output to a file. On later test runs, the current output is compared against the saved snapshot; if anything differs, the test fails and you decide whether the change is an intended update (in which case you update the snapshot) or a real regression.",[507,29019,29021],{"className":8782,"code":29020,"language":8784,"meta":512,"style":512},"import { mount } from '@vue/test-utils'\nimport { it, expect } from 'vitest'\nimport Badge from './Badge.vue'\n\nit('matches snapshot', () => {\n    const wrapper = mount(Badge, { props: { label: 'New' } })\n    expect(wrapper.html()).toMatchSnapshot()\n})\n",[66,29022,29023,29033,29043,29055,29059,29074,29091,29106],{"__ignoreMap":512},[516,29024,29025,29027,29029,29031],{"class":518,"line":519},[516,29026,8614],{"class":1749},[516,29028,28366],{"class":1227},[516,29030,8620],{"class":1749},[516,29032,28184],{"class":1248},[516,29034,29035,29037,29039,29041],{"class":518,"line":525},[516,29036,8614],{"class":1749},[516,29038,28377],{"class":1227},[516,29040,8620],{"class":1749},[516,29042,28382],{"class":1248},[516,29044,29045,29047,29050,29052],{"class":518,"line":531},[516,29046,8614],{"class":1749},[516,29048,29049],{"class":1227}," Badge ",[516,29051,8620],{"class":1749},[516,29053,29054],{"class":1248}," './Badge.vue'\n",[516,29056,29057],{"class":518,"line":1127},[516,29058,1131],{"emptyLinePlaceholder":1130},[516,29060,29061,29063,29065,29068,29070,29072],{"class":518,"line":1134},[516,29062,28403],{"class":4733},[516,29064,8643],{"class":1227},[516,29066,29067],{"class":1248},"'matches snapshot'",[516,29069,23234],{"class":1227},[516,29071,11036],{"class":1749},[516,29073,8713],{"class":1227},[516,29075,29076,29078,29080,29082,29084,29087,29089],{"class":518,"line":1275},[516,29077,12611],{"class":1749},[516,29079,28425],{"class":1233},[516,29081,1793],{"class":1749},[516,29083,28212],{"class":4733},[516,29085,29086],{"class":1227},"(Badge, { props: { label: ",[516,29088,12782],{"class":1248},[516,29090,12756],{"class":1227},[516,29092,29093,29095,29097,29099,29101,29104],{"class":518,"line":1302},[516,29094,28471],{"class":4733},[516,29096,28474],{"class":1227},[516,29098,11326],{"class":4733},[516,29100,28480],{"class":1227},[516,29102,29103],{"class":4733},"toMatchSnapshot",[516,29105,13318],{"class":1227},[516,29107,29108],{"class":518,"line":1308},[516,29109,11530],{"class":1227},[11,29111,29112],{},"The upside is speed: you get regression coverage on markup with almost no test-writing effort, which is handy for stable, mostly presentational components. The tradeoffs are real, though. Snapshots don't test behavior, only output shape, so a snapshot passing tells you nothing about whether an emitted event or a computed value is correct. They also tend to grow stale; developers get into the habit of running the \"update snapshots\" command without carefully reviewing the diff, which defeats the purpose. And snapshots are brittle against unrelated markup changes (a class name tweak fails every snapshot that touches that component) and against dynamic content like generated ids or timestamps, unless you specifically mock or strip those. In practice, snapshot testing works best sparingly, for a handful of stable UI components, alongside explicit assertions on props, emitted events, and text content for anything that actually has logic.",[18,29114,29116],{"id":29115},"server-side-rendering-and-nuxt","Server-Side Rendering and Nuxt",[23,29118,29120],{"id":29119},"_146-what-is-server-side-rendering-ssr-and-what-specific-benefits-does-it-bring-to-a-vue-application","146. What is server-side rendering (SSR), and what specific benefits does it bring to a Vue application?",[11,29122,29123,29124,29127],{},"Server-side rendering means running your Vue component tree on the server for each request and sending the browser a fully formed HTML page, instead of an empty shell that JavaScript fills in later. In a plain client-rendered Vue app, the initial response is close to ",[66,29125,29126],{},"\u003Cdiv id=\"app\">\u003C/div>",", and the user sees nothing meaningful until the JS bundle downloads, parses, and Vue mounts and renders the tree. With SSR, that rendering already happened on the server, so the browser can paint real content immediately.",[11,29129,29130],{},"This brings two concrete benefits. First, faster perceived performance, particularly on slow networks or devices, since there's visible content before any JavaScript has run. Second, better SEO and link-preview support, since crawlers and social media bots that don't execute JavaScript (or execute it poorly) still receive complete HTML. The tradeoff is that the server now has to do rendering work on every request, and the app needs to run in a Node environment, which is part of why Nuxt exists, to handle that server-side rendering setup for you.",[23,29132,29134],{"id":29133},"_147-what-is-nuxt-and-how-does-it-relate-to-vue","147. What is Nuxt, and how does it relate to Vue?",[11,29136,29137,29138,29141,29142,405],{},"Nuxt is the official meta-framework built on top of Vue. Vue itself is just the component and reactivity library; it doesn't dictate how routing, data fetching conventions, server rendering, or deployment work. Nuxt fills in that layer: it adds file-based routing (files in ",[66,29139,29140],{},"pages/"," automatically become routes), auto-imports (components and composables are available without manual import statements), a Nitro server engine that can run API routes and server middleware alongside your app, and hybrid rendering, where you choose per-route whether a page is server-rendered, statically prerendered, or client-rendered, via ",[66,29143,29144],{},"routeRules",[11,29146,29147],{},"A useful analogy: Nuxt is to Vue roughly what Next.js is to React. You could hand-wire Vue Router, Vite, an SSR entry point, and a Node server yourself, but Nuxt packages all of that into sensible conventions so you write pages and components and get routing, SSR, and deployment mostly for free.",[23,29149,29151],{"id":29150},"_148-what-is-hydration-and-what-causes-a-hydration-mismatch-in-an-ssr-vue-app","148. What is hydration, and what causes a hydration mismatch in an SSR Vue app?",[11,29153,29154],{},"Hydration is the process of taking HTML that the server already rendered and making it interactive on the client, without throwing it away and re-rendering from scratch. Vue walks the existing DOM nodes the server produced, matches them up against its virtual DOM tree, and attaches the event listeners and reactive bindings needed to turn static markup into a live, working app. Because it reuses the DOM nodes instead of recreating them, hydration is much cheaper than a full client render.",[11,29156,29157],{},[2160,29158],{"alt":29159,"src":29160},"Vue SSR hydration flow diagram","/post-images/top-150-vuejs-interview-questions/vue-ssr-hydration-flow-diagram.png",[11,29162,29163,29164,154,29166,154,29168,741,29171,29174,29175,29177,29178,29180],{},"A hydration mismatch happens when the HTML Vue expects to produce on the client doesn't match what the server actually sent. The most common cause is using a browser-only API during render, things like ",[66,29165,20049],{},[66,29167,2755],{},[66,29169,29170],{},"Date.now()",[66,29172,29173],{},"Math.random()",", since those produce different values (or throw) on the server versus the client. It can also come from invalid HTML nesting that the browser silently auto-corrects (for example a ",[66,29176,16587],{}," placed inside a ",[66,29179,26182],{},"), which changes the DOM structure the browser hands back versus what the server sent. When Vue detects the mismatch, it warns in the console and, in development, patches the affected DOM to match the client's version, which causes a visible flicker and throws away the performance benefit SSR was supposed to provide for that part of the page.",[507,29182,29184],{"className":8546,"code":29183,"language":8548,"meta":512,"style":512},"\u003Cscript setup>\n// bad: differs between server render and client render\nconst now = Date.now()\n\u003C/script>\n\n\u003Ctemplate>\n    \u003Cp>{{ now }}\u003C/p>\n\u003C/template>\n",[66,29185,29186,29196,29201,29218,29226,29230,29238,29251],{"__ignoreMap":512},[516,29187,29188,29190,29192,29194],{"class":518,"line":519},[516,29189,3042],{"class":1227},[516,29191,8604],{"class":8557},[516,29193,8607],{"class":4733},[516,29195,8561],{"class":1227},[516,29197,29198],{"class":518,"line":525},[516,29199,29200],{"class":3076},"// bad: differs between server render and client render\n",[516,29202,29203,29205,29208,29210,29213,29216],{"class":518,"line":531},[516,29204,8632],{"class":1749},[516,29206,29207],{"class":1233}," now",[516,29209,1793],{"class":1749},[516,29211,29212],{"class":1227}," Date.",[516,29214,29215],{"class":4733},"now",[516,29217,13318],{"class":1227},[516,29219,29220,29222,29224],{"class":518,"line":1127},[516,29221,8589],{"class":1227},[516,29223,8604],{"class":8557},[516,29225,8561],{"class":1227},[516,29227,29228],{"class":518,"line":1134},[516,29229,1131],{"emptyLinePlaceholder":1130},[516,29231,29232,29234,29236],{"class":518,"line":1275},[516,29233,3042],{"class":1227},[516,29235,8558],{"class":8557},[516,29237,8561],{"class":1227},[516,29239,29240,29242,29244,29247,29249],{"class":518,"line":1302},[516,29241,8566],{"class":1227},[516,29243,11],{"class":8557},[516,29245,29246],{"class":1227},">{{ now }}\u003C/",[516,29248,11],{"class":8557},[516,29250,8561],{"class":1227},[516,29252,29253,29255,29257],{"class":518,"line":1308},[516,29254,8589],{"class":1227},[516,29256,8558],{"class":8557},[516,29258,8561],{"class":1227},[11,29260,29261,29262,29264,29265,405],{},"The fix is usually to compute anything environment-dependent inside ",[66,29263,19141],{}," (so it only ever runs on the client) or to wrap that part of the template in ",[66,29266,29267],{},"\u003CClientOnly>",[23,29269,29271,29272,29274],{"id":29270},"_149-what-is-the-clientonly-component-used-for","149. What is the ",[66,29273,29267],{}," component used for?",[11,29276,29277,29279],{},[66,29278,29267],{}," is a Nuxt component that renders its default slot only on the client, and skips it entirely during server-side rendering. It's used for anything that depends on browser-only APIs or assumes a real DOM to work, common examples being chart libraries, rich text editors, or animation libraries that would either throw an error during SSR or produce output that doesn't match what the client renders, causing a hydration mismatch.",[507,29281,29283],{"className":8546,"code":29282,"language":8548,"meta":512,"style":512},"\u003Ctemplate>\n    \u003CClientOnly>\n        \u003CHeavyChart :data=\"chartData\" />\n        \u003Ctemplate #fallback>\n            \u003Cp>Loading chart...\u003C/p>\n        \u003C/template>\n    \u003C/ClientOnly>\n\u003C/template>\n",[66,29284,29285,29293,29302,29319,29331,29344,29352,29360],{"__ignoreMap":512},[516,29286,29287,29289,29291],{"class":518,"line":519},[516,29288,3042],{"class":1227},[516,29290,8558],{"class":8557},[516,29292,8561],{"class":1227},[516,29294,29295,29297,29300],{"class":518,"line":525},[516,29296,8566],{"class":1227},[516,29298,29299],{"class":8557},"ClientOnly",[516,29301,8561],{"class":1227},[516,29303,29304,29306,29309,29312,29314,29317],{"class":518,"line":531},[516,29305,9868],{"class":1227},[516,29307,29308],{"class":8557},"HeavyChart",[516,29310,29311],{"class":4733}," :data",[516,29313,1894],{"class":1227},[516,29315,29316],{"class":1248},"\"chartData\"",[516,29318,9667],{"class":1227},[516,29320,29321,29323,29325,29327,29329],{"class":518,"line":1127},[516,29322,9868],{"class":1227},[516,29324,8558],{"class":8557},[516,29326,18096],{"class":1227},[516,29328,26967],{"class":4733},[516,29330,8561],{"class":1227},[516,29332,29333,29335,29337,29340,29342],{"class":518,"line":1134},[516,29334,17730],{"class":1227},[516,29336,11],{"class":8557},[516,29338,29339],{"class":1227},">Loading chart...\u003C/",[516,29341,11],{"class":8557},[516,29343,8561],{"class":1227},[516,29345,29346,29348,29350],{"class":518,"line":1275},[516,29347,9898],{"class":1227},[516,29349,8558],{"class":8557},[516,29351,8561],{"class":1227},[516,29353,29354,29356,29358],{"class":518,"line":1302},[516,29355,9907],{"class":1227},[516,29357,29299],{"class":8557},[516,29359,8561],{"class":1227},[516,29361,29362,29364,29366],{"class":518,"line":1308},[516,29363,8589],{"class":1227},[516,29365,8558],{"class":8557},[516,29367,8561],{"class":1227},[11,29369,29370,29371,29373],{},"The optional ",[66,29372,27021],{}," slot renders on the server (and briefly on the client before hydration finishes), which lets you show a placeholder instead of leaving an empty gap and avoids layout shift once the real content mounts.",[23,29375,29377,29378,202,29380,29383],{"id":29376},"_150-what-is-the-difference-between-nuxts-usefetch-and-useasyncdata-for-data-fetching","150. What is the difference between Nuxt's ",[66,29379,21330],{},[66,29381,29382],{},"useAsyncData"," for data fetching?",[11,29385,29386,29387,9934,29390,29392,29393,29396],{},"Both are Nuxt composables for fetching data in a way that's SSR-aware: they run during server rendering, serialize the result into the page payload, and skip re-fetching on the client during hydration, avoiding the double-fetch problem you'd get from calling a plain ",[66,29388,29389],{},"fetch",[66,29391,19141],{},". Both also return the same shape, ",[66,29394,29395],{},"{ data, pending, error, refresh }",", and integrate with Nuxt's loading and Suspense handling.",[11,29398,29399,29400,29403,29404,29406,29407,29410],{},"The difference is scope. ",[66,29401,29402],{},"useFetch(url, options)"," is a thin, convenient wrapper around ",[66,29405,29382],{}," plus ",[66,29408,29409],{},"$fetch",", purpose-built for \"call this URL.\" It generates a cache key from the URL and options automatically, so you don't have to think about it.",[11,29412,29413,29416],{},[66,29414,29415],{},"useAsyncData(key, handler)"," is the more general primitive. The handler can be any async function, not just a single URL call, so it's what you reach for when you need to combine multiple requests, call a Pinia store action, or run logic that isn't a plain fetch. You're expected to provide the key yourself.",[507,29418,29420],{"className":8782,"code":29419,"language":8784,"meta":512,"style":512},"// useFetch: shorthand for a single endpoint\nconst { data: posts } = await useFetch('/api/posts')\n\n// useAsyncData: custom or combined logic\nconst { data: dashboard } = await useAsyncData('dashboard', async () => {\n    const [posts, user] = await Promise.all([\n        $fetch('/api/posts'),\n        $fetch('/api/user'),\n    ])\n    return { posts, user }\n})\n",[66,29421,29422,29427,29456,29460,29465,29502,29531,29542,29552,29557,29564],{"__ignoreMap":512},[516,29423,29424],{"class":518,"line":519},[516,29425,29426],{"class":3076},"// useFetch: shorthand for a single endpoint\n",[516,29428,29429,29431,29433,29435,29437,29440,29442,29444,29446,29449,29451,29454],{"class":518,"line":525},[516,29430,8632],{"class":1749},[516,29432,12228],{"class":1227},[516,29434,9006],{"class":9080},[516,29436,1245],{"class":1227},[516,29438,29439],{"class":1233},"posts",[516,29441,12238],{"class":1227},[516,29443,1894],{"class":1749},[516,29445,23477],{"class":1749},[516,29447,29448],{"class":4733}," useFetch",[516,29450,8643],{"class":1227},[516,29452,29453],{"class":1248},"'/api/posts'",[516,29455,8649],{"class":1227},[516,29457,29458],{"class":518,"line":531},[516,29459,1131],{"emptyLinePlaceholder":1130},[516,29461,29462],{"class":518,"line":1127},[516,29463,29464],{"class":3076},"// useAsyncData: custom or combined logic\n",[516,29466,29467,29469,29471,29473,29475,29478,29480,29482,29484,29487,29489,29492,29494,29496,29498,29500],{"class":518,"line":1134},[516,29468,8632],{"class":1749},[516,29470,12228],{"class":1227},[516,29472,9006],{"class":9080},[516,29474,1245],{"class":1227},[516,29476,29477],{"class":1233},"dashboard",[516,29479,12238],{"class":1227},[516,29481,1894],{"class":1749},[516,29483,23477],{"class":1749},[516,29485,29486],{"class":4733}," useAsyncData",[516,29488,8643],{"class":1227},[516,29490,29491],{"class":1248},"'dashboard'",[516,29493,154],{"class":1227},[516,29495,13284],{"class":1749},[516,29497,28062],{"class":1227},[516,29499,11036],{"class":1749},[516,29501,8713],{"class":1227},[516,29503,29504,29506,29508,29510,29512,29515,29517,29519,29521,29524,29526,29528],{"class":518,"line":1275},[516,29505,12611],{"class":1749},[516,29507,14214],{"class":1227},[516,29509,29439],{"class":1233},[516,29511,154],{"class":1227},[516,29513,29514],{"class":1233},"user",[516,29516,12016],{"class":1227},[516,29518,1894],{"class":1749},[516,29520,23477],{"class":1749},[516,29522,29523],{"class":1233}," Promise",[516,29525,405],{"class":1227},[516,29527,598],{"class":4733},[516,29529,29530],{"class":1227},"([\n",[516,29532,29533,29536,29538,29540],{"class":518,"line":1302},[516,29534,29535],{"class":4733},"        $fetch",[516,29537,8643],{"class":1227},[516,29539,29453],{"class":1248},[516,29541,26014],{"class":1227},[516,29543,29544,29546,29548,29550],{"class":518,"line":1308},[516,29545,29535],{"class":4733},[516,29547,8643],{"class":1227},[516,29549,26842],{"class":1248},[516,29551,26014],{"class":1227},[516,29553,29554],{"class":518,"line":1314},[516,29555,29556],{"class":1227},"    ])\n",[516,29558,29559,29561],{"class":518,"line":8656},[516,29560,9089],{"class":1749},[516,29562,29563],{"class":1227}," { posts, user }\n",[516,29565,29566],{"class":518,"line":8668},[516,29567,11530],{"class":1227},[11,29569,29570,29571,29573,29574,29576,29577,29581],{},"A good rule of thumb: reach for ",[66,29572,21330],{}," when you're calling a single API endpoint, and drop down to ",[66,29575,29382],{}," as soon as the fetching logic needs to do more than that. For a closer look at what happens after the server sends that HTML, the ",[761,29578,29580],{"href":29579},"/post/hydration-in-frontend-frameworks","hydration in frontend frameworks"," article covers hydration in more general, framework-agnostic detail.",[18,29583,4860],{"id":4859},[11,29585,29586,29587,29589],{},"These 150 questions cover the bulk of what Vue interviews actually ask, from template basics to the internals of the compiler and the reactivity system. Do not try to memorize every answer word for word. Instead, build a mental model of how Vue actually works: how a ",[66,29588,9387],{}," becomes reactive, why the Composition API exists, how the compiler skips work it does not need to do. Once that model is solid, you can reason through a question you have never seen before instead of freezing because it does not match a memorized script.",[11,29591,4866],{},[4868,29593,29594],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#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 pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":512,"searchDepth":525,"depth":525,"links":29596},[29597,29613,29643,29673,29688,29712,29724,29735,29752,29762,29779,29793,29805,29820,29836,29844,29853],{"id":8457,"depth":525,"text":8458,"children":29598},[29599,29600,29601,29603,29605,29606,29608,29609,29611,29612],{"id":8461,"depth":531,"text":8462},{"id":8478,"depth":531,"text":8479},{"id":8530,"depth":531,"text":29602},"3. What is a Single File Component (.vue file), and what are its three blocks?",{"id":8766,"depth":531,"text":29604},"4. How do you create and mount a Vue application (createApp)?",{"id":8869,"depth":531,"text":8870},{"id":9016,"depth":531,"text":29607},"6. What does the Vue template compiler do to your \u003Ctemplate> block?",{"id":9115,"depth":531,"text":9116},{"id":9141,"depth":531,"text":29610},"8. What is \u003Cscript setup>, and why is it now the recommended way to write components?",{"id":9369,"depth":531,"text":9370},{"id":9456,"depth":531,"text":9457},{"id":9478,"depth":525,"text":9479,"children":29614},[29615,29617,29619,29621,29623,29625,29627,29629,29631,29633,29635,29637,29639,29641],{"id":9482,"depth":531,"text":29616},"11. What is template interpolation (the mustache {{ }} syntax)?",{"id":9557,"depth":531,"text":29618},"12. What is the difference between v-bind and v-on, and what are their shorthand forms?",{"id":9720,"depth":531,"text":29620},"13. What is the difference between v-if and v-show?",{"id":9829,"depth":531,"text":29622},"14. What does v-for do, and why does it need a :key?",{"id":9930,"depth":531,"text":29624},"15. Why is using the array index as a :key in v-for considered risky?",{"id":10093,"depth":531,"text":29626},"16. How do you bind dynamic classes with :class (object and array syntax)?",{"id":10236,"depth":531,"text":29628},"17. How do you bind dynamic inline styles with :style?",{"id":10367,"depth":531,"text":29630},"18. What are event modifiers in Vue (.stop, .prevent, .once, .self, .capture, .passive)?",{"id":10553,"depth":531,"text":29632},"19. What are the built-in v-model modifiers (.lazy, .number, .trim)?",{"id":10704,"depth":531,"text":29634},"20. What does v-bind=\"object\" do (binding a whole object of attributes at once)?",{"id":10881,"depth":531,"text":29636},"21. Can you use v-if and v-for on the same element, and why is it discouraged?",{"id":11194,"depth":531,"text":29638},"22. What is v-once, and when would you use it?",{"id":11248,"depth":531,"text":29640},"23. What is v-pre, and when would you use it?",{"id":11311,"depth":531,"text":29642},"24. What is v-cloak, and is it still relevant in modern Vue?",{"id":11425,"depth":525,"text":11426,"children":29644},[29645,29646,29648,29650,29652,29654,29656,29658,29660,29662,29664,29666,29668,29669,29670,29672],{"id":11429,"depth":531,"text":11430},{"id":11557,"depth":531,"text":29647},"26. What is the difference between ref() and reactive()?",{"id":11733,"depth":531,"text":29649},"27. Why do you need .value to read a ref in a \u003Cscript> block but not in the template?",{"id":11905,"depth":531,"text":29651},"28. How is Vue 3's Proxy-based reactivity different from Vue 2's Object.defineProperty based reactivity?",{"id":12059,"depth":531,"text":29653},"29. What are the limitations of reactive() that make ref() necessary for primitives?",{"id":12165,"depth":531,"text":29655},"30. What happens if you destructure a reactive() object, and how do toRefs fix it?",{"id":12376,"depth":531,"text":29657},"31. What is the difference between toRef and toRefs?",{"id":12503,"depth":531,"text":29659},"32. What does readonly() do, and when would you wrap a value with it?",{"id":12683,"depth":531,"text":29661},"33. What is the difference between shallowRef/shallowReactive and their deep versions?",{"id":12843,"depth":531,"text":29663},"34. What is markRaw(), and when would you use it?",{"id":12957,"depth":531,"text":29665},"35. What do isRef, unref, and toValue do?",{"id":13198,"depth":531,"text":29667},"36. What is nextTick(), and why do you sometimes need it after changing reactive state?",{"id":13365,"depth":531,"text":13366},{"id":13387,"depth":531,"text":13388},{"id":13516,"depth":531,"text":29671},"39. What is effectScope(), and when would you reach for it?",{"id":13703,"depth":531,"text":13704},{"id":13859,"depth":525,"text":13860,"children":29674},[29675,29676,29677,29678,29680,29682,29684,29686],{"id":13863,"depth":531,"text":13864},{"id":14007,"depth":531,"text":14008},{"id":14062,"depth":531,"text":14063},{"id":14293,"depth":531,"text":29679},"44. What is the difference between computed and watch?",{"id":14397,"depth":531,"text":29681},"45. What is the difference between watch and watchEffect?",{"id":14499,"depth":531,"text":29683},"46. What does the deep option do on watch, and when do you actually need it?",{"id":14616,"depth":531,"text":29685},"47. What does the immediate option do on watch?",{"id":14676,"depth":531,"text":29687},"48. How do you clean up a side effect inside watchEffect using its onCleanup callback?",{"id":14843,"depth":525,"text":14844,"children":29689},[29690,29691,29692,29694,29696,29697,29699,29701,29703,29705,29706,29708,29709,29710],{"id":14847,"depth":531,"text":14848},{"id":15012,"depth":531,"text":15013},{"id":15192,"depth":531,"text":29693},"51. How do you use PropType for typing props in the Options API?",{"id":15422,"depth":531,"text":29695},"52. What are custom events, and how do you emit one with defineEmits?",{"id":15602,"depth":531,"text":15603},{"id":15758,"depth":531,"text":29698},"54. How does v-model on a custom component work under the hood?",{"id":16003,"depth":531,"text":29700},"55. How do you support multiple v-model bindings on the same component?",{"id":16220,"depth":531,"text":29702},"56. What is defineModel (Vue 3.4+), and how does it simplify writing v-model support?",{"id":16413,"depth":531,"text":29704},"57. What is $attrs, and what does setting inheritAttrs: false do?",{"id":16590,"depth":531,"text":16591},{"id":16714,"depth":531,"text":29707},"59. What is defineExpose, and why do you need it with \u003Cscript setup>?",{"id":16963,"depth":531,"text":16964},{"id":17115,"depth":531,"text":17116},{"id":17229,"depth":531,"text":29711},"62. What does defineOptions do in \u003Cscript setup>?",{"id":17326,"depth":525,"text":17327,"children":29713},[29714,29715,29716,29717,29718,29719,29721,29722],{"id":17330,"depth":531,"text":17331},{"id":17461,"depth":531,"text":17462},{"id":17660,"depth":531,"text":17661},{"id":17841,"depth":531,"text":17842},{"id":17949,"depth":531,"text":17950},{"id":18005,"depth":531,"text":29720},"68. What is the difference between the modern v-slot/# syntax and the legacy slot/slot-scope syntax?",{"id":18145,"depth":531,"text":18146},{"id":18167,"depth":531,"text":29723},"70. What does useSlots() do, and when would you use it in \u003Cscript setup>?",{"id":18374,"depth":525,"text":18375,"children":29725},[29726,29728,29730,29731,29732,29733],{"id":18378,"depth":531,"text":29727},"71. What is provide/inject, and what problem does it solve?",{"id":18542,"depth":531,"text":29729},"72. Why is it a good idea to use a Symbol as a provide/inject key in larger applications?",{"id":18700,"depth":531,"text":18701},{"id":18893,"depth":531,"text":18894},{"id":18993,"depth":531,"text":18994},{"id":19217,"depth":531,"text":29734},"76. What does useAttrs() do, and when would you use it?",{"id":19413,"depth":525,"text":19414,"children":29736},[29737,29738,29740,29742,29744,29746,29748,29750],{"id":19417,"depth":531,"text":19418},{"id":19596,"depth":531,"text":29739},"78. What is the difference between beforeMount and mounted?",{"id":19778,"depth":531,"text":29741},"79. What is the difference between beforeUpdate and updated?",{"id":19925,"depth":531,"text":29743},"80. What is the difference between beforeUnmount and unmounted?",{"id":20062,"depth":531,"text":29745},"81. How do Composition API lifecycle hooks (onMounted, etc.) differ from Options API lifecycle hooks?",{"id":20205,"depth":531,"text":29747},"82. What lifecycle hooks does \u003CKeepAlive> add, and what are they for?",{"id":20335,"depth":531,"text":29749},"83. What does onErrorCaptured (or the Options API errorCaptured) do?",{"id":20537,"depth":531,"text":29751},"84. Why doesn't the Composition API have beforeCreate or created hooks?",{"id":20662,"depth":525,"text":20663,"children":29753},[29754,29755,29756,29758,29760,29761],{"id":20666,"depth":531,"text":20667},{"id":20695,"depth":531,"text":20696},{"id":20804,"depth":531,"text":29757},"87. What is the setup() function, and what arguments does it receive?",{"id":20962,"depth":531,"text":29759},"88. Why is there no this inside setup() or \u003Cscript setup>?",{"id":21012,"depth":531,"text":21013},{"id":21277,"depth":531,"text":21278},{"id":21347,"depth":525,"text":21348,"children":29763},[29764,29765,29766,29767,29768,29769,29770,29772,29773,29774,29776,29777],{"id":21351,"depth":531,"text":21352},{"id":21580,"depth":531,"text":21581},{"id":21636,"depth":531,"text":21637},{"id":21825,"depth":531,"text":21826},{"id":21909,"depth":531,"text":21910},{"id":22149,"depth":531,"text":22150},{"id":22314,"depth":531,"text":29771},"97. What are navigation guards, and what are the differences between beforeEach, beforeEnter, and beforeRouteLeave?",{"id":22593,"depth":531,"text":22594},{"id":22740,"depth":531,"text":22741},{"id":22842,"depth":531,"text":29775},"100. What is the difference between router.push and router.replace?",{"id":22888,"depth":531,"text":22889},{"id":23026,"depth":531,"text":29778},"102. What is the difference between \u003Crouter-link> and a plain \u003Ca> tag?",{"id":23137,"depth":525,"text":23138,"children":29780},[29781,29782,29783,29784,29785,29786,29787,29788,29789,29790,29791,29792],{"id":23141,"depth":531,"text":23142},{"id":23156,"depth":531,"text":23157},{"id":23325,"depth":531,"text":23326},{"id":23529,"depth":531,"text":23530},{"id":23813,"depth":531,"text":23814},{"id":23840,"depth":531,"text":23841},{"id":23914,"depth":531,"text":23915},{"id":23934,"depth":531,"text":23935},{"id":24079,"depth":531,"text":24080},{"id":24186,"depth":531,"text":24187},{"id":24304,"depth":531,"text":24305},{"id":24560,"depth":531,"text":24561},{"id":24575,"depth":525,"text":24576,"children":29794},[29795,29797,29799,29800,29801,29803],{"id":24579,"depth":531,"text":29796},"115. How does v-model behave differently on a text input, a checkbox, a radio button, and a select?",{"id":24721,"depth":531,"text":29798},"116. How do you bind v-model to a group of checkboxes or radio buttons?",{"id":25045,"depth":531,"text":25046},{"id":25221,"depth":531,"text":25222},{"id":25375,"depth":531,"text":29802},"119. What is the difference between listening to @input and @change on a text field?",{"id":25452,"depth":531,"text":29804},"120. How would you debounce a v-model bound search input?",{"id":25687,"depth":525,"text":25688,"children":29806},[29807,29809,29811,29813,29814,29815,29816,29817,29818,29819],{"id":25691,"depth":531,"text":29808},"121. What is v-memo, and when would you use it?",{"id":25799,"depth":531,"text":29810},"122. What is \u003CKeepAlive>, and how does it improve performance?",{"id":25919,"depth":531,"text":29812},"123. How do you lazy load a component with defineAsyncComponent?",{"id":26061,"depth":531,"text":26062},{"id":26100,"depth":531,"text":26101},{"id":26186,"depth":531,"text":26187},{"id":26217,"depth":531,"text":26218},{"id":26271,"depth":531,"text":26272},{"id":26291,"depth":531,"text":26292},{"id":26486,"depth":531,"text":26487},{"id":26609,"depth":525,"text":26610,"children":29821},[29822,29824,29826,29827,29828,29829,29831,29833,29834,29835],{"id":26613,"depth":531,"text":29823},"131. What is Teleport, and what problem does it solve?",{"id":26775,"depth":531,"text":29825},"132. What is Suspense, and how do you use it with an async setup() or async component?",{"id":27028,"depth":531,"text":27029},{"id":27122,"depth":531,"text":27123},{"id":27141,"depth":531,"text":27142},{"id":27178,"depth":531,"text":29830},"136. What are compiler macros like defineProps and defineEmits, and why don't you need to import them?",{"id":27311,"depth":531,"text":29832},"137. What is app.config.globalProperties, and when would you use it?",{"id":27445,"depth":531,"text":27446},{"id":27746,"depth":531,"text":27747},{"id":27991,"depth":531,"text":27992},{"id":28123,"depth":525,"text":28124,"children":29837},[29838,29840,29841,29842,29843],{"id":28127,"depth":531,"text":29839},"141. What is Vue Test Utils, and what is the difference between mount and shallowMount?",{"id":28248,"depth":531,"text":28249},{"id":28529,"depth":531,"text":28530},{"id":28748,"depth":531,"text":28749},{"id":29009,"depth":531,"text":29010},{"id":29115,"depth":525,"text":29116,"children":29845},[29846,29847,29848,29849,29851],{"id":29119,"depth":531,"text":29120},{"id":29133,"depth":531,"text":29134},{"id":29150,"depth":531,"text":29151},{"id":29270,"depth":531,"text":29850},"149. What is the \u003CClientOnly> component used for?",{"id":29376,"depth":531,"text":29852},"150. What is the difference between Nuxt's useFetch and useAsyncData for data fetching?",{"id":4859,"depth":525,"text":4860},"2026-07-15","A comprehensive, Vue-specific list of 150 interview questions and answers covering the Composition API, reactivity, components, Vue Router, Pinia, performance, and Nuxt, with clear explanations and code examples.","top-150-vuejs-interview-questions.png",{},"/frontend/top-150-vuejs-interview-questions",{"title":8437,"description":29855},"Frontend/3.top-150-vuejs-interview-questions",[29862,29863,5020,8514,5024],"Vue.js","Frontend","U-reZsAmi6AcojdiN0Nysht5mTvpcQAmlSxPH4Kq_tU",{"id":29866,"title":29867,"author":6,"body":29868,"date":30301,"description":30302,"draft":5010,"extension":5011,"guide":5012,"image":30303,"meta":30304,"navigation":1130,"path":30305,"seo":30306,"stem":30307,"tags":30308,"__hash__":30310},"blog/Backend/5.soap-api.md","SOAP API: Why the Enterprise Still Runs on XML",{"type":8,"value":29869,"toc":30285},[29870,29874,29877,29884,29891,29895,29898,29905,29915,29919,29922,29928,29932,29939,29942,29945,29949,29956,29967,29974,29978,29981,29984,29987,29991,29994,30164,30167,30171,30182,30188,30191,30195,30202,30208,30214,30220,30224,30227,30230,30233,30237,30252,30255,30259,30266,30269,30273,30276,30279,30282],[18,29871,29873],{"id":29872},"soap-simple-object-access-protocol","SOAP: Simple Object Access Protocol",[11,29875,29876],{},"In the modern era of distributed computing, the exchange of information is often treated with a casual indifference. We rely on lightweight, loosely defined formats that prioritize speed over structural integrity. However, there exists a world where ambiguity is the enemy of progress.",[11,29878,29879,29880,29883],{},"This is the world of the ",[31,29881,29882],{},"Simple Object Access Protocol",", or SOAP. To understand SOAP is to understand the fundamental necessity of rigorous standards in high-stakes environments. It is not merely a method of sending data; it is a philosophy of communication based on strict contracts.",[11,29885,29886,29887,29890],{},"Before we explore the technical syntax, we must define its purpose. ",[31,29888,29889],{},"SOAP was designed to allow applications running on different operating systems to communicate over the internet",". It achieved this by utilizing XML, the eXtensible Markup Language, as its universal medium.",[18,29892,29894],{"id":29893},"the-genesis-of-a-standard","The Genesis of a Standard",[11,29896,29897],{},"In the late 1990s, the software industry faced a crisis of fragmentation. Systems built in Java could not easily talk to systems built in C#. The industry needed a bridge that was independent of the underlying platform.",[11,29899,29900,29901,29904],{},"SOAP emerged as that bridge. It was adopted by the ",[31,29902,29903],{},"World Wide Web Consortium (W3C)"," as a recommendation, transforming it from a corporate project into a global standard. It provided a level of predictability that the industry had never seen before.",[11,29906,29907,29908,29910,29911,29914],{},"While newer architectures like ",[31,29909,808],{}," emphasize the Resource, SOAP emphasizes the Procedure. It is a protocol for ",[31,29912,29913],{},"Remote Procedure Calls (RPC)",", allowing one system to invoke logic on another as if it were local.",[18,29916,29918],{"id":29917},"structure-of-soap","Structure of SOAP",[11,29920,29921],{},"The structure of SOAP is wrapped in what we call the \"Envelope.\" This is the root element of the XML document. It acts as the boundary of the message, declaring to any receiving server that what follows is a formal SOAP request. Inside envelope, you have a header for metadata (like auth) and a body for the actual data.",[11,29923,29924],{},[2160,29925],{"alt":29926,"src":29927},"SOAP Envelope Structure","/post-images/soap-api/soap-envelope-structure.png",[23,29929,29931],{"id":29930},"the-header","The Header",[11,29933,29934,29935,29938],{},"Within the Envelope, we have the Header. This is an ",[31,29936,29937],{},"optional"," yet powerful section. It is used to pass metadata that is not part of the primary payload.",[11,29940,29941],{},"For example, a Header might contain a complex authentication token. It might also include routing instructions for middle-tier servers. This separation of concerns make sure the Body to remain focused solely on the business logic of the request.",[11,29943,29944],{},"Most importantly, the Header supports the \"mustUnderstand\" attribute. If this attribute is set to true, the receiver must process the header or fail the entire request. This ensures that security or transactional requirements are never ignored by a lazy implementation.",[23,29946,29948],{"id":29947},"the-body","The Body",[11,29950,29951,29952,29955],{},"This part is the heart of the message. It contains the ",[31,29953,29954],{},"actual data"," meant for the end application. If you are querying a database for a user’s medical record, the user ID resides here.",[11,29957,29958,29959,29962,29963,29966],{},"The Body is where the ",[31,29960,29961],{},"Remote Procedure"," is defined. In a banking application, the Body might contain an instruction like ",[66,29964,29965],{},"TransferFunds",". It specifies the source account, the destination, and the exact amount to three decimal places.",[11,29968,29969,29970,29973],{},"This precision is mandatory. ",[31,29971,29972],{},"Because SOAP relies on XML Schemas (XSD), the data types must match exactly",". If the server expects an integer and you send a string, the message is rejected before the application logic even sees it.",[18,29975,29977],{"id":29976},"how-soap-handles-error","How SOAP Handles Error?",[11,29979,29980],{},"No system is perfect, and networks are inherently unreliable. SOAP manages this reality through a specialized sub-element located within the Body; the \"Fault\" element. It appears only when an error occurs.",[11,29982,29983],{},"The Fault element provides a structured way to report what went wrong. It includes a \"FaultCode\" for machine parsing and a \"FaultString\" for human readability. It may also include \"Detail\" for specific debugging information.",[11,29985,29986],{},"You can compare this to other systems that might return a generic \"404\" or \"500\" error. SOAP tells you exactly which part of the XML failed validation. It identifies whether the error was caused by the client or the server.",[18,29988,29990],{"id":29989},"a-sample-of-the-protocol-in-practice","A Sample of the Protocol in Practice",[11,29992,29993],{},"Let us examine a concrete example of a request sent to a sophisticated inventory system. Notice how namespaces prevent the mixing of different data definitions.",[507,29995,29999],{"className":29996,"code":29997,"language":29998,"meta":512,"style":512},"language-xml shiki shiki-themes github-dark","\u003C?xml version=\"1.0\"?>\n\u003Csoap:Envelope xmlns:soap=\"[http://www.w3.org/2003/05/soap-envelope/](http://www.w3.org/2003/05/soap-envelope/)\"\n               xmlns:inv=\"[http://www.global-logistics.org/inventory](http://www.global-logistics.org/inventory)\">\n  \u003Csoap:Header>\n    \u003Cinv:TransactionID>TR-99821-X\u003C/inv:TransactionID>\n    \u003Cinv:SecurityToken>f47ac10b-58cc-4372-a567-0e02b2c3d479\u003C/inv:SecurityToken>\n  \u003C/soap:Header>\n  \u003Csoap:Body>\n    \u003Cinv:GetProductAvailability>\n      \u003Cinv:SKU>APL-IPH-15-PRO\u003C/inv:SKU>\n      \u003Cinv:WarehouseCode>WH-NORTH-01\u003C/inv:WarehouseCode>\n    \u003C/inv:GetProductAvailability>\n  \u003C/soap:Body>\n\u003C/soap:Envelope>\n","xml",[66,30000,30001,30019,30034,30046,30056,30070,30084,30093,30102,30111,30126,30140,30148,30156],{"__ignoreMap":512},[516,30002,30003,30006,30008,30011,30013,30016],{"class":518,"line":519},[516,30004,30005],{"class":1227},"\u003C?",[516,30007,29998],{"class":8557},[516,30009,30010],{"class":4733}," version",[516,30012,1894],{"class":1227},[516,30014,30015],{"class":1248},"\"1.0\"",[516,30017,30018],{"class":1227},"?>\n",[516,30020,30021,30023,30026,30029,30031],{"class":518,"line":525},[516,30022,3042],{"class":1227},[516,30024,30025],{"class":8557},"soap:Envelope",[516,30027,30028],{"class":4733}," xmlns:soap",[516,30030,1894],{"class":1227},[516,30032,30033],{"class":1248},"\"[http://www.w3.org/2003/05/soap-envelope/](http://www.w3.org/2003/05/soap-envelope/)\"\n",[516,30035,30036,30039,30041,30044],{"class":518,"line":531},[516,30037,30038],{"class":4733},"               xmlns:inv",[516,30040,1894],{"class":1227},[516,30042,30043],{"class":1248},"\"[http://www.global-logistics.org/inventory](http://www.global-logistics.org/inventory)\"",[516,30045,8561],{"class":1227},[516,30047,30048,30051,30054],{"class":518,"line":1127},[516,30049,30050],{"class":1227},"  \u003C",[516,30052,30053],{"class":8557},"soap:Header",[516,30055,8561],{"class":1227},[516,30057,30058,30060,30063,30066,30068],{"class":518,"line":1134},[516,30059,8566],{"class":1227},[516,30061,30062],{"class":8557},"inv:TransactionID",[516,30064,30065],{"class":1227},">TR-99821-X\u003C/",[516,30067,30062],{"class":8557},[516,30069,8561],{"class":1227},[516,30071,30072,30074,30077,30080,30082],{"class":518,"line":1275},[516,30073,8566],{"class":1227},[516,30075,30076],{"class":8557},"inv:SecurityToken",[516,30078,30079],{"class":1227},">f47ac10b-58cc-4372-a567-0e02b2c3d479\u003C/",[516,30081,30076],{"class":8557},[516,30083,8561],{"class":1227},[516,30085,30086,30089,30091],{"class":518,"line":1302},[516,30087,30088],{"class":1227},"  \u003C/",[516,30090,30053],{"class":8557},[516,30092,8561],{"class":1227},[516,30094,30095,30097,30100],{"class":518,"line":1308},[516,30096,30050],{"class":1227},[516,30098,30099],{"class":8557},"soap:Body",[516,30101,8561],{"class":1227},[516,30103,30104,30106,30109],{"class":518,"line":1314},[516,30105,8566],{"class":1227},[516,30107,30108],{"class":8557},"inv:GetProductAvailability",[516,30110,8561],{"class":1227},[516,30112,30113,30116,30119,30122,30124],{"class":518,"line":8656},[516,30114,30115],{"class":1227},"      \u003C",[516,30117,30118],{"class":8557},"inv:SKU",[516,30120,30121],{"class":1227},">APL-IPH-15-PRO\u003C/",[516,30123,30118],{"class":8557},[516,30125,8561],{"class":1227},[516,30127,30128,30130,30133,30136,30138],{"class":518,"line":8668},[516,30129,30115],{"class":1227},[516,30131,30132],{"class":8557},"inv:WarehouseCode",[516,30134,30135],{"class":1227},">WH-NORTH-01\u003C/",[516,30137,30132],{"class":8557},[516,30139,8561],{"class":1227},[516,30141,30142,30144,30146],{"class":518,"line":8677},[516,30143,9907],{"class":1227},[516,30145,30108],{"class":8557},[516,30147,8561],{"class":1227},[516,30149,30150,30152,30154],{"class":518,"line":8682},[516,30151,30088],{"class":1227},[516,30153,30099],{"class":8557},[516,30155,8561],{"class":1227},[516,30157,30158,30160,30162],{"class":518,"line":8691},[516,30159,8589],{"class":1227},[516,30161,30025],{"class":8557},[516,30163,8561],{"class":1227},[11,30165,30166],{},"The response to this message would be equally structured. It would return the stock levels, the last update timestamp, and perhaps a list of nearby warehouses with available stock.",[18,30168,30170],{"id":30169},"wsdl-the-master-blueprint","WSDL: The Master Blueprint",[11,30172,30173,30174,30177,30178,30181],{},"One cannot discuss SOAP without mentioning the WSDL. The heart of any SOAP API is the ",[31,30175,30176],{},"WSDL (Web Services Description Language)",". It’s ",[31,30179,30180],{},"an XML file"," that describes exactly what the service does, what arguments it takes, and what it returns.",[11,30183,30184,30185],{},"In other words, a WSDL file defines the \"Endpoints\" where the service lives. ",[31,30186,30187],{},"It lists every operation the service can perform. It describes the exact format of the input messages and the expected output messages.",[11,30189,30190],{},"This allows for the automation of client creation. In many professional environments, a developer simply points a tool at a WSDL URL. The tool then generates all the necessary code to communicate with that service. This is the \"Contract-First\" approach.",[18,30192,30194],{"id":30193},"the-superiority-of-ws-standards","The Superiority of WS-* Standards",[11,30196,30197,30198,30201],{},"Why do we continue to use such a heavy protocol? The answer lies in the ",[31,30199,30200],{},"WS-* (Web Services) specifications",". These are a suite of extensions that sit on top of SOAP to solve complex enterprise problems.",[11,30203,30204,30207],{},[31,30205,30206],{},"WS-Security"," is perhaps the most vital. It allows for end-to-end security. Unlike SSL, which only encrypts the \"pipe\" between two points, WS-Security encrypts the message itself. Even if the message passes through five different servers, only the final recipient can read it.",[11,30209,30210,30213],{},[31,30211,30212],{},"WS-AtomicTransaction"," provides a mechanism for distributed transactions. Think of a process that involves updating a database in London and another in Tokyo. This standard ensures that either both updates happen, or neither does. It prevents data corruption.",[11,30215,30216,30219],{},[31,30217,30218],{},"WS-ReliableMessaging"," ensures that messages are delivered exactly once, in the correct order. In high-frequency trading or industrial control systems, \"maybe\" is not an acceptable answer. SOAP provides the guarantees that modern business requires.",[18,30221,30223],{"id":30222},"soap-vs-rest-an-intellectual-distinction","SOAP vs. REST: An Intellectual Distinction",[11,30225,30226],{},"You will often hear debates comparing SOAP to REST. These debates often miss the point. They are different tools for different tasks. REST is an architectural style designed for the web. It is flexible and easy to consume.",[11,30228,30229],{},"SOAP is a protocol designed for the enterprise. It is rigid, typed, and stateful. While REST is perfect for a mobile app showing weather updates, SOAP is the right choice for an international wire transfer.",[11,30231,30232],{},"In a RESTful world, you are responsible for your own security and error handling. In the SOAP world, these are built into the protocol. We're talking about WS-Security.",[18,30234,30236],{"id":30235},"the-performance-trade-off","The Performance Trade-off",[11,30238,30239,30240,30243,30244,30247,30248,30251],{},"It is undeniable that ",[31,30241,30242],{},"SOAP is slower"," than its alternatives. The XML format is chatty. It requires ",[31,30245,30246],{},"more CPU power to parse"," than the simpler JSON format. It uses ",[31,30249,30250],{},"more bandwidth to transmit"," the same amount of information.",[11,30253,30254],{},"However, in the context of a million-dollar transaction, a 200-millisecond delay for security validation is negligible. Efficiency is not always measured in bytes per second. Sometimes, efficiency is measured in the absence of catastrophic errors.",[18,30256,30258],{"id":30257},"the-role-of-acid-compliance","The Role of ACID Compliance",[11,30260,30261,30262,30265],{},"For those focused on data integrity, SOAP’s compatibility with ",[31,30263,30264],{},"ACID (Atomicity, Consistency, Isolation, Durability)"," properties is paramount. Most REST implementations struggle to provide these guarantees across distributed nodes.",[11,30267,30268],{},"SOAP excels here. By using the built-in standards for coordination, it allows multiple services to participate in a single logical transaction. This is a foundational requirement for any system handling financial ledgers or legal records.",[18,30270,30272],{"id":30271},"final-reflections-the-future-of-soap","Final Reflections: The Future of SOAP",[11,30274,30275],{},"As we look toward the future, we see a world that is becoming more interconnected and more dangerous. The need for verified, secure, and transactional communication is not shrinking; it is expanding.",[11,30277,30278],{},"SOAP may not be the fashionable choice in Silicon Valley startups. Yet, it remains the backbone of the global economy. It powers the SWIFT network. It manages the supply chains of the world’s largest retailers.",[11,30280,30281],{},"As professionals, you must be polyglots. You must know when to use the speed of REST and when to use the safety of SOAP. To ignore SOAP is to ignore the foundation of the modern enterprise.",[4868,30283,30284],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#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);}",{"title":512,"searchDepth":525,"depth":525,"links":30286},[30287,30288,30289,30293,30294,30295,30296,30297,30298,30299,30300],{"id":29872,"depth":525,"text":29873},{"id":29893,"depth":525,"text":29894},{"id":29917,"depth":525,"text":29918,"children":30290},[30291,30292],{"id":29930,"depth":531,"text":29931},{"id":29947,"depth":531,"text":29948},{"id":29976,"depth":525,"text":29977},{"id":29989,"depth":525,"text":29990},{"id":30169,"depth":525,"text":30170},{"id":30193,"depth":525,"text":30194},{"id":30222,"depth":525,"text":30223},{"id":30235,"depth":525,"text":30236},{"id":30257,"depth":525,"text":30258},{"id":30271,"depth":525,"text":30272},"2026-05-16","Meet SOAP API, the father of REST APIs. Learn about WSDLs, WS-Security, and when to choose SOAP over REST for your next project.","soap-api.png",{},"/backend/soap-api",{"title":29867,"description":30302},"Backend/5.soap-api",[799,30309,5019],"Web Services","cRQ439Kv39sP45TxG1ceAIfyGiH6QJNr3gDNtp4jdq0",{"id":30312,"title":30313,"author":6,"body":30314,"date":30548,"description":30549,"draft":5010,"extension":5011,"guide":5012,"image":30550,"meta":30551,"navigation":1130,"path":30552,"seo":30553,"stem":30554,"tags":30555,"__hash__":30560},"blog/Frontend/2.hydration-in-frontend-frameworks.md","Hydration in Frontend Frameworks: Why We Hydrate",{"type":8,"value":30315,"toc":30541},[30316,30319,30326,30329,30335,30339,30342,30345,30348,30355,30358,30361,30364,30370,30373,30376,30379,30389,30392,30395,30398,30405,30408,30411,30414,30418,30421,30434,30437,30444,30447,30450,30453,30456,30459,30462,30465,30468,30475,30479,30486,30489,30496,30499,30502,30505,30508,30512,30515,30518,30520,30523,30526,30529,30532,30535,30538],[11,30317,30318],{},"Imagine a world where everything you see is a high resolution photograph. It looks perfect, the colors are vibrant and the details are sharp. But when you try to touch it, nothing happens. It’s just static ink on paper.",[11,30320,30321,30322,30325],{},"In the digital realm, we call this static state ",[31,30323,30324],{},"Server-Side Rendering",". It is the process of sending a pre-baked HTML document to your browser. It’s fast to look at, but functionally dead. How do we bring it to life?",[11,30327,30328],{},"We bring it to life through a process called hydration. Have you ever wondered why a website appears instantly but takes a few seconds before the buttons actually work? That brief, uncanny valley of time is hydration in action.",[11,30330,771,30331,30334],{},[761,30332,30333],{"href":8452},"question 99 of frontend interview questions guide"," covers SSR, CSR, SSG, and ISR in a way that pairs well with this article.",[18,30336,30338],{"id":30337},"what-hydration-actually-does","What Hydration Actually Does",[11,30340,30341],{},"Think of hydration as the \"soul\" entering the body. The server sends the \"body\" (the HTML) and the client sends the \"soul\" (the JavaScript). Once they merge, the page becomes an interactive, living organism. This is the core idea behind hydration in react or vue and, more broadly, javascript hydration across modern frontend stacks. But why do we bother?",[11,30343,30344],{},"Why not just send the JavaScript and let the browser build the whole thing from scratch? That would be Client-Side Rendering. It sounds simpler, doesn't it? Well, it is, but it comes with a massive cost to user experience.",[11,30346,30347],{},"If we relied solely on the client, the user would stare at a blank white screen while the JavaScript downloaded. Have you ever closed a tab because it didn't load within three seconds? Most people have.",[11,30349,30350,30351,30354],{},"By sending HTML first, we give the user something to read immediately. This ",[31,30352,30353],{},"First Contentful Paint"," is psychological gold. It reassures the user that the site is working, even if the engines are still warming up under the hood.",[11,30356,30357],{},"Hydration exists to bridge the gap between \"seeing\" and \"doing.\" It is the compromise we make to ensure the web is both fast to display and rich to use. It is a delicate handoff between server and client.",[11,30359,30360],{},"Let’s look at a real world example: an e-commerce product page. When you click a link from Google, you want to see the price and the image instantly. The server delivers those as static HTML right away.",[11,30362,30363],{},"But what about the \"Add to Cart\" button? That requires logic. It needs to know who you are and what is in your bag. This is where hydration steps in, attaching event listeners to those static buttons.",[11,30365,30366,30369],{},[31,30367,30368],{},"What happens if the hydration fails?"," You might click that \"Add to Cart\" button ten times and see nothing happen. This is the rage click, a symptom of a mismatch between the HTML structure and the JavaScript logic.",[11,30371,30372],{},"Is hydration a perfect solution? Not quite. It can be heavy. You are essentially sending the data twice: once as HTML and once as a JSON payload for the JavaScript to consume. It’s like buying two tickets for one seat.",[11,30374,30375],{},"Despite this overhead, hydration remains the backbone of modern frameworks like Nuxt, Next.js, and Remix. In hydration in next/nuxt js workflows, for example, the server renders the first pass and the client attaches behavior afterward. It allows developers to build complex, app-like experiences that still feel like traditional, fast-loading websites.",[11,30377,30378],{},"Consider a social media feed like Twitter or X. As you scroll, the initial posts are often pre-rendered. This ensures that even on a slow 3G connection, you have something to consume while the heavy app logic initializes.",[11,30380,30381,30382,756,30385,30388],{},"Could we avoid this double-loading? Some new patterns are emerging, like ",[31,30383,30384],{},"Partial Hydration",[31,30386,30387],{},"Resumability",". These techniques try to only hydrate the parts of the page that actually need to be interactive.",[11,30390,30391],{},"Imagine a blog post like this one. Does the text itself need JavaScript? No. Only the comment section or the search bar might need it. Why hydrate the whole page when only 10% is interactive?",[11,30393,30394],{},"This is the frontier of web performance. We are moving toward a world where we water only the plants that are thirsty, rather than flooding the entire garden. This saves bandwidth and CPU cycles on your phone.",[11,30396,30397],{},"But for now, standard hydration is our best tool for SEO. Search engines love HTML. They can crawl it easily. If your site is just a pile of JavaScript, search bots might struggle to understand your content.",[11,30399,30400,30401,30404],{},"Do you care about your ranking on Google? If so, you care about hydration. It ensures that your content is indexed properly while still providing a smooth, ",[31,30402,30403],{},"single page app"," feel once the user arrives.",[11,30406,30407],{},"Let's understand the mechanics. When your app starts, the server executes your components and produces a string of HTML. This string is what flies across the internet to the user's device.",[11,30409,30410],{},"Inside that HTML is a special script tag. It contains the state of your application. It’s like a save-game file. The browser reads this and says, \"yess! I know exactly where the server left off.\"",[11,30412,30413],{},"The browser then runs the same Vue components. But instead of creating new HTML, it dry-runs them. It compares its virtual map to the existing HTML already on the screen.",[18,30415,30417],{"id":30416},"hydration-mismatches-and-errors","Hydration Mismatches and Errors",[11,30419,30420],{},"If the maps match, the browser just attaches the event listeners. It’s like a glove sliding onto a hand. Perfect fit. This is the moment of successful hydration. The page is now fully interactive.",[11,30422,30423,30424,30427,30428,756,30431,30433],{},"But what if they don't match? This is the dreaded ",[31,30425,30426],{},"Hydration Mismatch Error",". It usually happens when you use something like ",[66,30429,30430],{},"new Date()",[66,30432,29173],{}," in your components.",[11,30435,30436],{},"Why does a date cause an error? Because the server might be in a different timezone than the user. If the server says \"10:00 AM\" and the browser says \"10:01 AM,\" the glove doesn't fit the hand anymore.",[11,30438,30439,30440,30443],{},"The browser gets confused. It might throw away the server's HTML and start over, causing a visible ",[31,30441,30442],{},"flicker",". This defeats the whole purpose of server-side rendering. It’s a waste of resources.",[11,30445,30446],{},"To fix this, developers must ensure their code is \"isomorphic\" or \"universal.\" This means the code must produce the exact same result regardless of where it is running. Consistency is the key to hydration.",[11,30448,30449],{},"Think of a weather app. If the server fetches data for London, but the client thinks it's in New York, the UI will clash. We solve this by passing the server's data down to the client as a \"payload.\"",[11,30451,30452],{},"This payload ensures the client doesn't have to fetch the data again. It just trusts what the server told it. \"The temperature is 15 degrees,\" says the server. \"Okay,\" says the client, \"I'll start with that.\"",[11,30454,30455],{},"Is hydration only for big frameworks? Theoretically, no. You could write manual hydration logic in vanilla JavaScript. You’d find elements by ID and attach listeners. But that would be a nightmare to maintain.",[11,30457,30458],{},"Frontend frameworks automate this. They handle the complex diffing and event delegation so you can focus on building features. They make the \"soul-to-body\" transition seamless for the developer.",[11,30460,30461],{},"Let’s look at another example: a live dashboard. The static HTML shows the last known stock prices. Once hydrated, a WebSocket connection kicks in and starts updating those prices in real-time.",[11,30463,30464],{},"Without hydration, the user would see the initial prices but they would never change. They’d have to refresh the page like it was 1995. Hydration is what makes the \"real-time\" web possible.",[11,30466,30467],{},"Have you ever noticed how some sites feel \"janky\" for a second? That's usually because the main thread is busy hydrating. The CPU is working hard to turn that static text into interactive components.",[11,30469,30470,30471,30474],{},"On low-end mobile devices, this is a major bottleneck. The ",[31,30472,30473],{},"Time to Interactive (TTI)"," metric measures this. A site might look ready in 1 second, but if it takes 5 seconds to hydrate, the user is frustrated.",[18,30476,30478],{"id":30477},"the-lazy-hydration","The Lazy Hydration",[11,30480,30481,30482,30485],{},"This is why we talk about ",[31,30483,30484],{},"Lazy Hydration",". We can tell the browser: \"Don't worry about the footer yet. Only hydrate the header and the main content because that's what the user sees.\" You must have experienced this in websites.",[11,30487,30488],{},"By prioritizing what the user can see, we make the app feel faster than it actually is. It’s a form of digital sleight of hand. We manage the user's perception of speed through clever scheduling.",[11,30490,30491,30492,30495],{},"What does the future hold? We are seeing the rise of ",[31,30493,30494],{},"Server Components."," In this model, some parts of your UI stay on the server forever. They never send JavaScript to the client.",[11,30497,30498],{},"Imagine a complex data table that only displays information. In the old way, we'd hydrate the whole table. In the new way, we send the HTML and zero JavaScript. The hydration cost becomes zero.",[11,30500,30501],{},"This is a massive shift. It acknowledges that not everything on a webpage needs to be smart. Sometimes, a button is just a link, and a table is just a list of rows. Less is more.",[11,30503,30504],{},"If you are a Frontend developer, you are already standing on the shoulders of giants. The framework handles the \"Why\" and \"How\" of hydration for you, but understanding it makes you a better architect. This applies whether you are studying hydration in react, vue or building with hydration in next, nuxt js.",[11,30506,30507],{},"You start to see your components as two-sided coins. One side is the HTML representation for the server; the other side is the interactive logic for the client. Both must exist in harmony.",[18,30509,30511],{"id":30510},"hydration-in-action","Hydration in Action",[11,30513,30514],{},"Do you want to see hydration in action? Open your browser's developer tools and disable JavaScript. Refresh the page. What you see is the \"pre-hydrated\" state. It’s the skeleton of your site.",[11,30516,30517],{},"Now, re-enable JavaScript. Watch the console. See how the page suddenly gains its capabilities. That transition is the magic of the modern web. It is the reason our digital world feels so responsive.",[18,30519,4860],{"id":4859},[11,30521,30522],{},"So, why does hydration exist? It exists because we refuse to choose between speed and power. We want the instant gratification of a static document and the infinite potential of a software application.",[11,30524,30525],{},"It is the bridge across the performance chasm. It is the technique that allows a simple browser to feel like a high-end operating system. It is, quite literally, what makes the web \"fluid.\"",[11,30527,30528],{},"Next time you build a component, ask yourself: \"What does this look like before the soul enters the body?\" If the answer is \"nothing,\" you might want to rethink your server side rendering strategy.",[11,30530,30531],{},"Hydration is more than a technical term; it's a philosophy of balance. It's about respecting the user's time by showing them content early, and respecting their needs by giving them interaction later.",[11,30533,30534],{},"We are the curators of this experience. Every kilobyte of JavaScript we add is a tax on the hydration process. Our job is to keep the water flowing smoothly without drowning the user's device.",[11,30536,30537],{},"So you ready to optimize your hydration? Start by looking at your bundles. Use tools like the Nuxt Bundle Analyzer to see what's being sent to the client. Every small win counts for your users.",[11,30539,30540],{},"The web is a living thing. Hydration is its heartbeat. By mastering this concept, whether through hydration in react, hydration in next js, or plain javascript hydration, you aren't just writing code; you are bringing digital experiences to life.",{"title":512,"searchDepth":525,"depth":525,"links":30542},[30543,30544,30545,30546,30547],{"id":30337,"depth":525,"text":30338},{"id":30416,"depth":525,"text":30417},{"id":30477,"depth":525,"text":30478},{"id":30510,"depth":525,"text":30511},{"id":4859,"depth":525,"text":4860},"2026-05-14","A detailed article on hydration in frontend web development, exploring its necessity, mechanics, and real-world implications","hydration-in-frontend-frameworks.png",{},"/frontend/hydration-in-frontend-frameworks",{"title":30313,"description":30549},"Frontend/2.hydration-in-frontend-frameworks",[29863,30556,30557,30558,30559],"React","Next.js","Vue","Nuxt.js","QIqLRwxgtUJrbUCXe_QKZny0PBB74tI8XoSGgSWTlhU",{"id":30562,"title":30563,"author":6,"body":30564,"date":31686,"description":31687,"draft":5010,"extension":5011,"guide":5012,"image":31688,"meta":31689,"navigation":1130,"path":31690,"seo":31691,"stem":31692,"tags":31693,"__hash__":31698},"blog/Backend/4.local-storage-vs-session-storage-vs-cookies.md","Local Storage vs Session Storage vs Cookies: Sessions and Cookies Explained Without the Drama",{"type":8,"value":30565,"toc":31671},[30566,30569,30572,30575,30584,30591,30595,30601,30720,30726,30729,30732,30736,30742,30754,30757,30777,30780,30791,30794,30798,30801,30804,30813,30816,30825,30835,30839,30842,30937,30940,30949,30952,30955,30959,30965,31027,31030,31033,31050,31053,31067,31072,31096,31099,31106,31110,31116,31182,31188,31191,31208,31211,31220,31226,31230,31235,31243,31246,31286,31289,31292,31303,31307,31310,31317,31320,31323,31326,31393,31396,31425,31428,31437,31445,31448,31452,31459,31472,31477,31482,31487,31490,31493,31553,31556,31560,31563,31570,31573,31576,31581,31586,31597,31600,31604,31607,31613,31624,31627,31630,31634,31640,31654,31657,31660,31668],[11,30567,30568],{},"A login bug can eat your team's afternoon as snacks before they realizes the problem is sitting in plain sight.",[11,30570,30571],{},"The app works perfectly in one browser suppose Chrome. Fails mysteriously in another e.g. Safari. Works again in incognito. Then breaks again after refresh. Someone blames CORS, someone blames the backend, and eventually someone opens DevTools and says, \"Wait, why are we storing this token in three different places?\"",[11,30573,30574],{},"That was the whole problem.",[11,30576,30577,30578,30580,30581,30583],{},"Browser storage looks simple until it becomes part of your auth model. A little ",[66,30579,2755],{}," here, a cookie there, maybe ",[66,30582,24321],{}," for temporary stuff, and suddenly nobody knows where the truth lives.",[11,30585,30586,30587,30590],{},"So let's talk like developers, not textbook authors: ",[31,30588,30589],{},"local storage vs session storage vs cookies",", what each one actually does, where sessions fit in, and how you should choose between them without overengineering your app into a security-themed escape room.",[18,30592,30594],{"id":30593},"the-short-version-first","The Short Version First",[11,30596,30597,30598,30600],{},"If you're comparing ",[31,30599,30589],{},", here's the TL;DR:",[36,30602,30603,30619],{},[39,30604,30605],{},[42,30606,30607,30610,30613,30616],{},[45,30608,30609],{},"Feature",[45,30611,30612],{},"local storage",[45,30614,30615],{},"session storage",[45,30617,30618],{},"cookies",[58,30620,30621,30639,30653,30664,30678,30691,30705],{},[42,30622,30623,30626,30630,30634],{},[63,30624,30625],{},"Browser API",[63,30627,30628],{},[66,30629,2755],{},[63,30631,30632],{},[66,30633,24321],{},[63,30635,30636,30638],{},[66,30637,2786],{},", server headers",[42,30640,30641,30644,30647,30650],{},[63,30642,30643],{},"Lifetime",[63,30645,30646],{},"Until manually cleared",[63,30648,30649],{},"Until tab or browser session ends",[63,30651,30652],{},"Based on expiration settings",[42,30654,30655,30658,30660,30662],{},[63,30656,30657],{},"Sent to server automatically",[63,30659,74],{},[63,30661,74],{},[63,30663,90],{},[42,30665,30666,30669,30671,30673],{},[63,30667,30668],{},"Accessible from JavaScript",[63,30670,90],{},[63,30672,90],{},[63,30674,30675,30676],{},"Yes, unless ",[66,30677,699],{},[42,30679,30680,30683,30686,30688],{},[63,30681,30682],{},"Typical size limit",[63,30684,30685],{},"Around 5 to 10 MB",[63,30687,30685],{},[63,30689,30690],{},"Around 4 KB per cookie",[42,30692,30693,30696,30699,30702],{},[63,30694,30695],{},"Best for",[63,30697,30698],{},"Non-sensitive preferences, UI state",[63,30700,30701],{},"Temporary tab-level state",[63,30703,30704],{},"Sessions, server-readable auth, tracking consent",[42,30706,30707,30710,30713,30715],{},[63,30708,30709],{},"Biggest risk",[63,30711,30712],{},"XSS can read it",[63,30714,30712],{},[63,30716,30717,30718],{},"CSRF if misconfigured, XSS if not ",[66,30719,699],{},[11,30721,30722,30723,30725],{},"My opinion: if it's an authentication secret, don't casually toss it into ",[66,30724,2755],{}," because a tutorial did it in 2018.",[11,30727,30728],{},"Convenient? Yes.",[11,30730,30731],{},"Secure by default? Not really.",[18,30733,30735],{"id":30734},"what-are-sessions-really","What Are Sessions, Really?",[11,30737,784,30738,30741],{},[31,30739,30740],{},"session"," is the server's way of remembering that \"this request belongs to that user.\"",[11,30743,30744,30745,1492,30747,1492,30750,30753],{},"HTTP itself is stateless. Your browser asks for ",[66,30746,22875],{},[66,30748,30749],{},"/settings",[66,30751,30752],{},"/api/invoices",", and the server doesn't naturally remember that those requests came from the same logged-in person. A session fills that gap.",[11,30755,30756],{},"In a classic session-based setup:",[2868,30758,30759,30762,30765,30768,30771,30774],{},[720,30760,30761],{},"You log in with your email and password.",[720,30763,30764],{},"The server checks your credentials.",[720,30766,30767],{},"The server creates a session record, often in Redis, a database, or memory.",[720,30769,30770],{},"The server sends your browser a cookie containing a random session ID.",[720,30772,30773],{},"On later requests, the browser sends that cookie back automatically.",[720,30775,30776],{},"The server looks up the session ID and knows who you are.",[11,30778,30779],{},"Notice the cookie doesn't need to contain your name, role, or permissions. It can just hold a boring random identifier like:",[507,30781,30785],{"className":30782,"code":30783,"language":30784,"meta":512,"style":512},"language-txt shiki shiki-themes github-dark","sid=s%3A4f8a92c7d1e0...\n","txt",[66,30786,30787],{"__ignoreMap":512},[516,30788,30789],{"class":518,"line":519},[516,30790,30783],{},[11,30792,30793],{},"Boring is good here. Boring is underrated in security.",[18,30795,30797],{"id":30796},"cookies-small-old-weird-still-very-useful","Cookies: Small, Old, Weird, Still Very Useful",[11,30799,30800],{},"Cookies have been around forever, so they come with some baggage. But they're still the browser's native way to send small bits of data back to the server on every matching request.",[11,30802,30803],{},"The server can set a cookie like this:",[507,30805,30807],{"className":509,"code":30806,"language":511,"meta":512,"style":512},"Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600\n",[66,30808,30809],{"__ignoreMap":512},[516,30810,30811],{"class":518,"line":519},[516,30812,30806],{},[11,30814,30815],{},"After that, the browser automatically includes it:",[507,30817,30819],{"className":509,"code":30818,"language":511,"meta":512,"style":512},"Cookie: session_id=abc123\n",[66,30820,30821],{"__ignoreMap":512},[516,30822,30823],{"class":518,"line":519},[516,30824,30818],{},[11,30826,30827,30828,30830,30831,756,30833,405],{},"You don't manually attach it from frontend JavaScript. That's the main difference between ",[31,30829,30618],{}," and Web Storage APIs like ",[66,30832,2755],{},[66,30834,24321],{},[23,30836,30838],{"id":30837},"cookie-flags-you-should-actually-care-about","Cookie Flags You Should Actually Care About",[11,30840,30841],{},"Some cookie flags are not optional decoration. They're the difference between \"fine for production\" and \"please don't ship that.\"",[36,30843,30844,30854],{},[39,30845,30846],{},[42,30847,30848,30851],{},[45,30849,30850],{},"Flag",[45,30852,30853],{},"What it does",[58,30855,30856,30865,30874,30883,30892,30904,30917,30927],{},[42,30857,30858,30862],{},[63,30859,30860],{},[66,30861,699],{},[63,30863,30864],{},"Prevents JavaScript from reading the cookie",[42,30866,30867,30871],{},[63,30868,30869],{},[66,30870,702],{},[63,30872,30873],{},"Sends the cookie only over HTTPS",[42,30875,30876,30880],{},[63,30877,30878],{},[66,30879,755],{},[63,30881,30882],{},"Helps reduce CSRF risk for normal navigation",[42,30884,30885,30889],{},[63,30886,30887],{},[66,30888,2845],{},[63,30890,30891],{},"Stronger CSRF protection, but can break cross-site flows",[42,30893,30894,30899],{},[63,30895,30896],{},[66,30897,30898],{},"SameSite=None",[63,30900,30901,30902],{},"Allows cross-site cookies, requires ",[66,30903,702],{},[42,30905,30906,30914],{},[63,30907,30908,756,30911],{},[66,30909,30910],{},"Max-Age",[66,30912,30913],{},"Expires",[63,30915,30916],{},"Controls how long the cookie lives",[42,30918,30919,30924],{},[63,30920,30921],{},[66,30922,30923],{},"Path",[63,30925,30926],{},"Limits where the cookie is sent",[42,30928,30929,30934],{},[63,30930,30931],{},[66,30932,30933],{},"Domain",[63,30935,30936],{},"Controls which hostnames receive the cookie",[11,30938,30939],{},"For login sessions, a strong default often looks like this:",[507,30941,30943],{"className":509,"code":30942,"language":511,"meta":512,"style":512},"Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400\n",[66,30944,30945],{"__ignoreMap":512},[516,30946,30947],{"class":518,"line":519},[516,30948,30942],{},[11,30950,30951],{},"Can cookies be annoying with CORS, subdomains, mobile WebViews, and third-party browser rules? Absolutely.",[11,30953,30954],{},"But for server-managed sessions, they're still usually the grown-up choice.",[18,30956,30958],{"id":30957},"local-storage-persistent-simple-and-too-easy-to-misuse","Local Storage: Persistent, Simple, and Too Easy to Misuse",[11,30960,30961,30964],{},[31,30962,30963],{},"Local storage"," is part of the Web Storage API. It stores key-value pairs in the browser with no automatic expiration.",[507,30966,30968],{"className":8782,"code":30967,"language":8784,"meta":512,"style":512},"localStorage.setItem('theme', 'dark')\nlocalStorage.setItem('sidebar', 'collapsed')\n\nconst theme = localStorage.getItem('theme')\n",[66,30969,30970,30987,31005,31009],{"__ignoreMap":512},[516,30971,30972,30975,30977,30979,30981,30983,30985],{"class":518,"line":519},[516,30973,30974],{"class":1227},"localStorage.",[516,30976,24534],{"class":4733},[516,30978,8643],{"class":1227},[516,30980,18465],{"class":1248},[516,30982,154],{"class":1227},[516,30984,14557],{"class":1248},[516,30986,8649],{"class":1227},[516,30988,30989,30991,30993,30995,30998,31000,31003],{"class":518,"line":525},[516,30990,30974],{"class":1227},[516,30992,24534],{"class":4733},[516,30994,8643],{"class":1227},[516,30996,30997],{"class":1248},"'sidebar'",[516,30999,154],{"class":1227},[516,31001,31002],{"class":1248},"'collapsed'",[516,31004,8649],{"class":1227},[516,31006,31007],{"class":518,"line":531},[516,31008,1131],{"emptyLinePlaceholder":1130},[516,31010,31011,31013,31015,31017,31019,31021,31023,31025],{"class":518,"line":1127},[516,31012,8632],{"class":1749},[516,31014,18446],{"class":1233},[516,31016,1793],{"class":1749},[516,31018,24469],{"class":1227},[516,31020,24472],{"class":4733},[516,31022,8643],{"class":1227},[516,31024,18465],{"class":1248},[516,31026,8649],{"class":1227},[11,31028,31029],{},"Close the tab, restart the browser, come back next week, and the data is probably still there unless the user cleared site data or the browser evicted it.",[11,31031,31032],{},"That's perfect for things like:",[717,31034,31035,31038,31041,31044,31047],{},[720,31036,31037],{},"Theme preference",[720,31039,31040],{},"Draft UI state",[720,31042,31043],{},"Recently selected filters",[720,31045,31046],{},"Non-sensitive feature flags",[720,31048,31049],{},"Cached public data",[11,31051,31052],{},"It's less perfect for:",[717,31054,31055,31058,31061,31064],{},[720,31056,31057],{},"Access tokens",[720,31059,31060],{},"Refresh tokens",[720,31062,31063],{},"Passwords, yes, people still try this",[720,31065,31066],{},"Anything you'd panic about seeing in a bug report screenshot",[11,31068,31069,31070,405],{},"Here's the uncomfortable bit: if an attacker gets JavaScript running on your page through XSS, they can read ",[66,31071,2755],{},[507,31073,31075],{"className":8782,"code":31074,"language":8784,"meta":512,"style":512},"const token = localStorage.getItem('access_token')\n",[66,31076,31077],{"__ignoreMap":512},[516,31078,31079,31081,31083,31085,31087,31089,31091,31094],{"class":518,"line":519},[516,31080,8632],{"class":1749},[516,31082,24412],{"class":1233},[516,31084,1793],{"class":1749},[516,31086,24469],{"class":1227},[516,31088,24472],{"class":4733},[516,31090,8643],{"class":1227},[516,31092,31093],{"class":1248},"'access_token'",[516,31095,8649],{"class":1227},[11,31097,31098],{},"That's it. No clever exploit chain needed.",[11,31100,31101,31102,31105],{},"So when people search for ",[31,31103,31104],{},"localstorage vs sessionstorage",", they're often really asking, \"Which one is safer for tokens?\" The honest answer is: neither is magic. Both are readable by JavaScript.",[18,31107,31109],{"id":31108},"session-storage-like-local-storage-but-tab-scoped","Session Storage: Like Local Storage, But Tab-Scoped",[11,31111,31112,31115],{},[31,31113,31114],{},"Session storage"," also stores key-value pairs, but it lives for the lifetime of a page session. In plain English: usually one browser tab.",[507,31117,31119],{"className":8782,"code":31118,"language":8784,"meta":512,"style":512},"sessionStorage.setItem('checkoutStep', 'payment')\nsessionStorage.setItem('returnTo', '/pricing')\n\nconst step = sessionStorage.getItem('checkoutStep')\n",[66,31120,31121,31140,31158,31162],{"__ignoreMap":512},[516,31122,31123,31126,31128,31130,31133,31135,31138],{"class":518,"line":519},[516,31124,31125],{"class":1227},"sessionStorage.",[516,31127,24534],{"class":4733},[516,31129,8643],{"class":1227},[516,31131,31132],{"class":1248},"'checkoutStep'",[516,31134,154],{"class":1227},[516,31136,31137],{"class":1248},"'payment'",[516,31139,8649],{"class":1227},[516,31141,31142,31144,31146,31148,31151,31153,31156],{"class":518,"line":525},[516,31143,31125],{"class":1227},[516,31145,24534],{"class":4733},[516,31147,8643],{"class":1227},[516,31149,31150],{"class":1248},"'returnTo'",[516,31152,154],{"class":1227},[516,31154,31155],{"class":1248},"'/pricing'",[516,31157,8649],{"class":1227},[516,31159,31160],{"class":518,"line":531},[516,31161,1131],{"emptyLinePlaceholder":1130},[516,31163,31164,31166,31169,31171,31174,31176,31178,31180],{"class":518,"line":1127},[516,31165,8632],{"class":1749},[516,31167,31168],{"class":1233}," step",[516,31170,1793],{"class":1749},[516,31172,31173],{"class":1227}," sessionStorage.",[516,31175,24472],{"class":4733},[516,31177,8643],{"class":1227},[516,31179,31132],{"class":1248},[516,31181,8649],{"class":1227},[11,31183,31184,31185,31187],{},"Open the same app in another tab, and that tab gets its own ",[66,31186,24321],{},". Close the tab, and the data disappears.",[11,31189,31190],{},"That's useful for short-lived state:",[717,31192,31193,31196,31199,31202,31205],{},[720,31194,31195],{},"Multi-step form progress",[720,31197,31198],{},"Checkout flow state",[720,31200,31201],{},"OAuth return paths",[720,31203,31204],{},"Temporary search filters",[720,31206,31207],{},"Tab-specific UI state",[11,31209,31210],{},"Would I store a long-lived auth token there? No.",[11,31212,31213,31214,31216,31217,31219],{},"Would I use ",[66,31215,24321],{}," for a one-time OAuth ",[66,31218,259],{}," value or a short return URL during login? Sure, if the flow fits.",[11,31221,31222,31223,31225],{},"The key detail: ",[31,31224,30615],{}," is not \"server session storage.\" The name confuses people. It has nothing to do with backend sessions unless you deliberately connect the two in your app logic.",[18,31227,31229],{"id":31228},"local-storage-vs-session-storage-the-real-difference","Local Storage vs Session Storage: The Real Difference",[11,31231,771,31232,31234],{},[31,31233,31104],{}," debate is mostly about lifetime and scope.",[11,31236,31237,31239,31240,31242],{},[66,31238,2755],{}," is persistent across tabs and browser restarts. ",[66,31241,24321],{}," is scoped to a tab and cleared when that tab's page session ends.",[11,31244,31245],{},"Try this in DevTools:",[507,31247,31249],{"className":8782,"code":31248,"language":8784,"meta":512,"style":512},"localStorage.setItem('demo', 'still here later')\nsessionStorage.setItem('demo', 'gone when tab closes')\n",[66,31250,31251,31269],{"__ignoreMap":512},[516,31252,31253,31255,31257,31259,31262,31264,31267],{"class":518,"line":519},[516,31254,30974],{"class":1227},[516,31256,24534],{"class":4733},[516,31258,8643],{"class":1227},[516,31260,31261],{"class":1248},"'demo'",[516,31263,154],{"class":1227},[516,31265,31266],{"class":1248},"'still here later'",[516,31268,8649],{"class":1227},[516,31270,31271,31273,31275,31277,31279,31281,31284],{"class":518,"line":525},[516,31272,31125],{"class":1227},[516,31274,24534],{"class":4733},[516,31276,8643],{"class":1227},[516,31278,31261],{"class":1248},[516,31280,154],{"class":1227},[516,31282,31283],{"class":1248},"'gone when tab closes'",[516,31285,8649],{"class":1227},[11,31287,31288],{},"Now duplicate the tab, close tabs, reopen the browser, and watch what survives.",[11,31290,31291],{},"That's the practical difference. Not encryption. Not authorization. Not some hidden security boundary you can build your whole auth system around.",[11,31293,31294,31295,31298,31299,31302],{},"Both store strings. Both are accessible from JavaScript. Both are same-origin scoped, which means ",[66,31296,31297],{},"https://app.example.com"," can't read storage from ",[66,31300,31301],{},"https://admin.example.com"," unless your architecture intentionally puts them under the same origin.",[18,31304,31306],{"id":31305},"cookies-vs-web-storage-the-big-architectural-choice","Cookies vs Web Storage: The Big Architectural Choice",[11,31308,31309],{},"Here's where developers get tripped up.",[11,31311,31312,202,31314,31316],{},[66,31313,2755],{},[66,31315,24321],{}," are frontend storage. Your JavaScript reads and writes them. The browser does not automatically send them to your backend.",[11,31318,31319],{},"Cookies are request storage. The browser automatically sends them to matching server requests.",[11,31321,31322],{},"That one distinction changes everything.",[11,31324,31325],{},"With local storage:",[507,31327,31329],{"className":8782,"code":31328,"language":8784,"meta":512,"style":512},"const token = localStorage.getItem('access_token')\n\nfetch('/api/me', {\n  headers: {\n    Authorization: `Bearer ${token}`,\n  },\n})\n",[66,31330,31331,31349,31353,31364,31369,31384,31389],{"__ignoreMap":512},[516,31332,31333,31335,31337,31339,31341,31343,31345,31347],{"class":518,"line":519},[516,31334,8632],{"class":1749},[516,31336,24412],{"class":1233},[516,31338,1793],{"class":1749},[516,31340,24469],{"class":1227},[516,31342,24472],{"class":4733},[516,31344,8643],{"class":1227},[516,31346,31093],{"class":1248},[516,31348,8649],{"class":1227},[516,31350,31351],{"class":518,"line":525},[516,31352,1131],{"emptyLinePlaceholder":1130},[516,31354,31355,31357,31359,31362],{"class":518,"line":531},[516,31356,29389],{"class":4733},[516,31358,8643],{"class":1227},[516,31360,31361],{"class":1248},"'/api/me'",[516,31363,23371],{"class":1227},[516,31365,31366],{"class":518,"line":1127},[516,31367,31368],{"class":1227},"  headers: {\n",[516,31370,31371,31374,31377,31380,31382],{"class":518,"line":1134},[516,31372,31373],{"class":1227},"    Authorization: ",[516,31375,31376],{"class":1248},"`Bearer ${",[516,31378,31379],{"class":1227},"token",[516,31381,14760],{"class":1248},[516,31383,1252],{"class":1227},[516,31385,31386],{"class":518,"line":1275},[516,31387,31388],{"class":1227},"  },\n",[516,31390,31391],{"class":518,"line":1302},[516,31392,11530],{"class":1227},[11,31394,31395],{},"With cookies:",[507,31397,31399],{"className":8782,"code":31398,"language":8784,"meta":512,"style":512},"fetch('/api/me', {\n  credentials: 'include',\n})\n",[66,31400,31401,31411,31421],{"__ignoreMap":512},[516,31402,31403,31405,31407,31409],{"class":518,"line":519},[516,31404,29389],{"class":4733},[516,31406,8643],{"class":1227},[516,31408,31361],{"class":1248},[516,31410,23371],{"class":1227},[516,31412,31413,31416,31419],{"class":518,"line":525},[516,31414,31415],{"class":1227},"  credentials: ",[516,31417,31418],{"class":1248},"'include'",[516,31420,1252],{"class":1227},[516,31422,31423],{"class":518,"line":531},[516,31424,11530],{"class":1227},[11,31426,31427],{},"The first style is common in API-heavy SPAs. The second style is common in server-backed web apps and BFF architectures, where BFF means Backend for Frontend.",[11,31429,31430,31431,31433,31434,31436],{},"Neither pattern is automatically perfect. Token-in-header avoids some CSRF problems but exposes tokens to JavaScript if stored poorly. Cookie-based auth can protect the session ID with ",[66,31432,699],{},", but you need to configure ",[66,31435,705],{},", CSRF defenses, and CORS carefully.",[31438,31439,31440],"blockquote",{},[11,31441,31442,31443,405],{},"Related read: if you're using JWTs in either of these patterns, the storage decision matters a lot. I break down token structure, signing, expiry, and safer storage choices in ",[761,31444,2748],{"href":2747},[11,31446,31447],{},"Pick your tradeoff consciously.",[18,31449,31451],{"id":31450},"practical-recommendations-i-actually-use","Practical Recommendations I Actually Use",[11,31453,31454,31455,31458],{},"For most traditional web apps, I prefer ",[31,31456,31457],{},"HttpOnly, Secure, SameSite cookies"," with server-side sessions. It's boring, proven, and easy to reason about.",[11,31460,31461,31462,31464,31465,31467,31468,31471],{},"For SPAs talking to APIs, I still try to avoid long-lived tokens in ",[66,31463,2755],{},". If the backend can issue an ",[66,31466,699],{}," cookie and expose a clean ",[66,31469,31470],{},"/api/me"," endpoint, that's usually nicer than making the frontend babysit secrets.",[11,31473,12479,31474,31476],{},[31,31475,30612],{}," for durable, non-sensitive client preferences.",[11,31478,12479,31479,31481],{},[31,31480,30615],{}," for temporary, tab-level workflow state.",[11,31483,12479,31484,31486],{},[31,31485,30618],{}," when the server needs to receive a small value automatically, especially for sessions.",[11,31488,31489],{},"Use a server-side session store when you want revocation, forced logout, device management, or \"log out everywhere\" to behave reliably.",[11,31491,31492],{},"And please don't store this:",[507,31494,31496],{"className":8782,"code":31495,"language":8784,"meta":512,"style":512},"localStorage.setItem('user', JSON.stringify({\n  email: 'dev@example.com',\n  role: 'admin',\n  token: 'super-secret-refresh-token',\n}))\n",[66,31497,31498,31518,31528,31538,31548],{"__ignoreMap":512},[516,31499,31500,31502,31504,31506,31508,31510,31512,31514,31516],{"class":518,"line":519},[516,31501,30974],{"class":1227},[516,31503,24534],{"class":4733},[516,31505,8643],{"class":1227},[516,31507,22182],{"class":1248},[516,31509,154],{"class":1227},[516,31511,24493],{"class":1233},[516,31513,405],{"class":1227},[516,31515,24547],{"class":4733},[516,31517,12910],{"class":1227},[516,31519,31520,31523,31526],{"class":518,"line":525},[516,31521,31522],{"class":1227},"  email: ",[516,31524,31525],{"class":1248},"'dev@example.com'",[516,31527,1252],{"class":1227},[516,31529,31530,31533,31536],{"class":518,"line":531},[516,31531,31532],{"class":1227},"  role: ",[516,31534,31535],{"class":1248},"'admin'",[516,31537,1252],{"class":1227},[516,31539,31540,31543,31546],{"class":518,"line":1127},[516,31541,31542],{"class":1227},"  token: ",[516,31544,31545],{"class":1248},"'super-secret-refresh-token'",[516,31547,1252],{"class":1227},[516,31549,31550],{"class":518,"line":1134},[516,31551,31552],{"class":1227},"}))\n",[11,31554,31555],{},"It feels productive in the moment. It ages badly.",[18,31557,31559],{"id":31558},"a-simple-decision-guide","A Simple Decision Guide",[11,31561,31562],{},"Ask yourself one question first: who needs this data?",[11,31564,31565,31566,756,31568,405],{},"If only the browser UI needs it, choose ",[66,31567,2755],{},[66,31569,24321],{},[11,31571,31572],{},"If the server needs it on every request, cookies are probably a better fit.",[11,31574,31575],{},"If the data is sensitive, don't store it somewhere JavaScript can casually read it.",[11,31577,31578,31579,405],{},"If the data should disappear when the tab closes, use ",[31,31580,30615],{},[11,31582,31583,31584,405],{},"If it should survive browser restarts, use ",[31,31585,30612],{},[11,31587,31588,31589,154,31591,31593,31594,31596],{},"If it represents a logged-in user session, strongly consider a cookie-backed session with ",[66,31590,699],{},[66,31592,702],{},", and a sane ",[66,31595,705],{}," value.",[11,31598,31599],{},"That's the whole game. Not simple, exactly, but manageable.",[18,31601,31603],{"id":31602},"common-mistakes-worth-avoiding","Common Mistakes Worth Avoiding",[11,31605,31606],{},"The first mistake is treating browser storage like a database. It's not. Users can clear it, browsers can evict it, private browsing changes behavior, and extensions can make your assumptions look silly.",[11,31608,31609,31610,31612],{},"The second mistake is storing sensitive auth data in ",[66,31611,2755],{}," because \"JWTs are stateless.\" Stateless doesn't mean harmless. A stolen token is still a stolen token.",[11,31614,31615,31616,154,31618,31620,31621,31623],{},"The third mistake is assuming cookies are automatically secure. A cookie without ",[66,31617,699],{},[66,31619,702],{},", and thoughtful ",[66,31622,705],{}," settings is just a tiny text file with confidence issues.",[11,31625,31626],{},"The fourth mistake is mixing all three storage types for the same responsibility. If login state lives partly in a cookie, partly in local storage, and partly in session storage, debugging logout will become your new personality.",[11,31628,31629],{},"Keep one source of truth.",[18,31631,31633],{"id":31632},"final-take","Final Take",[11,31635,31636,31637,31639],{},"The best answer to ",[31,31638,30589],{}," is not \"always use X.\" That's a lazy answer.",[11,31641,12479,31642,31644,31645,31647,31648,31650,31651,405],{},[31,31643,30612],{}," when you need persistent client-side convenience. Use ",[31,31646,30615],{}," when the data should be temporary and tab-specific. Use ",[31,31649,30618],{}," when the browser and server need to cooperate on requests, especially around ",[31,31652,31653],{},"sessions",[11,31655,31656],{},"And when authentication is involved, get a little more boring than your instincts want you to be.",[11,31658,31659],{},"Boring auth is usually good auth.",[31438,31661,31662],{},[11,31663,31664,31665,405],{},"Want a quick interview-style version of this topic? See question 73 in ",[761,31666,31667],{"href":8452},"Top 100 Frontend Interview Questions and Answers",[4868,31669,31670],{},"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 pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":512,"searchDepth":525,"depth":525,"links":31672},[31673,31674,31675,31678,31679,31680,31681,31682,31683,31684,31685],{"id":30593,"depth":525,"text":30594},{"id":30734,"depth":525,"text":30735},{"id":30796,"depth":525,"text":30797,"children":31676},[31677],{"id":30837,"depth":531,"text":30838},{"id":30957,"depth":525,"text":30958},{"id":31108,"depth":525,"text":31109},{"id":31228,"depth":525,"text":31229},{"id":31305,"depth":525,"text":31306},{"id":31450,"depth":525,"text":31451},{"id":31558,"depth":525,"text":31559},{"id":31602,"depth":525,"text":31603},{"id":31632,"depth":525,"text":31633},"2026-05-07","A practical developer guide to local storage vs session storage vs cookies, including sessions, cookies, localStorage, sessionStorage, security tradeoffs, and real browser examples.","local-storage-vs-session-storage-vs-cookies.png",{},"/backend/local-storage-vs-session-storage-vs-cookies",{"title":30563,"description":31687},"Backend/4.local-storage-vs-session-storage-vs-cookies",[31694,711,31695,31696,31697],"Sessions","Local Storage","Session Storage","Web Security","PvFNJ3N49aNQL4l0sk5ojXfSwBE_fojsaGs4JpryY0w",1785938229190]