拓冰建站拓冰建站
首页 / 资讯中心 / 正文

FrankenPHP 热重载(Hot Reload)实战指南:PHP、模板与前端资源的实时刷新

FrankenPHP 热重载Hot Reload实战指南PHP、模板与前端资源的实时刷新【免费下载链接】frankenphp The modern PHP app server项目地址: https://gitcode.com/GitHub_Trending/fr/frankenphpFrankenPHP 内置了开箱即用的**热重载Hot Reload**功能用于大幅改善本地开发体验。它的工作方式与现代 JavaScript 工具链中的Hot Module ReplacementHMR如 Vite、webpack类似当 PHP 代码、模板、JavaScript 或 CSS 文件发生变化时浏览器中的页面内容会被实时更新无需手动刷新。本文以 docs/ru/hot-reload.md对应英文原版 docs/hot-reload.md为主体结合仓库中的 Caddy 模块、文件监听器与测试用例源码完整讲解热重载的开启方式、Caddyfile 配置语法、客户端集成、Worker 模式配合使用以及底层实现原理。该功能原生兼容 WordPress、Laravel、Symfony 及任何其他 PHP 应用或框架。启用后FrankenPHP 会监听当前工作目录的文件系统变更一旦文件被修改便通过内置的 Mercure Hub 向浏览器推送更新。浏览器端根据加载情况采取两种行为之一若已加载Idiomorph对 DOM 进行变形Morph保留滚动位置与输入框状态实现类似 HMR 的无感更新若未加载 Idiomorph执行window.location.reload()退化为标准的 live reload 整页刷新。一、启用热重载最小 Caddyfile 配置热重载依赖 Mercure Hub 来推送事件因此启用流程分两步先启用 Mercure再在php_server指令中添加hot_reload子指令。以下是最小可用配置出自 docs/hot-reload.mdlocalhost mercure { anonymous } root public/ php_server { hot_reload }[!WARNING]仅限开发环境。请勿在生产环境启用hot_reload该功能不安全会暴露敏感的内部细节并且会拖慢应用性能。从源码看hot_reload子指令由 Caddy 模块在 caddy/module.go 中分发到unmarshalHotReload解析随后由configureHotReload完成装配见 caddy/hotreload.go。其中有两个关键默认行为值得注意默认监听模式未显式指定watch时FrankenPHP 监听当前工作目录下匹配以下 glob 模式的所有文件常量定义于 caddy/hotreload.go./**/*.{css,env,gif,htm,html,jpg,jpeg,js,mjs,php,png,svg,twig,webp,xml,yaml,yml}默认 Mercure Topic未显式指定topic时FrankenPHP 会基于当前模块配置生成一个唯一 ID使用 gob 编码 FNV-64a 哈希见 caddy/hotreload.go 与uniqueID实现默认 Topic 形如https://frankenphp.dev/hot-reload/唯一ID。依赖检查若未配置 Mercure Hub 就启用热重载configureHotReload会直接返回错误unable to enable hot reloading: no Mercure hub configured见 caddy/hotreload.go这解释了为何必须先写mercure块。二、配置可监听的文件与目录2.1 短格式直接指定 glob 模式默认模式会监听工作目录下所有常见前端与 PHP 相关文件。若项目较大可以显式收紧监听范围使用 glob 语法直接在hot_reload后跟参数localhost mercure { anonymous } root public/ php_server { hot_reload src/**/*{.php,.js} config/**/*.yaml }此处hot_reload后的所有参数会通过d.RemainingArgs()全部收集为监听模式见 caddy/hotreload.go。2.2 长格式指定 Topic 与多个 watch需要同时控制 Mercure Topic 和监听范围时使用块语法。topic与watch子指令均可重复出现localhost mercure { anonymous } root public/ php_server { hot_reload { topic hot-reload-topic watch src/**/*.php watch assets/**/*.{ts,json} watch templates/ watch public/css/ } }解析逻辑见 caddy/hotreload.gotopic取单个参数watch取剩余参数可写多次、逐个追加。除topic、watch之外的子指令会触发wrongSubDirectiveError(hot_reload, topic, watch, ...)报错。2.3 glob 模式解析与花括号展开内部文件监听器位于 internal/watcher其中 internal/watcher/pattern.go 负责把配置中的 glob 拆解为可实际匹配的路径规则关键细节如下**递归匹配模式按**分段见 internal/watcher/pattern.go例如src/**/*.php会递归匹配src下所有层级的 PHP 文件花括号展开{php,js}、{ts,json}这类语法由expandCurlyBraces展开成多个子模式后逐一匹配见 internal/watcher/pattern.go因此assets/**/*.{ts,json}等价于分别监听.ts与.json文件目录级监听watch templates/、watch public/css/这种以目录结尾的模式同样支持会监听该目录下的文件变化临时文件过滤由于部分编辑器会先创建临时文件再替换原文件allowReload同时校验Event.PathName与Event.AssociatedPathName见 internal/watcher/pattern.go对应上游 issue frankenphp#1375避免误触发重载防抖debounce事件到达后统一等待 150msdebounceDuration再触发回调把连续写入合并为一次更新见 internal/watcher/watcher.go 与 internal/watcher/watcher.go。三、客户端集成让浏览器订阅更新服务端负责检测变更浏览器端则需要订阅这些事件才能刷新页面。FrankenPHP 通过环境变量$_SERVER[FRANKENPHP_HOT_RELOAD]向 PHP 应用暴露 Mercure Hub 的订阅 URL。该变量由configureHotReload写入见 caddy/hotreload.go值为形如/.well-known/mercure?topicURL 编码后的 Topic的地址。集成测试也验证了这一契约在 caddy/hotreload_test.go 中测试向index.php写入内容后断言其输出即为该 Mercure 订阅 URL。3.1 使用官方 JavaScript 库推荐官方提供了便捷库frankenphp-hot-reloadnpm 包与 GitHub 仓库dunglas/frankenphp-hot-reload处理全部客户端逻辑。在主布局模板中加入以下代码!DOCTYPE html titleFrankenPHP Hot Reload/title ?php if (isset($_SERVER[FRANKENPHP_HOT_RELOAD])): ? meta namefrankenphp-hot-reload:url content?$_SERVER[FRANKENPHP_HOT_RELOAD]? script srchttps://cdn.jsdelivr.net/npm/idiomorph/script script srchttps://cdn.jsdelivr.net/npm/frankenphp-hot-reload/esm typemodule/script ?php endif ?isset($_SERVER[FRANKENPHP_HOT_RELOAD])保证该代码只在热重载开启的开发环境中被输出生产环境不加载任何额外脚本页面通过meta namefrankenphp-hot-reload:url向库提供 Hub 地址库会自动订阅 Mercure Hub在检测到文件变更时于后台获取当前 URL 并执行 DOM 变形morph实现无刷新更新。该库同时也适合集成到主流框架Symfony 的 Twig 模板写法见 docs/symfony.md使用app.request.server.get(FRANKENPHP_HOT_RELOAD)WordPress 主题的写法见 docs/wordpress.md。3.2 自实现客户端逻辑也可以不使用库直接用浏览器原生EventSource类订阅 Mercure Hubconst source new EventSource(? $_SERVER[FRANKENPHP_HOT_RELOAD] ?); source.addEventListener(message, (event) { // event.data 为包含变更文件列表的 JSON 字符串 // 此处可自行决定调用 window.location.reload() 或执行 DOM 更新 window.location.reload(); });3.3 保留特定 DOM 节点某些场景下不希望某些 DOM 节点被变形覆盖例如 Symfony web debug toolbar 这类开发工具面板。为对应 HTML 元素添加data-frankenphp-hot-reload-preserve属性即可在 DOM 变形时保留该节点div>localhost mercure { anonymous } root public/ php_server { hot_reload worker { file /path/to/my_worker.php watch } }worker指令下watch的完整语法见 docs/config.md支持指定路径、多次指定多个路径未指定路径时默认回退到./**/*.{env,php,twig,yaml,yml}监听目录及子目录下所有.env、.php、.twig、.yaml、.yml文件。需注意**表示递归监听要小心监听运行期动态生成的文件如日志它们可能引发非预期的 Worker 重启该文件监听器同样基于e-dant/watcher见 docs/config.md。五、热重载的完整工作流程综合源码可以梳理出热重载的五步链路监听WatchFrankenPHP 基于e-dant/watcherInitWatcher根据配置的多个PatternGroup建立监听会话每个pattern维护独立的底层 watcher见 internal/watcher/pattern.go。重启Worker 模式若 Worker 配置中启用了watchWorker 会先重启以加载新代码。这也是 hotreload.go 中回调注释「Wait for workers to restart before sending the update」的含义——先等 Worker 重启完成再推送更新避免浏览器拿到旧内容。推送Push包含变更文件列表的JSON 负载被发送到内置 Mercure Hub。具体实现在 hotreload.go通过hub.Publish发布一条 MercureUpdate其Data为 watcher 事件含变更文件路径的 JSON 序列化结果Topic 即配置或默认生成的 Topic。接收Receive浏览器端的 JavaScript 库或自实现的EventSource订阅收到 Mercure 事件。更新Update检测到Idiomorph时拉取更新后的内容并对当前 HTML 执行 DOM 变形瞬间应用变更且不丢失页面状态滚动位置、输入内容否则调用window.location.reload()整页刷新。整个过程在 caddy/hotreload_test.go 中有端到端的集成测试佐证测试搭建了带mercurehot_reload的 Caddy 服务器客户端通过 SSE 订阅 Mercure 事件流随后写入index.php文件断言事件流中能收到包含index.php的变更通知并验证$_SERVER[FRANKENPHP_HOT_RELOAD]变量正确输出订阅 URL。六、使用要点小结场景推荐配置普通 PHP 项目经典模式mercure { anonymous }php_server { hot_reload }项目较大、仅需监听特定目录hot_reload src/**/*{.php,.js} config/**/*.yaml短格式需要自定义 Topic 与多目录监听hot_reload { topic ... watch ... }长格式Worker 模式hot_reloadworker { file ... watch }组合使用生产环境不要启用hot_reload核心原则hot_reload只为开发体验而生务必仅在本地开发环境开启生产环境应关闭该功能以避免安全风险与性能损耗。若希望进一步了解其底层监听器的实现细节可深入阅读 internal/watcher/watcher.go 与 internal/watcher/pattern.go或参考 caddy/hotreload_test.go 中的端到端测试用例。【免费下载链接】frankenphp The modern PHP app server项目地址: https://gitcode.com/GitHub_Trending/fr/frankenphp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门