From 87c8d3670ba967c0b41e048bf549944f5758220c Mon Sep 17 00:00:00 2001 From: Emma De Silva Date: Tue, 14 Apr 2026 00:56:16 +0200 Subject: [PATCH] Fix realtime compiler loading assets from production URL When the realtime compiler served pages with a configured site URL (e.g. hydephp.com), asset and media file references were generated as absolute URLs pointing to the production host, causing the browser to request files from production instead of the local server. Override the configured site URL to the current request's host:port when booting the application for page compilation. This ensures all generated asset links resolve against localhost (or the configured dev server) rather than production. Skip the override when save_preview is enabled to avoid baking the local URL into persisted output files. Closes #2327 Co-Authored-By: Claude Opus 4.6 --- .../realtime-compiler/src/Routing/Router.php | 23 ++++++++ .../tests/RealtimeCompilerTest.php | 58 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/packages/realtime-compiler/src/Routing/Router.php b/packages/realtime-compiler/src/Routing/Router.php index 9fb7dcf5e46..ec2b80cf207 100644 --- a/packages/realtime-compiler/src/Routing/Router.php +++ b/packages/realtime-compiler/src/Routing/Router.php @@ -32,6 +32,8 @@ public function handle(): Response $this->bootApplication(); + $this->overrideSiteUrl(); + $virtualRoutes = app(RealtimeCompiler::class)->getVirtualRoutes(); if (isset($virtualRoutes[$this->request->path])) { @@ -71,6 +73,27 @@ protected function shouldProxy(Request $request): bool return true; } + /** + * Override the configured site URL so compiled pages reference the local + * server instead of the production URL. Without this, assets such as + * media files would be loaded from the production host when previewing + * the site locally. + */ + protected function overrideSiteUrl(): void + { + // When save_preview is enabled, the compiled page is written to disk, + // so we leave the configured site URL alone to avoid baking the local + // preview URL into the persisted output. + if (config('hyde.server.save_preview')) { + return; + } + + $scheme = (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; + $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; + + config(['hyde.url' => "$scheme://$host"]); + } + /** * Proxy a static file or return a 404. */ diff --git a/packages/realtime-compiler/tests/RealtimeCompilerTest.php b/packages/realtime-compiler/tests/RealtimeCompilerTest.php index da7ce65688a..0b8494fc2b0 100644 --- a/packages/realtime-compiler/tests/RealtimeCompilerTest.php +++ b/packages/realtime-compiler/tests/RealtimeCompilerTest.php @@ -11,6 +11,7 @@ use Hyde\RealtimeCompiler\Http\ExceptionHandler; use Desilva\Microserve\HtmlResponse; use Hyde\RealtimeCompiler\Http\HttpKernel; +use Hyde\RealtimeCompiler\Routing\Router; class RealtimeCompilerTest extends TestCase { @@ -211,9 +212,66 @@ public function testExceptionHandling() $this->assertSame('Internal Server Error', $response->statusMessage); } + public function testOverridesSiteUrlWithRequestUrl() + { + $this->mockCompilerRoute(''); + $_SERVER['HTTP_HOST'] = 'localhost:8080'; + + config(['hyde.url' => 'https://hydephp.com']); + + $this->invokeOverrideSiteUrl(); + + $this->assertSame('http://localhost:8080', config('hyde.url')); + } + + public function testOverridesSiteUrlUsesHttpsSchemeForSecureRequests() + { + $this->mockCompilerRoute(''); + $_SERVER['HTTP_HOST'] = 'hyde.test'; + $_SERVER['HTTPS'] = 'on'; + + $this->invokeOverrideSiteUrl(); + + $this->assertSame('https://hyde.test', config('hyde.url')); + + unset($_SERVER['HTTPS']); + } + + public function testOverridesSiteUrlFallsBackToLocalhostWhenHostIsMissing() + { + $this->mockCompilerRoute(''); + unset($_SERVER['HTTP_HOST']); + + $this->invokeOverrideSiteUrl(); + + $this->assertSame('http://localhost', config('hyde.url')); + } + + public function testDoesNotOverrideSiteUrlWhenSavePreviewIsEnabled() + { + $this->mockCompilerRoute(''); + $_SERVER['HTTP_HOST'] = 'localhost:8080'; + + config([ + 'hyde.server.save_preview' => true, + 'hyde.url' => 'https://hydephp.com', + ]); + + $this->invokeOverrideSiteUrl(); + + $this->assertSame('https://hydephp.com', config('hyde.url')); + } + protected function mockCompilerRoute(string $route, $method = 'GET'): void { $_SERVER['REQUEST_METHOD'] = $method; $_SERVER['REQUEST_URI'] = "/$route"; } + + protected function invokeOverrideSiteUrl(): void + { + $method = new ReflectionMethod(Router::class, 'overrideSiteUrl'); + $method->setAccessible(true); + $method->invoke(new Router(new Request())); + } }