jensroland / skybolt
High-performance asset caching for multi-page applications
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/jensroland/skybolt
Requires
- php: >=8.1
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^11.0
README
PHP adapter for Skybolt - High-performance asset caching for multi-page applications.
Installation
composer require jensroland/skybolt
Prerequisites
- Install and configure the Vite plugin:
npm install @skybolt/vite-plugin - Build your project:
npm run build - Ensure
render-map.jsonis generated in your build output
Usage
<?php require_once __DIR__ . '/vendor/autoload.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>
API
new Skybolt(string $renderMapPath, ?array $cookies = null, ?string $cdnUrl = null)
Create a new Skybolt instance.
$renderMapPath- Path torender-map.jsongenerated by Vite plugin$cookies- Cookie array (defaults to$_COOKIE)$cdnUrl- Optional CDN URL prefix (e.g.,'https://cdn.example.com')
// Basic usage $sb = new Skybolt\Skybolt(__DIR__ . '/dist/.skybolt/render-map.json'); // With CDN $sb = new Skybolt\Skybolt( __DIR__ . '/dist/.skybolt/render-map.json', cdnUrl: 'https://cdn.example.com' );
css(string $entry, bool $async = false): string
Render CSS asset.
- First visit: Inlines CSS with caching attributes
- Repeat visit: Outputs
<link>tag (Service Worker serves from cache)
When $async is true, CSS loads non-blocking:
- First visit: Uses
media="print"trick, swaps toallon load - Repeat visit: Uses
<link rel="preload">withonload
// Blocking (default) - for critical CSS <?= $sb->css('src/css/critical.css') ?> // Non-blocking - for non-critical CSS <?= $sb->css('src/css/main.css', async: true) ?>
script(string $entry, bool $module = true): string
Render JavaScript asset.
- First visit: Inlines JS with caching attributes
- Repeat visit: Outputs
<script>tag (Service Worker serves from cache)
// ES module (default) <?= $sb->script('src/js/app.js') ?> // Classic script <?= $sb->script('src/js/legacy.js', module: false) ?>
launchScript(): string
Render the Skybolt client launcher. Call once in <head> before other assets.
<head>
<?= $sb->launchScript() ?>
</head>
getAssetUrl(string $entry): ?string
Get the URL for an asset (for manual use cases).
$url = $sb->getAssetUrl('src/css/main.css'); // "/assets/main-Pw3rT8vL.css"
getAssetHash(string $entry): ?string
Get the content hash for an asset.
$hash = $sb->getAssetHash('src/css/main.css'); // "Pw3rT8vL"
preload(string $entry, string $as, ...): string
Render preload link for critical resources like fonts and images.
// Preload hero image with high priority <?= $sb->preload('images/hero.jpg', as: 'image', fetchpriority: 'high') ?> // Preload font <?= $sb->preload('fonts/inter.woff2', as: 'font', type: 'font/woff2', crossorigin: 'anonymous') ?> // Preload a Vite-built asset (resolved from render-map) <?= $sb->preload('src/css/main.css', as: 'style') ?>
Parameters:
$entry- Source file path or direct URL$as- Resource type ('image','font','style','script','fetch')$type- MIME type (e.g.,'font/woff2','image/webp')$crossorigin- Crossorigin attribute ('anonymous','use-credentials')$fetchpriority- Fetch priority ('high','low','auto')
Service Worker Setup
The Service Worker must be served from your domain root. Options:
Option 1: Direct file (recommended)
Copy dist/skybolt-sw.js to your public directory, or configure your web server:
Apache (.htaccess):
RewriteRule ^skybolt-sw\.js$ dist/skybolt-sw.js [L]
Nginx:
location = /skybolt-sw.js { alias /path/to/dist/skybolt-sw.js; }
Option 2: PHP endpoint
<?php // public/skybolt-sw.js (use .htaccess to route .js to PHP, or name it .php) header('Content-Type: application/javascript'); header('Service-Worker-Allowed: /'); header('Cache-Control: public, max-age=86400'); readfile(__DIR__ . '/../dist/skybolt-sw.js');
Framework Integration
Laravel
// app/Providers/AppServiceProvider.php public function register(): void { $this->app->singleton(\Skybolt\Skybolt::class, function () { return new \Skybolt\Skybolt(public_path('dist/.skybolt/render-map.json')); }); } // app/Providers/AppServiceProvider.php (boot method) Blade::directive('skyboltCss', function ($entry) { return "<?php echo app(\Skybolt\Skybolt::class)->css({$entry}); ?>"; }); Blade::directive('skyboltScript', function ($entry) { return "<?php echo app(\Skybolt\Skybolt::class)->script({$entry}); ?>"; }); Blade::directive('skyboltLaunch', function () { return "<?php echo app(\Skybolt\Skybolt::class)->launchScript(); ?>"; });
{{-- resources/views/layout.blade.php --}} <head> @skyboltCss('src/css/critical.css') @skyboltLaunch @skyboltCss('src/css/main.css') </head>
Symfony
// src/Twig/SkyboltExtension.php class SkyboltExtension extends AbstractExtension { public function __construct(private Skybolt $skybolt) {} public function getFunctions(): array { return [ new TwigFunction('skybolt_css', [$this->skybolt, 'css'], ['is_safe' => ['html']]), new TwigFunction('skybolt_script', [$this->skybolt, 'script'], ['is_safe' => ['html']]), new TwigFunction('skybolt_launch', [$this->skybolt, 'launchScript'], ['is_safe' => ['html']]), ]; } }
{# templates/base.html.twig #} <head> {{ skybolt_css('src/css/critical.css') }} {{ skybolt_launch() }} {{ skybolt_css('src/css/main.css') }} </head>
Requirements
- PHP 8.1+
- Vite with
@skybolt/vite-plugin
License
MIT