wa72/html-pretty-min
wa72/html-pretty-min is a PHP library for minifying and pretty-printing HTML. It removes unnecessary whitespace to compress markup and can reformat HTML for readable output, helping optimize templates and generated pages.
Minimal setup:
composer require wa72/html-pretty-min
Ensure PHP has ext-dom enabled. The package is a small DOM-based library, not a Laravel service provider, so there is no config to publish.
Look first at:
src/HtmlMinifier.php and src/HtmlIndenter.php for available methods and defaults.First use case: minify rendered HTML in a response middleware.
use Wa72\HtmlPrettyMin\HtmlMinifier;
$minifier = new HtmlMinifier();
$html = $minifier->minify($response->getContent());
$response->setContent($html);
A good second use case is an Artisan command or test helper that indents generated HTML so failures are readable:
use Wa72\HtmlPrettyMin\HtmlIndenter;
$indenter = new HtmlIndenter();
file_put_contents('debug.html', $indenter->indent($html));
Treat it as a low-level HTML string utility. Wrap it in your own Laravel service or middleware rather than scattering direct instantiation through controllers.
Response middleware for production minification
Only process real HTML responses:
if (! str_contains($response->headers->get('Content-Type', ''), 'text/html')) {
return $response;
}
if ($response->getContent() === false) {
return $response;
}
Skip streamed, binary, and already-compressed responses. After replacing content, remove or recalculate Content-Length and avoid stale ETag values.
Cache minified output
DOM parsing is not free. For static pages, cache the minified HTML keyed by content hash, route, locale, or deployment version:
$key = 'html-min:' . sha1($html);
$minified = Cache::rememberForever($key, fn () => $minifier->minify($html));
This is especially useful if you minify CMS pages, generated documentation, or email templates repeatedly.
Indent for debugging and tests
Use the indenter in local tooling, snapshot tests, or an Artisan command such as html:pretty storage/debug/response.html. Do not indent production responses unless you explicitly want readable HTML and accept the size increase.
Pipeline: inspect, then minify
A practical workflow is:
Fragment handling wrapper
If you are minifying a partial rather than a full document, account for DOMDocument wrapping fragments in <html><body>. A safe pattern is to minify a full document or extract the body content after processing, depending on what the package returns for your input.
Laravel integration shape
Keep the package behind a small wrapper:
final class HtmlFormatter
{
public function minify(string $html): string
{
return (new HtmlMinifier())->minify($html);
}
public function indent(string $html): string
{
return (new HtmlIndenter())->indent($html);
}
}
This gives you one place to change options, add feature flags, or replace the package later.
It is DOM-based, not an HTML5 parser
DOMDocument is not a full HTML5 parser. Modern markup such as custom elements, <template>, SVG, MathML, and unusual nesting can be normalized, moved, or dropped. Test real templates, especially component-heavy Blade output.
Whitespace between inline elements matters
Removing whitespace can change rendering:
<span>Hello</span> <span>world</span>
Minification may collapse the space and produce Helloworld. Be careful with inline elements, buttons, links, and content where whitespace is semantically meaningful.
Check preserved-content behavior
Verify how your version handles <pre>, <textarea>, <script>, <style>, and inline event handlers. These are common breakage points for minifiers. Add regression tests using representative templates.
Comments can be functional
Removing comments is usually desirable, but comments are sometimes used by frameworks, build tools, conditional comments, or template engines. Confirm the default behavior and disable comment removal if needed.
Encoding and doctype quirks
Ensure input is UTF-8 and includes a proper doctype/meta charset. DOMDocument can behave differently with missing encoding declarations, XML prologs, and malformed markup. Test non-ASCII content such as accented characters, emoji, and RTL text.
Full document vs fragment output
DOMDocument tends to create a full document structure even for fragments. If you pass a partial, you may get <html> and <body> wrappers back. Decide explicitly whether you want full-document output or body extraction.
Option API names vary by version
Do not assume a Laravel-style config array. Check the README and source for the exact methods, such as setters or constructor options, before wiring them into middleware. Pin the package version if behavior matters.
Minification is not idempotent by assumption
Run it twice in a test. Double-processing can expose wrapper insertion, comment handling, or whitespace edge cases.
Performance and memory
Every request parses and rebuilds the DOM. For large HTML documents or high-traffic pages, benchmark before enabling globally. Cache aggressively or minify at build/deploy time where possible.
Response headers and debugging
After modifying response content, remove stale Content-Length and ETag headers. During rollout, log the before/after byte sizes and keep a sample of original HTML so you can compare when something renders incorrectly.
Extension point: wrap, don’t fork
Because the package is small and has few dependents, avoid modifying vendor code. Put option choices, skip rules, and fragment handling in your own service or middleware. That also makes it easy to swap in a different minifier if HTML5 parsing becomes necessary.
How can I help you explore Laravel packages today?