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

Hashed Asset Bundle Laravel Package

incenteev/hashed-asset-bundle

incenteev/hashed-asset-bundle is a Symfony bundle for cache-busting static assets by generating and resolving hashed filenames. It helps serve versioned CSS, JavaScript, and images with long-lived browser caching while keeping templates clean and deployments predictable.

View on GitHub
Deep Wiki
Context7

Getting Started

The bundle slots into Symfony's Asset component as a VersionStrategyInterface implementation: instead of one global version string, every asset gets a version derived from the hash of its file contents. asset('css/app.css') becomes css/app.css?v=9f2c… and the query string changes only when the file changes.

Minimal setup:

composer require incenteev/hashed-asset-bundle

Enable the bundle (Symfony 4+/Flex):

// config/bundles.php
return [
    // ...
    Incenteev\HashedAssetBundle\IncenteevHashedAssetBundle::class => ['all' => true],
];

Configure the strategy options (algorithm is the main knob; the bundle also exposes format/length options — read DependencyInjection/Configuration.php in the vendor dir for the authoritative list):

# config/packages/incenteev_hashed_asset.yaml
incenteev_hashed_asset:
    algorithm: sha1   # md5, sha1, xxh128, etc.

Wire it as the version strategy. The bundle registers a version-strategy service; reference that service id (confirm with bin/console debug:container incenteev — it is typically incenteev_hashed_asset.version_strategy):

# config/packages/framework.yaml
framework:
    assets:
        version_strategy: incenteev_hashed_asset.version_strategy

First use case: render {{ asset('css/app.css') }}, confirm the ?v=<hash> suffix, edit the file, reload, and confirm the hash changed. If it did, everything else is a matter of scoping (packages) and deployment.

Where to look first:

  1. The README for current option names and the exact service id.
  2. DependencyInjection/Configuration.php — the real API surface.
  3. The version strategy class itself (small, single responsibility) — it shows how the file path is resolved from the asset path, which is the source of most setup pain.

Implementation Patterns

Global default strategy. Set framework.assets.version_strategy once and every asset() call in the default package is hashed. This is the right default for a small app with a public/ (or web/) directory of hand-managed CSS/JS/images.

Per-package strategies. The strategy is a package-level concern, so use named packages to keep concerns separate:

framework:
    assets:
        version_strategy: incenteev_hashed_asset.version_strategy
        packages:
            encore:            # Webpack Encore output — leave to the manifest strategy
                json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
            vendor:
                base_path: '/vendor'
                version_strategy: incenteev_hashed_asset.version_strategy

Then in Twig: {{ asset('js/app.js', 'encore') }} vs {{ asset('css/app.css') }}. Don't route Encore output through this bundle; Encore already versions filenames via its manifest.

Hashing compiled assets. The hash is of the file on disk after install. If you compile Sass/JS, compile first, then bin/console assets:install --symlink (or copy), then let the strategy read the installed file. In CI, the order is: build → install → deploy → warm cache.

Query-string format. If you want ?h= instead of ?v=, set the bundle's format option (placeholders are %s; escape as %%s?%%s in Symfony YAML). Keep in mind this bundle only appends a version — it does not rewrite filenames to app.abc123.css. If you need filename-based versioning, use a manifest strategy instead.

Absolute URLs and CDNs. Versioning happens before absolute_url(), so absolute_url(asset('img/x.png')) is safe. Hash is computed from the local file; the URL host comes from base_urls. As long as the local file exists and matches what the CDN serves, this works with a CDN.

Testing. Assert output shape with a regex (/\.css\?v=[0-9a-f]+$/), and unit-test the strategy directly against a temp file if you extend it. Ensure assets are installed in the test environment's web dir in CI; otherwise hashing fails.

Extension points. The strategy is a plain service: decorate it (decorates: incenteev_hashed_asset.version_strategy) to add APCu/Redis memoization, logging, or per-extension behavior (e.g., hash only .css, .js, images). Alternatively, implement VersionStrategyInterface yourself for manifest lookups or filename rewriting.

Gotchas and Tips

  • Path resolution is the #1 failure. The strategy needs the physical file to hash it. On Symfony 4+/5+ the web root is public/, on Symfony 2/3 it's web/. If the bundle's lookup path doesn't match your layout, hashing fails or silently skips. Check the config option for the web/base dir and point it at %kernel.project_dir%/public.
  • Missing files at runtime. Verify whether the strategy throws or falls back when a file is missing (behavior has changed across versions). A single missing asset can 500 a page in production; add a smoke test that renders your main layout in prod.
  • Don't set version and version_strategy together. Symfony throws a LogicException. Package-level version creates a static strategy and overrides whatever the default is.
  • Performance. Hashing reads the file on each asset() call unless the strategy memoizes. Small asset counts are fine; large pages with dozens of assets add file I/O. Realpath/OPcache caches help with stat calls but not with content hashing. If it matters, decorate the strategy with a cache keyed on path + mtime.
  • CSS url() references are not rewritten by the Asset component at all. Query-string versioning of app.css does not bust images referenced inside it — those keep their own URLs. Reference bustable images through Twig, or move to a manifest strategy.
  • CDN/proxy cache keys. Some CDNs ignore query strings by default (CloudFront historically). If the CDN doesn't include the query string in the cache key, cache-busting silently does nothing. Verify with curl -I against the CDN edge.
  • Rolling deploys. Query-string versioning is safer than filename versioning here because the path is stable, but you can still serve new HTML referencing a hash whose file hasn't been installed on that node yet. Always run assets:install before traffic shifts.
  • hash_length trade-off. Truncated hashes are fine for cache-busting but increase collision risk. Anything ≥ 8 hex chars is practically safe; don't go to 4.
  • Symlink installs. assets:install --symlink works fine as long as the symlink resolves and the file is readable by the PHP process (permissions in containers are a common trap).
  • Debugging. bin/console debug:container incenteev to confirm the service id and tags; bin/console debug:config incenteev_hashed_asset if the bundle supports config dumping; clear var/cache after config changes; view-source (not the network tab, which may cache) to confirm the query string actually changes.
  • Symfony version constraints. It's a small bundle with a narrow purpose; check its composer.json constraints before a major Symfony upgrade. If it lags, the strategy class is small enough to copy into your app as a custom VersionStrategyInterface implementation.
  • Environment asymmetry. A strategy that depends on the request or on files present only in prod will behave differently in dev/test. Keep the file lookup purely config-driven so all environments agree.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
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