@skybolt/server-adapter
v3.5.0
Published
Skybolt server adapter for Node.js/Bun - High-performance asset caching for multi-page applications
Maintainers
Readme
@skybolt/server-adapter
Skybolt server adapter for Node.js and Bun. High-performance asset caching for multi-page applications.
Installation
npm install @skybolt/server-adapter
# or
pnpm add @skybolt/server-adapter
# or
bun add @skybolt/server-adapterQuick Start
import { Skybolt } from '@skybolt/server-adapter'
// Create instance with render map path and request cookies
const skybolt = new Skybolt(
'./dist/.skybolt/render-map.json',
req.cookies // Your framework's cookies object
)
// Generate HTML
const html = `
<!DOCTYPE html>
<html>
<head>
${skybolt.css('src/css/main.css')}
${skybolt.launchScript()}
</head>
<body>
<h1>Hello Skybolt!</h1>
${skybolt.script('src/js/app.js')}
</body>
</html>
`How It Works
First visit: Assets are inlined directly in the HTML. The Skybolt client script caches them in the browser's Cache API and registers a Service Worker.
Repeat visits: The server outputs standard <link> and <script> tags. The Service Worker intercepts these requests and serves assets from cache (~5ms response time). Zero network requests.
After rebuilds: Content hashes change, causing a cache miss. Assets are re-inlined and the cache is updated automatically.
API
new Skybolt(renderMapPath, cookies?, cdnUrl?)
Create a new Skybolt instance.
renderMapPath(string) - Path to therender-map.jsonfile generated by@skybolt/vite-plugincookies(object | null) - Request cookies object from your frameworkcdnUrl(string | null) - Optional CDN base URL to prefix asset URLs
skybolt.css(entry, options?)
Render a CSS asset.
// Blocking CSS (in <head>)
skybolt.css('src/css/main.css')
// Non-blocking CSS (async loading)
skybolt.css('src/css/main.css', { async: true })Options:
async(boolean, default:false) - Load CSS asynchronously
skybolt.script(entry, options?)
Render a JavaScript asset.
// ES module (default)
skybolt.script('src/js/app.js')
// Classic script
skybolt.script('src/js/legacy.js', { module: false })Options:
module(boolean, default:true) - Usetype="module"for ES modules
skybolt.preload(entry, options?)
Render a preload link for early resource fetching.
skybolt.preload('src/fonts/Inter.woff2', {
as: 'font',
type: 'font/woff2',
crossorigin: 'anonymous'
})Options:
as(string) - Resource type ('font','image','script','style')type(string) - MIME typecrossorigin(string) - Crossorigin attributefetchpriority(string) -'high','low', or'auto'
skybolt.launchScript()
Render the Skybolt client launcher. Include this once per page.
// In <head> or before </body>
skybolt.launchScript()skybolt.getAssetUrl(entry)
Get the URL for an asset (for manual use).
const url = skybolt.getAssetUrl('src/images/hero.webp')
// => '/assets/hero-Abc123.webp'skybolt.getAssetHash(entry)
Get the content hash for an asset.
const hash = skybolt.getAssetHash('src/css/main.css')
// => 'Pw3rT8vL'skybolt.isCached(entry)
Check if the client has an asset cached.
if (skybolt.isCached('src/css/main.css')) {
// Client has current version cached
}Framework Examples
Express
import express from 'express'
import cookieParser from 'cookie-parser'
import { Skybolt } from '@skybolt/server-adapter'
const app = express()
app.use(cookieParser())
app.use(express.static('dist'))
app.get('/', (req, res) => {
const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)
res.send(`
<!DOCTYPE html>
<html>
<head>
${skybolt.css('src/css/main.css')}
${skybolt.launchScript()}
</head>
<body>
<h1>Express + Skybolt</h1>
${skybolt.script('src/js/app.js')}
</body>
</html>
`)
})
app.listen(8080)Hono (Bun)
import { Hono } from 'hono'
import { getCookie } from 'hono/cookie'
import { serveStatic } from 'hono/bun'
import { Skybolt } from '@skybolt/server-adapter'
const app = new Hono()
app.use('/*', serveStatic({ root: './dist' }))
app.get('/', (c) => {
const cookies = { sb_digest: getCookie(c, 'sb_digest') }
const skybolt = new Skybolt('./dist/.skybolt/render-map.json', cookies)
return c.html(`
<!DOCTYPE html>
<html>
<head>
${skybolt.css('src/css/main.css')}
${skybolt.launchScript()}
</head>
<body>
<h1>Hono + Skybolt</h1>
${skybolt.script('src/js/app.js')}
</body>
</html>
`)
})
export default appFastify
import Fastify from 'fastify'
import fastifyCookie from '@fastify/cookie'
import fastifyStatic from '@fastify/static'
import { Skybolt } from '@skybolt/server-adapter'
const fastify = Fastify()
await fastify.register(fastifyCookie)
await fastify.register(fastifyStatic, { root: './dist' })
fastify.get('/', (req, reply) => {
const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)
reply.type('text/html').send(`
<!DOCTYPE html>
<html>
<head>
${skybolt.css('src/css/main.css')}
${skybolt.launchScript()}
</head>
<body>
<h1>Fastify + Skybolt</h1>
${skybolt.script('src/js/app.js')}
</body>
</html>
`)
})
await fastify.listen({ port: 8080 })CDN Support
Prefix asset URLs with a CDN base URL:
const skybolt = new Skybolt(
'./dist/.skybolt/render-map.json',
req.cookies,
'https://cdn.example.com'
)
// URLs become: https://cdn.example.com/assets/main-Abc123.cssTypeScript
Full TypeScript support is included:
import { Skybolt, type RenderMap, type Asset } from '@skybolt/server-adapter'
const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)Requirements
- Node.js 18+ or Bun
- Assets built with
@skybolt/vite-plugin
License
MIT
