[{"data":1,"prerenderedAt":845},["ShallowReactive",2],{"post-index":3,"post-vue-vapor-benchmark-metodologia":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":35,"created_at":171,"published_at":38,"updated_at":172,"id":173,"uuid":174,"content":175,"slug":34,"full_slug":837,"sort_by_date":179,"position":838,"tag_list":839,"is_startpage":840,"parent_id":841,"meta_data":179,"group_id":842,"first_published_at":38,"release_id":179,"lang":843,"path":179,"alternates":844,"default_full_slug":179,"translated_slugs":179},"2026-11-14T14:03:38.987Z","2026-11-14T14:07:52.166Z",241563316192331,"46e18e25-29cc-4fca-b39a-a74ce29b6e6f",{"_uid":176,"demo":177,"image":178,"level":21,"title":35,"video":182,"content":184,"excerpt":37,"category":9,"component":836,"description":36,"youtube_url":13,"editorial_rank":13},"bccf7300-a860-4256-b17a-1e4402bcb0de",[],{"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,201,223,228,233,239,244,261,284,289,300,305,343,348,365,377,382,387,430,435,440,451,478,483,488,596,607,612,617,622,663,668,673,725,730,735,740,751,762,767,824],{"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],{"text":200,"type":194},"Cuando ves una tabla que dice “Vapor es 15 veces más rápido”, la pregunta correcta no es cuánto, sino cómo se midió. En este artículo montamos un benchmark pequeño para comparar Virtual DOM y Vapor Mode en Vue 3.6, y cada decisión de medición tiene su razón: qué se cronometra, cuándo, en qué orden y con cuántas repeticiones.",{"type":196,"attrs":202,"content":203},{"textAlign":179},[204,206,211,213,221],{"text":205,"type":194},"Necesitas Vue 3.6 (la versión candidata ",{"text":207,"type":194,"marks":208},"3.6.0-rc.15",[209],{"type":210},"code",{"text":212,"type":194}," o superior) y un proyecto Vite con TypeScript, como el del ",{"text":214,"type":194,"marks":215},"post anterior sobre Vapor Mode",[216],{"type":217,"attrs":218},"link",{"href":219,"uuid":179,"anchor":179,"target":179,"linktype":220},"https://elrincondevue.com/article-list/vue-vapor-mode-sin-virtual-dom","url",{"text":222,"type":194},". Medir en modo desarrollo no sirve: lo explicamos más abajo.",{"type":189,"attrs":224,"content":225},{"level":82,"textAlign":179},[226],{"text":227,"type":194},"Dos apps aisladas con el mismo componente",{"type":196,"attrs":229,"content":230},{"textAlign":179},[231],{"text":232,"type":194},"La comparación justa exige que solo cambie el motor. Por eso creamos dos archivos idénticos salvo una palabra:",{"type":234,"attrs":235,"content":236},"code_block",{"class":179},[237],{"text":238,"type":194},"\u003C!-- VdomRowTable.vue -->\n\u003Cscript setup lang=\"ts\">\nimport type { RowStoreApi } from '@/modules/benchmark/models/benchmark.models'\n\nconst props = defineProps\u003C{ store: RowStoreApi }>()\nconst { rows, selectedId, select, remove } = props.store\n\u003C/script>\n",{"type":234,"attrs":240,"content":241},{"class":179},[242],{"text":243,"type":194},"\u003C!-- VaporRowTable.vue -->\n\u003Cscript setup vapor lang=\"ts\">\nimport type { RowStoreApi } from '@/modules/benchmark/models/benchmark.models'\n\nconst props = defineProps\u003C{ store: RowStoreApi }>()\nconst { rows, selectedId, select, remove } = props.store\n\u003C/script>\n",{"type":196,"attrs":245,"content":246},{"textAlign":179},[247,249,253,255,259],{"text":248,"type":194},"Cada tabla se monta en su propia aplicación: ",{"text":250,"type":194,"marks":251},"createApp",[252],{"type":210},{"text":254,"type":194}," para una y ",{"text":256,"type":194,"marks":257},"createVaporApp",[258],{"type":210},{"text":260,"type":194}," para la otra. Así no hay interop ni runtime compartido que contamine la medición. Cada una tiene su propio almacén de filas, de modo que una operación en una no toca a la otra.",{"type":196,"attrs":262,"content":263},{"textAlign":179},[264,266,270,272,276,278,282],{"text":265,"type":194},"Un detalle que parece menor y no lo es: el template de ambas tablas tiene el mismo color de selección. Si una usa ",{"text":267,"type":194,"marks":268},"bg-vdom/20",[269],{"type":210},{"text":271,"type":194}," y la otra ",{"text":273,"type":194,"marks":274},"bg-vapor/20",[275],{"type":210},{"text":277,"type":194},", el diff ya no es solo el atributo ",{"text":279,"type":194,"marks":280},"vapor",[281],{"type":210},{"text":283,"type":194},", y el resultado mezcla dos cosas.",{"type":189,"attrs":285,"content":286},{"level":82,"textAlign":179},[287],{"text":288,"type":194},"Qué se mide exactamente",{"type":196,"attrs":290,"content":291},{"textAlign":179},[292,294,298],{"text":293,"type":194},"Una operación consiste en cambiar el estado y esperar a que el DOM esté listo. Ahí hay una trampa. Vue actualiza el DOM de forma asíncrona, en el siguiente microtask. Si cronometras solo la llamada que cambia el estado, mides casi nada. Si esperas a ",{"text":295,"type":194,"marks":296},"nextTick",[297],{"type":210},{"text":299,"type":194},", mides el trabajo del framework. Si fuerzas el layout del navegador, mides además lo que el navegador tiene que calcular.",{"type":196,"attrs":301,"content":302},{"textAlign":179},[303],{"text":304,"type":194},"Por eso distinguimos dos métricas:",{"type":306,"content":307},"bullet_list",[308,326],{"type":309,"content":310},"list_item",[311],{"type":196,"attrs":312,"content":313},{"textAlign":179},[314,319,321,324],{"text":315,"type":194,"marks":316},"Solo JS:",[317],{"type":318},"bold",{"text":320,"type":194}," desde el cambio de estado hasta que ",{"text":295,"type":194,"marks":322},[323],{"type":210},{"text":325,"type":194}," resuelve. Es el trabajo del framework.",{"type":309,"content":327},[328],{"type":196,"attrs":329,"content":330},{"textAlign":179},[331,335,337,341],{"text":332,"type":194,"marks":333},"JS + layout:",[334],{"type":318},{"text":336,"type":194}," lo anterior, más una lectura de ",{"text":338,"type":194,"marks":339},"offsetHeight",[340],{"type":210},{"text":342,"type":194}," que obliga al navegador a calcular el layout.",{"type":234,"attrs":344,"content":345},{"class":179},[346],{"text":347,"type":194},"async function measure(renderer: Renderer, scenario: Scenario): Promise\u003CSample> {\n  const store = stores[renderer]\n  const host = hosts[renderer].value!\n\n  scenario.prepare(store)\n  await nextTick()\n  void host.offsetHeight   // deja el DOM en un estado estable\n  await pause()            // 25 ms para que el navegador termine\n\n  const start = performance.now()\n  scenario.run(store)\n  await nextTick()\n  const script = performance.now() - start\n\n  void host.offsetHeight   // fuerza el layout\n  return { script, total: performance.now() - start }\n}\n",{"type":196,"attrs":349,"content":350},{"textAlign":179},[351,353,357,359,363],{"text":352,"type":194},"Hay dos decisiones aquí que cambian el resultado. La primera es el ",{"text":354,"type":194,"marks":355},"await pause()",[356],{"type":210},{"text":358,"type":194}," antes de empezar: sin él, el trabajo pendiente de la preparación se cuela en la medición. La segunda es que ",{"text":360,"type":194,"marks":361},"script",[362],{"type":210},{"text":364,"type":194}," se toma antes de forzar el layout, para que la métrica del framework no incluya el costo del navegador.",{"type":196,"attrs":366,"content":367},{"textAlign":179},[368,370,375],{"text":369,"type":194},"Ninguna de las dos métricas incluye el ",{"text":371,"type":194,"marks":372},"paint",[373],{"type":374},"italic",{"text":376,"type":194},". Eso queda fuera de este benchmark y debe decirse en el post.",{"type":189,"attrs":378,"content":379},{"level":82,"textAlign":179},[380],{"text":381,"type":194},"Calentamiento, orden alternado y mediana",{"type":196,"attrs":383,"content":384},{"textAlign":179},[385],{"text":386,"type":194},"Una sola medición no sirve. El primer render de una app carga código, compila y llena cachés. Por eso:",{"type":388,"attrs":389,"content":390},"ordered_list",{"order":54},[391,408,419],{"type":309,"content":392},[393],{"type":196,"attrs":394,"content":395},{"textAlign":179},[396,400,402,406],{"text":397,"type":194,"marks":398},"Hay una corrida de calentamiento",[399],{"type":318},{"text":401,"type":194}," que se descarta. La primera iteración del bucle (",{"text":403,"type":194,"marks":404},"iteration = 0",[405],{"type":210},{"text":407,"type":194},") solo prepara el terreno.",{"type":309,"content":409},[410],{"type":196,"attrs":411,"content":412},{"textAlign":179},[413,417],{"text":414,"type":194,"marks":415},"El orden de los runtimes se alterna",[416],{"type":318},{"text":418,"type":194}," en cada iteración. Si siempre midieras VDOM primero, cualquier efecto de la carga previa caería siempre sobre el mismo lado.",{"type":309,"content":420},[421],{"type":196,"attrs":422,"content":423},{"textAlign":179},[424,428],{"text":425,"type":194,"marks":426},"Se reporta la mediana, no el promedio.",[427],{"type":318},{"text":429,"type":194}," Una pausa del recolector de basura o una pestaña que compite por CPU puede inflar una muestra. La mediana no se mueve con un valor atípico.",{"type":234,"attrs":431,"content":432},{"class":179},[433],{"text":434,"type":194},"for (let iteration = 0; iteration \u003C= iterations; iteration++) {\n  const order = iteration % 2 ? [...rendererList].reverse() : rendererList\n  for (const renderer of order) {\n    const sample = await measure(renderer, scenario)\n    if (iteration > 0) result.samples[renderer].push(sample)\n  }\n}\n",{"type":189,"attrs":436,"content":437},{"level":82,"textAlign":179},[438],{"text":439,"type":194},"El modo desarrollo distorsiona los números",{"type":196,"attrs":441,"content":442},{"textAlign":179},[443,445,449],{"text":444,"type":194},"La primera vez que corrí el benchmark estaba en el servidor de desarrollo. Los resultados fueron estos, para crear 1.000 filas: VDOM 57,9 ms y Vapor 50,9 ms. Al compilar en producción y servir con ",{"text":446,"type":194,"marks":447},"vite preview",[448],{"type":210},{"text":450,"type":194},", la misma operación dio 36,7 ms contra 35,1 ms.",{"type":196,"attrs":452,"content":453},{"textAlign":179},[454,456,460,464,468,472,476],{"text":455,"type":194},"El modo desarrollo agrega comprobaciones y advertencias que cuestan tiempo. Ese costo no es igual en los dos motores, así que la proporción también cambia. ",{"text":457,"type":194,"marks":458},"Mide siempre con ",[459],{"type":318},{"text":461,"type":194,"marks":462},"npm run build",[463],{"type":210},{"text":465,"type":194,"marks":466}," y ",[467],{"type":318},{"text":469,"type":194,"marks":470},"npm run preview",[471],{"type":210},{"text":473,"type":194,"marks":474},".",[475],{"type":318},{"text":477,"type":194}," En la página del benchmark dejé un aviso para que nadie tome cifras del modo dev.",{"type":189,"attrs":479,"content":480},{"level":82,"textAlign":179},[481],{"text":482,"type":194},"Una corrida no basta: mira la variación",{"type":196,"attrs":484,"content":485},{"textAlign":179},[486],{"text":487,"type":194},"Corrí el benchmark dos veces en la misma máquina, con la misma versión y el mismo navegador. Compara la operación de crear 1.000 filas en JS + layout:",{"type":489,"content":490},"table",[491,527,562],{"type":492,"content":493},"tableRow",[494,503,511,519],{"type":495,"attrs":496,"content":497},"tableHeader",{"colspan":54,"rowspan":54,"colwidth":179},[498],{"type":196,"attrs":499,"content":500},{"textAlign":179},[501],{"text":502,"type":194},"Corrida",{"type":495,"attrs":504,"content":505},{"colspan":54,"rowspan":54,"colwidth":179},[506],{"type":196,"attrs":507,"content":508},{"textAlign":179},[509],{"text":510,"type":194},"Iteraciones",{"type":495,"attrs":512,"content":513},{"colspan":54,"rowspan":54,"colwidth":179},[514],{"type":196,"attrs":515,"content":516},{"textAlign":179},[517],{"text":518,"type":194},"VDOM",{"type":495,"attrs":520,"content":521},{"colspan":54,"rowspan":54,"colwidth":179},[522],{"type":196,"attrs":523,"content":524},{"textAlign":179},[525],{"text":526,"type":194},"Vapor",{"type":492,"content":528},[529,538,546,554],{"type":530,"attrs":531,"content":532},"tableCell",{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[533],{"type":196,"attrs":534,"content":535},{"textAlign":179},[536],{"text":537,"type":194},"1",{"type":530,"attrs":539,"content":540},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[541],{"type":196,"attrs":542,"content":543},{"textAlign":179},[544],{"text":545,"type":194},"5 (solo total)",{"type":530,"attrs":547,"content":548},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[549],{"type":196,"attrs":550,"content":551},{"textAlign":179},[552],{"text":553,"type":194},"36,7 ms",{"type":530,"attrs":555,"content":556},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[557],{"type":196,"attrs":558,"content":559},{"textAlign":179},[560],{"text":561,"type":194},"35,1 ms",{"type":492,"content":563},[564,572,580,588],{"type":530,"attrs":565,"content":566},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[567],{"type":196,"attrs":568,"content":569},{"textAlign":179},[570],{"text":571,"type":194},"2",{"type":530,"attrs":573,"content":574},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[575],{"type":196,"attrs":576,"content":577},{"textAlign":179},[578],{"text":579,"type":194},"10",{"type":530,"attrs":581,"content":582},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[583],{"type":196,"attrs":584,"content":585},{"textAlign":179},[586],{"text":587,"type":194},"43,1 ms",{"type":530,"attrs":589,"content":590},{"colspan":54,"rowspan":54,"colwidth":179,"backgroundColor":179},[591],{"type":196,"attrs":592,"content":593},{"textAlign":179},[594],{"text":595,"type":194},"37,3 ms",{"type":196,"attrs":597,"content":598},{"textAlign":179},[599,601,605],{"text":600,"type":194},"Los dos números de VDOM difieren un 17 %. Con esa variación, “Vapor es 1,05 veces más rápido” y “Vapor es 1,16 veces más rápido” son el mismo resultado: ambos dicen que la diferencia en crear es pequeña. Por eso el benchmark muestra un ",{"text":602,"type":194,"marks":603},"“Empate técnico”",[604],{"type":318},{"text":606,"type":194}," cuando la diferencia está entre 0,95× y 1,05×, en vez de proclamar un ganador.",{"type":196,"attrs":608,"content":609},{"textAlign":179},[610],{"text":611,"type":194},"Lo mismo pasa con “Crear 10.000 filas”, en JS + layout. En modo desarrollo VDOM ganó (420 ms frente a 443 ms). En la primera corrida de producción empataron (425 ms cada uno). En la segunda ganó Vapor (446 ms frente a 392 ms). Cuando el resultado cambia de signo entre corridas, la conclusión honesta es que no hay diferencia medible en esa operación.",{"type":189,"attrs":613,"content":614},{"level":82,"textAlign":179},[615],{"text":616,"type":194},"Cómo leer los resultados",{"type":196,"attrs":618,"content":619},{"textAlign":179},[620],{"text":621,"type":194},"Con la métrica “Solo JS” y 10 corridas, las diferencias son más claras:",{"type":306,"content":623},[624,635,652],{"type":309,"content":625},[626],{"type":196,"attrs":627,"content":628},{"textAlign":179},[629,633],{"text":630,"type":194,"marks":631},"Actualizar 1 de cada 10 filas:",[632],{"type":318},{"text":634,"type":194}," 2,0 ms frente a 0,3 ms.",{"type":309,"content":636},[637],{"type":196,"attrs":638,"content":639},{"textAlign":179},[640,644,646,650],{"text":641,"type":194,"marks":642},"Seleccionar una fila:",[643],{"type":318},{"text":645,"type":194}," 1,6 ms frente a 0,1 ms. Aquí el compilador usa ",{"text":647,"type":194,"marks":648},"createSelector",[649],{"type":210},{"text":651,"type":194},", así que solo se actualizan dos filas.",{"type":309,"content":653},[654],{"type":196,"attrs":655,"content":656},{"textAlign":179},[657,661],{"text":658,"type":194,"marks":659},"Crear 1.000 filas:",[660],{"type":318},{"text":662,"type":194}," 9,4 ms frente a 5,6 ms.",{"type":196,"attrs":664,"content":665},{"textAlign":179},[666],{"text":667,"type":194},"Pero las mismas operaciones en “JS + layout” se acercan mucho: la selección pasa de 1,6 ms a 0,1 ms en JS, y de 5,1 ms a 3,9 ms con el layout incluido. El navegador calcula el layout de la misma manera con los dos motores, y ese costo se queda igual. Vapor elimina el trabajo del framework, pero no puede eliminar el del navegador.",{"type":189,"attrs":669,"content":670},{"level":82,"textAlign":179},[671],{"text":672,"type":194},"Lo que este benchmark no mide",{"type":306,"content":674},[675,686,697,714],{"type":309,"content":676},[677],{"type":196,"attrs":678,"content":679},{"textAlign":179},[680,684],{"text":681,"type":194,"marks":682},"No es js-framework-benchmark.",[683],{"type":318},{"text":685,"type":194}," Ese proyecto usa trazas de Chrome y una batería estándar de operaciones. Este es un laboratorio para comparar tendencias en tu máquina.",{"type":309,"content":687},[688],{"type":196,"attrs":689,"content":690},{"textAlign":179},[691,695],{"text":692,"type":194,"marks":693},"No mide el paint",[694],{"type":318},{"text":696,"type":194}," ni la interacción real del usuario.",{"type":309,"content":698},[699],{"type":196,"attrs":700,"content":701},{"textAlign":179},[702,706,708,712],{"text":703,"type":194,"marks":704},"Valores menores de 0,5 ms",[705],{"type":318},{"text":707,"type":194}," están cerca de la resolución de ",{"text":709,"type":194,"marks":710},"performance.now()",[711],{"type":210},{"text":713,"type":194},". La selección de fila en Vapor (0,1 ms) está en ese rango: úsala como orden de magnitud, no como cifra exacta.",{"type":309,"content":715},[716],{"type":196,"attrs":717,"content":718},{"textAlign":179},[719,723],{"text":720,"type":194,"marks":721},"Una máquina, un navegador.",[722],{"type":318},{"text":724,"type":194}," Cambia la CPU y cambian los números. Lo que se sostiene entre corridas y máquinas son las proporciones, y aun así conviene repetirlas.",{"type":189,"attrs":726,"content":727},{"level":82,"textAlign":179},[728],{"text":729,"type":194},"Comprueba el resultado",{"type":196,"attrs":731,"content":732},{"textAlign":179},[733],{"text":734,"type":194},"Para repetir la medición en tu equipo, compila y sirve en producción:",{"type":234,"attrs":736,"content":737},{"class":179},[738],{"text":739,"type":194},"npm run build\nnpm run preview\n",{"type":196,"attrs":741,"content":742},{"textAlign":179},[743,745,749],{"text":744,"type":194},"Abre la página de benchmark, elige 10 corridas y pulsa ",{"text":746,"type":194,"marks":747},"Correr todo",[748],{"type":318},{"text":750,"type":194},". Repite al menos dos veces y compara. Si tus dos corridas dan resultados con signos distintos en una operación, esa operación no tiene diferencia medible en tu máquina.",{"type":196,"attrs":752,"content":753},{"textAlign":179},[754,756,760],{"text":755,"type":194},"Para copiar la tabla, usa ",{"text":757,"type":194,"marks":758},"Copiar como Markdown",[759],{"type":318},{"text":761,"type":194},": incluye la métrica, el número de corridas, la versión de Vue y el user agent. Pega ese bloque tal cual en tu reporte; sin esos datos, la cifra no se puede reproducir.",{"type":189,"attrs":763,"content":764},{"level":82,"textAlign":179},[765],{"text":766,"type":194},"Errores frecuentes al medir",{"type":306,"content":768},[769,780,791,802,813],{"type":309,"content":770},[771],{"type":196,"attrs":772,"content":773},{"textAlign":179},[774,778],{"text":775,"type":194,"marks":776},"Cronometrar el cambio de estado sin esperar al DOM.",[777],{"type":318},{"text":779,"type":194}," Mides una asignación de JavaScript, no el render.",{"type":309,"content":781},[782],{"type":196,"attrs":783,"content":784},{"textAlign":179},[785,789],{"text":786,"type":194,"marks":787},"Comparar un motor que calentó con uno que no.",[788],{"type":318},{"text":790,"type":194}," Descarta siempre la primera corrida.",{"type":309,"content":792},[793],{"type":196,"attrs":794,"content":795},{"textAlign":179},[796,800],{"text":797,"type":194,"marks":798},"Usar promedios con valores atípicos.",[799],{"type":318},{"text":801,"type":194}," Una sola pausa del recolector de basura cambia el promedio, no la mediana.",{"type":309,"content":803},[804],{"type":196,"attrs":805,"content":806},{"textAlign":179},[807,811],{"text":808,"type":194,"marks":809},"Un solo orden de ejecución.",[810],{"type":318},{"text":812,"type":194}," Alterna el orden o el sesgo queda del lado del que corre primero.",{"type":309,"content":814},[815],{"type":196,"attrs":816,"content":817},{"textAlign":179},[818,822],{"text":819,"type":194,"marks":820},"Sacar conclusiones de diferencias menores que la variación entre corridas.",[821],{"type":318},{"text":823,"type":194}," Antes de decir “más rápido”, compara la variación.",{"type":196,"attrs":825,"content":826},{"textAlign":179},[827,829,834],{"text":828,"type":194},"Si quieres profundizar en la otra parte de la historia, el ",{"text":830,"type":194,"marks":831},"post sobre cómo Vapor compila los templates",[832],{"type":217,"attrs":833},{"href":219,"uuid":179,"anchor":179,"target":179,"linktype":220},{"text":835,"type":194}," explica qué código genera cada motor y por qué la selección de filas es tan barata.","posts","posts/vue-vapor-benchmark-metodologia",-120,[21,9],false,20030325,"ba2d89a4-1589-4199-a1cf-edbd44eefb5c","default",[],1794670873243]