@skybolt/server-adapter
Version:
Skybolt server adapter for Node.js/Bun - High-performance asset caching for multi-page applications
281 lines (204 loc) • 6.02 kB
Markdown
# @skybolt/server-adapter
Skybolt server adapter for Node.js and Bun. High-performance asset caching for multi-page applications.
## Installation
```bash
npm install @skybolt/server-adapter
# or
pnpm add @skybolt/server-adapter
# or
bun add @skybolt/server-adapter
```
## Quick Start
```javascript
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 = `
<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 the `render-map.json` file generated by `@skybolt/vite-plugin`
- `cookies` (object | null) - Request cookies object from your framework
- `cdnUrl` (string | null) - Optional CDN base URL to prefix asset URLs
### `skybolt.css(entry, options?)`
Render a CSS asset.
```javascript
// 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.
```javascript
// ES module (default)
skybolt.script('src/js/app.js')
// Classic script
skybolt.script('src/js/legacy.js', { module: false })
```
**Options:**
- `module` (boolean, default: `true`) - Use `type="module"` for ES modules
### `skybolt.preload(entry, options?)`
Render a preload link for early resource fetching.
```javascript
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 type
- `crossorigin` (string) - Crossorigin attribute
- `fetchpriority` (string) - `'high'`, `'low'`, or `'auto'`
### `skybolt.launchScript()`
Render the Skybolt client launcher. **Include this once per page.**
```javascript
// In <head> or before </body>
skybolt.launchScript()
```
### `skybolt.getAssetUrl(entry)`
Get the URL for an asset (for manual use).
```javascript
const url = skybolt.getAssetUrl('src/images/hero.webp')
// => '/assets/hero-Abc123.webp'
```
### `skybolt.getAssetHash(entry)`
Get the content hash for an asset.
```javascript
const hash = skybolt.getAssetHash('src/css/main.css')
// => 'Pw3rT8vL'
```
### `skybolt.isCached(entry)`
Check if the client has an asset cached.
```javascript
if (skybolt.isCached('src/css/main.css')) {
// Client has current version cached
}
```
## Framework Examples
### Express
```javascript
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)
```javascript
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 app
```
### Fastify
```javascript
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:
```javascript
const skybolt = new Skybolt(
'./dist/.skybolt/render-map.json',
req.cookies,
'https://cdn.example.com'
)
// URLs become: https://cdn.example.com/assets/main-Abc123.css
```
## TypeScript
Full TypeScript support is included:
```typescript
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