ju1ius/webpack-assets-bundle
Symfony bundle that integrates Webpack-built assets into your templates. It reads the Webpack manifest and exposes Twig helpers for rendering versioned JavaScript and CSS tags, making it easy to reference compiled entrypoints and chunks in development and production.
composer require ju1ius/webpack-assets-bundle
app/AppKernel.php:
$bundles = [
// ...
new Ju1ius\WebpackAssetsBundle\Ju1iusWebpackAssetsBundle(),
];
stats.json or manifest) so Symfony can resolve hashed filenames:
webpack --json > web/assets/stats.json
In watch/dev mode, either regenerate this file or point the bundle at the webpack-dev-server.app/config/config.yml. Start by reading the bundle README and DependencyInjection/Configuration.php for the exact keys in your version; expect settings for:
<script src="{{ webpack_asset('app.js') }}"></script>
The helper resolves the logical entry name through the manifest and returns the hashed public URL.Where to look first:
README.md for the supported webpack version and config shape.DependencyInjection/Configuration.php for available options.Twig/) for the exact function names and signatures.Twig-first asset resolution. The normal day-to-day pattern is to treat webpack entry points as logical names in templates and let the bundle resolve them to versioned filenames. Keep templates free of /build/... paths:
<link rel="stylesheet" href="{{ webpack_asset('styles/app.css') }}">
<script src="{{ webpack_asset('scripts/app.js') }}"></script>
Centralize build output. Configure webpack to write into a single public directory (e.g. web/build/) and set the bundle's manifest path to the generated stats file. This keeps Symfony's document root clean and makes it obvious what is generated vs. checked in.
Separate dev and prod behavior. The usual workflow is:
webpack-dev-server and configure the bundle to serve assets from it, so hot reload works and Symfony doesn't need a rebuild on every template change.Inject the asset service outside Twig. For controllers, console commands, or email templates, inject the bundle's asset-resolving service rather than calling Twig. This lets you reuse the same manifest lookup logic in non-HTML contexts (e.g. generating absolute URLs for transactional emails).
Treat entry points as your contract. Define a small, stable set of webpack entry names (app, admin, vendor) and reference those names everywhere. Avoid referencing individual chunk files directly; chunk names and hashes are implementation details.
Build pipeline integration. Wire the manifest generation into your deploy script, CI, or a Composer post-install hook. The bundle only reads the manifest — it does not run webpack — so a missing build step is a runtime failure waiting to happen.
Cache busting comes for free. Because the manifest maps logical names to hashed filenames, HTTP caching can be aggressive for the build directory. Set long Cache-Control headers on /build/* and let the hashed filenames handle invalidation.
manifest.json via webpack-manifest-plugin and verify the bundle can read it, or add a small adapter.dev can fail in prod if the path is resolved differently after cache warmup. Use an absolute path parameter where possible.webpack_asset() in CI.localhost:8000 and webpack-dev-server from localhost:8080, asset URLs must be absolute and the dev server must allow cross-origin requests. Check the configured public host, not just the port.config_dev.yml and manifest-based settings in config_prod.yml; a mis-merged config can ship dev-server URLs to production.json_decode(file_get_contents($path), true)) and compare entry names with what your Twig templates request. Most "asset not found" issues are a name mismatch or a manifest generated before the latest build.integrity attributes or CDN-aware URL rewriting, plan to add a small Twig extension or service decorator on top.composer.json and document the fork/commit you rely on, so a future composer update doesn't silently change behavior.How can I help you explore Laravel packages today?