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.

Components on the page can consume this metadata in their server() or data() blocks:

HTML
Code copied!

<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>
javascript
Code copied!
  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) #

Planned Feature

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:

javascript
Code copied!
  export function server ({ route }) {
    return {
      canonicalUrl: `https://example.com${route.path}`
    }
  }
HTML
Code copied!
<link rel="canonical" href=""></link>

3. Open Graph and Twitter Cards (Planned Extraction) #

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:

HTML
Code copied!
<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.

javascript
Code copied!
  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&apos;
  
          for (const page of pages) {
            const loc = `&#x24;{siteUrl}&#x24;{page.routePath}`
            xml += &apos;  <url>\n&apos;
            xml += `    <loc>&#x24;{loc}</loc>\n`
            xml += &apos;  </url>\n&apos;
          }
  
          xml += &apos;</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.

javascript
Code copied!
  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&apos;
          xml += `    <title>&#x24;{options.title || &apos;My Blog&apos;}</title>\n`
          xml += `    <link>&#x24;{siteUrl}\n`
  
          for (const post of posts) {
            xml += &apos;    <item>\n&apos;
            xml += `      <title>&#x24;{post.title}</title>\n`
            xml += `      <link>&#x24;{siteUrl}&#x24;{post.path}\n`
            xml += &apos;    </item>\n&apos;
          }
  
          xml += &apos;  </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.

text
Code copied!
  User-agent: *
  Allow: /
  
  Sitemap: https://example.com/sitemap.xml

7. JSON-LD Structured Data (Planned) #

Planned Feature

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:


Next: Explore Authoring Plugins to learn more about extending build tasks with plugins.

Start Building with Coralite!

Use the scaffolding script to get jump started into your next project with Coralite

Copied commandline!