@skybolt/vite-plugin
v3.5.1
Published
Vite plugin for Skybolt - High-performance asset caching for multi-page applications
Maintainers
Readme
@skybolt/vite-plugin
Vite plugin for Skybolt - High-performance asset caching for multi-page applications.
What is Skybolt?
Skybolt eliminates HTTP requests for cached assets on repeat visits by using Service Workers and the Cache API. On first visit, assets are inlined in the HTML and cached. On subsequent visits, the server sends regular <link> and <script> tags, which the Service Worker intercepts and serves instantly from cache.
Result: Zero network requests for CSS/JS on repeat visits. Assets load in ~5ms.
Installation
pnpm add @skybolt/vite-pluginUsage
1. Configure Vite
// vite.config.js
import { defineConfig } from 'vite'
import { skybolt } from '@skybolt/vite-plugin'
export default defineConfig({
base: '/assets/',
build: {
manifest: true, // Required!
outDir: 'dist',
rollupOptions: {
input: {
critical: 'src/css/critical.css',
main: 'src/css/main.css',
app: 'src/js/app.js'
}
}
},
plugins: [skybolt()]
})2. Build
pnpm run buildThis generates:
dist/
├── assets/
│ ├── critical-Hx7kQ9mN.css
│ ├── main-Pw3rT8vL.css
│ └── app-Km5nR2xQ.js
├── .skybolt/
│ └── render-map.json # For server adapters
└── skybolt-sw.js # Service Worker3. Use with a Server Adapter
Install a Skybolt adapter for your language:
- PHP:
composer require jensroland/skybolt - Ruby:
gem install skybolt - Python:
pip install skybolt(or:uv add skybolt/poetry add skybolt) - Go:
go get github.com/JensRoland/skybolt-go
Then, use the adapter to include Skybolt-managed assets in your HTML.
Example (PHP):
<?php
$sb = new Skybolt\Skybolt(__DIR__ . '/dist/.skybolt/render-map.json');
?>
<!DOCTYPE html>
<html>
<head>
<?= $sb->css('src/css/critical.css') ?>
<?= $sb->launchScript() ?>
<?= $sb->css('src/css/main.css') ?>
</head>
<body>
<h1>Hello Skybolt!</h1>
<?= $sb->script('src/js/app.js') ?>
</body>
</html>4. Serve the Service Worker
Configure your web server to serve /skybolt-sw.js from dist/skybolt-sw.js.
Apache (.htaccess):
RewriteRule ^skybolt-sw\.js$ dist/skybolt-sw.js [L]Nginx:
location = /skybolt-sw.js {
alias /path/to/dist/skybolt-sw.js;
}PHP (development):
<?php
// public/skybolt-sw.js (or use a router)
header('Content-Type: application/javascript');
header('Service-Worker-Allowed: /');
readfile(__DIR__ . '/../dist/skybolt-sw.js');Options
skybolt({
// Output directory for render-map.json (relative to build output)
outDir: '.skybolt',
// URL path where Service Worker will be served
swPath: '/skybolt-sw.js',
// Enable debug logging
debug: false
})How It Works
First Visit
- Server reads
render-map.json - Server checks cookie (empty - new visitor)
- Server inlines assets with
sb-*attributes - Browser receives HTML with inlined CSS/JS
- Skybolt client extracts content and caches via Service Worker
- Client writes asset versions to cookie
Repeat Visit
- Server reads
render-map.json - Server checks cookie (has asset versions)
- Server sends regular
<link>and<script>tags - Browser requests assets
- Service Worker intercepts and serves from Cache API (~5ms)
- Zero network requests!
After Build (Cache Invalidation)
- You run
pnpm run build - Vite generates new hashes for changed files
- Plugin updates
render-map.json - Visitor returns, server detects hash mismatch
- Server inlines new assets
- Client updates cache and cookie
- Automatic invalidation!
Cache Digest
Skybolt uses Cache Digest - a Cuckoo filter-based probabilistic data structure that provides compact cookie storage for cache state tracking.
Size Comparison
Instead of storing asset names and hashes explicitly (src/css/main.css:Pw3rT8vL,...), Skybolt compresses this into a compact binary filter stored in the sb_digest cookie:
| Assets | Plain Text | Cache Digest | Compression | | ------ | ------------ | ------------ | ----------- | | 10 | ~400 bytes | ~50 bytes | 88% | | 50 | ~2,000 bytes | ~350 bytes | 84% | | 100 | ~4,000 bytes | ~700 bytes | 84% | | 200 | ~8,000 bytes | ~1,400 bytes | 84% |
Trade-offs
- No false negatives: If an asset is cached, the filter will always report it
- Small false positive rate (~1-3%): Occasionally reports uncached assets as cached, causing a network fetch instead of inline - a minor one-time performance hit
- Supports deletion: Unlike Bloom filters, items can be removed when evicting or invalidating cache entries
API
import { CuckooFilter, createCacheDigest } from '@skybolt/vite-plugin/cache-digest'
// Create from asset list
const assets = ['src/css/main.css:Pw3rT8vL', 'src/js/app.js:Km5nR2xQ']
const digest = createCacheDigest(assets)
// Serialize to cookie (URL-safe base64)
const cookie = digest.toBase64()
// Restore on server
const restored = CuckooFilter.fromBase64(cookie)
restored.lookup('src/css/main.css:Pw3rT8vL') // true
restored.lookup('unknown:asset') // false (definitely not present)Render Map Schema
The render-map.json contains everything server adapters need:
{
"version": 1,
"generated": "2025-11-24T12:00:00.000Z",
"skyboltVersion": "3.0.0",
"basePath": "/assets/",
"assets": {
"src/css/main.css": {
"url": "/assets/main-Pw3rT8vL.css",
"hash": "Pw3rT8vL",
"size": 85000,
"content": "body{margin:0}..."
}
},
"client": {
"script": "class SkyboltClient{..."
},
"serviceWorker": {
"filename": "skybolt-sw.js",
"path": "/skybolt-sw.js"
}
}Browser Support
- Chrome/Edge 60+
- Firefox 55+
- Safari 11.1+
Requires Service Worker and Cache API support. Falls back gracefully to standard external assets when unavailable.
Publishing
To publish a new version, run one command from the packages/vite-plugin directory:
pnpm version patch # 3.1.1 → 3.1.2
pnpm version minor # 3.1.1 → 3.2.0
pnpm version major # 3.1.1 → 4.0.0This automatically:
- Updates
package.json - Syncs version to
README.mdand the JS source files usingscripts/sync-version.js - Regenerates minified files
- Commits all changes
- Creates a git tag (e.g.,
v3.1.2) - Triggers the
postversionscript, which creates thevite-plugin-v*tag
You then have to run git push origin main --tags to push the changes and tag to GitHub, which triggers the publish workflow.
The workflow uses vite-plugin-v* tags (not just v*) to differentiate from the adapter package tags. It also includes --provenance for supply chain security.
The publish-vite-plugin.yml Github Action will automatically build and publish the package to NPM using OIDC authentication.
License
MIT
