Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Assetic Laravel Package

sanpi/assetic

Laravel integration for the Assetic asset management library. Define CSS/JS asset collections, apply filters such as LESS, Sass, CoffeeScript and minification, then dump and serve compiled, cached assets via Blade helpers for a simple PHP asset pipeline.

View on GitHub
Deep Wiki
Context7

Getting Started

Despite the package description's claims of Laravel view/helper integration, there is no service provider, facade, config publisher, or Blade directive. sanpi/assetic is a fork of kriswallsmith/assetic and is a plain Composer library. Everything in this guide is glue you write and own.

Install

composer require sanpi/assetic

Then immediately confirm it did not disturb the Symfony components Laravel already pins (this is the #1 failure mode):

composer why symfony/process
composer why symfony/filesystem
composer show sanpi/assetic

If Composer downgraded a Symfony component, stop and reconsider before writing any code — the whole integration rests on a resolvable dependency graph.

Where to look first (all under vendor/sanpi/assetic/)

  1. src/Assetic/Factory/AssetFactory.php — the object you will actually drive every day.
  2. src/Assetic/Filter/ — built-in filters (Less, Sass, CssMin, JSMin, UglifyJs2, CoffeeScript, etc.).
  3. src/Assetic/AssetWriter.php — writes compiled output to disk.
  4. src/Assetic/Factory/Worker/CacheBustingWorker.php — renames/rewrites output for versioning.
  5. src/Assetic/AssetManager.php / AssetCollection — the collection model.
  6. The fork's composer.json and changelog — its value over upstream is PSR-4/autoloading and updated PHP/Symfony constraints; the API is upstream-identical. If you know Assetic, you know this.

First use case — compile one stylesheet at build time

Assetic's mental model is load assets → apply filters in order → write combined output. A minimal container binding:

// app/Providers/AsseticServiceProvider.php
namespace App\Providers;

use Assetic\Factory\AssetFactory;
use Assetic\Filter\CssRewriteFilter;
use Assetic\Filter\CssMinFilter;
use Illuminate\Support\ServiceProvider;

class AsseticServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(AssetFactory::class, function () {
            $factory = new AssetFactory(public_path());
            $factory->setDebug(app()->environment('local'));

            return $factory;
        });
    }
}

Then a one-off compile in a command or test to prove the pipeline works before building config around it:

$factory = app(AssetFactory::class);
$collection = $factory->createAsset(
    ['css/app.css', 'css/theme.css'],
    [new CssRewriteFilter()],
    ['output' => 'css/all.css']
);

(new \Assetic\AssetWriter(public_path()))->writeAsset($collection);

That's the whole first milestone: two files combined into public/css/all.css with a filter applied, executed from the CLI, not from a controller.

Implementation Patterns

The reliable pattern is build-time compile + manifest contract + runtime lookup. The application never touches Assetic during a request.

1. Config-driven collections

Model each asset group as config, not code:

// config/assetic.php
return [
    'css' => [
        'app' => [
            'inputs'  => ['resources/css/app.css', 'resources/css/theme.css'],
            'filters' => ['cssrewrite', 'cssmin'],
            'output'  => 'build/app.css',
        ],
    ],
    'js' => [
        'app' => [
            'inputs'  => ['resources/js/vendor.js', 'resources/js/app.js'],
            'filters' => ['jsmin'],
            'output'  => 'build/app.js',
        ],
    ],
];

2. A filter registry in the service provider

Translate string filter names to Assetic filter instances once, so config stays declarative:

$filters = [
    'cssrewrite' => fn () => new \Assetic\Filter\CssRewriteFilter(),
    'cssmin'     => fn () => new \Assetic\Filter\CssMinFilter(),
    'jsmin'      => fn () => new \Assetic\Filter\JSMinFilter(),
];

Then loop config('assetic.*'), call $factory->createAsset($inputs, $resolvedFilters, ['output' => $output]), and hand each collection to the AssetWriter.

3. The dump step is a command, run in CI

Wrap the compile loop in php artisan assetic:dump. Run it in your deploy pipeline (composer install → php artisan assetic:dump → serve). Never invoke it from a route, middleware, or view — that couples request latency to disk I/O and external binaries.

4. Cache-busting via the CacheBustingWorker + manifest

Assetic's versioning renames files to app-<hash>.css and rewrites references. Because you cannot rely on @vite or asset() to know the new name, emit your own manifest at dump time:

$writer = new \Assetic\AssetWriter(public_path());
$worker = new \Assetic\Factory\Worker\CacheBustingWorker();
$factory->addWorker($worker);

// after writing, record logical name → hashed filename
$manifest = ['app.css' => 'build/app-48f1c2.css'];
file_put_contents(public_path('build/manifest.json'), json_encode($manifest));

5. Runtime lookup: a Blade helper, not the Assetic API

// app/Support/Asset.php
class Asset
{
    public static function url(string $logical): string
    {
        $manifest = json_decode(
            file_get_contents(public_path('build/manifest.json')), true
        );
        return asset($manifest[$logical] ?? $logical);
    }
}

Expose it as a Blade directive (@asseticUrl('app.css')). This is the "integration" the package description advertises and the package does not provide.

6. Environment-aware behavior

Use AssetFactory::setDebug(). In local, emit individual unminified files (faster iteration, readable output). In production, apply minifiers and the cache-busting worker. Drive this from app()->environment(), not from Assetic itself — it has no concept of Laravel environments.

7. Order of operations matters

Filters run left-to-right as configured. Preprocessors (less/sass) must precede minifiers (cssmin), and cssrewrite must run after any URL-relative rewriting. Encapsulate common chains as named presets in config so nobody hand-orders filters per collection.

Gotchas and Tips

  • Composer resolution is the most likely break. Laravel 10/11 pin Symfony 6/7; this fork's constraints may not reconcile. Test composer install on your exact PHP/Laravel versions before committing to the approach. If it fails, isolate Assetic in a dedicated build container and ship only public/build/ output.

  • No request-time execution — ever. If you find yourself calling AssetFactory inside a controller, you have misread the model. Runtime filtering ties availability to external binaries and degrades under concurrency.

  • Filter binaries drift silently. uglify-js, lessc, node-sass, ImageMagick — several are deprecated or removed from current base images. Verify every binary exists in your CI image and pin its version. A missing binary produces confusing exceptions deep in filter classes, not a clean "binary not found."

  • Silent stale assets. The worst failure mode: the dump step is skipped or the manifest diverges from disk, and users get old CSS with no error. Guard by running assetic:dump in the deploy script and asserting the manifest file exists and its entries resolve to real files in a post-deploy smoke check.

  • The CacheBustingWorker only helps if the manifest matches. It renames files; you must still persist the mapping yourself. Don't assume asset() will resolve hashed names.

  • setDebug() changes output shape, not just minification. In debug mode Assetic emits separate files; make sure your manifest helper handles both the debug and production case, or your local @asseticUrl calls will point at files that don't exist.

  • Over-bundling destroys caching. Combining every stylesheet into one file means a one-character change invalidates the whole bundle. Define bundle boundaries deliberately (vendor vs. app vs. per-page) rather than dumping all inputs into one collection.

  • No security response path. Zero stars, zero dependents, single maintainer over an EOL upstream means you own every transitive vulnerability. Pin an exact commit/version, vendor or fork internally if needed, and assign a named owner.

  • Extension point: custom filters. Implement Assetic\Filter\FilterInterface (filterLoad, filterDump) to wrap any tool Assetic lacks a built-in for. This is the only sanctioned extension surface — don't patch the library in vendor/.

  • Debugging the pipeline. There is almost no logging. When output is wrong, dump the resolved collection graph ($collection->all() to see inputs/filters) and inspect the public/build/ directory directly. Adding a temporary dd() on the filter list before AssetWriter::writeAsset() resolves most "filter didn't apply" cases.

  • Treat the whole thing as a time-boxed shim. For any greenfield Laravel work, skip this entirely and use Vite (laravel-vite-plugin + @vite). Adopt sanpi/assetic only to keep a pre-existing Assetic pipeline installable, behind a clean AsseticServiceProvider + manifest boundary, with a dated migration checkpoint.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings