@skybolt/server-adapter
Version:
Skybolt server adapter for Node.js/Bun - High-performance asset caching for multi-page applications
275 lines (258 loc) • 7.01 kB
TypeScript
/**
* @skybolt/server-adapter - Skybolt server adapter for Node.js/Bun
*
* High-performance asset caching for multi-page applications.
* Eliminates HTTP requests for cached assets on repeat visits.
*
* @module @skybolt/server-adapter
*/
/**
* Asset metadata from the render map.
*/
export interface Asset {
/** The URL path to the asset */
url: string
/** Content hash for cache invalidation */
hash: string
/** File size in bytes */
size: number
/** Full asset content for inlining */
content: string
}
/**
* Client script configuration.
*/
export interface ClientConfig {
/** Minified client launcher script */
script: string
}
/**
* Service Worker configuration.
*/
export interface ServiceWorkerConfig {
/** Service worker filename */
filename: string
/** URL path for service worker */
path: string
}
/**
* Render map structure generated by @skybolt/vite-plugin.
*/
export interface RenderMap {
/** Render map schema version */
version: number
/** ISO timestamp of generation */
generated: string
/** Skybolt version used */
skyboltVersion: string
/** Base path for assets */
basePath: string
/** Map of source paths to asset data */
assets: Record<string, Asset>
/** Client script configuration */
client: ClientConfig
/** Service worker configuration */
serviceWorker: ServiceWorkerConfig
}
/**
* Options for rendering CSS assets.
*/
export interface CssOptions {
/**
* If true, load CSS asynchronously (non-blocking).
* @default false
*/
async?: boolean
}
/**
* Options for rendering JavaScript assets.
*/
export interface ScriptOptions {
/**
* If true, use type="module"; if false, classic script.
* @default true
*/
module?: boolean
}
/**
* Options for preloading assets.
*/
export interface PreloadOptions {
/** Resource type (e.g., 'style', 'script', 'font', 'image') */
as?: string
/** MIME type (e.g., 'font/woff2') */
type?: string
/** Crossorigin attribute value */
crossorigin?: string
/** Fetch priority ('high', 'low', 'auto') */
fetchpriority?: 'high' | 'low' | 'auto'
}
/**
* Skybolt server adapter for Node.js and Bun.
*
* Reads the render map generated by @skybolt/vite-plugin and renders
* HTML tags for CSS and JavaScript assets. On first visit, assets are
* inlined; on repeat visits, external links are used (served from SW cache).
*
* @example
* ```javascript
* import { Skybolt } from '@skybolt/server-adapter'
*
* const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)
*
* const html = `
* <head>
* ${skybolt.css('src/css/main.css')}
* ${skybolt.script('src/js/app.js')}
* ${skybolt.launchScript()}
* </head>
* `
* ```
*/
export class Skybolt {
/**
* Create a new Skybolt instance.
*
* @param renderMapPath - Path to the render-map.json file
* @param cookies - Request cookies object (e.g., req.cookies)
* @param cdnUrl - Optional CDN base URL to prefix asset URLs
* @throws {Error} If render map cannot be read or parsed
*/
constructor(
renderMapPath: string,
cookies?: Record<string, string> | null,
cdnUrl?: string | null
)
/**
* Render a CSS asset.
*
* On first visit (or cache miss), returns an inlined `<style>` tag with
* `sb-asset` and `sb-url` attributes for the client to cache.
*
* On repeat visits (cache hit), returns a `<link>` tag. The Service Worker
* will serve the asset from cache (~5ms response time).
*
* @param entry - Source path of the CSS file (e.g., 'src/css/main.css')
* @param options - Options
* @returns HTML string (`<style>` or `<link>` tag)
*
* @example
* ```javascript
* // Blocking CSS (in <head>)
* skybolt.css('src/css/main.css')
*
* // Non-blocking CSS (above </body>)
* skybolt.css('src/css/main.css', { async: true })
* ```
*/
css(entry: string, options?: CssOptions): string
/**
* Render a JavaScript asset.
*
* On first visit (or cache miss), returns an inlined `<script>` tag with
* `sb-asset` and `sb-url` attributes for the client to cache.
*
* On repeat visits (cache hit), returns an external `<script>` tag. The
* Service Worker will serve the asset from cache (~5ms response time).
*
* @param entry - Source path of the JS file (e.g., 'src/js/app.js')
* @param options - Options
* @returns HTML string (`<script>` tag)
*
* @example
* ```javascript
* // ES module (default)
* skybolt.script('src/js/app.js')
*
* // Classic script
* skybolt.script('src/js/legacy.js', { module: false })
* ```
*/
script(entry: string, options?: ScriptOptions): string
/**
* Render a preload link for an asset.
*
* Preloads are useful for critical resources that should be fetched early.
* Note: Preloaded resources are NOT cached by the Service Worker.
*
* @param entry - Source path of the asset
* @param options - Options
* @returns HTML string (`<link rel="preload">` tag)
*
* @example
* ```javascript
* // Preload a font
* skybolt.preload('src/fonts/Inter.woff2', {
* as: 'font',
* type: 'font/woff2',
* crossorigin: 'anonymous'
* })
* ```
*/
preload(entry: string, options?: PreloadOptions): string
/**
* Render the Skybolt client launcher script.
*
* This must be included once per page, typically at the end of `<head>` or
* before `</body>`. It registers the Service Worker and processes any
* inlined assets on the page.
*
* @returns HTML string (meta tag + script tag)
*
* @example
* ```javascript
* // In your template
* `<head>
* ${skybolt.css('src/css/main.css')}
* ${skybolt.launchScript()}
* </head>`
* ```
*/
launchScript(): string
/**
* Get the URL for an asset.
*
* Useful when you need the asset URL for manual use (e.g., in a srcset
* or for JavaScript dynamic imports).
*
* @param entry - Source path of the asset
* @returns The asset URL, or null if not found
*
* @example
* ```javascript
* const url = skybolt.getAssetUrl('src/images/hero.webp')
* // => '/assets/hero-Abc123.webp'
* ```
*/
getAssetUrl(entry: string): string | null
/**
* Get the content hash for an asset.
*
* Useful for cache busting or versioning.
*
* @param entry - Source path of the asset
* @returns The asset hash, or null if not found
*
* @example
* ```javascript
* const hash = skybolt.getAssetHash('src/css/main.css')
* // => 'Pw3rT8vL'
* ```
*/
getAssetHash(entry: string): string | null
/**
* Check if an asset is currently cached by the client.
*
* @param entry - Source path of the asset
* @returns True if the asset is cached with the current hash
*
* @example
* ```javascript
* if (skybolt.isCached('src/css/main.css')) {
* // Client has this asset cached
* }
* ```
*/
isCached(entry: string): boolean
}
export default Skybolt