[{"data":1,"prerenderedAt":837},["ShallowReactive",2],{"post-index":3,"post-vue-vapor-compilador-v-if-v-for-v-model-slots":170},[4,15,25,33,41,49,63,75,87,99,109,121,131,141,150,160],{"slug":5,"title":6,"description":7,"excerpt":8,"category":9,"level":10,"publishedAt":11,"updatedAt":11,"readingTime":12,"image":13,"tags":14},"vue-vapor-adopcion-interop-bundle","Adoptar Vapor en una app Vue real: interop, componentes y bundle","Cómo migrar una app Vue a Vapor sin reescribirla: activar la interop, migrar componentes hoja, medir y entender el peso del bundle.","Migra una app Vue a Vapor sin reescribirla: activa la interop, migra componentes hoja, mide y entiende el peso del bundle.","performance","intermediate","2026-11-14T14:38:14.852Z",6,"",[10,9],{"slug":16,"title":17,"description":18,"excerpt":19,"category":20,"level":21,"publishedAt":22,"updatedAt":22,"readingTime":23,"image":13,"tags":24},"vue-3-6-reactividad-alien-signals","Reactividad de Vue 3.6: qué cambió con alien-signals y cómo medirlo","Qué cambió en el sistema de reactividad de Vue 3.6 con alien-signals, cuánto mejora medido en tu máquina y cómo comprobarlo en tu app.","Qué cambió en la reactividad de Vue 3.6 con alien-signals, cuánto mejora medido en tu máquina y cómo comprobarlo.","reactivity","advanced","2026-11-14T14:29:47.062Z",5,[21,9],{"slug":26,"title":27,"description":28,"excerpt":29,"category":9,"level":21,"publishedAt":30,"updatedAt":31,"readingTime":12,"image":13,"tags":32},"vue-vapor-compilador-v-if-v-for-v-model-slots","Dentro del compilador de Vapor: v-if, v-for, v-model y slots en Vue 3.6","Qué código genera Vapor para v-if, v-for, v-model y slots frente al Virtual DOM, leído con el compilador de Vue 3.6.","Compara el código que genera Vapor y Virtual DOM para v-if, v-for, v-model y slots, con el compilador de Vue 3.6.","2026-11-14T14:11:32.855Z","2026-11-14T14:18:07.483Z",[21,9],{"slug":34,"title":35,"description":36,"excerpt":37,"category":9,"level":21,"publishedAt":38,"updatedAt":38,"readingTime":39,"image":13,"tags":40},"vue-vapor-benchmark-metodologia","Medir sin engañarse: benchmark de Virtual DOM frente a Vapor en Vue 3.6","Cómo medir Virtual DOM frente a Vapor en Vue 3.6 sin engañarse: apps aisladas, calentamiento, orden alternado, mediana y medición en producción.","Mide Virtual DOM frente a Vapor sin engañarse: apps aisladas, calentamiento, orden alternado, mediana y pruebas en producción.","2026-11-14T14:07:52.145Z",7,[21,9],{"slug":42,"title":43,"description":44,"excerpt":45,"category":9,"level":10,"publishedAt":46,"updatedAt":46,"readingTime":47,"image":13,"tags":48},"vue-vapor-mode-sin-virtual-dom","Vapor Mode en Vue 3.6: Vue sin Virtual DOM, explicado y medido","Qué es Vapor Mode en Vue 3.6, cómo activarlo, qué código genera el compilador y cuánto mejora frente al Virtual DOM, con mediciones reales.","Activa Vapor Mode en Vue 3.6 con una sola palabra, mira qué compila y mide cuánto mejora frente al Virtual DOM, con cifras reales.","2026-11-14T14:01:56.481Z",9,[10,9],{"slug":50,"title":51,"description":52,"excerpt":53,"rank":54,"category":20,"level":10,"publishedAt":55,"updatedAt":56,"readingTime":39,"image":57,"tags":58},"watch-vs-watcheffect-cotizador-envios-vue-3","watch vs. watchEffect en Vue 3: evita cotizaciones de envío desactualizadas","Construye un cotizador de envíos con Vue 3.5+: usa watch, debounce y onWatcherCleanup para evitar tarifas obsoletas en un checkout real.","Evita respuestas HTTP desactualizadas con watch, debounce y cancelación en un cotizador de envíos.",1,"2026-09-27T18:12:58.826Z","2026-10-05T04:27:15.492Z","https://a-us.storyblok.com/f/1022875/1672x941/2033377396/watch-vs-watcheffect-cotizador-envios-vue-3.png",[59,60,10,61,62],"backend","composition-api","watch","watch-effect",{"slug":64,"title":65,"description":66,"excerpt":66,"rank":12,"category":67,"level":10,"publishedAt":68,"updatedAt":69,"readingTime":70,"image":71,"tags":72},"how-to-use-teleport-in-vue-3","Teleport en Vue 3: notificaciones con limpieza y claves estables","Mueve notificaciones al body con Teleport, claves estables y limpieza de temporizadores.","components","2025-07-26T01:49:43.552Z","2026-10-05T04:02:39.181Z",3,"https://a-us.storyblok.com/f/1022875/1376x768/9bbb639e1d/teleport.jpg",[67,10,73,74],"teleport","ui-patterns",{"slug":76,"title":77,"description":78,"excerpt":78,"rank":39,"category":67,"level":79,"publishedAt":80,"updatedAt":81,"readingTime":82,"image":83,"tags":84},"use-definemodel","defineModel() en Vue 3.4+: La evolución elegante del v-model en componentes","Crea un input reutilizable con defineModel y aplica un modificador personalizado sin duplicar el modelo.","beginner","2025-07-21T03:03:33.292Z","2026-10-05T03:55:33.832Z",2,"https://a-us.storyblok.com/f/1022875/1536x1024/7c8b51e1ae/definemodel2.png",[67,85,10,86],"define-model","v-model",{"slug":88,"title":89,"description":90,"excerpt":90,"rank":91,"category":92,"level":10,"publishedAt":93,"updatedAt":94,"readingTime":82,"image":95,"tags":96},"vue-fire","Autenticación con Google en Vue 3 y VueFire","Conecta Firebase Auth con VueFire y añade acceso con Google, cierre de sesión y errores visibles.",10,"integrations","2025-06-10T03:22:00.345Z","2026-10-05T04:03:20.036Z","https://a-us.storyblok.com/f/1022875/1376x768/9774bccf90/vuefire.jpg",[59,97,10,98],"firebase","vuefire",{"slug":100,"title":101,"description":102,"excerpt":102,"rank":47,"category":92,"level":21,"publishedAt":103,"updatedAt":104,"readingTime":70,"image":105,"tags":106},"web-components-with-modern-vue","Web Components con Vue 3: distribuye un contador con defineCustomElement","Publica un contador Vue como Custom Element con estilos encapsulados y eventos para HTML.","2025-04-15T02:46:47.631Z","2026-10-05T04:02:55.512Z","https://a-us.storyblok.com/f/1022875/1536x1024/7b5cd5a452/web-components.png",[21,67,107,108],"define-custom-element","interoperability",{"slug":110,"title":111,"description":112,"excerpt":112,"rank":113,"category":92,"level":10,"publishedAt":114,"updatedAt":115,"readingTime":82,"image":116,"tags":117},"tailwind-4-integration-with-vue-cli","Tailwind CSS 4 con Vue CLI: guía para proyectos existentes","Mantén un proyecto existente con Vue CLI y compila Tailwind 4 sin desactivar la optimización de producción.",11,"2025-03-16T16:48:02.739Z","2026-10-05T04:03:28.685Z","https://a-us.storyblok.com/f/1022875/1792x1024/71cb200538/vue-cli-and-tailwind-4.webp",[10,118,119,120],"styling","tailwind","vue-cli",{"slug":122,"title":123,"description":124,"excerpt":124,"rank":125,"category":67,"level":79,"publishedAt":126,"updatedAt":127,"readingTime":82,"image":128,"tags":129},"how-to-use-defineexpose","¿Cómo usar defineExpose?","Expón una API pequeña desde un modal y contrólala desde el padre con una referencia tipada.",4,"2025-02-26T02:23:58.312Z","2026-10-05T04:06:26.788Z","https://a-us.storyblok.com/f/1022875/1376x768/487e84614f/defineexpose.jpg",[79,67,60,130],"define-expose",{"slug":132,"title":133,"description":134,"excerpt":134,"rank":23,"category":9,"level":21,"publishedAt":135,"updatedAt":136,"readingTime":23,"image":137,"tags":138},"how-to-use-v-memo","Cómo usar v-memo en Vue 3: dependencias y medición de rendimiento","Optimiza una lista con v-memo, elige dependencias completas y compara el resultado antes de adoptarlo.","2025-02-08T18:55:25.441Z","2026-10-05T04:06:52.708Z","https://a-us.storyblok.com/f/1022875/1376x768/b989b9ebdf/v-memo-image.jpg",[139,10,9,140],"directives","v-memo",{"slug":142,"title":143,"description":144,"excerpt":144,"rank":70,"category":20,"level":10,"publishedAt":145,"updatedAt":146,"readingTime":70,"image":147,"tags":148},"what-is-a-composable","¿Qué es un Composable?","Extrae consultas HTTP a un composable tipado que cancela peticiones anteriores y maneja errores.","2025-02-05T03:00:11.569Z","2026-10-05T04:00:35.499Z","https://a-us.storyblok.com/f/1022875/1376x768/0c48bd03b4/vue-composables.jpg",[79,149,60],"composables",{"slug":151,"title":152,"description":153,"excerpt":153,"rank":82,"category":9,"level":10,"publishedAt":154,"updatedAt":155,"readingTime":70,"image":156,"tags":157},"use-defineasynccomponent","defineAsyncComponent en Vue 3: Implementación y casos de uso.","Carga componentes bajo demanda y muestra estados de carga y error con defineAsyncComponent.","2025-01-15T03:44:46.169Z","2026-10-05T04:01:11.606Z","https://a-us.storyblok.com/f/1022875/1376x768/ff546597c5/vue_defineasync_img.jpg",[67,158,10,159,9],"define-async-component","lazy-loading",{"slug":161,"title":162,"description":163,"excerpt":163,"rank":164,"category":92,"level":79,"publishedAt":165,"updatedAt":166,"readingTime":82,"image":167,"tags":168},"tailwind-4-integration-in-vue-js-3","¿Cómo integrar Tailwind 4 en Vue.js 3 + Vite?","Configura Tailwind CSS 4 en Vue 3 con los plugins de Vue y Tailwind para Vite.",8,"2025-01-12T02:34:06.176Z","2026-10-05T04:02:46.836Z","https://a-us.storyblok.com/f/1022875/1376x768/626e80a702/taiwlind4_vue_3.jpg",[10,118,119,169],"vite",{"name":27,"created_at":171,"published_at":31,"updated_at":172,"id":173,"uuid":174,"content":175,"slug":26,"full_slug":829,"sort_by_date":179,"position":830,"tag_list":831,"is_startpage":832,"parent_id":833,"meta_data":179,"group_id":834,"first_published_at":30,"release_id":179,"lang":835,"path":179,"alternates":836,"default_full_slug":179,"translated_slugs":179},"2026-11-14T14:09:12.604Z","2026-11-14T14:18:07.497Z",241564682683468,"dc369b13-1c19-419b-95f2-41783c4d5939",{"_uid":176,"demo":177,"image":178,"level":21,"title":27,"video":182,"content":184,"excerpt":29,"category":9,"component":828,"description":28,"youtube_url":13,"editorial_rank":13},"18aa629d-9e78-4523-b0bb-225e717fd48e",[],{"id":179,"alt":179,"name":13,"focus":179,"title":179,"source":179,"filename":13,"copyright":179,"fieldtype":180,"meta_data":181},null,"asset",{},{"id":179,"alt":179,"name":13,"focus":179,"title":179,"source":179,"filename":13,"copyright":179,"fieldtype":180,"meta_data":183},{},{"type":185,"attrs":186,"content":187},"doc",{"backgroundColor":179},[188,195,228,245,251,256,273,278,289,300,308,313,318,323,328,339,344,349,357,362,367,396,401,418,423,454,462,471,476,504,509,520,525,530,545,550,555,570,575,591,596,601,606,692,697,702,713,718,750,755,816],{"type":189,"attrs":190,"content":191},"heading",{"level":82,"textAlign":179},[192],{"text":193,"type":194},"Objetivo y requisitos","text",{"type":196,"attrs":197,"content":198},"paragraph",{"textAlign":179},[199,201,209,211,216,218,222,223,226],{"text":200,"type":194},"En el ",{"text":202,"type":194,"marks":203},"post sobre Vapor Mode",[204],{"type":205,"attrs":206},"link",{"href":207,"uuid":179,"anchor":179,"target":179,"linktype":208},"https://elrincondevue.com/article-list/vue-vapor-mode-sin-virtual-dom","url",{"text":210,"type":194}," vimos que Vapor no usa el Virtual DOM. Aquí entramos al compilador para responder la pregunta práctica: ¿qué código genera Vapor para ",{"text":212,"type":194,"marks":213},"v-if",[214],{"type":215},"code",{"text":217,"type":194},", ",{"text":219,"type":194,"marks":220},"v-for",[221],{"type":215},{"text":217,"type":194},{"text":86,"type":194,"marks":224},[225],{"type":215},{"text":227,"type":194}," y los slots, y qué cambia frente al Virtual DOM?",{"type":196,"attrs":229,"content":230},{"textAlign":179},[231,233,237,239,243],{"text":232,"type":194},"Necesitas Vue ",{"text":234,"type":194,"marks":235},"3.6.0-rc.15",[236],{"type":215},{"text":238,"type":194}," o superior y ",{"text":240,"type":194,"marks":241},"@vue/compiler-sfc",[242],{"type":215},{"text":244,"type":194}," con la misma versión. Para ver la salida, usamos el compilador directamente en Node, sin proyecto completo.",{"type":246,"attrs":247,"content":248},"code_block",{"class":179},[249],{"text":250,"type":194},"npm install @vue/compiler-sfc@3.6.0-rc.15\n",{"type":189,"attrs":252,"content":253},{"level":82,"textAlign":179},[254],{"text":255,"type":194},"Cómo leer la salida",{"type":196,"attrs":257,"content":258},{"textAlign":179},[259,261,265,267,271],{"text":260,"type":194},"Compilamos el mismo SFC dos veces, con ",{"text":262,"type":194,"marks":263},"vapor: false",[264],{"type":215},{"text":266,"type":194}," y con ",{"text":268,"type":194,"marks":269},"vapor: true",[270],{"type":215},{"text":272,"type":194},":",{"type":246,"attrs":274,"content":275},{"class":179},[276],{"text":277,"type":194},"import { parse, compileScript } from '@vue/compiler-sfc'\n\nconst { descriptor } = parse(source, { filename: 'Demo.vue' })\n\nfor (const vapor of [false, true]) {\n  const { content } = compileScript(descriptor, { id: 'demo', inlineTemplate: true, vapor })\n  console.log(content)\n}\n",{"type":196,"attrs":279,"content":280},{"textAlign":179},[281,283,287],{"text":282,"type":194},"Un detalle para evitar confusiones: si el archivo ya tiene ",{"text":284,"type":194,"marks":285},"\u003Cscript setup vapor>",[286],{"type":215},{"text":288,"type":194},", esa marca manda sobre la opción. Para comparar los dos modos, quita el atributo del archivo antes de compilar, como hacemos en el script del post anterior.",{"type":196,"attrs":290,"content":291},{"textAlign":179},[292,294,298],{"text":293,"type":194},"El código generado incluye imports, ",{"text":295,"type":194,"marks":296},"_hoisted",[297],{"type":215},{"text":299,"type":194}," y envoltorios que no cambian la historia. Lo que sigue son solo las partes que importan.",{"type":189,"attrs":301,"content":302},{"level":82,"textAlign":179},[303,306],{"text":212,"type":194,"marks":304},[305],{"type":215},{"text":307,"type":194},": una rama, una clonación",{"type":196,"attrs":309,"content":310},{"textAlign":179},[311],{"text":312,"type":194},"Este template muestra dos ramas:",{"type":246,"attrs":314,"content":315},{"class":179},[316],{"text":317,"type":194},"\u003Cp v-if=\"show\">Visible\u003C/p>\n\u003Cp v-else>Oculto\u003C/p>\n",{"type":196,"attrs":319,"content":320},{"textAlign":179},[321],{"text":322,"type":194},"Con Virtual DOM, el compilador elige entre dos bloques con un operador ternario. Cada bloque devuelve un vnode nuevo, y Vue lo compara con el anterior:",{"type":246,"attrs":324,"content":325},{"class":179},[326],{"text":327,"type":194},"return (_ctx, _cache) => {\n  return (show.value)\n    ? (_openBlock(), _createElementBlock(\"p\", _hoisted_1, \"Visible\"))\n    : (_openBlock(), _createElementBlock(\"p\", _hoisted_2, \"Oculto\"))\n}\n",{"type":196,"attrs":329,"content":330},{"textAlign":179},[331,333,337],{"text":332,"type":194},"Con Vapor, el compilador usa ",{"text":334,"type":194,"marks":335},"createIf",[336],{"type":215},{"text":338,"type":194},". Recibe la condición y una fábrica por rama, y cada rama clona su propio template:",{"type":246,"attrs":340,"content":341},{"class":179},[342],{"text":343,"type":194},"const t0 = _template(\"\u003Cp>Visible\", 3)\nconst t1 = _template(\"\u003Cp>Oculto\", 3)\n\nconst n0 = _createIf(() => (show.value), () => {\n  const n2 = t0()\n  return n2\n}, () => {\n  const n4 = t1()\n  return n4\n})\nreturn n0\n",{"type":196,"attrs":345,"content":346},{"textAlign":179},[347],{"text":348,"type":194},"La diferencia de fondo: en Vapor, al cambiar la condición se monta la rama nueva y se desmonta la anterior. No hay un render del componente completo que genere un árbol para comparar después.",{"type":189,"attrs":350,"content":351},{"level":82,"textAlign":179},[352,355],{"text":219,"type":194,"marks":353},[354],{"type":215},{"text":356,"type":194},": una fuente reactiva por fila",{"type":196,"attrs":358,"content":359},{"textAlign":179},[360],{"text":361,"type":194},"Este template renderiza una lista con clave:",{"type":246,"attrs":363,"content":364},{"class":179},[365],{"text":366,"type":194},"\u003Cli v-for=\"row in rows\" :key=\"row.id\">{{ row.label }}\u003C/li>\n",{"type":196,"attrs":368,"content":369},{"textAlign":179},[370,372,376,378,382,384,388,390,394],{"text":371,"type":194},"Con Virtual DOM, el compilador llama a ",{"text":373,"type":194,"marks":374},"renderList",[375],{"type":215},{"text":377,"type":194}," dentro de un ",{"text":379,"type":194,"marks":380},"Fragment",[381],{"type":215},{"text":383,"type":194}," marcado como ",{"text":385,"type":194,"marks":386},"KEYED_FRAGMENT",[387],{"type":215},{"text":389,"type":194},". Cada vez que cambia ",{"text":391,"type":194,"marks":392},"rows",[393],{"type":215},{"text":395,"type":194},", Vue vuelve a ejecutar la función del render, crea los vnodes de todas las filas y los compara por clave:",{"type":246,"attrs":397,"content":398},{"class":179},[399],{"text":400,"type":194},"return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(rows.value, (row) => {\n  return (_openBlock(), _createElementBlock(\"li\", {\n    key: row.id\n  }, _toDisplayString(row.label), 1 /* TEXT */))\n}), 128 /* KEYED_FRAGMENT */))\n",{"type":196,"attrs":402,"content":403},{"textAlign":179},[404,406,410,412,416],{"text":405,"type":194},"Con Vapor, el compilador genera ",{"text":407,"type":194,"marks":408},"createFor",[409],{"type":215},{"text":411,"type":194},". La clave se obtiene con una función, y cada fila recibe el dato como una fuente reactiva (de ahí el ",{"text":413,"type":194,"marks":414},".value",[415],{"type":215},{"text":417,"type":194}," que aparece dentro de la fila):",{"type":246,"attrs":419,"content":420},{"class":179},[421],{"text":422,"type":194},"const t0 = _template(\"\u003Cli> \")\n\nconst n0 = _createFor(() => (rows.value), (_for_item0) => {\n  const n2 = t0()\n  const x2 = _txt(n2)\n  _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value.label)))\n  return n2\n}, (row) => (row.id), 8 /* IS_SINGLE_NODE */)\n",{"type":196,"attrs":424,"content":425},{"textAlign":179},[426,428,432,434,438,440,444,446,452],{"text":427,"type":194},"Aquí está la explicación de por qué las listas son rápidas en Vapor. Cuando cambia el ",{"text":429,"type":194,"marks":430},"label",[431],{"type":215},{"text":433,"type":194}," de una fila, solo se ejecuta su ",{"text":435,"type":194,"marks":436},"renderEffect",[437],{"type":215},{"text":439,"type":194},", que escribe en el nodo ",{"text":441,"type":194,"marks":442},"x2",[443],{"type":215},{"text":445,"type":194},". El resto de filas no se evalúa. Eso es lo que medimos en el ",{"text":447,"type":194,"marks":448},"benchmark de actualizar 1 de cada 10 filas",[449],{"type":205,"attrs":450},{"href":451,"uuid":179,"anchor":179,"target":179,"linktype":208},"https://elrincondevue.com/article-list/vue-vapor-benchmark-metodologia",{"text":453,"type":194},": 2,0 ms frente a 0,3 ms en JavaScript.",{"type":189,"attrs":455,"content":456},{"level":82,"textAlign":179},[457,460],{"text":86,"type":194,"marks":458},[459],{"type":215},{"text":461,"type":194},": un helper en lugar de una directiva",{"type":196,"attrs":463,"content":464},{"textAlign":179},[465,467,470],{"text":466,"type":194},"Un input con ",{"text":86,"type":194,"marks":468},[469],{"type":215},{"text":272,"type":194},{"type":246,"attrs":472,"content":473},{"class":179},[474],{"text":475,"type":194},"\u003Cinput v-model=\"name\" />\n",{"type":196,"attrs":477,"content":478},{"textAlign":179},[479,481,484,486,490,492,496,498,502],{"text":480,"type":194},"Con Virtual DOM, ",{"text":86,"type":194,"marks":482},[483],{"type":215},{"text":485,"type":194}," se compila a ",{"text":487,"type":194,"marks":488},"withDirectives",[489],{"type":215},{"text":491,"type":194}," con ",{"text":493,"type":194,"marks":494},"vModelText",[495],{"type":215},{"text":497,"type":194},", más un listener ",{"text":499,"type":194,"marks":500},"onUpdate:modelValue",[501],{"type":215},{"text":503,"type":194},". La directiva se aplica en cada render:",{"type":246,"attrs":505,"content":506},{"class":179},[507],{"text":508,"type":194},"return _withDirectives((_openBlock(), _createElementBlock(\"input\", {\n  \"onUpdate:modelValue\": _cache[0] || (_cache[0] = $event => ((name).value = $event))\n}, null, 512 /* NEED_PATCH */)), [\n  [_vModelText, name.value]\n])\n",{"type":196,"attrs":510,"content":511},{"textAlign":179},[512,514,518],{"text":513,"type":194},"Con Vapor, el compilador genera una sola llamada a ",{"text":515,"type":194,"marks":516},"applyTextModel",[517],{"type":215},{"text":519,"type":194},", que recibe el nodo, un getter y un setter:",{"type":246,"attrs":521,"content":522},{"class":179},[523],{"text":524,"type":194},"const t0 = _template(\"\u003Cinput>\", 1)\n\nconst n0 = t0()\n_applyTextModel(n0, () => (name.value), _value => (name.value = _value))\nreturn n0\n",{"type":196,"attrs":526,"content":527},{"textAlign":179},[528],{"text":529,"type":194},"No hay directiva que se reevalúe en cada render, porque el enlace se registra una vez, con sus efectos. Las directivas personalizadas también cambian en Vapor: no tienen la misma firma que en el Virtual DOM. Antes de migrar un componente que las use, revisa la documentación de la versión que vas a usar.",{"type":189,"attrs":531,"content":532},{"level":82,"textAlign":179},[533,535,539,541],{"text":534,"type":194},"Slots: sin ",{"text":536,"type":194,"marks":537},"withCtx",[538],{"type":215},{"text":540,"type":194}," ni caché de ",{"text":542,"type":194,"marks":543},"_cache",[544],{"type":215},{"type":196,"attrs":546,"content":547},{"textAlign":179},[548],{"text":549,"type":194},"Un componente con contenido en su slot por defecto:",{"type":246,"attrs":551,"content":552},{"class":179},[553],{"text":554,"type":194},"\u003CCard>\u003Cb>Hola\u003C/b>\u003C/Card>\n",{"type":196,"attrs":556,"content":557},{"textAlign":179},[558,560,563,565,568],{"text":559,"type":194},"Con Virtual DOM, el slot se envuelve en ",{"text":536,"type":194,"marks":561},[562],{"type":215},{"text":564,"type":194}," y el contenido estático se guarda en ",{"text":542,"type":194,"marks":566},[567],{"type":215},{"text":569,"type":194}," para no recrearlo:",{"type":246,"attrs":571,"content":572},{"class":179},[573],{"text":574,"type":194},"return (_openBlock(), _createBlock(Card, null, {\n  default: _withCtx(() => [...(_cache[0] || (_cache[0] = [\n    _createElementVNode(\"b\", null, \"Hola\", -1 /* CACHED */)\n  ]))]),\n  _: 1 /* STABLE */\n}))\n",{"type":196,"attrs":576,"content":577},{"textAlign":179},[578,580,584,586,590],{"text":579,"type":194},"Con Vapor, el componente se crea con ",{"text":581,"type":194,"marks":582},"createComponent",[583],{"type":215},{"text":585,"type":194}," y el slot es una función que devuelve el nodo clonado. El contenido estático sigue siendo un ",{"text":587,"type":194,"marks":588},"_template",[589],{"type":215},{"text":272,"type":194},{"type":246,"attrs":592,"content":593},{"class":179},[594],{"text":595,"type":194},"const t0 = _template(\"\u003Cb>Hola\", 2)\n\nconst n1 = _createComponent(Card, null, () => {\n  const n0 = t0()\n  return n0\n}, true)\nreturn n1\n",{"type":196,"attrs":597,"content":598},{"textAlign":179},[599],{"text":600,"type":194},"Para tu código, la conclusión es que la sintaxis de slots no cambia. Lo que cambia es el envoltorio que genera el compilador.",{"type":189,"attrs":602,"content":603},{"level":82,"textAlign":179},[604],{"text":605,"type":194},"Qué no cambia",{"type":607,"content":608},"bullet_list",[609,641,667],{"type":610,"content":611},"list_item",[612],{"type":196,"attrs":613,"content":614},{"textAlign":179},[615,620,622,625,626,629,630,633,635,639],{"text":616,"type":194,"marks":617},"La sintaxis del template.",[618],{"type":619},"bold",{"text":621,"type":194}," ",{"text":212,"type":194,"marks":623},[624],{"type":215},{"text":217,"type":194},{"text":219,"type":194,"marks":627},[628],{"type":215},{"text":217,"type":194},{"text":86,"type":194,"marks":631},[632],{"type":215},{"text":634,"type":194}," y ",{"text":636,"type":194,"marks":637},"\u003Cslot>",[638],{"type":215},{"text":640,"type":194}," se escriben igual.",{"type":610,"content":642},[643],{"type":196,"attrs":644,"content":645},{"textAlign":179},[646,650,651,655,656,660,661,665],{"text":647,"type":194,"marks":648},"Los props y los eventos.",[649],{"type":619},{"text":621,"type":194},{"text":652,"type":194,"marks":653},"defineProps",[654],{"type":215},{"text":217,"type":194},{"text":657,"type":194,"marks":658},"defineEmits",[659],{"type":215},{"text":634,"type":194},{"text":662,"type":194,"marks":663},"v-on",[664],{"type":215},{"text":666,"type":194}," funcionan igual.",{"type":610,"content":668},[669],{"type":196,"attrs":670,"content":671},{"textAlign":179},[672,676,677,681,682,686,687,690],{"text":673,"type":194,"marks":674},"La reactividad que escribes.",[675],{"type":619},{"text":621,"type":194},{"text":678,"type":194,"marks":679},"ref",[680],{"type":215},{"text":217,"type":194},{"text":683,"type":194,"marks":684},"computed",[685],{"type":215},{"text":634,"type":194},{"text":61,"type":194,"marks":688},[689],{"type":215},{"text":691,"type":194}," son los mismos.",{"type":196,"attrs":693,"content":694},{"textAlign":179},[695],{"text":696,"type":194},"Lo que cambia es el código que el compilador produce detrás. Por eso la forma de medir el impacto es con benchmarks como los del post anterior, no leyendo la sintaxis.",{"type":189,"attrs":698,"content":699},{"level":82,"textAlign":179},[700],{"text":701,"type":194},"Comprueba el resultado",{"type":196,"attrs":703,"content":704},{"textAlign":179},[705,707,711],{"text":706,"type":194},"Para ver la salida de cualquier componente tuyo, crea ",{"text":708,"type":194,"marks":709},"inspect-vapor.mjs",[710],{"type":215},{"text":712,"type":194}," en la raíz del proyecto:",{"type":246,"attrs":714,"content":715},{"class":179},[716],{"text":717,"type":194},"import { readFileSync } from 'node:fs'\nimport { parse, compileScript } from '@vue/compiler-sfc'\n\nconst file = process.argv[2]\n// Quita el atributo vapor del archivo para controlar el modo con la opción.\nconst source = readFileSync(file, 'utf8').replace('\u003Cscript setup vapor', '\u003Cscript setup')\nconst { descriptor } = parse(source, { filename: file })\n\nfor (const vapor of [false, true]) {\n  const { content } = compileScript(descriptor, { id: 'demo', inlineTemplate: true, vapor })\n  console.log(`\\n--- vapor: ${vapor} ---\\n${content}`)\n}\n",{"type":196,"attrs":719,"content":720},{"textAlign":179},[721,723,727,729,733,734,738,739,743,744,748],{"text":722,"type":194},"Ejecútalo con ",{"text":724,"type":194,"marks":725},"node inspect-vapor.mjs src/components/MiComponente.vue",[726],{"type":215},{"text":728,"type":194}," y busca ",{"text":730,"type":194,"marks":731},"_createIf",[732],{"type":215},{"text":217,"type":194},{"text":735,"type":194,"marks":736},"_createFor",[737],{"type":215},{"text":217,"type":194},{"text":740,"type":194,"marks":741},"_applyTextModel",[742],{"type":215},{"text":634,"type":194},{"text":745,"type":194,"marks":746},"_createComponent",[747],{"type":215},{"text":749,"type":194}," en la salida de Vapor.",{"type":189,"attrs":751,"content":752},{"level":82,"textAlign":179},[753],{"text":754,"type":194},"Errores frecuentes",{"type":607,"content":756},[757,776,787,805],{"type":610,"content":758},[759],{"type":196,"attrs":760,"content":761},{"textAlign":179},[762,766,770,774],{"text":763,"type":194,"marks":764},"Comparar sin quitar el atributo ",[765],{"type":619},{"text":767,"type":194,"marks":768},"vapor",[769],{"type":215},{"text":771,"type":194,"marks":772},".",[773],{"type":619},{"text":775,"type":194}," Si el archivo lo tiene, ambos resultados salen en Vapor.",{"type":610,"content":777},[778],{"type":196,"attrs":779,"content":780},{"textAlign":179},[781,785],{"text":782,"type":194,"marks":783},"Leer la salida como si fuera el código que escribes.",[784],{"type":619},{"text":786,"type":194}," Es el código que Vue ejecuta; cambia con cada versión del compilador. Úsala para entender, no para copiar.",{"type":610,"content":788},[789],{"type":196,"attrs":790,"content":791},{"textAlign":179},[792,796,799,803],{"text":793,"type":194,"marks":794},"Esperar que ",[795],{"type":619},{"text":140,"type":194,"marks":797},[798],{"type":215},{"text":800,"type":194,"marks":801}," tenga efecto.",[802],{"type":619},{"text":804,"type":194}," En Vapor no existe. La directiva servía para evitar renders del Virtual DOM, y aquí no hay render que evitar.",{"type":610,"content":806},[807],{"type":196,"attrs":808,"content":809},{"textAlign":179},[810,814],{"text":811,"type":194,"marks":812},"Usar directivas personalizadas sin revisar su comportamiento en Vapor.",[813],{"type":619},{"text":815,"type":194}," Su firma es distinta.",{"type":196,"attrs":817,"content":818},{"textAlign":179},[819,821,826],{"text":820,"type":194},"Si quieres ver el lado del rendimiento de estas piezas, el ",{"text":822,"type":194,"marks":823},"benchmark con la métrica de JavaScript",[824],{"type":205,"attrs":825},{"href":451,"uuid":179,"anchor":179,"target":179,"linktype":208},{"text":827,"type":194}," muestra cómo se traduce cada patrón en tiempo.","posts","posts/vue-vapor-compilador-v-if-v-for-v-model-slots",-130,[21,9],false,20030325,"2a7295fc-e66e-450b-b406-b4144dfc86ff","default",[],1794670872770]