À propos du projet

esen_seo est un package Flutter qui répond à un problème structurel de Flutter Web : une application Flutter rend un arbre de widgets plutôt qu’un document, de sorte que les crawlers ne trouvent ni titres, ni paragraphes, ni liens à lire. Le package reflète cet arbre de widgets sous forme de HTML sémantique directement dans le DOM, gère les balises meta, OpenGraph et Schema.org JSON-LD, et inclut un composant de rendu côté serveur basé sur shelf qui fournit aux bots un document HTML complet dans le code source de la page. Il est en Dart pur et n’utilise ni Puppeteer ni Chrome headless. L’usage est incrémental plutôt qu’une réécriture : la plupart des widgets sont reflétés automatiquement, les appels d’extension `.seo()` ajoutent une signification sémantique, et un ensemble de widgets de bibliothèque couvre les cas que le miroir ne peut pas voir (menus déroulants fermés, listes virtualisées, onglets inactifs, graphiques peints). Sur iOS, Android et desktop, chaque appel est un no-op et les widgets se rendent comme avant ; le HTML n’existe que sur le web. Capacités clés décrites dans le README : - Extensions `.seo()` pour Text, Image, Column, Row et GestureDetector, avec des constantes de balises typées (SeoTextTag.h1, SeoContainerTag.section) et des raccourcis tels que .h1–.h6, .p, .li, .ul, .section, .article, .nav, .tr. - Valeurs par défaut intelligentes : les pages sans aucun appel `.seo()` sont quand même rendues, avec le premier texte en h1, les textes suivants en p, et les images en img en utilisant semanticLabel comme alt. Les balises bloquées ou invalides retombent sur des éléments sûrs. - Traductions personnalisées via `.seoNodes()`, permettant à n’importe quel widget de déclarer son propre HTML ; la bibliothèque de widgets SEO traduit le contenu peint (par exemple SeoBarChart est reflété en barres CSS plus un vrai tableau de ses données). - SeoRichText construit des TextSpans Flutter natifs et des éléments imbriqués strong, em, code et a sûrs à partir d’un seul arbre de spans déclaratif. - Balises meta, OpenGraph et Twitter Cards via un seul appel EsenSeo.setMeta() par page, avec des replis tels que og:title à partir de title. - Générateurs Schema.org JSON-LD pour Article, Product (y compris AggregateRating), Review, Event, LocalBusiness, Organization, WebSite, BreadcrumbList et FAQPage, plus une échappatoire générique. - Un serveur SSR conscient des bots : un middleware shelf détecte les crawlers par User-Agent et sert un vrai document HTML, exécutable avec `dart run`. - Routage d’URL comme source unique de vérité : une table de routes en Dart pur pilote les balises meta de l’application lors de la navigation et les corps de routes rendus côté serveur pour les bots, et génère sitemap.xml (avec lastmod et alternates hreflang), robots.txt, URL canoniques et de vrais 404 HTTP. - Prérendu statique de la table de routes dans le build web sous forme de fichiers HTML statiques pour un hébergement CDN sans serveur. - Shell visible optionnel, où le HTML prérendu constitue la première frame avant le chargement du moteur Flutter. - Routes DOM-first opt-in qui peuvent conserver un corps de route pur comme page permanente sans charger Flutter Web, avec SeoTabs, SeoCarousel et interactions SeoCollection bornées compilées depuis la même source Dart pure. - llms.txt et llms-full.txt générés depuis la table de routes, plus des pings IndexNow pour un indexage plus rapide. Les politiques de sécurité sont explicites : les balises sont une liste d’autorisation, donc script, style, iframe, form, plaintext, svg, balises réservées au head, éléments personnalisés et noms invalides sont refusés au moment du rendu et retombent sur span/div (avec un avertissement de debug en SeoMode.strict). La gestion des attributs supprime les gestionnaires d’événements et les noms invalides tout en autorisant data-*, aria-*, id, lang et cite ; les attributs d’URL sont limités aux URL relatives plus http, https, mailto, tel, sms et ftp, bloquant javascript: et schémas similaires. Le README documente aussi la bibliothèque de widgets SEO : SeoBarChart, SeoPieChart (camembert en conic-gradient CSS pur plus un tableau), SeoRating, SeoDataTable, SeoFaq (accordéon details/summary), SeoBreadcrumbs, SeoFigure, SeoResponsiveImage (picture/srcset avec sources AVIF/WebP), SeoTestimonial et SeoRichText. Cinq widgets traitent du contenu que Flutter ne construit jamais : SeoNavMenu (entrées de menu déroulant sous forme de données), SeoListView (tous les éléments reflétés malgré le rendu paresseux), SeoCarousel, SeoTabs et SeoStepper. Sur les plateformes non web, tous sont des no-ops rendant de simples widgets Flutter. Le routage est défini une fois dans un fichier Dart pur sans imports Flutter, partagé par main.dart et le serveur. SeoRoute.dynamic résout les métadonnées et le corps à partir d’une seule lecture de base de données, avec enumeratePaths pour sitemap, llms.txt et prerender. Un SeoRouteObserver maintient le miroir et les balises meta en suivant la navigation, et fonctionne avec go_router, beamer, auto_route ou d’autres packages basés sur Router. Le README note que le miroir DOM live est dérivé de l’arbre de widgets et ne nécessite pas un second arbre de contenu rédigé, tandis que les corps de routes rendus côté serveur sont séparés sauf si les deux dérivent d’un modèle de données pur partagé ; auditSeoParity est fourni pour détecter les dérives. Le README indique que le miroir est masqué par défaut (aria-hidden, taille nulle) et n’est explicitement pas une fonctionnalité d’accessibilité, puisque Flutter publie son propre arbre de sémantique.