dvStaticPage function
A route's own HTML: the app shell with this page's head tags and, where prerendering captured it, this page's text.
Implementation
String dvStaticPage({
required String shell,
required String route,
required String title,
String? description,
String? content,
String? siteUrl,
String? image,
String? siteName,
Map<String, String> alternates = const <String, String>{},
String? defaultAlternate,
String? favicon,
String? schemaType,
}) {
final canonical =
siteUrl == null ? null : dvStaticCanonical(siteUrl, route);
// What the page *is*, which OpenGraph cannot say: og:type is "website" for
// every page on every site. This is what produces a site name in a result
// and a breadcrumb trail under a link.
//
// Folded into the one head application rather than applied after it.
// dvSeoApply writes into a marked region, so a second call replaces the
// first call's tags -- which took the title and the canonical with it.
final String jsonLd = dvStructuredData(
route: route,
title: title,
siteName: siteName ?? title,
description: description,
siteUrl: siteUrl,
image: dvAbsoluteAsset(image, siteUrl),
schemaType: schemaType,
);
var html = dvSeoApply(
shell,
dvSeoHead(
title: title,
description: description,
// Its own URL, not the site root. Every page canonicalising to `/` tells
// a crawler they are the same page, which is worse than no canonical.
siteUrl: canonical,
// Resolved against the site root here, because dvSeoHead resolves a
// relative image against whatever it is given as siteUrl -- and that is
// the page's canonical URL, which is what the canonical link and og:url
// need. Passing both through one argument put the route into the image:
// /docs asked for https://example.com/docs/icons/Icon-512.png, which
// does not exist. A broken og:image is invisible until someone shares
// the link.
image: dvAbsoluteAsset(image, siteUrl),
siteName: siteName,
alternates: alternates,
defaultAlternate: defaultAlternate,
) + (jsonLd.isEmpty ? '' : '\n$jsonLd'),
);
// Outside the marked region deliberately. dvSeoApply rewrites what is
// between its markers, and the shell's icon link is not in there -- it is a
// tag Flutter wrote, and replacing it is the only way a page gets its own
// icon rather than a second one next to the application's.
html = dvApplyFavicon(html, favicon);
if (content != null && content.trim().isNotEmpty) {
html = _injectContent(html, content);
}
return html;
}