websharks/css-minifier
A PHP CSS minifier that strips whitespace, comments, and redundant syntax to shrink stylesheets for faster page loads. Simple API for minifying CSS strings or files, usable in Laravel or any standalone PHP project.
Install it like any Composer package and confirm what actually landed in vendor/:
composer require websharks/css-minifier
composer show websharks/css-minifier # verify version + source
Before writing code, look at three things in this order:
vendor/websharks/css-minifier/composer.json — check the PHP constraint (^5.x-era constraints are common here) and the autoload map. Old WebSharks packages sometimes ship a classmap rather than PSR-4.vendor/websharks/css-minifier/src/Core.php — this is the entire minifier. Read the constructor defaults and the public method signature before trusting any snippet (including the README). The class is namespaced WebSharks\CssMinifier\Core; the entry point is a single minify()/compress()-style string-in/string-out method./*! ... */) and any options array.The first real-world use case is a build-time pass, not a request-time one: take your compiled public/css/app.css, run it through the minifier, and write public/css/app.min.css. That gives you a working baseline and a fixture you can diff against. Only move to on-the-fly minification once you have a cache in front of it.
A minimal smoke test to prove the install works:
use WebSharks\CssMinifier\Core;
$css = '.a { color: #ffffff; margin: 0px 0px 0px 0px; }';
echo (new Core())->minify($css);
// .a{color:#fff;margin:0}
If that doesn't run, stop and resolve the autoload/PHP-version issue before building anything else on top of it.
Licensing check first, not last. This is GPL-3.0. Server-side use in a SaaS is generally fine, but if you distribute the application (sold product, Docker image with vendor/ baked in, appliance), the copyleft obligations become a real review item. Decide this before the package is woven into your asset pipeline.
Wrap it in an application service. Never call new Core() from controllers — you want one place to swap in matthiasmullie/minify (MIT) later if the licensing or PHP-8 behavior forces your hand.
namespace App\Support;
use WebSharks\CssMinifier\Core;
class CssMinifier
{
public function __construct(private Core $core = new Core()) {}
public function minify(string $css): string
{
if (trim($css) === '') {
return '';
}
// Trim BOM / normalize line endings before minifying.
$css = ltrim($css, "\xEF\xBB\xBF");
$css = str_replace(["\r\n", "\r"], "\n", $css);
return $this->core->minify($css);
}
}
// AppServiceProvider::register()
$this->app->singleton(\App\Support\CssMinifier::class);
Artisan command as the primary workflow. This is where the package earns its keep day-to-day — a deterministic step you can run in CI and in your deploy script.
protected $signature = 'css:minify {--in=public/css} {--out=public/build}';
public function handle(CssMinifier $minifier): int
{
foreach (File::glob($this->option('in').'/*.css') as $file) {
if (str_ends_with($file, '.min.css')) {
continue;
}
$min = $minifier->minify(File::get($file));
File::put(
$this->option('out').'/'.basename($file, '.css').'.min.css',
$min
);
}
return self::SUCCESS;
}
Run it after Mix/Vite emits assets, then fingerprint the output for cache-busting (app.min.{hash}.css).
Cache aggressively if you minify at runtime. A middleware or Blade helper that minifies on every request is a latency bug waiting to happen. Key the cache on file mtime + size, not just path:
$key = 'css.min.'.sha1($path.filemtime($path).filesize($path));
$css = Cache::remember($key, now()->addDay(), fn () => $minifier->minify(File::get($path)));
Use it for a small critical-CSS block inlined in the layout, where the source lives in the repo and changes only on deploy — not for arbitrary per-user CSS.
Don't double-minify with HTML Compressor. If you already run websharks/html-compressor, it invokes this minifier internally when CSS compression is enabled. Pick one layer; stacking them costs CPU and makes output diffs confusing.
Pin the version and add a fixture test. Snapshot one representative stylesheet (media queries, calc(), custom properties, a data-URI, a font shorthand) into tests/fixtures/ and assert both that output shrinks and that known-fragile constructs survive verbatim. This is your regression net for PHP upgrades, since the package itself will not give you one.
${var} string interpolation, each()-era patterns). Run your fixture test with error_reporting(E_ALL) before rolling out; don't discover it in production logs.calc(100% - 10px) (spaces around - are semantically required), data: URIs containing ;/base64,, content: "\2014" escapes, custom properties (--gap: 0 1rem) and @supports/@media preambles are the classic breakage points. Assert each one in your fixture; if any fail, restrict the minifier to stylesheets you control or post-process the output.@charset and BOM. Strip the BOM yourself (see the wrapper) and verify @charset handling — most minifiers hoist or drop it, and if your CSS is served with a non-UTF-8 header you'll get mojibake in content strings.</style> boundary. Inlining minified output with {!! !!} in Blade is fine for repo-owned CSS, but never feed user-controlled content through it into a <style> block without escaping </style>.App\Support\CssMinifier is the extension point.repositories with a VCS entry in composer.json) — but seriously evaluate matthiasmullie/minify (MIT, maintained) or tubalmartin/cssmin side-by-side first. This package's main justification for existing is that HTML Compressor depends on it; if you're not using HTML Compressor, that justification is weak.How can I help you explore Laravel packages today?