hostnet/webpack-bundle
A Symfony bundle that integrates Webpack and Webpack Encore into your PHP application, providing asset manifest versioning, dev-server support, and Twig helpers for including compiled JavaScript and CSS assets in templates.
First, the reality check — now official. The 2.0.8 release is not a feature release; its entire changelog reads: "The webpack-bundle is abandoned. Use alternative solutions as described in the README.md." That upgrades the previous assessment's warning ("archived since 2020, zero dependents") into an explicit upstream abandonment notice. hostnet/webpack-bundle is a Symfony bundle, not a Laravel package: no service provider, no Blade directive, no Artisan command, no config/webpack.php to publish. For a Laravel codebase the day-to-day answer is do not install this — use first-party Vite (laravel/vite-plugin), or laravel-mix if you are pinned to webpack. The rest of this assessment covers (a) what to do if you inherit a Symfony app using it, and (b) how to translate its ideas into Laravel.
If you are in a Symfony app that already uses it:
composer require hostnet/webpack-bundle as a legacy-migration task, not a new dependency.composer.json — it targets Symfony 2.x/3.x-era APIs. Installing it into a Symfony 5/6 app will fail dependency resolution.AppKernel::registerBundles() on old Symfony, or config/bundles.php on Symfony 4+ (Hostnet\Bundle\WebpackBundle\WebpackBundle::class => ['all' => true]).npm install (or yarn) with webpack, webpack-cli, and your loaders (sass-loader, less-loader, css-loader, mini-css-extract-plugin).DependencyInjection/Configuration.php in the repo for the exact key names — typically webpack config path, node executable path, working directory, and output/public dir).bin/console list | grep -i webpack) to trigger a build, then reference compiled assets from Twig via the bundle's Twig extension.Where to look first, in order:
README.md — the only real documentation, and as of 2.0.8 the only actively maintained content: it now carries the abandonment banner plus the upstream-recommended alternatives. Read the alternatives section before anything else; it is the migration brief.DependencyInjection/Configuration.php — the authoritative list of config keys and defaults. This is where you learn what is actually configurable versus hard-coded.Resources/config/services.xml (or .yml) — shows the compiler service, Twig extension, and console commands registered.Best first use case: an older Symfony app still compiling LESS/SASS through Assetic or leafo/lessphp, where you want one webpack pipeline to handle less, sass, css, and JS with a content-hashed manifest. Prove it on a single stylesheet before migrating the whole web/ directory — but scope that work as a hop toward Symfony Webpack Encore, since the bundle itself is now end-of-life by upstream decree.
Build at deploy, never at request time. The bundle's command should run in your deploy script or CI step, producing static files into the public directory. Wire it as, e.g., bin/console <webpack build command> --env=prod in your release pipeline (Capistrano/Deployer/Envoyer-style). The runtime framework should only read the already-built manifest. Because the bundle is abandoned, keep the build invocation in your repo (a Makefile target or npm script) rather than relying on the bundle's command contract, so cutting the bundle over to Encore later is a one-line change.
Watch mode for local dev. Run the bundle's watch/dev command in a second terminal alongside bin/console server:run, or background it in your Procfile/docker-compose dev service. Do not try to make Symfony invoke webpack lazily per page load — you will introduce 5–10 second TTFB spikes and race conditions on parallel requests writing the same output files.
Manifest-based cache busting in Twig. The typical pattern is webpack emitting a manifest.json (via webpack-manifest-plugin) and the bundle's Twig helper resolving a logical name to the hashed filename:
<link rel="stylesheet" href="{{ webpack_asset('css/app.css') }}">
<script src="{{ webpack_asset('js/app.js') }}"></script>
Keep logical names stable (app.css) and let the hash change; never hard-code app.4f3a1c.css in templates.
Configuration as parameters. Push environment-specific values (node binary path, webpack config path, NODE_ENV) into Symfony parameters so dev and prod differ without code edits:
parameters:
node.binary: /usr/local/bin/node
webpack.config: '%kernel.project_dir%/webpack.config.js'
Docker/CI multi-stage pattern. Stage 1 (node image): npm ci && npx webpack --mode=production. Stage 2 (php image): copy public/build/ from stage 1. This sidesteps the bundle's node-path resolution entirely, which is where most failures happen — and it is exactly the shape you need post-migration, so nothing is wasted.
Laravel translation of the same patterns:
| Symfony bundle concept | Laravel equivalent |
|---|---|
Twig webpack_asset() |
@vite(['resources/css/app.css', 'resources/js/app.js']) |
manifest.json lookup |
public/build/manifest.json + Vite::asset() |
| Console build command | npm run build (vite build) |
| Watch command | npm run dev (vite dev server) |
| Deploy-time compile | npm ci && npm run build in your release script |
Use Vite::asset('resources/images/logo.png') in Blade when you need a hashed non-entry asset, and keep public/build out of git (it is a build artifact; regenerate in CI).
artisan webpack:build. Forcing it means manual Symfony\Component\Process calls and reimplementing the manifest reader — strictly worse than laravel-mix or Vite.PATH and no nvm shim. Symptom: "node: command not found" or an empty build with exit code 0. Fix by setting an absolute node path in config, or better, build in a node image and copy artifacts.output.path and publicPath must agree with where Symfony serves assets from. A correct build + 404s in the browser almost always means publicPath is wrong, not that the build failed.bin/console cache:clear --env=prod — otherwise you debug a config that is no longer loaded.npx webpack --config webpack.config.js --mode=production. Add -vvv to the console command to surface the child process output.www-data) needs write access to the output directory only during deploy, not at runtime. Restrict it: builds should be owned by the deploy user, read-only to the web user.npm audit and pin modern sass-loader/css-loader; the bundle does not care which loader version you use, only that webpack writes the expected manifest. This is also where an abandoned bundle hurts most: the JS half is your responsibility either way.public/build/manifest.json exist? → does the key in your template exactly match the manifest key? → does the file it points to exist on disk? → is publicPath correct? In that order, every time.How can I help you explore Laravel packages today?