improvements

This commit is contained in:
Kévin Dunglas
2025-12-22 20:37:42 +01:00
parent 33f5bacf8d
commit 2c80f8a47b
5 changed files with 61 additions and 32 deletions

View File

@@ -128,6 +128,7 @@ Go to `https://localhost`, and enjoy!
- [Worker mode](https://frankenphp.dev/docs/worker/)
- [Early Hints support (103 HTTP status code)](https://frankenphp.dev/docs/early-hints/)
- [Real-time](https://frankenphp.dev/docs/mercure/)
- [Hot reloading](https://frankenphp.dev/docs/hot-reload/)
- [Efficiently Serving Large Static Files](https://frankenphp.dev/docs/x-sendfile/)
- [Configuration](https://frankenphp.dev/docs/config/)
- [Writing PHP Extensions in Go](https://frankenphp.dev/docs/extensions/)

View File

@@ -213,7 +213,9 @@ This is useful for development environments.
}
```
If the `watch` directory is not specified, it will fall back to `./**/*.{php,yaml,yml,twig,env}`,
This feature is often used in combination with [hot reload](hot-reload.md)
If the `watch` directory is not specified, it will fall back to `./**/*.{env,php,twig,yaml,yml}`,
which watches all `.php`, `.yaml`, `.yml`, `.twig` and `.env` files in the directory and subdirectories
where the FrankenPHP process was started. You can instead also specify one or more directories via a
[shell filename pattern](https://pkg.go.dev/path/filepath#Match):
@@ -239,7 +241,7 @@ where the FrankenPHP process was started. You can instead also specify one or mo
The file watcher is based on [e-dant/watcher](https://github.com/e-dant/watcher).
## Matching the worker to a path
## Matching the Worker To a Path
In traditional PHP applications, scripts are always placed in the public directory.
This is also true for worker scripts, which are treated like any other PHP script.

View File

@@ -2,6 +2,8 @@
FrankenPHP includes a built-in **hot reload** feature designed to vastly improve the developer experience.
![Mercure](hot-reload.png)
This feature provides a workflow similar to **Hot Module Replacement (HMR)** found in modern JavaScript tooling (like Vite or Webpack).
Instead of manually refreshing the browser after every file change (PHP code, templates, JavaScript and CSS files...),
FrankenPHP updates the content in real-time.
@@ -18,7 +20,7 @@ Depending on your setup, the browser will either:
## Configuration
To enable hot reloading, enable Mercure, then add the `hot_reload` option to the `php_server` directive in your `Caddyfile`.
To enable hot reloading, enable Mercure, then add the `hot_reload` sub-directive to the `php_server` directive in your `Caddyfile`.
> [!WARNING]
> This feature is intended for **development environments only**.
@@ -37,7 +39,24 @@ php_server {
}
```
You can also explicitly specify the Mercure topic to use as well as which directories or files to watch by providing paths to the `hot_reload` option:
By default, FrankenPHP will watch all files in the current working directory matching this glob pattern: `./**/*.{css,env,gif,htm,html,jpg,jpeg,js,mjs,php,png,svg,twig,webp,xml,yaml,yml}`
It's possible to explicitly set the files to watch using the glob syntax:
```caddyfile
localhost
mercure {
anonymous
}
root public/
php_server {
hot_reload src/**/*{.php,.js} config/**/*.yaml
}
```
Use the long form to specify the Mercure topic to use as well as which directories or files to watch by providing paths to the `hot_reload` option:
```caddyfile
localhost
@@ -50,23 +69,46 @@ root public/
php_server {
hot_reload {
topic hot-reload-topic
watch src/
watch src/**/*.php
watch assets/**/*.{ts,json}
watch templates/
watch public/js/
watch public/css/
}
}
```
## Client-Side Integration
While the server detects changes, the browser needs to subscribe to these events to update the page.
FrankenPHP exposes the Mercure Hub URL to use for the subscribing to file changes via the `$_SERVER['FRANKENPHP_HOT_RELOAD']` environment variable.
A convenience JavaScript library, [frankenphp-hot-reload](https://www.npmjs.com/package/frankenphp-hot-reload), is also available to handle the client-side logic.
To use it, add the following to your main layout:
```php
<!DOCTYPE html>
<title>FrankenPHP Hot Reload</title>
<?php if (isset($_SERVER['FRANKENPHP_HOT_RELOAD']): ?>
<meta name="frankenphp-hot-reload:url" content="<?=$_SERVER['FRANKENPHP_HOT_RELOAD']?>">
<script src="https://cdn.jsdelivr.net/npm/idiomorph"></script>
<script src="https://cdn.jsdelivr.net/npm/frankenphp-hot-reload/+esm" type="module"></script>
<?php endif ?>
```
The library will automatically subscribe to the Mercure hub, fetch current URL in the background when a file change is detected and morph the DOM.
It is available as a [npm](https://www.npmjs.com/package/frankenphp-hot-reload) package and on [GitHub](https://github.com/dunglas/frankenphp-hot-reload).
Alternatively, you can implement your own client-side logic by subscribing directly to the Mercure hub using the `EventSource` native JavaScript class.
### Worker Mode
If you are running your application in [Worker Mode](https://frankenphp.dev/docs/worker/), your application script remains in memory.
This means changes to your PHP code will not be reflected immediately, even if the browser reloads.
For the best developer experience, you should combine `hot_reload` with the `watch` option in the `worker` directive.
For the best developer experience, you should combine `hot_reload` with [the `watch` sub-directive in the `worker` directive](config.md#watching-for-file-changes).
* `hot_reload`: Refreshes the **browser** when files change.
* `watch`: Refreshes the **application kernel** (restarts the worker) when files change.
* `hot_reload`: refreshes the **browser** when files change
* `worker.watch`: restarts the worker when files change
```caddy
localhost
@@ -79,36 +121,18 @@ root public/
php_server {
hot_reload
worker {
file my_worker.php
file /path/to/my_worker.php
watch
}
}
```
## Client-Side Integration
While the server detects changes, the browser needs to subscribe to these events to update the page. FrankenPHP exposes the Mercure Hub URL required for the subscription via the `$_SERVER['FRANKENPHP_HOT_RELOAD']` environment variable.
You must include the URL in a meta tag and load the FrankenPHP Hot Reload library.
Add the following to your main layout or HTML template:
```php
<!DOCTYPE html>
<title>FrankenPHP Hot Reload</title>
<?php if (isset($_SERVER['FRANKENPHP_HOT_RELOAD']): ?>
<meta name="frankenphp-hot-reload:url" content="<?=$_SERVER['FRANKENPHP_HOT_RELOAD']?>">
<script src="https://cdn.jsdelivr.net/npm/idiomorph"></script>
<script src="https://cdn.jsdelivr.net/npm/frankenphp-hot-reload/+esm" type="module"></script>
<?php endif ?>
```
### How it works
1. **Watch**: FrankenPHP monitors the filesystem for modifications.
2. **Restart (Worker Mode)**: If `watch` is enabled in the worker config, the PHP worker is restarted to load the new code.
3. **Push**: A payload containing the list of changed files is sent to the built-in Mercure Hub.
4. **Receive**: The browser, listening via the JS library, receives the event.
1. **Watch**: FrankenPHP monitors the filesystem for modifications using [the `e-dant/watcher` library](https://github.com/e-dant/watcher) under the hood (we contributed the Go binding).
2. **Restart (Worker Mode)**: if `watch` is enabled in the worker config, the PHP worker is restarted to load the new code.
3. **Push**: a JSON payload containing the list of changed files is sent to the built-in [Mercure hub](https://mercure.rocks).
4. **Receive**: The browser, listening via the JavaScript library, receives the Mercure event.
5. **Update**:
* If **Idiomorph** is detected, it fetches the updated content and morphs the current HTML to match the new state, applying changes instantly without losing state.
* Otherwise, `window.location.reload()` is called to refresh the page.

BIN
docs/hot-reload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

View File

@@ -35,6 +35,8 @@ The following command will trigger a restart if any file ending in `.php` in the
frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"
```
This feature is often used in combination with [hot reloading](hot-reload.md).
## Symfony Runtime
> [!TIP]