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 Cache Busting Worker Bundle Laravel Package

jeroenvdheuve/assetic-cache-busting-worker-bundle

Symfony bundle that adds an Assetic worker appending cache-busting query strings to asset URLs, so updated CSS, JS, and images are served fresh without stale browser caches. Integrates with Assetic's worker pipeline for automatic asset versioning.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: this is a Symfony bundle, not a Laravel package. It registers a worker into Symfony's AsseticBundle asset pipeline so that dumped asset filenames get a content hash (e.g. app-a1b2c3d4.css). There is no service provider, no facade, no config file in config/, and Assetic itself has been effectively abandoned since Symfony 3.x. With 2 stars, 0 dependents, nothing of note since March 2016, and the repo archived, treat this as a reference implementation of an idea, not a dependency.

What the latest release changed (v1.0.3), and why it doesn't change the verdict: the only addition is a documentation suggestion to enable Assetic's cached worker so a single asset that appears in multiple Twig templates isn't recompiled once per template. It is a performance tip for a build step, not a new API, not a Laravel affordance, and not a fix to the abandoned dependency chain. If you are not maintaining a legacy Symfony app, nothing in v1.0.3 is relevant to you.

What to look at first (5 minutes, not an afternoon):

  1. composer.json — note the symfony/* and assetic/* requirements and the PHP constraint. This tells you immediately whether it can even resolve in a modern Laravel app.
  2. DependencyInjection/*Extension.php and Resources/config/services.* — this is the entire package. It wires one worker service into the Assetic factory.
  3. README.md — one config snippet showing how the worker is enabled, plus (as of v1.0.3) the note about the cached worker.

First use case (the one you should actually copy): content-hashed filenames so you can serve Cache-Control: immutable for a year.

If you are maintaining a legacy Symfony app:

composer require jeroenvdheuvel/assetic-cache-busting-worker-bundle
// app/AppKernel.php
$bundles = [
    // ...
    new JeroenVdHeuvel\AsseticCacheBustingWorkerBundle\AsseticCacheBustingWorkerBundle(),
];

Then dump assets (php app/console assetic:dump --env=prod) and reference them through Twig's {% stylesheets %} / {% javascripts %} tags — the asset_url variable picks up the hashed name automatically.

If you are on Laravel, do not install it. Install nothing and instead reach for the tool you already have:

{{-- resources/views/layout.blade.php --}}
<link rel="stylesheet" href="{{ Vite::asset('resources/css/app.css') }}">

Vite/Mix already produce a manifest.json with content hashes — and Vite's build is already incremental, so you get the v1.0.3 "don't recompile the same asset twice" benefit for free. That is the 2016 bundle's entire value proposition, and you get it without the dependency.

Implementation Patterns

Pattern 1 — Symfony/Assetic worker (legacy maintenance only)

The worker runs at dump time, not at request time. The shape is:

# app/config/config.yml
assetic:
    # confirm in the bundle's DI extension whether the worker is
    # auto-registered or must be named here for your version
    workers:
        cache_busting: ~
{% stylesheets 'css/app.css' filter='cssrewrite' output='css/*.css' %}
    <link rel="stylesheet" href="{{ asset_url }}">
{% endstylesheets %}

asset_url becomes /css/app-<hash>.css after assetic:dump. The hash is derived from file contents, so unchanged files keep their name across deploys and stay warm in caches.

v1.0.3 addition — the cached worker. If the same stylesheet or script is pulled into several Twig templates (a shared base.html.twig plus a partial, say), Assetic will compile it once per template unless you enable its cached worker, which memoises compiled output so repeated references are cheap. Enable it alongside the cache-busting worker in the same assetic: block. Read the DI extension to confirm the exact key for your Assetic version — the release notes describe the intent, not a config schema, and the bundle itself ships no new service for it. The trade-off is real: a memoised compile means a filter/config change can keep serving the previous bytes under the previous hash, so flush the cache as part of any deploy where you touch assetic: settings (see Gotchas).

Pattern 2 — Reproduce the behaviour in Laravel with a manifest (recommended)

This is the day-to-day pattern you should actually own. A build command hashes files and writes a manifest; a helper resolves names at render time.

// app/Console/Commands/BuildAssets.php
public function handle(): int
{
    $manifest = [];

    foreach (File::allFiles(public_path('assets')) as $file) {
        $relative = str_replace(public_path().'/', '', $file->getPathname());
        $hash     = substr(hash_file('xxh128', $file->getPathname()), 0, 8);

        $hashed = preg_replace(
            '/\.([^.]+)$/',
            "-{$hash}.\$1",
            $relative
        );

        File::ensureDirectoryExists(dirname(public_path($hashed)));
        File::copy($file->getPathname(), public_path($hashed));

        $manifest[$relative] = $hashed;
    }

    File::put(public_path('build/manifest.json'), json_encode($manifest, JSON_PRETTY_PRINT));

    return self::SUCCESS;
}
// app/Support/helpers.php
function hashed_asset(string $path): string
{
    static $manifest = null;

    $manifest ??= json_decode(
        @file_get_contents(public_path('build/manifest.json')) ?: '{}',
        true
    );

    return asset($manifest[$path] ?? $path);
}
<link rel="stylesheet" href="{{ hashed_asset('assets/css/app.css') }}">
<script src="{{ hashed_asset('assets/js/app.js') }}" defer></script>

This is ~30 lines, has no dependency risk, and mirrors the bundle's semantics exactly (hash-on-content, resolve-by-manifest). Because it hashes each file once in a single pass, it is already immune to the duplicate-compile problem v1.0.3 is trying to paper over.

Pattern 3 — Long-lived cache headers + CDN publish

The whole point of the hash is to make the caching aggressive. Pair it with:

location ~* \.(css|js|png|jpg|jpeg|svg|woff2)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

And in your deploy pipeline, upload the hashed files to S3/CloudFront and keep only the manifest plus unhashed HTML in origin. Because the filename changes on content change, you never need to purge — you just deploy a new manifest.

Integration tips

Concern Practical approach
Blade/API consistency One helper, resolved from the same manifest, used in Blade and in any JSON API that returns asset URLs.
CI Run the hash step as a post-autoload-dump script so local and prod never diverge.
Rollbacks Keep the previous manifest alongside the previous release directory; hashed files are additive, so rollback is a symlink swap.
Dev vs prod In local, skip hashing entirely and serve source paths — hashes just make stack traces harder to read.
Testing Assert the manifest contains every key your views reference; a missing key silently falls back to an unhashed (404ing) path.
Duplicate compiles (the v1.0.3 concern) Build once, resolve everywhere. A single manifest written by one command is the Laravel-native fix; you should never be compiling the same source per view.

Gotchas and Tips

  • It will install into a Laravel app and do absolutely nothing. Symfony components resolve fine under Composer, but the bundle's Bundle class is only instantiated by a Symfony kernel. There is no Illuminate\Support\ServiceProvider, so Laravel's container never sees it. Any time spent trying to bootstrap it is wasted.
  • v1.0.3 is a docs suggestion, not a feature. "Assetic cached worker suggestion added" means the README grew a tip. Do not read a version bump as renewed maintenance — the archive flag, the 2016-era code, and the dead upstream all still apply.
  • Assetic is dead upstream. symfony/assetic-bundle was deprecated in Symfony 3.0 and removed as a recommendation in 4.0; Symfony's own answer is Webpack Encore, and Laravel's is Vite. Depending on this package in 2024+ means pinning a chain of abandoned packages.
  • Enable the cached worker and you inherit a stale-output failure mode. Memoised compiles key off Assetic's cache, which is not keyed on your filter configuration. Change a minifier, an import path, or a cssrewrite setting and the previously compiled artifact can be served back with a matching (now wrong) content hash. Flush the Assetic cache in the same deploy step that changes assetic: config — the bundle does not do this for you.
  • No releases of substance since 2016 and archived. Expect PHP 7.x-era code, possible each()/create_function style deprecations, and zero security response. If you must run it, vendor it or fork it; do not rely on Packagist availability long-term.
  • The hash only changes with content, not with config. Change a filter, an import path, or a minifier setting and the filename can stay identical while the bytes change. Always bust cache manually (or bump a build number) when tooling changes, not just source files. The v1.0.3 caching tip makes this failure more likely, not less.
  • Dump-time only. In dev, the worker doesn't run, so asset_url looks different from prod. Bugs of the "works locally, 404s in prod" variety almost always come from a view hardcoding an unhashed path that only exists in the dev pipeline.
  • Manifest and files must ship together. The single most common production failure in any hash-on-content scheme is a stale manifest.json pointing at a file that wasn't uploaded (or vice versa). Validate in the deploy step: every manifest value must exist on disk.
  • Hashing the query string is not the same thing. Appending ?v=abc123 (Laravel's mix()/Vite style for older versions, or a naive asset().'?v='.$hash) works, but some CDNs and proxies strip query strings for caching. Filename hashing — what this bundle does — is strictly more robust.
  • Extension points are thin. If you're forking, the seam is a single Assetic factory worker: decorate the factory or register your own worker to change how names are composed. There's no Laravel-side extension point at all — your seam is your own build command and helper.
  • Naming inconsistency in the wild. The repo path in listings is sometimes spelled jeroenvdheuve/ and sometimes jeroenvdheuvel/; check the actual name field in composer.json before require-ing, or you'll chase a phantom package-not-found.
  • Bottom line for a Laravel developer: score 0.1 and 2 stars are accurate, and v1.0.3 does not move them. Skim it once to understand content-hash cache busting (and, now, why you never want to compile the same asset twice), then use Vite's manifest or the ~30-line helper above. Do not add this to composer.json.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast