Publicado el 14 de octubre de 2026
Probamos SortyNow en WebAssembly y volvimos atrás (por ahora)
Compilamos nuestra app Flutter a WebAssembly, la publicamos y la retiramos. Qué cambia realmente con --wasm, qué navegadores lo soportan y por qué hoy SortyNow sigue con CanvasKit.
flutter · webassembly · web · sortynow
SortyNow es nuestra app de sorteos: ruleta, sorteo rápido, amigo secreto, equipos y emparejador. Está hecha en Flutter, se publica en Google Play y también funciona aquí mismo, en la web, dentro de kitusoft.com.
Hace unos meses probamos compilar la versión web con la opción --wasm de Flutter. La publicamos, encontramos un problema visible y volvimos a la compilación anterior. Esta es la historia completa, con lo que dicen las fuentes oficiales y lo que vimos nosotros.
Primero, aclarar un malentendido
Es común leer que la compilación normal de Flutter para la web es "JavaScript" y la nueva es "WebAssembly". Es más matizado:
- La compilación por defecto convierte tu código Dart a JavaScript (con
dart2js) y dibuja la interfaz con CanvasKit, que es el motor gráfico Skia compilado a WebAssembly. O sea: WebAssembly ya estaba ahí. - La compilación con
--wasmcompila además tu propio código Dart a WebAssembly (condart2wasm) y usa skwasm, una versión más compacta de Skia, también en WebAssembly.
Incluso con --wasm, Flutter sigue generando la versión en JavaScript: si el navegador no soporta lo necesario, la app arranca con esa versión automáticamente. No hay que mantener dos builds a mano.
Qué navegadores pueden usarla
La compilación a WebAssembly necesita un navegador con WasmGC (recolección de basura en WebAssembly). Según la documentación de Flutter:
- Chrome, Edge y demás navegadores basados en Chromium: sí, desde la versión 119.
- Firefox: anunció WasmGC en la versión 120, pero hoy no funciona con Flutter por una limitación conocida.
- Safari: ya soporta WasmGC, pero un error impide usar el renderer de Flutter.
- iPhone y iPad: ningún navegador, porque en iOS todos usan el motor de Safari.
En la práctica, una parte importante de los visitantes seguirá recibiendo la versión en JavaScript. Es un dato clave antes de decidir.
Lo que aprendimos al publicarla
1. La ruta base importa
SortyNow vive en una subcarpeta (/apps/sortynow/), no en la raíz del dominio. Flutter genera un index.html con <base href="/">, y con eso el navegador busca sus archivos en la raíz y no los encuentra. La solución es compilar indicando la ruta:
flutter build web --wasm --base-href /apps/sortynow/
La ruta debe empezar y terminar con /. Vale igual para la compilación sin --wasm.
2. Los encabezados de aislamiento son para los hilos
Para que skwasm use varios hilos, el servidor tiene que enviar los encabezados Cross-Origin-Opener-Policy: same-origin y Cross-Origin-Embedder-Policy (require-corp o credentialless). Sin ellos, skwasm funciona en un solo hilo.
Decidimos no activarlos: aplicados al sitio, podían bloquear recursos de otros dominios (como Firebase o imágenes externas). Para una app de sorteos, un solo hilo es suficiente.
3. Pasar el idioma desde el sitio
kitusoft.com está en cuatro idiomas y queríamos que SortyNow abriera en el idioma de la página, no en el del sistema. Lo resolvimos pasando el idioma en la URL del iframe (?lang=es) y leyéndolo al arrancar la app:
Locale? _localeFromQuery() {
final lang = Uri.base.queryParameters['lang'];
if (lang == null || lang.isEmpty) return null;
final code = lang.toLowerCase().split(RegExp(r'[-_]')).first;
const supported = {'es', 'en', 'fr', 'de'};
return supported.contains(code) ? Locale(code) : null;
}
En Android ese parámetro no existe, así que la función devuelve null y la app usa el idioma del teléfono.
4. El confeti desapareció
Con la versión en WebAssembly, al anunciar al ganador la ventana aparecía, pero la animación de confeti no se veía. En SortyNow ese momento es parte de la experiencia, así que volvimos a la compilación por defecto, donde funciona bien.
Eso sí: el paquete confetti figura en pub.dev como compatible con WebAssembly y no encontramos reportes públicos de este problema. No sabemos aún si la causa está en el paquete, en skwasm o en nuestro propio código. Lo que sí sabemos es que, para nuestra app y en ese momento, no estaba listo.
Entonces, ¿vale la pena?
La compilación a WebAssembly es el camino que Flutter está siguiendo, y probarla cuesta un comando. Nuestra recomendación:
- Pruébala si tu app es pública y quieres mejor rendimiento en Chrome y Edge.
- Revisa con cuidado todo lo visual (animaciones, efectos, pintura personalizada) en un navegador compatible antes de publicar.
- No esperes que llegue a todos: en Safari, en iPhone y hoy también en Firefox, tus usuarios recibirán la versión en JavaScript.
- Compila con
--base-hrefsi tu app no vive en la raíz del dominio.
Volveremos a intentarlo cuando podamos aislar el problema del confeti. Cuando lo hagamos, lo contaremos aquí.
Fuentes
- Flutter: Soporte para WebAssembly (Wasm) (en inglés).
- Flutter: Inicialización de apps web (en inglés).
- Flutter: Alojar una app en una ruta que no es la raíz (en inglés).
- pub.dev: Paquete confetti (en inglés).