UNPKG

@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
/** * @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