Sobre el proyecto
esen_seo es un paquete de Flutter que aborda un problema estructural de Flutter Web: una app de Flutter renderiza un árbol de widgets en lugar de un documento, por lo que los rastreadores no encuentran encabezados, párrafos ni enlaces que leer. El paquete refleja ese árbol de widgets como HTML semántico directamente en el DOM, gestiona metaetiquetas, OpenGraph y JSON-LD de Schema.org, e incluye un componente de renderizado del lado del servidor basado en shelf que entrega a los bots un documento HTML completo en el código fuente de la página. Es Dart puro y no utiliza Puppeteer ni Chrome headless.
El uso es incremental, no una reescritura: la mayoría de los widgets se reflejan automáticamente, las llamadas de extensión `.seo()` añaden significado semántico, y un conjunto de widgets de biblioteca cubren casos que el espejo no puede ver (menús desplegables cerrados, listas virtualizadas, pestañas inactivas, gráficos pintados). En iOS, Android y escritorio, cada llamada es una operación nula y los widgets se renderizan como antes; el HTML existe solo en la web.
Capacidades clave descritas en el README:
- Extensiones `.seo()` para Text, Image, Column, Row y GestureDetector, con constantes de etiqueta tipadas (SeoTextTag.h1, SeoContainerTag.section) y abreviaturas como .h1–.h6, .p, .li, .ul, .section, .article, .nav, .tr.
- Valores predeterminados inteligentes: las páginas sin llamadas `.seo()` aún se renderizan, con el primer texto como h1, los siguientes como p, y las imágenes como img usando semanticLabel como alt. Las etiquetas bloqueadas o inválidas recurren a elementos seguros.
- Traducciones personalizadas mediante `.seoNodes()`, permitiendo que cualquier widget declare su propio HTML; la biblioteca de widgets SEO traduce contenido pintado (por ejemplo, SeoBarChart se refleja como barras CSS más una tabla real de sus datos).
- SeoRichText construye TextSpans nativos de Flutter y elementos anidados strong, em, code y a seguros a partir de un árbol de spans declarativo.
- Metaetiquetas, OpenGraph y Twitter Cards mediante una sola llamada EsenSeo.setMeta() por página, con respaldos como og:title desde title.
- Constructores JSON-LD de Schema.org para Article, Product (incluyendo AggregateRating), Review, Event, LocalBusiness, Organization, WebSite, BreadcrumbList y FAQPage, además de una vía de escape genérica.
- Un servidor SSR consciente de bots: middleware de shelf detecta rastreadores por User-Agent y sirve un documento HTML real, ejecutable con `dart run`.
- Enrutamiento de URL como fuente única de verdad: una tabla de rutas en Dart puro impulsa las metaetiquetas de la app en la navegación y los cuerpos de rutas renderizados en servidor para bots, y genera sitemap.xml (con lastmod y alternativas hreflang), robots.txt, URLs canónicas y códigos HTTP 404 reales.
- Prerenderizado estático de la tabla de rutas en la compilación web como archivos HTML estáticos para alojamiento en CDN sin servidor.
- Carcasa visible opcional, donde el HTML prerenderizado es el primer fotograma antes de que cargue el motor de Flutter.
- Rutas DOM-first opcionales que pueden mantener un cuerpo de ruta puro como página permanente sin cargar Flutter Web, con interacciones de SeoTabs, SeoCarousel y SeoCollection acotado compiladas desde el mismo código Dart puro.
- llms.txt y llms-full.txt generados desde la tabla de rutas, más pings de IndexNow para indexación más rápida.
Las políticas de seguridad son explícitas: las etiquetas son una lista de permitidos, por lo que script, style, iframe, form, plaintext, svg, etiquetas solo de head, elementos personalizados y nombres inválidos se rechazan en tiempo de renderizado y recurren a span/div (con advertencia de depuración en SeoMode.strict). El manejo de atributos elimina manejadores de eventos y nombres inválidos, permitiendo data-*, aria-*, id, lang y cite; los atributos de URL se restringen a URLs relativas más http, https, mailto, tel, sms y ftp, bloqueando javascript: y esquemas similares.
El README también documenta la biblioteca de widgets SEO: SeoBarChart, SeoPieChart (pastel de conic-gradient en CSS puro más tabla), SeoRating, SeoDataTable, SeoFaq (acordeón details/summary), SeoBreadcrumbs, SeoFigure, SeoResponsiveImage (picture/srcset con fuentes AVIF/WebP), SeoTestimonial y SeoRichText. Cinco widgets abordan contenido que Flutter nunca construye: SeoNavMenu (entradas de menú desplegable como datos), SeoListView (todos los elementos reflejados a pesar del renderizado perezoso), SeoCarousel, SeoTabs y SeoStepper. En plataformas no web, todos son operaciones nulas que renderizan widgets Flutter normales.
El enrutamiento se define una vez en un archivo Dart puro sin importaciones de Flutter, compartido por main.dart y el servidor. SeoRoute.dynamic resuelve metadatos y cuerpo desde una sola lectura de base de datos, con enumeratePaths para sitemap, llms.txt y prerender. Un SeoRouteObserver mantiene el espejo y las metaetiquetas siguiendo la navegación, y funciona con go_router, beamer, auto_route u otros paquetes basados en Router. El README señala que el espejo DOM en vivo se deriva del árbol de widgets y no requiere un segundo árbol de contenido autoral, mientras que los cuerpos de rutas renderizados en servidor son separados a menos que ambos deriven de un modelo de datos puro compartido; se proporciona auditSeoParity para detectar desviaciones.
El README afirma que el espejo está oculto por defecto (aria-hidden, tamaño cero) y explícitamente no es una característica de accesibilidad, ya que Flutter publica su propio árbol de semántica.
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.