nowo-tech / hot-reload-bundle
Symfony bundle that injects FrankenPHP (Dunglas) Hot Reload client assets when FRANKENPHP_HOT_RELOAD is available.
Package info
github.com/nowo-tech/HotReloadBundle
Type:symfony-bundle
pkg:composer/nowo-tech/hot-reload-bundle
Requires
- php: >=8.1 <8.6
- symfony/config: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/http-foundation: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- twig/extra-bundle: ^3.12
- twig/string-extra: ^3.12
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- nowo-tech/phpstan-frankenphp: ^1.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^10.0
- rector/rector: ^2.0
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/yaml: ^7.4 || ^8.0
- twig/twig: ^3.12
Suggests
- symfony/flex: For automatic recipe installation
- symfony/web-profiler-bundle: For the Hot Reload Web Debug Toolbar / Profiler panel
- twig/twig: Required for {{ nowo_hot_reload_assets() }} Twig helper
README
⭐ Found this useful? Install from Packagist · Give it a star on GitHub so more developers can find it.
Hot Reload Bundle — Symfony integration for FrankenPHP Hot Reload (dunglas/frankenphp-hot-reload). When enabled, it injects the Mercure hub meta tag, optional Idiomorph, and the frankenphp-hot-reload ESM module into HTML responses so the browser can morph or reload after PHP (and watched) file changes. Dev-only · PHP 8.1+ · Symfony 7.4+ and 8.0–8.2.
📋 Compatible with Symfony 7.4+ and 8.0–8.2 — PHP 8.1+ (Symfony 8.x requires PHP 8.4+).
This bundle is FrankenPHP worker mode friendly.
Pair with worker { …; watch } in your Caddyfile.
Features
- Auto-inject —
HotReloadResponseSubscriberinserts assets before</head>(else</body>) on HTML responses. - Twig helper —
{{ nowo_hot_reload_assets() }}for manual layouts whenauto_injectis off. - Env-aware — Renders only when
enabledand (mercure_urlorFRANKENPHP_HOT_RELOADis set, orrequire_frankenphp_env: false). - Doctor command —
php bin/console nowo:hot-reload:checklists what is configured vs missing (Caddymercure/hot_reload, env gate, auto-inject). The same checklist is on the profiler panel. - Idiomorph — Optional DOM morphing instead of a full page reload (on by default).
- Web Debug Toolbar — Profiler panel (
nowo_hot_reload) with status, truncated Mercure URL (full value on hover), environment checks, and CSP/preserve settings. - Preserve selectors — Marks Symfony Web Debug Toolbar (
[id^="sfwdt"],.sf-toolbar,.sf-minitoolbar) withdata-frankenphp-hot-reload-preserve(optionalMutationObserver). - CSP-aware — Optional request-attribute nonce on the preserve boot script; can augment existing
Content-Security-Policyscript-srcfor jsDelivr (see docs/CSP.md).
Installation
composer require nowo-tech/hot-reload-bundle --dev
With Symfony Flex, the recipe registers the bundle and adds config. Without Flex, see docs/INSTALLATION.md.
Manual registration in config/bundles.php (prefer dev / test only):
return [ // ... Nowo\HotReloadBundle\NowoHotReloadBundle::class => ['dev' => true, 'test' => true], ];
Server side: enable Mercure (anonymous) and php_server { hot_reload } in your Caddyfile. For worker mode, add worker { file …; watch }. Full environment guide: Configure the environment.
Environment setup
Hot Reload needs FrankenPHP + Caddy, not only Symfony YAML. FRANKENPHP_HOT_RELOAD is injected by FrankenPHP on HTTP requests — do not put it in .env.
- Register the bundle for
dev/testonly. - Keep
nowo_hot_reload.enabled: trueandauto_inject: true(or call{{ nowo_hot_reload_assets() }}). - Caddyfile:
order mercure after encode,mercure { anonymous },php_server { hot_reload }(worker: alsoworker { …; watch }). - Recreate the FrankenPHP process/container after Caddy or Compose env changes.
- Validate:
php bin/console nowo:hot-reload:check php bin/console nowo:hot-reload:check --caddyfile=path/to/Caddyfile
Then load an HTML page and open the Web Debug Toolbar Hot Reload panel (same checklist). Step-by-step Caddyfile, Docker notes, and troubleshooting: docs/ENVIRONMENT.md.
Requirements
- PHP
>=8.1(<8.6); Symfony 8.x requires PHP 8.4+ - Symfony 7.4+ and 8.0–8.2 (
symfony/*^7.4 || ^8.0) - FrankenPHP with Hot Reload + Mercure configured in the Caddyfile (dev)
twig/extra-bundle+twig/string-extra(REQ-TWIG-004) — required for{{ nowo_hot_reload_assets() }}and the profiler panel; enableTwigExtraBundlein the host app
Configuration
nowo_hot_reload: enabled: true auto_inject: true require_frankenphp_env: true allow_production: false # mercure_url: null # defaults to $_SERVER['FRANKENPHP_HOT_RELOAD'] idiomorph: true # idiomorph_script_url: 'https://cdn.jsdelivr.net/npm/idiomorph@0.7.4' # hot_reload_script_url: 'https://cdn.jsdelivr.net/npm/frankenphp-hot-reload@1.0.1/+esm' preserve_selectors: - '[id^="sfwdt"]' - '.sf-toolbar' - '.sf-minitoolbar' # csp_nonce_request_attribute: '_csp_nonce' csp_augment_script_src: true
Usage
With auto_inject: true (default), no template changes are needed when FrankenPHP sets FRANKENPHP_HOT_RELOAD (or you set mercure_url).
Manual Twig injection:
{{ nowo_hot_reload_assets() }}
Official references:
Demo
demo/symfony8— Symfony 8.2 (PHP 8.5), host port 8011 by default (PORTin.env)
The demo runs FrankenPHP + Caddy in Docker. See docs/DEMO-FRANKENPHP.md.
Global demo commands: make -C demo help (e.g. make -C demo up-symfony8).
Development
make up
make install
make test
make cs-check
make phpstan
make release-check
Documentation
- Installation
- Environment setup (Caddy / FrankenPHP)
- Configuration
- CSP
- Usage
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
Additional documentation
Tests and coverage
- Tests: PHPUnit (PHP)
- PHP: 100%
License and author
MIT · Nowo.tech · Héctor Franco Aceituno
