From 82a3c6da30b476f80a54f90588dc628d0ceb09a0 Mon Sep 17 00:00:00 2001 From: Filip Ganyicz Date: Tue, 18 Aug 2026 16:36:16 +0200 Subject: [PATCH] Recompile cache with equal timestamps --- src/BladeRenderer.php | 2 +- src/Runtime/BlazeRuntime.php | 2 +- tests/BladeRendererTest.php | 45 ++++++++++++++++++++++++++++++ tests/Runtime/BlazeRuntimeTest.php | 30 ++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/BladeRenderer.php b/src/BladeRenderer.php index 9a308736..d2b5bed0 100644 --- a/src/BladeRenderer.php +++ b/src/BladeRenderer.php @@ -101,7 +101,7 @@ function ($input) { $this->manager->startFolding(); try { - if (! file_exists($compiled) || filemtime($path) > filemtime($compiled)) { + if (! file_exists($compiled) || filemtime($path) >= filemtime($compiled)) { $this->blade->compile($path); } diff --git a/src/Runtime/BlazeRuntime.php b/src/Runtime/BlazeRuntime.php index 55891266..3bc15efc 100644 --- a/src/Runtime/BlazeRuntime.php +++ b/src/Runtime/BlazeRuntime.php @@ -49,7 +49,7 @@ public function __construct( */ public function compile(string $path, string $compiledPath): void { - if (! file_exists($compiledPath) || filemtime($path) > filemtime($compiledPath)) { + if (! file_exists($compiledPath) || filemtime($path) >= filemtime($compiledPath)) { $this->compiler->compile($path); } } diff --git a/tests/BladeRendererTest.php b/tests/BladeRendererTest.php index fd6a4b78..b760328e 100644 --- a/tests/BladeRendererTest.php +++ b/tests/BladeRendererTest.php @@ -99,3 +99,48 @@ File::deleteDirectory($dir); } }); + +test('recompiles stale cache when source and compiled timestamps are equal', function () { + $dir = sys_get_temp_dir().'/blaze-'.uniqid(); + $path = $dir.'/button.blade.php'; + + try { + File::ensureDirectoryExists($dir); + File::put($path, '@blaze(fold: true) stale'); + + $blaze = app(BlazeManager::class); + $renderer = app(BladeRenderer::class); + $blade = app(BladeCompiler::class); + $bladeCachePath = invade($blade)->cachePath; + + // We can't use the renderer here because it would `require` the file + // and register a global function, which would produce stale output + // even after recompiling. So instead we'll simulate folding and + // we will only compile the file in the blaze cache directory + invade($blade)->cachePath = $renderer->getTemporaryCachePath(); + + $blaze->startFolding(); + $blade->compile($path); + $blaze->stopFolding(); + + invade($blade)->cachePath = $bladeCachePath; + + // Now change the source and give it the same timestamp as the compiled file + $compiled = $renderer->getTemporaryCachePath().'/'.Utils::hash($path).'.php'; + $timestamp = now()->addSecond()->timestamp; + + File::put($path, '@blaze(fold: true) fresh'); + + touch($path, $timestamp); + touch($compiled, $timestamp); + clearstatcache(true); + + expect(File::lastModified($path))->toBe(File::lastModified($compiled)); + + $node = app(Parser::class)->parse('')[0]; + + expect($renderer->render($node, $path))->toContain('fresh'); + } finally { + File::deleteDirectory($dir); + } +}); diff --git a/tests/Runtime/BlazeRuntimeTest.php b/tests/Runtime/BlazeRuntimeTest.php index 0fb56efd..c6151d85 100644 --- a/tests/Runtime/BlazeRuntimeTest.php +++ b/tests/Runtime/BlazeRuntimeTest.php @@ -1,7 +1,37 @@ getCompiledPath($path); + $timestamp = now()->addSecond()->timestamp; + + File::put($compiled, 'stale'); + + touch($path, $timestamp); + touch($compiled, $timestamp); + clearstatcache(true); + + expect(File::lastModified($path))->toBe(File::lastModified($compiled)); + + app(BlazeRuntime::class)->compile($path, $compiled); + + expect(File::get($compiled))->toContain('fresh'); + } finally { + File::delete($compiled ?? ''); + File::deleteDirectory($dir); + } +}); + it('processPassthroughContent', function ($input, $results) { $input = str_replace('[UNBLAZE]', '[STARTCOMPILEDUNBLAZE:XXX][ENDCOMPILEDUNBLAZE:XXX]', $input);