Search Engine Optimization (SEO)
Coralite provides lightweight building blocks and plugin hooks to ensure your static and server-rendered pages are fully optimized for search engines and social sharing platforms. By combining built-in metadata extraction with standard Web Platform practices, you can build search-friendly websites without heavy runtime overhead.
1. Built-in Metadata Extraction #
Coralite ships with a built-in metadataPlugin that runs on the server during page compilation. It scans the <head> of your page and populates the global page.meta object with extracted tags.
- Title Tag: The content of
<title>is stored aspage.meta.title. - Meta Tags: Standard
<meta name="X" content="Y">tags are stored aspage.meta.X. - HTML Language: The
langattribute on<html>is stored aspage.meta.lang.
Components on the page can consume this metadata in their server() or data() blocks:
<html lang="en">
<head>
<title>Getting Started with Coralite</title>
<meta name="description" content="A comprehensive guide to building fast websites with Coralite."></meta>
<meta name="author" content="Coralite Team"></meta>
</head>
<body>
<page-header></page-header>
</body>
</html>
import { defineComponent } from 'coralite'
export default defineComponent({
server: ({ page }) => ({
title: page.meta.title,
author: page.meta.author
})
})
The metadata plugin also evaluates custom components located inside the <head> tag (for example, reusable <seo-bundle> elements), extracting any generated title or meta tags into page.meta.
2. Canonical URLs (Planned) #
Automatic canonical URL derivation from baseURL and route.path is planned for a future release. Currently, canonical link tags must be declared explicitly in your page or head components.
To declare a canonical URL manually, add a standard <link rel="canonical"> element to your page's <head> or generate it dynamically in a server() block using route.path:
export function server ({ route }) {
return {
canonicalUrl: `https://example.com${route.path}`
}
}
<link rel="canonical" href=""></link>
3. Open Graph and Twitter Cards (Planned Extraction) #
Automatic extraction of property="og:*" and name="twitter:*" meta tags into page.meta is planned for a future release. Standard Open Graph and Twitter Card tags defined in <head> pass through directly to the rendered HTML output without modification.
You can author standard Open Graph and Twitter Card tags directly in your HTML page head:
<head>
<meta property="og:title" content="My Page Title"></meta>
<meta property="og:description" content="Page description for social sharing."></meta>
<meta property="og:type" content="website"></meta>
<meta name="twitter:card" content="summary_large_image"></meta>
<meta name="twitter:title" content="My Page Title"></meta>
</head>
4. Sitemap Generation (Plugin Pattern) #
Sitemaps are generated using a custom build plugin. During the onAfterBuild hook, the plugin accesses app.pages.list to iterate over all rendered pages and outputs an XML file via app.writeFile.
import { definePlugin } from 'coralite'
export function sitemapPlugin (options = {}) {
const siteUrl = options.siteUrl || 'https://example.com'
return definePlugin({
name: 'sitemap-plugin',
server: {
async onAfterBuild ({ app }) {
const pages = app.pages.list || []
let xml = '\n'
xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
for (const page of pages) {
const loc = `${siteUrl}${page.routePath}`
xml += ' <url>\n'
xml += ` <loc>${loc}</loc>\n`
xml += ' </url>\n'
}
xml += '</urlset>\n'
await app.writeFile('sitemap.xml', xml)
}
}
})
}
5. RSS and Atom Feeds (Plugin Pattern) #
Similarly, RSS and Atom feeds can be generated by querying collections during build hooks and writing the XML feed file to the output directory.
import { definePlugin } from 'coralite'
export function rssPlugin (options = {}) {
const siteUrl = options.siteUrl || 'https://example.com'
return definePlugin({
name: 'rss-plugin',
server: {
async onAfterBuild ({ app }) {
const posts = app.collections?.posts || []
let xml = '\n'
xml += '<rss version="2.0">\n <channel>\n'
xml += ` <title>${options.title || 'My Blog'}</title>\n`
xml += ` <link>${siteUrl}\n`
for (const post of posts) {
xml += ' <item>\n'
xml += ` <title>${post.title}</title>\n`
xml += ` <link>${siteUrl}${post.path}\n`
xml += ' </item>\n'
}
xml += ' </channel>\n</rss>\n'
await app.writeFile('feed.xml', xml)
}
}
})
}
6. robots.txt #
To serve a robots.txt file, place it in your project's public/ directory. Coralite copies all assets in public/ verbatim to the build output root during compilation.
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
7. JSON-LD Structured Data (Planned) #
Raw unescaped template interpolations (such as {}) are planned for a future release. Raw JSON-LD script block interpolation should not be attempted with standard double-brace tags.
Until raw token interpolation is available, JSON-LD structured data can be included by writing static <script type="application/ld+json"> blocks directly inside your page templates or component HTML.
8. What Coralite Does Not Provide #
To remain lightweight, predictable, and standards-compliant, Coralite intentionally does not ship built-in abstractions for several SEO concerns:
- No built-in sitemap generator in core: Use the plugin hook pattern with
onAfterBuildandapp.writeFile. - No built-in feed generator in core: Use custom plugin hooks to build RSS/Atom XML feeds from site collections.
- No schema.org type definitions: Author standard JSON-LD script tags or external schema helper libraries directly.
Next: Explore Authoring Plugins to learn more about extending build tasks with plugins.