Building Applications
Coralite provides a flexible, platform-native application architecture that scales from pure static content to highly dynamic, interactive single-page applications. Rather than forcing a single rendering model, Coralite allows you to choose the right strategy for your use case—or blend strategies across different sections of the same site.
1. Pure SSG (Default) #
By default, Coralite operates as a zero-JS Static Site Generator (SSG). During coralite build, every page in your src/pages directory is rendered to a static HTML file in dist/.
Best for: Blogs, documentation portals, marketing websites, content-driven publications, and e-commerce catalogs.
Key Characteristics #
- Zero Client JavaScript by Default: Unless a component explicitly includes a
client()block, Coralite strips hydration markers and outputs pure, standard HTML and CSS. - Native View Transitions: Smooth page-to-page transitions are enabled by default via standard browser View Transitions API, giving standard multi-page applications (MPAs) an app-like feel without SPA overhead.
- Optimal Performance & SEO: Search engines receive fully rendered HTML documents instantly, resulting in superior Core Web Vitals and zero cumulative layout shift (CLS).
Example: Navigation with View Transitions #
In Pure SSG mode, navigation relies on standard HTML links. Coralite automatically handles View Transition crossfades across page changes when enabled in coralite.config.js.
<!-- src/components/nav-header.html -->
<template id="nav-header">
<header class="site-header">
<nav>
<a href="/">Home</a>
<a href="/docs/guide.html">Documentation</a>
<a href="/blog.html">Blog</a>
</nav>
</header>
</template>
2. Hybrid Mode (Client-Side Data & Auth) #
Hybrid mode combines static HTML page shells with dynamic, client-side data fetching. The page structure is generated statically at build time, while user-specific, real-time, or authenticated widget data is fetched on the client after hydration.
Best for: User dashboards, account settings, live analytics widgets, authenticated web apps, and personal portals.
How Authentication & Client Fetching Work #
Because Coralite is an SSG with zero server runtime at request time, there are no server-side HTTP request sessions or cookies available during page compilation. Authentication in Coralite is handled entirely on the client after hydration using standard browser APIs (such as session cookies, bearer tokens in localStorage, or HTTP-only cookies sent via fetch).
Example: User Profile Widget #
In this example, the user profile component renders an initial static loading state during SSR. Once hydrated in the browser, its client() block fetches the current user session from an API endpoint and updates state reactively.
<template id="user-profile">
<div class="profile-card">
<span ref="status" class="status-badge">Loading session...</span>
<h3></h3>
<p></p>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
getters: {
userName: ({ state }) => state.user ? state.user.name : 'Guest',
userEmail: ({ state }) => state.user ? state.user.email : 'Not signed in'
},
async client ({ state, refs, signal }) {
const statusEl = refs('status')
try {
const res = await fetch('/api/user', { signal })
if (res.ok) {
state.user = await res.json()
statusEl.textContent = 'Authenticated'
statusEl.classList.add('active')
} else {
statusEl.textContent = 'Unauthenticated'
}
} catch (err) {
if (err.name !== 'AbortError') {
statusEl.textContent = 'Failed to load user'
}
}
}
})
</script>
3. Single-Page Application (SPA) Mode #
For applications that require persistent client state, background audio playback, persistent WebSockets, or zero full-page reloads across navigation, Coralite offers an opt-in client-side router plugin.
Best for: Audio/video streaming apps, complex step-by-step wizards, live chat tools, and media production dashboards.
For the router's complete API and configuration options, see the Router Plugin Reference; for worked patterns — outlet and persistent-element layout, guards, navigation events, and state that survives route swaps — see the SPA Router Guide.
Setting Up SPA Mode #
The SPA router is a core router plugin, and it is opt-in: it must be registered in coralite.config.js before any client-side routing behavior (link interception, history handling, guards) activates.
import { defineConfig } from 'coralite'
import router from 'coralite/plugins/router'
export default defineConfig({
plugins: [
router({
base: '/',
outlet: 'data-router-outlet'
})
]
})
Once the plugin is registered, any element carrying the data-router-outlet attribute (or the <router-outlet> component provided by the plugin) marks the SPA swap region. On each navigation only the outlet content is replaced, so elements outside it — a persistent navbar, a background audio player, connected WebSockets — survive every route change. Pages that declare no outlet of their own are automatically wrapped in a <router-outlet> element around their full body content at render time.
Note: A data-router-outlet element without the registered plugin is inert — it does not change navigation behavior on its own.
<!-- src/pages/app/dashboard.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<coralite-meta title="App Dashboard"></coralite-meta>
</head>
<body>
<coralite-navbar></coralite-navbar>
<!-- Persistent audio player outside the router outlet -->
<audio-player></audio-player>
<!-- SPA Router Outlet: Navigation swaps content inside here -->
<div data-router-outlet>
<h1 class="display">Dashboard</h1>
<p>Welcome to your application workspace.</p>
</div>
<coralite-footer></coralite-footer>
</body>
</html>
Navigation Guards with beforeEach #
You can register navigation guards via router.beforeEach in a client block or plugin to validate permissions, cancel unwanted transitions, or redirect unauthenticated users before client-side navigation occurs.
client ({ router }) {
router.beforeEach(({ to, from }) => {
// Check auth status before entering protected app routes
if (to.path.startsWith('/app') && !localStorage.getItem('auth_token')) {
// Return a redirect path
return '/login.html'
}
// Return true or undefined to allow navigation
return true
})
}
SPA Architecture Trade-Offs #
While SPA mode enables persistent client-side state across navigation, it introduces architectural trade-offs:
| Metric / Aspect | Pure SSG / Hybrid | SPA Mode |
|---|---|---|
| Client State | Resets on page transition | Persists across route changes |
| Navigation Model | Native browser multi-page load (View Transitions) | Client-side fetch + outlet DOM replacement |
| Component Hydration | Per-page initial hydration | Re-hydrates upgraded components in outlet per transition |
| SEO Indexability | 100% pre-rendered static HTML | Requires pre-built static HTML per route for crawlers |
Next: Learn about unit testing, E2E testing, deployment, and CSP configuration in the Testing & Deployment Guide.