juanmiguelbesada/amp-bundle
AMP Bundle for Symfony adds support for building Accelerated Mobile Pages, providing Twig helpers and template utilities to generate valid AMP HTML more easily.
This package is a middleware-driven HTML/CSS minifier for Laravel responses. You install it with Composer, publish its config, and register the middleware on the routes whose HTML you want to optimize.
composer require renatomarinho/laravel-page-speed
php artisan vendor:publish --provider="RenatoMarinho\LaravelPageSpeed\ServiceProvider"
Look first at:
config/page-speed.php — this is the control panel. It contains the enable/skip route patterns and the ordered filters array.RenatoMarinho\LaravelPageSpeed\Middleware\ — each filter is a small class with a applyFilter() method.app/Http/Kernel.php (or bootstrap/app.php on Laravel 11+) — where the middleware is registered globally or on a group.Register the middleware after the response has been generated (i.e. near the end of the global stack) so it sees the final HTML:
// Laravel 10 and below: app/Http/Kernel.php
protected $middleware = [
// ...
\RenatoMarinho\LaravelPageSpeed\Middleware\PageSpeed::class,
];
The first practical use case is enabling whitespace collapsing and comment removal on public web routes while leaving admin, API, and debug routes untouched. In v1.1.0 the new MinifyCss filter is available for the specific case where you inline critical CSS into a <style> block or use per-page custom CSS and want it minified before the response leaves the application.
Start narrow, then widen. Enable the middleware only on a route group first:
Route::middleware(['web', \RenatoMarinho\LaravelPageSpeed\Middleware\PageSpeed::class])
->group(function () {
Route::get('/', HomeController::class);
});
Configure filters explicitly. The filters array is ordered; earlier filters run first. A typical public-site configuration:
'filters' => [
\RenatoMarinho\LaravelPageSpeed\Middleware\RemoveComments::class,
\RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class,
\RenatoMarinho\LaravelPageSpeed\Middleware\RemoveQuotes::class,
\RenatoMarinho\LaravelPageSpeed\Middleware\MinifyCss::class, // v1.1.0
],
Put MinifyCss after comment removal but before whitespace collapsing if you want the smallest final payload; the CSS filter only rewrites the contents of <style> blocks, so the order relative to HTML filters is mostly about readability of the intermediate output.
Use skip patterns for anything dynamic. The package’s skip config accepts regex patterns and language lists. Always skip:
/(_debugbar|telescope|horizon)//api/.*/'skip' => [
'regexp' => '/(_debugbar|telescope|api)/',
],
Wrap it around the whole web group, not individual controllers. Day-to-day this means one registration, and route-level opt-out via the skip regex or a dedicated middleware group. Avoid adding the middleware in each controller — it becomes invisible and easy to double-apply.
Test the output, not the middleware. In feature tests, assert on the response body:
$response = $this->get('/');
$response->assertOk();
$this->assertStringNotContainsString('<!--', $response->getContent());
For the new CSS filter, add a fixture page with a <style> block containing comments and redundant whitespace, then assert the minified form:
$this->assertStringContainsString('.btn{color:red}', $response->getContent());
Integrate with cache warming. If you use response caching (spatie/laravel-responsecache, Cloudflare, etc.), minification happens before the cache stores the response only if the middleware order is right. Register PageSpeed before the cache middleware writes, or accept that cached responses skip minification. Verify with curl -I and a second request.
Extend with a custom filter. Each filter is a small class; create one that extends the package’s base middleware and implements the transformation you need:
namespace App\Http\Middleware;
use RenatoMarinho\LaravelPageSpeed\Middleware\PageSpeed;
class StripDataAttributes extends PageSpeed
{
public function applyFilter($buffer)
{
return preg_replace('/\sdata-tracking="[^"]*"/', '', $buffer);
}
}
Then append it to the filters array. This is the intended extension point and avoids forking the package.
Middleware ordering is the most common failure. If PageSpeed runs before the response body is fully built (e.g. before SubstituteBindings or before a response macro), it will minify an empty or partial buffer. Register it late in the global stack, and if you use web group middleware, confirm it runs after session and cookie middleware.
MinifyCss is not a general CSS pipeline. It minifies inline <style> blocks; it does not fetch, bundle, or minify linked stylesheets, and it will not process CSS injected later by JavaScript. For asset-pipeline minification use Vite/Mix. If you rely on CSS custom properties, calc(), or content: "..." strings, test carefully — naive regex minifiers can break whitespace-significant values. Keep a fixture with calc(100% - 2rem) and content: "a b" in your test suite.
Whitespace collapsing can break preformatted content and framework hydration. <pre>, <textarea>, and inline <script> templates are the usual casualties. If you use Alpine, Livewire, or Vue with in-DOM templates, either skip those routes or ensure the collapse filter preserves <pre>/<textarea> (check the filter source; if not, exclude the route).
Debugbar and Telescope will fight you. Both inject markup after the response is generated. Always keep them in the skip regex, and remember the regex is applied to the request path, not the route name.
Config caching hides changes. After editing config/page-speed.php, run php artisan config:clear (and config:cache in production). A stale config cache is the usual reason a newly added MinifyCss filter “does nothing.”
Double minification is wasteful but not fatal. If you also run a global HTML minifier or a CDN that minifies, PageSpeed’s work is redundant. Pick one layer. If PageSpeed is the chosen layer, disable the CDN’s auto-minify to keep output deterministic.
Debug by bisecting the filters array. When a page renders incorrectly, comment out filters one at a time rather than disabling the whole middleware. The output diff will point to the offending filter quickly.
Check Content-Type before transforming. The middleware should only operate on text/html responses. If you see JSON or file downloads corrupted, your skip regex is too broad or the middleware is registered globally without a content-type guard. Add a route-level exclusion rather than modifying vendor code.
v1.1.0 is additive. The MinifyCss filter is opt-in via the filters array, so existing installations are unaffected. The only action needed to adopt it is adding the middleware class to your config and clearing the config cache.
How can I help you explore Laravel packages today?