zaininnari/html-minifier
A Laravel/PHP package for minifying HTML output by removing unnecessary whitespace, comments, and redundant markup. It helps reduce response size and improve delivery speed, with simple configuration for adding HTML compression to your application.
Install and confirm the entry point before writing any integration code — this package is small (61 stars, no linked repo metadata), so treat the source as the source of truth:
composer require zaininnari/html-minifier
Open vendor/zaininnari/html-minifier/src/ and the README first. The package is a PHP port of the Blink HTMLTokenizer used by html-minifier, so the public surface is typically a single minifier class with a minify(string $html): string-style method. Confirm the exact namespace and whether the call is static or instance-based before wiring it in.
The smallest viable use case is minifying already-rendered HTML, not Blade source:
use Zaininnari\HtmlMinifier\HtmlMinifier;
$html = view('welcome')->render();
$minified = (new HtmlMinifier())->minify($html);
return response($minified);
Do not point it at .blade.php files — it will happily strip whitespace inside @if blocks and break directive parsing. It operates on final output only.
First real use case: a response middleware that minifies text/html responses in production. That is the 90% path for Laravel apps and gets you the bandwidth win without touching views.
Response middleware (recommended default). Minify at the edge of the request lifecycle so every controller, package, and error page benefits without per-controller changes:
class MinifyHtml
{
public function handle($request, Closure $next)
{
$response = $next($request);
if (! app()->isProduction()) {
return $response;
}
if (! $response instanceof \Illuminate\Http\Response) {
return $response;
}
$contentType = $response->headers->get('Content-Type', '');
if (! str_contains($contentType, 'text/html')) {
return $response;
}
$content = (new HtmlMinifier())->minify($response->getContent());
$response->setContent($content);
return $response;
}
}
Register it globally but after session/CSRF middleware so you never minify a redirect body or a streamed response.
Response macro for opt-in minification. When global middleware feels too broad, expose an explicit macro and use it on heavy public pages only:
Response::macro('minifiedHtml', function (string $view, array $data = []) {
return response((new HtmlMinifier())->minify(view($view, $data)->render()));
});
Build-time / cache-time minification. Runtime minification costs CPU on every request. For mostly-static marketing pages, render once, minify once, cache the result in Redis or the filesystem keyed by a content hash, and serve the stored bytes. Invalidate on deploy or when a model changes.
Artisan command for static output. If you pre-render pages (Laravel's route:cache + a crawler, or an SSG step), add a command that walks public/ HTML or a storage/app/prerender/ directory and rewrites files. This keeps the runtime completely free of the minifier.
Config-driven toggles. If the package exposes options (comment removal, whitespace collapsing, attribute quoting), bind them in a config/html-minifier.php you publish or define yourself, and read them in a service provider. Wrap instantiation in a singleton or a small HtmlMinifierFactory so toggling options in one place changes behavior everywhere.
Testing pattern. Never assert exact byte output. Assert semantic equivalence instead: load original and minified into DOMDocument, normalize whitespace-only text nodes, and compare serialized trees. For CSS/JS-in-HTML, additionally assert the extracted <script> and <style> bodies are identical.
<span>s, <a>s, or <button>s collapses words together. If your design relied on newlines between inline elements as spacing, keep the original whitespace-sensitive regions out of the minifier or fix the CSS (display: inline-block + explicit gap).<pre>, <textarea>, <code>, <script>, <style> must be preserved verbatim. A tokenizer-based minifier can behave differently here than a full DOM parser. Test each of these explicitly — especially <textarea> where leading newlines are meaningful per the HTML spec.Content-Type and short-circuit for BinaryFileResponse, StreamedResponse, JSON, XML, and file downloads. Minifying a PDF or an SVG you serve as image/svg+xml will corrupt or bloat it.Content-Length and ETag. If you or a proxy set these upstream, they must be recalculated or dropped. Laravel's Response usually recalculates on setContent, but Symfony's HTTP cache and reverse proxies can keep stale values.x-data, x-text, @click payloads are inside attributes; attribute-value quoting changes can break them. Alpine tolerates whitespace but not stripped quotes around values containing spaces. Verify any custom directive-heavy page.<!--[if IE]>...<![endif]--> if you still support them; naive comment removal deletes the whole block.php -r writing both to files and diff -u, or serve a /__debug/minify route that returns the minified output plus the byte savings. Bisect by disabling the middleware for one route at a time.memory_limit and keep an eye on response time — benchmark with your heaviest template before enabling globally.NOASSERTION. Do not ship this into a commercial product without resolving the actual license from the repository or a Packagist metadata check. Treat it as unlicensed until proven otherwise.composer.json and consider vendoring or wrapping the minifier behind your own interface so you can swap in voku/html-min or matthiasmullie/minify without touching call sites.HtmlMinifierService wrapping the package) rather than subclassing. If you need behavior like preserving specific markers (<!--MINIFIER:OFF-->), regex-strip those regions before minifying, minify the rest, then restore — do not try to configure it if the package doesn't support it.app()->isProduction() or an explicit env flag.How can I help you explore Laravel packages today?