3 puntos por GN⁺ 2024-03-29 | 1 comentarios | Compartir por WhatsApp
  • El framework GUI de Rust Dioxus 0.5 simplifica de forma importante el flujo de desarrollo web, de escritorio, móvil y Fullstack, centrado en la reescritura de dioxus-core y la eliminación de unsafe
  • Entre 0.4.3 y 0.5.0 se incorporaron más de 100,000 líneas de código y más de 1,400 commits, y el nuevo core cambió en la dirección de eliminar dependencias de lifetimes y de Scope
  • La gestión de estado anterior basada en use_state y use_ref fue reemplazada por una API de Signal que puede ser Copy, reduciendo la carga de Clone repetidos en event handlers y futures
  • Con un solo flujo de dioxus::launch y dx serve --platform, se pueden ejecutar apps web, de escritorio y Fullstack, y el CLI pasa automáticamente los build features adecuados para la plataforma objetivo
  • También cambiaron la recarga en caliente de assets, la reescritura de eventos, las mejoras de renderizado de escritorio y el streaming de funciones de servidor, ampliando el alcance de una sola base de código Rust

Dirección del lanzamiento de Dioxus 0.5

  • Dioxus es una librería para crear GUI con Rust, usada para desplegar apps web, de escritorio y móviles
  • La versión 0.5 fue diseñada con el objetivo de lograr la simplificación, solidez y mayor nivel de acabado que pedía la comunidad
  • Los cambios principales son los siguientes
    • Reescritura completa de dioxus-core y eliminación de código unsafe
    • Introducción de una API basada en Signal en lugar de use_state y use_ref
    • Eliminación de todos los lifetimes y del estado cx: Scope
    • Una sola función launch para iniciar apps en todas las plataformas
    • Recarga en caliente de assets compatible con Tailwind y Vanilla CSS
    • Reescritura de eventos que permite acceder a tipos de evento nativos de WebSys
    • Integración de Error Boundary, Server Future y Suspense
    • Mejora de 5 veces en la reconciliación de escritorio
    • Streaming de funciones de servidor y hot reload para Fullstack
  • Se ofrece una guía de migración para usuarios que actualicen desde Dioxus 0.4

Eliminación de lifetimes y Scope

  • Desde Dioxus 0.1 hasta 0.4, los valores internos de los componentes tenían el lifetime 'bump, lo que permitía usar hooks, props y scope en listeners de eventos sin necesidad de clonarlos
  • En event handlers eso funcionaba bien en general, pero los futures de Dioxus debían ser 'static, así que era necesario hacer clone antes de mover valores dentro de un future
  • Cuando aparecían errores de lifetime, los mensajes podían decir que cx debía vivir más que 'static en vez de señalar el hook en sí, lo que generaba confusión
  • Dioxus 0.5 elimina Scope y el lifetime 'bump, y convierte Element en una forma sin lifetime
  • Los componentes ahora pueden recibir props directamente, sin parámetro de scope
    • Ejemplo: fn MyComponent(name: String) -> Element
  • Las funciones de runtime pueden usarse directamente no solo dentro de componentes, sino también dentro de futures y event handlers
  • Al volverse 'static, Element también puede usarse dentro de hooks o proveerse a través de la API de context
  • Este cambio sienta una base que facilita implementar APIs como listas virtuales u offscreen rendering

Eliminación de unsafe en dioxus-core

  • La eliminación de 'bump y de scope creó una oportunidad para reducir el código unsafe dentro de Dioxus
  • dioxus-core 0.5 no contiene código unsafe
  • Algunas dependencias todavía conservan pequeñas cantidades de unsafe, y el equipo de Dioxus planea eliminarlas durante el ciclo de lanzamiento de 0.5
  • El unsafe restante se clasifica como código simplemente removible o código necesario por FFI

Gestión de estado basada en Signal

  • Dioxus 0.5 introduce Signal como tipo primitivo central de estado para componentes
  • Signal tiene dos ventajas frente a use_state y use_ref
    • Siempre puede ser Copy
    • No requiere suscripción manual
  • Estado Copy

    • Signal<T> es Copy incluso si el valor interno T no lo es
    • Este comportamiento es posible gracias al crate generational-box, implementado sin unsafe
    • Si hace falta, Signal puede convertirse en Send+Sync para moverlo entre hilos
    • La combinación de estado Copy, Signal Send+Sync y componentes static permite mover el estado fácilmente a futures, event handlers, hilos y otros lugares donde se necesite
    • El patrón de uso de memoria es casi igual al de 0.4, pero sin requerir Clone explícitos
  • Suscripción inteligente

    • Signal determina de forma más precisa qué componentes deben volver a ejecutarse cuando cambia un valor
    • Un componente solo se vuelve a ejecutar si leyó el valor de Signal
    • Las lecturas hechas dentro de tareas async o event handlers no se consideran suscripciones para reejecutar componentes
    • Si el padre modifica un Signal al hacer clic en un botón pero no lee el valor directamente, y solo el hijo lo lee, entonces solo el hijo se vuelve a renderizar
    • Gracias a esta estructura, ya no hace falta Fermi, que era un crate separado para gestión de estado
    • Fermi ofrecía una API similar a use_state usando static como clave
    • En Dioxus 0.5, se puede colocar GlobalSignal en un static y usarlo como un Signal normal
    • Signal también funciona con la API de context, por lo que es posible compartir estado entre componentes sin un hook separado use_shared_state
    • Si se lee un Signal dentro de hooks como use_future o use_memo, ese Signal se agrega automáticamente a las dependencias del hook

Hot reload de CSS y assets

  • Dioxus 0.5 implementa hot reload de archivos CSS del directorio de assets como parte de una renovación del sistema de assets
  • Si un archivo CSS aparece en RSX, el CLI dx observa ese archivo y transmite las actualizaciones de inmediato a la app en ejecución
  • Esto es compatible con Web, Desktop y Fullstack; el soporte móvil llegará en una futura actualización centrada en mobile
  • Si se usa junto con el watcher de Tailwind, también se admite hot reload de Tailwind CSS
  • En VSCode, también se puede obtener sugerencias de clases Tailwind mediante la custom regex extension
  • Los cambios pueden transmitirse a varios dispositivos al mismo tiempo para hacer hot reload en todos los dispositivos objetivo

Reescritura del sistema de eventos

  • Desde su lanzamiento, Dioxus había usado un sistema de synthetic events para crear una API de eventos multiplataforma
  • Los synthetic events son útiles para el comportamiento uniforme entre plataformas y la serialización por red, pero también tenían limitaciones
  • Dioxus 0.5 expone los tipos de evento subyacentes de cada plataforma y además ofrece traits para la API multiplataforma
  • Este cambio tiene dos ventajas
    • Permite obtener directamente la información necesaria desde el tipo de evento de la plataforma o pasarla a otras librerías
    • Permite hacer bundle splitting del código de eventos que la app no use
  • En el ejemplo de hello world, el tamaño comprimido con gzip se redujo alrededor de 25%
  • Consejos para generar bundles más pequeños están incluidos en la guía de optimización de Dioxus

API de ejecución multiplataforma

  • Dioxus 0.5 introduce una nueva API multiplataforma para ejecutar apps
  • En lugar de importar paquetes renderer separados, basta con activar features en el crate dioxus y llamar a la función launch del prelude
  • Una misma app puede ejecutarse para las siguientes plataformas
    • Desktop: dx serve --platform desktop
    • SPA Web: dx serve --platform web
    • Fullstack: dx serve --platform fullstack
  • El CLI pasa automáticamente los build features adecuados según la plataforma objetivo

Beta del sistema de assets y Manganis

  • En Dioxus y en las apps web, las rutas de assets tienden a quedarse obsoletas, los enlaces pueden diferir entre desktop y web, y suele ser necesario agregar manualmente los assets que se incluirán en el bundle
  • Los assets también pueden convertirse en un cuello de botella de rendimiento
  • En el ejemplo de la guía de Dioxus Mobile, la versión 0.4 tardaba 7 segundos en cargar y transfería 9 MB de recursos
  • La guía móvil de 0.5 usa la misma imagen, pero carga en menos de 1 segundo y reduce los recursos necesarios a 1/3
  • Dioxus 0.5 introduce el nuevo sistema de assets manganis
    • Se integra con el CLI para revisar, empaquetar y optimizar los assets de la app
    • La API todavía es inestable, por eso se distribuye como crate separado
    • Si se envuelve un asset con la macro mg!, el CLI lo detecta automáticamente
    • Más detalles están en la documentación de manganis
  • Durante el avance del lanzamiento 0.5, planean agregar hot reload también a los assets de manganis

Mejora de 5 veces en el renderizado de escritorio

  • Dioxus usa varias optimizaciones para generar rápidamente los diffs de renderizado
  • Templates permite omitir el diff de las partes estáticas en la macro rsx!
  • En Dioxus Web, los cambios al DOM se aplican rápidamente desde Rust mediante sledgehammer
  • Dioxus 0.5 aplica el mismo enfoque también a los cambios enviados por red
  • Los renderers Desktop y LiveView se comunican con un protocolo binario en lugar de JSON
  • En tareas con alta carga de renderizado, el nuevo renderer reduce a 1/5 el tiempo necesario para aplicar cambios en el navegador y reduce la latencia a la mitad
  • Un benchmark en el que el renderer de Dioxus 0.4 se detenía constantemente ahora se ejecuta con fluidez en Dioxus 0.5

Funciones de conveniencia al escribir componentes

  • Dioxus 0.5 permite extender un element específico y expandir atributos dentro del element
    • Ejemplo: en un componente ImgPlus que extiende los atributos de un element img, se pueden recibir directamente atributos comunes de img como width, height y src
  • Al pasar valores a atributos y componentes, se puede usar la sintaxis abreviada de inicialización de structs
    • Se puede escribir class en lugar de class: class
  • Los atributos abreviados funcionan con cualquier elemento que implemente IntoAttribute, y Signal también se beneficia de esto
  • Los atributos Signal todavía no omiten el diffing, pero planean añadir esa optimización durante el ciclo de lanzamiento 0.5
  • Los atributos divididos en varias líneas pueden fusionarse
    • Si se añaden valores condicionales al mismo atributo class, se fusionan usando espacios como separador
    • Esto es importante para librerías como Tailwind, que requieren parsing en tiempo de compilación pero también procesamiento dinámico en runtime
    • Esta sintaxis se integra con el compilador de Tailwind y elimina la sobrecarga de runtime de librerías como tailwind-merge

Streaming de funciones de servidor y Fullstack

  • Dioxus 0.5 es compatible con la versión más reciente del crate de server functions, que soporta datos en streaming
  • Las funciones de servidor pueden transmitir datos al cliente o del cliente al servidor
  • Las funciones de servidor con streaming pueden crearse definiendo un tipo de salida y retornando TextStream desde la función de servidor
  • Esto resulta adecuado para actualizar al cliente durante tareas de larga duración
  • Hay un ejemplo que usa Kalosm y LLM locales para ofrecer en hardware común una funcionalidad similar al endpoint de OpenAI ChatGPT
  • El CLI ahora también soporta la plataforma fullstack y ofrece hot reload y compilación en paralelo para cliente y servidor
    • dx serve
    • dx serve --platform fullstack

LiveView, asset handler y manejo de archivos

  • En Dioxus 0.5, el router funciona por defecto en apps LiveView
  • Dioxus Desktop soporta custom asset handler
  • Un custom asset handler permite transmitir datos de forma eficiente al navegador desde código Rust sin pasar por JavaScript
  • Esto es adecuado para comunicaciones de alto ancho de banda como video streaming
  • Es posible pasar datos de gstreamer o webrtc directamente al webview, reduciendo la necesidad de codificar y decodificar frames manualmente
  • El file drop de escritorio también quedó integrado de forma nativa al sistema de eventos

Manejo de errores

  • Dioxus permite manejar errores fácilmente en componentes superiores mediante Error Boundary y el trait throw
  • El enfoque throw combina las ventajas del estado de error y del early return
  • En tipos Result que implementan Debug, se puede llamar throw para convertirlos en estado de error y usar ? para hacer early return
  • El componente ErrorBoundary renderiza otro componente cuando hay errores lanzados por sus hijos
  • ErrorBoundary puede anidarse, lo que permite capturar errores en distintos niveles de la app
  • Este patrón es útil para manejar un estado de error global sin hacer panic cuando ocurra un error no recuperable ni gestionar manualmente el estado de cada error

Experiencia de desarrollo y plantillas

  • Dioxus introdujo hot reload en 0.3, lo agregó a Desktop en 0.4 y en 0.5 lo activa por defecto
  • Si se ejecuta la app con dx serve, el hot reload queda encendido por defecto en modo desarrollo
  • Incluso cuando en apps Desktop el hot reload no es posible y se requiere recompilar todo, se conserva y restaura el estado de la ventana abierta
    • Se mantiene el tamaño y la posición de la ventana de la app
    • Esto reduce las situaciones en que la app bloquea toda la pantalla con cada edición
  • Las nuevas plantillas quedaron organizadas para crear apps Web, Desktop, Mobile, TUI y Fullstack con un solo comando
  • La app por defecto de dx new cambió a una forma más cercana a create-react-app
    • Incluye assets, CSS y configuración básica de despliegue
    • Incluye enlaces a recursos útiles como dioxus-std, la extensión de VSCode, documentación y tutoriales

Dioxus Community y ecosistema

  • Dioxus Community actualizó crates importantes del ecosistema para el lanzamiento 0.5
  • Crates como icons, charts y una biblioteca estándar específica para Dioxus quedaron listos para usarse desde el momento del lanzamiento 0.5
  • El proyecto Dioxus Community es una nueva organización de GitHub creada para mantener actualizados crates importantes incluso si el maintainer original se retira
  • Si alguien desarrolla una librería para Dioxus, el equipo puede ayudar con su mantenimiento y apunta a ofrecer soporte equivalente a un “Tier 2” de facto

Funciones planeadas a futuro

  • Los planes después de 0.5 incluyen los siguientes puntos
    • Estabilización del sistema de assets e integración más profunda
    • Bundle splitting directo del .wasm de salida junto con lazy component
    • Islands, resumable interactivity y serialización de Signal
    • Fusión de server component y LiveView dentro de Fullstack
    • Devtools y framework de testing mejorados
    • Renovación completa de Mobile
    • Renovación de Fullstack, incluyendo WebSocket, SSE y progressive form

Vista previa de Dioxus-Blitz basado en Servo

  • En “Blitz 2.0” de Dioxus-Blitz se integra Servo para apuntar a renderizado nativo con WGPU usando el mismo motor CSS que al ejecutar Firefox
  • Nico Burns, creador de la librería de layout Taffy, se unió de tiempo completo para impulsar este trabajo
  • En la demo, google.com se renderiza en la GPU a 900 FPS
  • La implementación actual todavía no está completa y el renderizado de google.com aún se ve algo extraño, pero se está acercando rápidamente a un nivel utilizable
  • El repositorio puede verse en https://github.com/jkelleyrtp/stylo-dioxus

Cómo contribuir

  • El proyecto Dioxus busca contribuciones en lo siguiente
    • Traducción de documentación
    • Probar “Good First Issues”
    • Mejoras de documentación
    • Contribuciones al CLI
    • Responder preguntas en la comunidad de Discord
  • El equipo de Dioxus agradece el apoyo de la comunidad durante el resto de 2024 y pide ayuda para transformar el desarrollo de apps

1 comentarios

 
GN⁺ 2024-03-29
Opiniones en Hacker News
  • El año pasado hice Ebou, un cliente de Mastodon, con Dioxus y en general fue una buena experiencia, aunque faltaban muchas cosas.
    Cuando empecé a trabajar era la versión 0.2, y con los cambios de esta 0.5 parece que casi toda la complejidad que sufrí entonces desapareció. Todavía no lo he probado directamente, pero la eliminación de lifetimes y la menor carga de tener que clonar constantemente deberían hacerlo mucho más cómodo.
    • Me da curiosidad cómo elegiste Dioxus.
      Hay bastantes frameworks de Rust que intentan ofrecer una UI reactiva nativa desplegable en escritorio, web/wasm, móvil, etc. https://github.com/flosse/rust-web-framework-comparison, así que me preocupa elegir mal y tener que mantener un framework abandonado o hacer una migración dolorosa.
      Con los frameworks de servidor HTTP en Rust pasó algo parecido: había muchos, y ahora parece que Axum, Actix y Rocket van a la cabeza; además, la comunidad parece estar moviéndose hacia Axum, así que a veces me pregunto si elegir Actix fue un error. Me interesa saber si hay señales de que Dioxus vaya a ganar, o si además de una comunidad grande, el apoyo de YC y el momentum, hay indicadores de que sea una buena elección hoy.
      También quiero saber si Leptos y Yew son competidores principales, y por qué serían mejores o peores que Dioxus. Mi empresa ha invertido mucho en Rust, Actix y Bevy, y más adelante queremos combinar frameworks como Bevy y Dioxus para crear clientes nativos de escritorio y móvil.
      Y también me da curiosidad si el nombre Dioxus viene de Deoxys, el Pokémon. El logo da esa impresión, pero en el código no hay referencias a Pokémon.
  • Coincido con eso de “en general fue bueno, pero faltaban muchas cosas”.
    Hace unos 9 meses hice con Dioxus un frontend GUI para sshfs, y hasta que choqué con el muro de alguna función que los desarrolladores todavía no habían terminado, me pareció un framework GUI realmente excelente.
    Compartir estado entre distintos contextos también duele a veces, pero me ha pasado con todos los frameworks GUI que he usado, sin importar el lenguaje o la tecnología base. Dioxus 0.5 parece un gran avance en ese punto. Mi blog renderiza una buena parte del HTML con Dioxus, y como no lo estoy llevando al límite, funciona muy bien.
  • He estado siguiendo Dioxus con interés, pero todavía no he tenido oportunidad de probarlo.
    Dicho eso, la solución de eliminar lifetimes me parece un poco extraña. generational-box me suena a una especie de recolector de basura para pobres, y me pregunto qué impacto tuvo en el rendimiento.
    Además, el enlace [generational-box]([https://crates.io/crates/generational-box](<https://crates.io/crates/generational-box>;)) está roto.
    • Sí, es un recolector de basura para pobres, pero la semántica de memoria es exactamente la misma que en la versión anterior.
      use_hook posee el valor durante la vida del componente, así que cuando el componente desaparece, ese valor también se descarta. Todos los signals siguen usando use_hook, por lo que su vida útil también es la misma. Normalmente no se recomienda llamar a GenerationalBox::new() fuera de use_hook, así que no hay impacto en el rendimiento.
      Si abusas de GenerationalBox::new() dentro de un loop, esa basura quedará hasta que se descarte el componente, pero en la mayoría de los casos estarás haciendo push/pop en un Map o Vec, y ahí se aplica la semántica de memoria normal.
    • Esto es, en esencia, conteo automático de referencias: https://en.wikipedia.org/wiki/Automatic_Reference_Counting
  • No soy programador de Rust, pero me da curiosidad cómo funciona el crate generational-box.
    Entiendo que es una especie de asignación en arena, pero no entiendo cómo soporta “copiar sin copiar”, ni por qué es seguro que internamente cree una arena de RefCell con generaciones y que GenerationalBox sea Copy.
    Entiendo que se pueden crear punteros a datos estáticos, pero me pregunto qué pasa con valores que no tienen vida útil estática.
    • No copia los datos, sino referencias a los datos.
      Las referencias a los datos se mantienen durante toda la vida del programa. generational box permite meter datos que viven menos que el programa, pero esos datos no deben contener referencias. Cuando descartas los datos insertados, esa box se reutiliza para otra asignación.
      Es un enfoque muy parecido a una arena generacional, salvo que usa boxes en vez de una arena centralizada; esa elección se hizo para evitar problemas de locks. Si intentas acceder a los datos con una referencia Copy después de que se descartaron, falla con un buen mensaje de error.
    • No conozco bien este crate, pero desde el punto de vista de Rust, Copy tiene un significado específico.
      Si un tipo implementa el trait Copy, significa que puede copiarse con memcpy; no es una copia profunda, sino más bien una copia superficial.
      Así que no lo entiendo como “copiar sin copiar”, sino como permitir tratar tipos que no son Copy como si fueran tipos Copy. El README dice que se necesita contenido estático, así que para valores sin vida útil estática la respuesta es: “no se puede hacer eso”.
  • Lo he seguido desde hace un tiempo y me alegra mucho que haya salido.
    Me gusta que Dioxus tome muchos de los elementos que hicieron exitoso a React, pero que además innove y despliegue rápido sobre esa base. Tengo ganas de probar los signals de este release.
  • Me gustaría que, en vez de RSX, fuera algo más cercano a SwiftUI que a React/JSX.
    Reconozco las cosas buenas que React hizo por JS y la web, y también su peso como nombre, pero si en 2024 puedes diseñar un lenguaje o DSL desde cero, no creo que el código de una “UI reactiva” tenga que verse necesariamente como React.
    No digo que SwiftUI sea perfecto, pero el código escrito con SwiftUI se siente mucho más limpio, organizado y compartimentado que código similar escrito con React.

La verdadera ventaja de usar JSX para GUI multiplataforma es más o menos poder reutilizar bibliotecas existentes para la web, pero RSX parece tener poco “valor portable” aparte de permitir que los desarrolladores trasladen su conocimiento conceptual de JSX a RSX. Mejor sería un compromiso en el que se aprenda un paradigma nuevo que sea objetivamente superior al paradigma React/JSX.
En resumen, sería bueno que existiera un proyecto que fuera “SwiftUI, pero multiplataforma”, aunque todavía no existe. Conozco @Tokamak/TokamakUI, pero aún está muy incompleto y parece que la actividad bajó bastante.

  • Existe https://ribir.org/
    Por ahora solo soporta apps de escritorio nativas para Linux/mac/windows, pero tiene planes de soporte para WASM, web y móvil.
  • Elegí Dioxus para crear la página de inicio descentralizada de Freenet.
    Será el primer sitio web descentralizado que vean las personas que configuren Freenet. Se parece un poco a Kweb, el framework web en Kotlin en el que he trabajado de forma intermitente durante varios años, especialmente en el manejo de estado y en el enfoque DSL que mapea del código a HTML. Hasta ahora me gusta.
    https://freenet.org/
    https://kweb.io/
    • Genial. Creo que cuando diseñamos el DSL por primera vez vimos kweb, y realmente se parecen mucho.
      De hecho soy fan de Kotlin, y me gustan su DSL y su modelo de concurrencia.
  • Me da curiosidad cómo se compara con Tauri.
    • Dejamos eso en el README: https://github.com/dioxusLabs/dioxus/?tab=readme-ov-file#dioxus-vs-tauri
      Tauri mete el frontend en una webview, y para comunicarse con funciones nativas en Rust hay que pasar por un límite de IPC, como en Electron.
      En Dioxus, como el código Rust está del lado nativo, no se necesita IPC para operaciones como leer el sistema de archivos o usar websockets. Tauri obliga a compilar el frontend a WASM, y muchas crates interesantes de Rust no compilan a wasm.
      Es difícil expresar con palabras cuánto se simplifica el desarrollo cuando no hay un límite de IPC. Como las herramientas de Dioxus apuntan solo a Rust, puedes pasar de cero a una .app empaquetada en menos de 1 minuto. Un build nuevo tarda unos 12 segundos, y un bundle nuevo unos 20 segundos.
      Aun así, me gusta mucho la flexibilidad que ofrece Tauri, es decir, que puedes usar como frontend cualquier UI compatible con la web, y también puedes usar Dioxus dentro de una app Tauri.
    • Yo también entré para hacer esta pregunta.
      Me pareció bien que Dioxus lo abordara directamente en el README, pero también me interesan experiencias reales de gente que haya usado ambos.
      Hice una app de escritorio de juguete con Tauri, y comprobé si el IPC era lo bastante rápido como para que el frontend web se actualizara y trabajara con cada pulsación de tecla sin latencia; la respuesta fue “sí”. Si era posible mandar un archivo grande desde el frontend a la capa de Rust en cada pulsación y recibirlo de vuelta en el frontend, al menos con mi implementación ingenua, la respuesta fue “no”.
      Tanto Tauri como Dioxus tienen muchos casos donde encajan bien, y en algunos casos parece que Dioxus sería mejor. Me gustaría escuchar comparaciones tipo “en nuestro proyecto elegimos Dioxus o Tauri por X e Y”. Dioxus se ve realmente genial, y tengo ganas de probarlo.
  • Me da curiosidad cómo renderizan las apps nativas. ¿Siguen corriendo dentro de algún tipo de instancia de navegador?
    • Se puede usar la webview del sistema como renderer, o elegir un motor experimental basado en WGPU que incorpora stylo.
      stylo es la parte de Servo que se comparte con Firefox. A largo plazo nos gustaría mover a la gente al renderer WGPU, pero todavía está bastante verde, y muchas empresas que usan Dioxus saben de forma realista que una webview es una solución suficientemente buena para alrededor del 90% de una app.
  • En la parte que dice “durante el ciclo de lanzamiento de 0.5 planeamos eliminar el poquísimo unsafe que queda en varias dependencias”, me gustaría ver cuáles son esos usos y cuál es la motivación.
    Entiendo que a veces la gente usa unsafe demasiado a la ligera, pero la biblioteca estándar también está llena de unsafe, y trazar la línea ahí a veces parece como dibujar una raya en la arena.
    • En su mayoría se necesita para interactuar con FFI o para declarar algunos tipos como Send/Sync.
      Se usa en tres lugares: algunos ajustes de FFI en iOS, una implementación para permitir sintaxis de llamada a función en signal, y la implementación de Send/Sync para IDs que usan punteros como hash.
      Viendo ahora esto último, tal vez se podría eliminar reemplazándolo por usize.
    • Estoy de acuerdo en que la gente puede tenerle un poco de miedo excesivo a unsafe.
      Aun así, que el autor de una crate se proponga eliminar unsafe de su propia crate no necesariamente es una mala decisión.
      Los autores de crates que intentan eliminar todo unsafe a menudo buscan reducir la carga de confianza que debe asumir el usuario. Creo que ese es el poder de la palabra clave unsafe. De hecho, quizá debería haberse dividido en bloques trust_me y funciones check_yourself.
      unsafe limita la conversación sobre seguridad de memoria a lugares muy acotados y auditables del código, y al mismo tiempo crea una conversación nueva y manejable sobre la confianza.
  • Entiendo por qué React creó la convención de nombres use* para la API de hooks, pero me pregunto por qué en Dioxus la función que crea un signal nuevo se llama use_signal.
    let mut count = use_signal(|| 0); ¿no es una llamada que crea un signal nuevo? El signal no se vuelve a crear en cada renderizado, y ese es el punto central de un signal.
    En SolidJS se crea un signal con createSignal, como const [count, setCount] = createSignal(0), y eso es mucho más fácil de entender.
    Los nombres de API importan, porque los hooks de estado se comportan distinto y pueden generar la necesidad de complementos como useMemo. Me pregunto si hay alguna razón para haber elegido el nombre use_signal más allá de que Dioxus quiera parecerse a React.
    • Dioxus todavía vuelve a renderizar componentes, pero aplica muchas optimizaciones al rsx que generan los componentes para lograr un rendimiento cercano al de Solid.
      Se parece más a Preact que a Solid.
      Las optimizaciones incluyen separar las partes dinámicas de la UI en “diff bins” aparte, memoización por defecto y que los signals marquen implícitamente las propiedades como dirty/managed.