Svelte 5 no es JavaScript
(hodlbod.npub.pro)- Resumen de los problemas encontrados tras actualizar recientemente una aplicación web a Svelte 5
- Se produjeron comportamientos inesperados por la funcionalidad de reactividad profunda y los cambios en el ciclo de vida
- Aunque disfruté mucho Svelte 3/4 durante bastante tiempo, no creo que vuelva a elegir Svelte para proyectos nuevos
La necesidad de la velocidad
- El equipo de Svelte intentó optimizar el rendimiento mediante deep reactivity, logrando un mejor desempeño
- Ya antes ofrecía un rendimiento rápido gracias al proceso de compilación, y eso era una fortaleza que lo diferenciaba de otros frameworks
- Aunque eso hacía al framework más opaco y difícil de depurar, me parecía un trade-off aceptable en términos de rendimiento y productividad
La necesidad de la velocidad
- El principal cambio en el que se enfoca el equipo de Svelte en Svelte 5 es la “deep reactivity”, con la que busca mejorar el rendimiento mediante una reactividad más fina
- En versiones anteriores de Svelte, este objetivo se lograba principalmente aprovechando el compilador de Svelte
- Que el desarrollador no tuviera que aprender conceptos nuevos y que fuera fácil reorganizar la lógica interna resaltaba la originalidad de Svelte
- Al mismo tiempo, este proceso de compilación volvía opaco al framework, lo que dificultaba depurar problemas complejos
- Debido a bugs del propio compilador, podían aparecer errores cuya causa era difícil de identificar, y a veces solo se resolvían refactorizando por completo el componente problemático
- Aun así, me parecía un compromiso razonable por la velocidad y la productividad, así que incluso toleré la incomodidad de tener que reiniciar periódicamente los proyectos
Svelte no es JavaScript
- Svelte 5 duplica este trade-off
- La diferencia clave es que el punto de equilibrio entre abstracción y rendimiento ya no se queda en la etapa de compilación, sino que se mete también en el runtime
- Uso de proxies para soportar deep reactivity
- Estado implícito del ciclo de vida del componente
- Estos dos cambios mejoran el rendimiento y hacen que la API para desarrolladores se vea más pulida
- ¿Qué podría tener de malo? Lamentablemente, estas dos funciones son un ejemplo clásico de leaky abstraction
- Al final provocan un entorno más complejo de manejar para el desarrollador
Los Proxies no son objetos
- Gracias al uso de Proxy, el equipo de Svelte pudo exprimir un poco más el rendimiento del framework sin exigir trabajo adicional al desarrollador
- En frameworks como React, al pasar estado a través de varios componentes es fácil provocar rerenderizados innecesarios, y Svelte introdujo Proxy con el objetivo de reducir eso
- El compilador de Svelte ya evitaba algunos problemas que pueden surgir del diffing del DOM virtual, pero parece que consideraron que con Proxy podían mejorar aún más el rendimiento
- El equipo de Svelte también mencionó que Proxy ayuda a mejorar la experiencia del desarrollador, sosteniendo que “puede maximizar tanto la eficiencia como la facilidad de uso”
- El problema es que Svelte 5 parece más simple por fuera, pero en realidad añade más abstracción
- Por ejemplo, usar Proxy para detectar métodos de arreglos trae la ventaja de no tener que escribir código como
value = value, como sí ocurría en Svelte 4 - En Svelte 4, para activar la reactividad el desarrollador tenía que entender en cierta medida cómo funcionaba el compilador. En cambio, Svelte 5 da la impresión de que “ya puedes olvidarte del compilador”, pero en realidad no es así
- Tanto como gana en comodidad gracias a la nueva abstracción, también aumentan las reglas que el desarrollador debe conocer para hacer que el compilador se comporte como se espera
- Por ejemplo, usar Proxy para detectar métodos de arreglos trae la ventaja de no tener que escribir código como
- Después de usar Svelte durante mucho tiempo, personalmente fui usando cada vez más Svelte store y menos declaraciones reactivas
- Las Svelte store son, en esencia, más cercanas a conceptos básicos de JavaScript; llamar al método
updatees simple, y la sintaxis con$era más bien una ventaja adicional - Igual que las declaraciones reactivas, Proxy provoca el problema de que “parece una cosa, pero en los puntos límite se comporta de otra manera”
- Las Svelte store son, en esencia, más cercanas a conceptos básicos de JavaScript; llamar al método
- Cuando empecé a usar Svelte 5, todo parecía funcionar bien, pero al intentar guardar estado Proxy en IndexedDB apareció un
DataCloneError- Peor aún: para saber con certeza si un valor es Proxy, hay que intentar una clonación estructurada con
try/catch, lo que tiene un costo de rendimiento - Al final, uno termina teniendo que recordar qué es Proxy y usar
$state.snapshotcada vez en contextos externos que no reconocen Proxy - Eso termina creando una situación en la que, en contra de la intención original de que “la abstracción mejora la comodidad del desarrollador”, se le exigen al desarrollador reglas y procedimientos más complejos
- Peor aún: para saber con certeza si un valor es Proxy, hay que intentar una clonación estructurada con
Los componentes no son funciones
- La razón por la que el DOM virtual se volvió popular hacia 2013 fue que permitía modelar las aplicaciones como una composición de funciones
- Svelte había mantenido un enfoque de usar un compilador en lugar del DOM virtual para simplificar las funciones del ciclo de vida y mejorar el rendimiento
- Sin embargo, en Svelte 5 el concepto de ciclo de vida volvió a introducirse de una forma parecida a React Hooks
- En React, Hooks es una abstracción que reduce el código relacionado con estado dentro de los métodos del ciclo de vida
- El código queda más limpio, pero hay muchas cosas a las que el desarrollador debe prestar atención, como cuando se consulta estado dentro de
setTimeout - Incluso en Svelte 4 podía haber problemas si código asíncrono accedía a elementos del DOM en el momento en que el componente se desmontaba
- Ahora, en Svelte 5, parece que se añadió estado implícito al ciclo de vida del componente para coordinar cambios de estado y efectos
- El código queda más limpio, pero hay muchas cosas a las que el desarrollador debe prestar atención, como cuando se consulta estado dentro de
- La documentación oficial sobre $effect lo explica así:
“$effect can be placed anywhere, but can only be called during component initialisation (or while a parent effect is active). It will only run while the component (or parent effect) is mounted.”
- Esto sugiere que, a diferencia de la explicación de que el ciclo de vida solo tiene dos etapas, mount/unmount, en realidad existe una estructura compleja de efectos que requiere rastrear cambios de estado
- La documentación oficial del ciclo de vida dice que “no hay before update/after update”, pero aparecen conceptos nuevos como
$effect.preytick - En la práctica, eso significa que además de mount/unmount también hace falta entender los momentos en que cambia el estado
- La parte que realmente causó problemas en uso real fue que incluso el estado pasado a funciones ajenas a Svelte queda atado al ciclo de vida del componente
- Por ejemplo, se usaba un patrón en el que una ventana modal se gestionaba con una store y se pasaba un callback al componente hijo
const { value } = $props() const callback = () => console.log(value) const openModal = () => pushModal(MyModal, { callback }) - Si este código está dentro del componente que invoca el modal, el componente que llamó al modal se desmonta primero, y en ese momento
valuepasa a serundefined - En ese repositorio hay un ejemplo mínimo reproducible
- Es decir, props a las que hacía referencia un callback que seguía vivo incluso después de terminado el ciclo de vida del componente pasan repentinamente a ser
undefined - Esto se comporta distinto al JavaScript básico, y da la impresión de que Svelte está haciendo algo parecido a recolección de basura por su cuenta
- Puede haber una razón de ingeniería detrás, pero como comportamiento inesperado resulta sorprendente
Conclusión
- Lo fácil sin duda resulta atractivo, pero como dijo Rich Hickey, fácil no significa simple
- Como decía Joel Spolsky, no me agrada cuando ocurren comportamientos inesperados
- Svelte ha mostrado mucha “magia” hasta ahora, pero en esta versión hay demasiado que memorizar para poder usar esa magia, y la carga termina siendo mayor que el beneficio
- El punto de este texto no es criticar al equipo de Svelte; al contrario, reconozco que hay muchas personas que prefieren Svelte 5 (y React Hooks)
- Lo importante es el equilibrio entre ofrecer comodidad al usuario y permitir que el usuario conserve el control
- El software realmente bueno no se basa en ser “ingenioso”, sino en la “comprensión”
- A medida que las herramientas de IA avanzan, es importante elegir herramientas que aprovechen la sabiduría acumulada y ayuden a una comprensión profunda, en lugar de herramientas que hagan que uno no sepa lo que está haciendo
- Gracias a Rich Harris y al equipo por la grata experiencia de desarrollo hasta ahora. Espero que este texto sirva como feedback que no sea del todo desacertado
7 comentarios
Las
proxyle facilitan la vida a quien las crea, pero hacen enojar a quien tiene que depurarlas jajajaSideproject tiene el mejor DX de solidjs >.< / felicidad
Creo que, como existían alternativas como Svelte, React/nextjs también pudo recibir un gran estímulo.
En esencia, Svelte es un language, así que espero que también pueda mostrar bien la dirección hacia la que debería avanzar un lenguaje para describir UI.
Yo usaré React
Demasiado es tan malo como demasiado poco
obsesión que lleva al desvío
poner un techo sobre otro techo
Creo que cambió de una forma extraña al recibir bastante influencia de React y, en especial, de Next.
+pagees difícil de entender si lo ves sin conocer Svelte, y los rune como$statey$derivedparecen seguir a React; sinceramente, la época en la que solo se ponía$:delante de una variable me parecía mejor. También puedo tolerar una sintaxis anticuada como{#each a in array} {/each}, pero sigue siendo molesta. Si se trata de mejorar el rendimiento mediante reactividad opcional, me parece que SolidJS va en una dirección mucho mejor. Como usa JSX tal cual, en comparación también es más fácil pasarse desde React. Hasta resulta extraño que SolidJS reciba relativamente tan poca atención.Parece que Signals se está acercando al Trough of disillusionment del Gartner hype cycle 🤔. A medida que sus casos de uso se vayan definiendo mejor, creo que su evaluación podría mejorar.
Opinión de Hacker News
Al principio no me interesaban mucho las runes. Pero cambié de opinión cuando vi que puedes importar componentes externos reactivos a una plantilla
.sveltey encapsular la reactividad internamente. Eso significa que puedes escribir pruebas con vitest y aun así obtener los beneficios de la reactividad. Es realmente poderoso y, AFAIK, algo único en el mundo del frontendEstoy desarrollando activamente una aplicación SvelteKit desplegada comercialmente y quería compartir algunas ideas sobre la experiencia
+page. Podías poner archivos Svelte donde quisieras y se renderizaban sin fricción, mientras seguías disfrutando de los beneficios de un framework modernoEs una lástima que EmberJS haya desaparecido. Su API fue bastante estable durante los últimos 10 años. Irónicamente, alguien que haya escrito apps en EmberJS durante la última década probablemente tendrá menos dificultades de migración que alguien que haya hecho lo mismo con React, Svelte, Vue, etc.
Los dos enlaces de Github que el autor enumera al inicio de la publicación apuntan al mismo problema, y ese problema tiene solución (usa
$state.raw)Svelte 5 no es JavaScript de la <i>peor</i> manera. No resuelve los problemas de js, y ofrece abstracciones con fugas para algunos problemas de frontend. Creo que Solid va en mejor dirección que Svelte. Solid no depende de un lenguaje nuevo. Sin embargo, existe ese impulso de crear algo que no sea js, porque js no es ideal. Elm es el precursor de svelte. Pero creo que se puede hacer algo mejor...[0]
Empecé a usar Svelte 5 porque realmente odiaba las stores en Svelte 4. Estoy usando Sveltekit y Svelte 5 en un proyecto nuevo y debo decirlo... la productividad de React sigue siendo imbatible, aunque Sveltekit y Svelte sean técnicamente mejores
+page.server.tso+page.svelteo alguna variante, así que es difícil buscar código fácilmente. Las herramientas de Svelte existen separadas detscy ESLint, por lo que es más difícil integrarlas en CI y usarlas en desarrolloSe siente raro decir que Svelte no es JavaScript por un comportamiento inesperado al pasar un closure como callback. Un mejor título sería: "No me gusta Svelte 5 porque me sorprendió"
Si buscas una librería con la que puedas construir componentes y aplicaciones usando JavaScript puro, revisa Lit: Lit
¿Quieres una experiencia frontend razonable? Usa JavaScript vanilla, web components, htmx, Blazor