kunstmaan/live-reload-bundle
Symfony bundle that adds automatic live reload to development: it watches templates, assets and config, then refreshes the browser when files change, so updates appear instantly without manual reloads. Handy for Kunstmaan CMS projects.
This is a Symfony bundle, not a Laravel package. There is no service provider, no config/live_reload.php, and nothing in it will autoload under Laravel. If you're evaluating it from a Laravel context, read this as "what the equivalent thing costs to build" — you can reproduce 100% of its behaviour with a five-line response listener or, more likely, just use Vite's HMR which Laravel ships with.
What it actually does is narrow: on kernel.response, if the response looks like HTML, it appends a <script src="//host:port/livereload.js"> tag before </body>. The script is the client half of grunt-contrib-watch's live reload (or any LiveReload-protocol server on port 35729). Nothing more.
Minimal steps:
composer require --dev kunstmaan/live-reload-bundle — expect resolver pain. Last tagged release is 2014-08-13, so the constraints target Symfony 2.x and PHP 5.x. On a modern stack you'll need a fork, a path repository, or --ignore-platform-reqs plus luck. Verify the bundle class namespace from composer.json before wiring it up.// app/AppKernel.php
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Kunstmaan\LiveReloadBundle\KunstmaanLiveReloadBundle();
}
watch: {
options: { livereload: true },
styles: { files: ['web/scss/**/*.scss'], tasks: ['sass'] }
}
livereload.js and the subsequent WebSocket upgrade.Where to look first, since documentation is essentially nonexistent: DependencyInjection/Configuration.php (the real config keys and defaults), then the event listener under EventListener/ (confirms injection point, content-type check, and script URL shape). Read those two files before guessing at YAML.
First real use case: editing SCSS and having the browser swap the stylesheet without a reload — the same feedback loop Laravel Mix/Vite gives you via npm run dev, but driven by a Grunt daemon.
Dev-only registration is the whole pattern. This bundle has no business being enabled in production, and it has no environment guard of its own — the guard is the AppKernel conditional. If you copy bundle registration into a shared config file, you will ship a script tag pointing at localhost:35729 to users.
Auto-injection with a manual fallback. The listener only reliably catches full HTML responses. When it misses (streamed responses, unusual content types, responses short-circuited by another listener with higher priority), put the tag in your base layout yourself:
{% if app.environment == 'dev' %}
<script src="//{{ live_reload_host|default('localhost') }}:35729/livereload.js"></script>
{% endif %}
This is also the escape hatch when you want the tag in a specific position, or only on certain pages.
One reload server, not two. This bundle overlaps with Assetic's watch, Webpack Encore's dev server, and Browsersync. Pick one. Double-injection produces two WebSocket connections and double reloads, which looks like a bug in your asset pipeline and isn't.
Configuration belongs in config_dev.yml. Anything you set — host, port, enabled flag — should live in the dev config file so production config never mentions the bundle. Confirm exact key names against Configuration.php; don't trust blog posts, the bundle predates most of them.
In a Laravel context, the direct analogue is:
// webpack.mix.js
mix.browserSync('myapp.test');
or, on a current Laravel, Vite's HMR which is already wired into @vite and needs no bundle at all. If you genuinely need "inject into arbitrary HTML responses," a small middleware mirroring the listener is ~20 lines and you control the content-type check.
EventSubscriberInterface, autowiring, kernel.response) in less time than you'll spend fighting Composer constraints.Content-Length is not recalculated. Appending bytes to a response that already declared a length truncates the page behind strict servers, some proxies, and certain PHP-FPM setups. If pages cut off mid-script, this is why. Strip the header or recalculate after injection.http://localhost:35729/livereload.js is mixed content and is silently blocked in every modern browser. Either serve on the same scheme or put the reload server behind your dev proxy on a path.Content-Security-Policy will reject the script and the WebSocket. Add localhost:35729 to script-src and connect-src in dev, or don't use this.lsof -i :35729.bin/console debug:event-dispatcher kernel.response should list the listener. If it isn't there, the bundle isn't registered in this environment — that's a config problem, not a bundle problem. Use config:dump-reference to see real config keys instead of guessing.browser-sync in front of the dev server. All three are maintained, handle HTTPS and CSP, and don't touch your response bodies.How can I help you explore Laravel packages today?