El 28 de septiembre de 2026, se lanzó oficialmente EmDash 1.0.
EmDash es un CMS de código abierto basado en Astro desarrollado por Cloudflare que se integra directamente en sitios Astro con su propio panel de administración y funciona con Cloudflare Workers + D1 + R2.
Es como decir que es la versión Astro de WordPress.
En un artículo anterior, migramos el blog interno «ゆるろぐ» desde microCMS, que se había quedado en la versión 0.22 subida en junio, así que en este momento decidí actualizarlo de una vez a la última versión 1.2.0.
Los puntos destacados de la versión 1.0 son la estabilidad, la seguridad de las actualizaciones, los complementos que se ejecutan en un entorno aislado y los servidores MCP para agentes.
En conclusión, la migración se completó en un día, pero había muchas trampas.
Si comienzas pensando «como es la versión 1.0 debe ser estable», te encontrarás con problemas no en EmDash en sí, sino en sus dependencias.
Contexto: De 0.22 → 1.2 no había más remedio que actualizar manualmente
En la versión 1.2 se incluye upgrade-emdash, un CLI oficial de actualización.
Actualiza las dependencias y genera un archivo UPGRADE.md específico del sitio, pero solo funciona a partir de la versión 0.35, así que no podía usarse desde 0.22.
Entre las versiones 0.22 y 1.2 hay 47 migraciones de base de datos, algunas de ellas bastante disruptivas.
No era cuestión de simplemente hacer «npm install emdash@latest».
1. Hacer una copia de seguridad y duplicar la BD de producción localmente
npx wrangler d1 export <database-name> --remote --output=backups/pre-1.2.sql
Cargué esto en el D1 local para probar la migración con los mismos datos que en producción.
2. Actualizar dependencias
Paquete | Antes de la migración | Después de la migración |
|---|---|---|
emdash / @emdash-cms/cloudflare / @emdash-cms/admin | 0.22.0 | 1.2.0 |
@emdash-cms/plugin-forms | 0.1.1 | 0.2.9 |
astro | 6.1.2 | 6.4.8 |
wrangler | 4.80 | 4.148 |
Wrangler necesitaba ser actualizado para cumplir con el requisito peer de emdash 1.2 (4.99 o superior), así que también eliminamos la solución temporal de la era 0.22 en este momento. @astrojs/cloudflare cumplía con los requisitos peer, así que en este punto lo mantuvimos en 13.1.6. Esto se convierte en la causa de la siguiente trampa.
- patch-package para la ruta OAuth: Se aplicaba para evitar un bug en 0.22. Ya está corregido en el cuerpo principal
- Inyección de CSS en la pantalla de administración: El admin 0.22 estaba dirigido a la librería UI kumo 2.4, pero el lockfile traía 2.6, lo que hacía que los botones de énfasis de inicio de sesión y publicación fueran invisibles ("texto blanco sobre fondo transparente"). En 1.2 está corregido en el cuerpo principal
3. Dev no inicia (trampa: desajuste de versión de miniflare)
La razón por la que no se inicia después de elevar las dependencias y ejecutar npm run dev fue un desajuste de versión de miniflare.
Wrangler 4.148 utiliza miniflare 5 y actualiza la tabla _cf_ALARM del estado D1 local (bajo .wrangler/state/v3/) a 3 columnas.
Por otro lado, miniflare 4 incluido en @astrojs/cloudflare 13.1.6 no puede leer el estado local debido a la discrepancia en el número de columnas.
La solución es actualizar también @astrojs/cloudflare, que estaba siendo mantenido sin cambios, para alinear la versión de miniflare con wrangler. Si solo recuerdas "alinea la versión de miniflare entre wrangler y el adaptador", la próxima vez lo tendrás resuelto de inmediato.
Junto con eso, el comando emdash dev que existía en la versión 0.22 fue descontinuado, así que revertimos el script dev a astro dev. La migración y la generación de tipos se ejecutan cuando se inicia astro dev.
4. El menú de staging desapareció (trampa: seed.json > menus)
Después de iniciar dev, las 90 migraciones pasaron correctamente, subí los cambios a staging y abrí la consola de administración, pero la navegación global en japonés estaba vacía.
El problema se debe a seed/seed.json, específicamente menus y widgetAreas.
El proceso de semilla de EmDash elimina todos los elementos y luego los recrea vacíos cuando encuentra menús o áreas de widget con el mismo nombre.
El archivo seed.json contenía una definición de menú de plantilla con "items": [], por lo que el menú se reiniciaba cada vez que se ejecutaba el proceso de semilla.
La solución fue eliminar completamente los keys menus y widgetAreas.
El contenido de los menús debe administrarse a través de la consola de administración, por lo que no hay razón para incluirlos en el seed.
5. Los enlaces de artículos en inglés se vuelven /en/posts/en/slug (trampa: prefijo de locale en entry.id)
Este es un cambio de especificación en la versión 1.2.
En sitios multilingües, el entry.id retornado por getEmDashCollection() ahora incluye un prefijo de locale. Para un artículo en inglés sería en/my-post.
Dado que Yuru Log construía las URLs de artículos a partir de entry.id, los enlaces de artículos en inglés terminaban siendo /en/posts/en/my-post, con duplicación.
Estoy reemplazando entry.data.slug en todos los lugares donde se construyen URLs: listas, destacados, resultados de búsqueda, RSS y canonical.
Dado que el tipo de entry.data.slug es string | null, también necesito ajustar el tipo en el lado receptor.
Es útil recordar que entry.id es la clave, entry.data.slug es la URL, y entry.data.id es el ULID de la base de datos (para llamadas a API), cada uno con su propósito específico.
6. Se genera un error cada minuto (trampa: Cron Trigger y entrada de Worker)
Cloudflare Workers 1.x permite que los posts programados se publiquen y que los plugins ejecuten tareas periódicas a través del manejador scheduled() de Worker.
Como Cloudflare no tiene un temporizador interno, sin un Cron Trigger, los posts programados no se publican aunque llegue la hora de publicación.
Por eso, agregamos un Cron Trigger a wrangler.jsonc.
"triggers": { "crons": ["* * * * *"] }Entonces cada minuto aparece "Handler does not export a scheduled() function".
Esto ocurre porque el punto de entrada del Worker no exporta scheduled().
La solución es reemplazar src/worker.ts por el punto de entrada oficial.
export { default, PluginBridge } from "@emdash-cms/cloudflare/worker";Ahora contamos con fetch, scheduled y también PluginBridge para complementos de tipo sandbox.
Después de probarlo
Lo que mejoró al actualizar a 1.2.
- El editor fue completamente rediseñado y es más fácil de usar. El menú de barra diagonal se agrupa y la barra de herramientas ahora sigue el desplazamiento. También funciona en dispositivos móviles.
- El bloque de video ahora viene de serie. Como antes hacía la incrustación de videos con un complemento personalizado, en algún momento me gustaría reemplazarlo.
- Se eliminaron todas las soluciones provisionales de la era 0.22. Ya no necesitamos patch-package ni inyecciones CSS.
Aspectos que llaman la atención.
- De 1.0 a 1.2 pasaron 10 días, el ritmo de desarrollo es rápido. Parece que durante un tiempo será necesario verificar en staging con cada versión menor.
Conclusión
- La migración de 0.22 → 1.2 es manual.
El CLI upgrade-emdashsolo es compatible con 0.35 en adelante. - Alinear las generaciones de wrangler y miniflare del adaptador → si no están alineadas, dev no inicia
- No dejar plantillas vacías de
menus/widgetAreasen seed.json → desaparecen en cada seed - Los sitios multilingües tienen prefijo de configuración regional en
entry.id→ la URL viene deentry.data.slug - Si agregas Cron Trigger, asigna el punto de entrada de Worker a
@emdash-cms/cloudflare/worker
Aunque todo requiere solo algunas líneas de corrección una vez que lo entiendes, avanzar investigando uno por uno consume mucho más tiempo del esperado.
Dicho esto, el hecho de que pudiera eliminar todos los parches que había aplicado en la versión 0.22 y todas las soluciones temporales de CSS es prueba de que se han corregido errores menores de cara al lanzamiento oficial.
Hace seis meses teníamos una actitud de «probamos a reemplazarlo experimentalmente», pero después de pasar por la versión 1.0, considerando el esfuerzo necesario para seguir los updates, se ha convertido en un CMS suficientemente viable como opción para producción.
Desde que saltó del mundo del DTP a la web, ha dominado markups, frontend, dirección y accesibilidad, convirtiéndose en el "sabio técnico" de la empresa. Ha sido un pilar multifacético desde los inicios de Liberogic y es ahora una referencia indispensable dentro de la organización. Últimamente está explorando eficiencias basadas en prompts, preguntándose «¿podríamos delegar más trabajo de accesibilidad a la IA?». Tanto su tecnología como su pensamiento siguen evolucionando.
Ayumi Futamata
Especialista en web accesibilidad certificado por IAAP (WAS) / Ingeniero de markups / Ingeniero frontend / Director web