vinkius-labs/laravel-page-speed
Laravel Page Speed adds a configurable optimization pipeline to Laravel apps, improving latency and bandwidth for Blade pages and API responses. Enable only the middleware you need; works with common cache drivers and supports Laravel 10–13.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require vinkius-labs/laravel-page-speed
php artisan vendor:publish --provider="VinkiusLabs\LaravelPageSpeed\ServiceProvider"
bootstrap/app.php (Laravel 11+) or app/Http/Kernel.php (Laravel 10):
// For Blade/HTML optimization
$middleware->appendToGroup('web', [
\VinkiusLabs\LaravelPageSpeed\Middleware\InlineCss::class,
\VinkiusLabs\LaravelPageSpeed\Middleware\CollapseWhitespace::class,
]);
// For API optimization
$middleware->appendToGroup('api', [
\VinkiusLabs\LaravelPageSpeed\Middleware\ApiResponseCache::class,
\VinkiusLabs\LaravelPageSpeed\Middleware\ApiResponseCompression::class,
]);
config/laravel-page-speed.php):
'enable' => env('LARAVEL_PAGE_SPEED_ENABLE', true),
'api_cache' => [
'enabled' => env('API_CACHE_ENABLED', true),
'driver' => env('API_CACHE_DRIVER', 'redis'),
'ttl' => env('API_CACHE_TTL', 300),
],
Optimize a critical page:
web group.php artisan page-speed:test
Start with caching:
// bootstrap/app.php
$middleware->appendToGroup('api', [
\VinkiusLabs\LaravelPageSpeed\Middleware\ApiResponseCache::class,
]);
Configure dynamic tags for cache invalidation:
'api_cache' => [
'dynamic_tags' => true,
'tag_derivation' => [
'user/{id}' => ['user:{id}'],
'posts' => ['posts:latest'],
],
],
Add compression:
$middleware->appendToGroup('api', [
\VinkiusLabs\LaravelPageSpeed\Middleware\ApiResponseCompression::class,
]);
Configure thresholds:
'api_compression' => [
'min_size' => 1024, // bytes
'max_size' => 1048576, // 1MB
],
Optimize HTML:
$middleware->appendToGroup('web', [
\VinkiusLabs\LaravelPageSpeed\Middleware\InlineCss::class,
\VinkiusLabs\LaravelPageSpeed\Middleware\DeferJavascript::class,
]);
Exclude specific routes:
'web_optimization' => [
'excluded_routes' => [
'admin/*',
'debugbar/*',
],
],
app/Providers/AppServiceProvider.php:
public function boot(): void
{
if (app()->runningInConsole()) return;
\VinkiusLabs\LaravelPageSpeed\PageSpeed::resetState();
}
app/Providers/PageSpeedServiceProvider.php:
use VinkiusLabs\LaravelPageSpeed\Contracts\CacheTagDeriver;
public function register(): void
{
$this->app->bind(CacheTagDeriver::class, function () {
return new CustomTagDeriver();
});
}
/health endpoint for Kubernetes probes:
Route::get('/health', \VinkiusLabs\LaravelPageSpeed\Middleware\ApiHealthCheck::class);
Middleware Order:
ApiResponseCache before ApiETag to avoid ETag generation on uncached responses.InlineCss after ElideAttributes to prevent CSS inlining on removed elements.Persistent Environments (Octane/Swoole):
InlineCss uses static counters. Reset state in boot():
\VinkiusLabs\LaravelPageSpeed\PageSpeed::resetState();
php artisan page-speed:clear-cache to reset.Content-Type Guard:
\VinkiusLabs\LaravelPageSpeed\PageSpeed::setContentTypeGuard(function ($contentType) {
return !in_array($contentType, ['text/html', 'application/xhtml+xml']);
});
Livewire/Alpine Attributes:
CollapseWhitespace preserves wire:, x-, and data-* attributes by default. To customize:
'whitespace_preservation' => [
'attributes' => ['wire:', 'x-', 'data-*', 'custom-attr'],
],
Performance Headers:
X-Response-Time, X-Memory-Usage, and X-Cache-Status in responses. Example:
X-Cache-Status: HIT (TTL: 240s)
X-Response-Time: 12ms
X-Memory-Usage may indicate regex exhaustion (see #217).Circuit Breaker:
X-Circuit-Breaker-State: OPEN, check:
API_CIRCUIT_BREAKER_THRESHOLD (default: 5 failures).API_CIRCUIT_BREAKER_TIMEOUT (default: 60s).php artisan page-speed:reset-circuit-breaker
Cache Issues:
API_CACHE_DRIVER matches your CACHE_DRIVER (e.g., redis).php artisan page-speed:debug-cache
Custom Middleware:
Extend VinkiusLabs\LaravelPageSpeed\PageSpeed:
namespace App\Middleware;
use VinkiusLabs\LaravelPageSpeed\PageSpeed;
class CustomOptimizer extends PageSpeed
{
public function apply($content): string
{
// Custom logic
return parent::apply($content);
}
}
Tag Derivation:
Implement CacheTagDeriver:
use VinkiusLabs\LaravelPageSpeed\Contracts\CacheTagDeriver;
class CustomTagDeriver implements CacheTagDeriver
{
public function deriveTags(string $path): array
{
return ['custom:tag'];
}
}
Compression Strategies:
Override ApiResponseCompression:
protected function getCompressionAlgorithm(): string
{
return 'zstd'; // Use Zstandard instead of Brotli
}
API_CACHE_DYNAMIC_TAGS:
Set to false for static APIs (e.g., documentation). Dynamic tags add overhead (~1-2ms per request).INLINE_CSS_MAX_SIZE:
Default: 10KB. Increase for complex stylesheets to avoid performance cliffs.DEFER_JS_EXCLUDE_PATTERNS:
Exclude critical scripts:
'defer_javascript' => [
'exclude_patterns' => [
'https://cdn.example.com/critical.js',
'*.analytics.js',
],
],
LARAVEL_PAGE_SPEED_ENABLE=false in a cookie-based flag to compare optimized vs. non-optimized paths.X-Cache-Status: HIT headers.X-Performance-Warning headers to your APM (e.g., Datadog) to track slow queries or large payloads.How can I help you explore Laravel packages today?