Skip to content

Commit 1c75cd7

Browse files
authored
Fix handling of deleted compiled files (#114)
* Fix handling of deleted compiled files * Update BlazeRuntime.php
1 parent 61318c7 commit 1c75cd7

File tree

7 files changed

+38
-33
lines changed

7 files changed

+38
-33
lines changed

src/BladeRenderer.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Contracts\View\Factory;
66
use Illuminate\Support\Facades\File;
77
use Illuminate\View\Compilers\BladeCompiler;
8+
use Illuminate\View\Component;
89
use Livewire\Blaze\Runtime\BlazeRuntime;
910
use ReflectionClass;
1011

@@ -79,13 +80,15 @@ function ($input) {
7980
]);
8081

8182
$restoreRuntime = $this->freezeObjectProperties($this->runtime, [
82-
'compiled' => [],
83-
'paths' => [],
8483
'compiledPath' => $temporaryCachePath,
8584
'dataStack' => [],
8685
'slotsStack' => [],
8786
]);
8887

88+
$restoreComponent = $this->freezeObjectProperties(Component::class, [
89+
'bladeViewCache' => [],
90+
]);
91+
8992
try {
9093
$this->manager->startFolding();
9194

@@ -94,6 +97,7 @@ function ($input) {
9497
$restoreCompiler();
9598
$restoreFactory();
9699
$restoreRuntime();
100+
$restoreComponent();
97101

98102
$this->manager->stopFolding();
99103
}
@@ -114,7 +118,7 @@ public function deleteTemporaryCacheDirectory(): void
114118
/**
115119
* Snapshot object properties and return a restore closure to revert them.
116120
*/
117-
protected function freezeObjectProperties(object $object, array $properties)
121+
protected function freezeObjectProperties(object|string $object, array $properties)
118122
{
119123
$reflection = new ReflectionClass($object);
120124

@@ -125,7 +129,7 @@ protected function freezeObjectProperties(object $object, array $properties)
125129

126130
$property = $reflection->getProperty($name);
127131

128-
$frozen[$name] = $property->getValue($object);
132+
$frozen[$name] = $property->getValue(is_object($object) ? $object : null);
129133

130134
if (! is_numeric($key)) {
131135
$property->setValue($object, $value);

src/Compiler/Compiler.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Livewire\Blaze\Support\Utils;
1515

1616
/**
17-
* Compiles component nodes into PHP require_once + function call output.
17+
* Compiles component nodes into PHP function call output.
1818
*/
1919
class Compiler
2020
{
@@ -31,7 +31,7 @@ public function __construct(
3131
}
3232

3333
/**
34-
* Compile a component node into ensureCompiled + require_once + function call.
34+
* Compile a component node into ensureRequired + function call.
3535
*/
3636
public function compile(Node $node): Node
3737
{
@@ -91,7 +91,7 @@ protected function hasDynamicSlotNames(ComponentNode $node): bool
9191
}
9292

9393
/**
94-
* Compile a standard component tag into ensureCompiled + require_once + function call.
94+
* Compile a standard component tag into ensureRequired + function call.
9595
*/
9696
protected function compileComponentTag(ComponentNode $node, ComponentSource $source): string
9797
{
@@ -100,8 +100,7 @@ protected function compileComponentTag(ComponentNode $node, ComponentSource $sou
100100
$slotsVariableName = '$slots' . $hash;
101101
[$attributesArrayString, $boundKeysArrayString] = $this->getAttributesAndBoundKeysArrayStrings($node->attributeString);
102102

103-
$output = '<' . '?php $__blaze->ensureCompiled(\'' . $source->path . '\', $__blaze->compiledPath.\'/'. $hash . '.php\'); ?>' . "\n";
104-
$output .= '<' . '?php require_once $__blaze->compiledPath.\'/'. $hash . '.php\'; ?>' . "\n";
103+
$output = '<' . '?php $__blaze->ensureRequired(\'' . $source->path . '\', $__blaze->compiledPath.\'/'. $hash . '.php\'); ?>' . "\n";
105104

106105
if ($node->selfClosing) {
107106
$output .= '<' . '?php $__blaze->pushData(' . $attributesArrayString . '); ?>' . "\n";
@@ -136,7 +135,6 @@ protected function compileDelegateComponentTag(ComponentNode $node): string
136135
$output .= '<' . '?php $__blaze->pushData($attributes->all()); ?>' . "\n";
137136

138137
$output .= '<' . '?php if ($__resolved !== false): ?>' . "\n";
139-
$output .= '<' . '?php require_once $__blaze->compiledPath . \'/\' . $__resolved . \'.php\'; ?>' . "\n";
140138

141139
if ($node->selfClosing) {
142140
$output .= '<' . '?php ' . $functionName . '($__blaze, $attributes->all(), $__blaze->mergedComponentSlots(), [], isset($this) ? $this : null); ?>' . "\n";

src/Compiler/Profiler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
*
1515
* This runs as the final step in the AST pipeline, AFTER folder, memoizer,
1616
* and compiler. It wraps the call site — not the function body — so the
17-
* timer captures initialization, require_once, pushData, the render itself,
18-
* and popData. This gives us unified timing for both Blaze-compiled and
19-
* standard Blade components.
17+
* timer captures initialization, pushData, the render itself, and
18+
* popData. This gives us unified timing for both Blaze-compiled
19+
* and standard Blade components.
2020
*/
2121
class Profiler
2222
{

src/Runtime/BlazeRuntime.php

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class BlazeRuntime
2222
protected ?string $compiledPath = null;
2323

2424
protected array $paths = [];
25-
protected array $compiled = [];
25+
protected array $required = [];
2626
protected array $blazed = [];
2727

2828
protected array $dataStack = [];
@@ -40,19 +40,19 @@ public function __construct(
4040
/**
4141
* Compile a component if its source is newer than the cached output.
4242
*/
43-
public function ensureCompiled(string $path, string $compiledPath): void
43+
public function ensureRequired(string $path, string $compiledPath): void
4444
{
45-
if (isset($this->compiled[$path])) {
45+
if (isset($this->required[$path])) {
4646
return;
4747
}
4848

49-
$this->compiled[$path] = true;
50-
51-
if (file_exists($compiledPath) && filemtime($path) <= filemtime($compiledPath)) {
52-
return;
49+
if (! file_exists($compiledPath) || filemtime($path) > filemtime($compiledPath)) {
50+
$this->compiler->compile($path);
5351
}
5452

55-
$this->compiler->compile($path);
53+
require_once $compiledPath;
54+
55+
$this->required[$path] = true;
5656
}
5757

5858
/**
@@ -77,8 +77,8 @@ public function resolve(string $component): string|false
7777
$hash = Utils::hash($path);
7878
$compiled = $this->getCompiledPath().'/'.$hash.'.php';
7979

80-
if (! isset($this->compiled[$path])) {
81-
$this->ensureCompiled($path, $compiled);
80+
if (! isset($this->required[$path])) {
81+
$this->ensureRequired($path, $compiled);
8282
}
8383

8484
return $hash;
@@ -251,9 +251,6 @@ public function setApplication(Application $app): void
251251
*/
252252
public function flushState(): void
253253
{
254-
$this->paths = [];
255-
$this->compiled = [];
256-
$this->blazed = [];
257254
$this->dataStack = [];
258255
$this->slotsStack = [];
259256
}

tests/Compiler/CompilerTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
$hash = Utils::hash($path);
1515

1616
expect($compiled->render())->toEqualCollapsingWhitespace(join('', [
17-
'<?php $__blaze->ensureCompiled(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
18-
'<?php require_once $__blaze->compiledPath.\'/'. $hash .'.php\'; ?> ',
17+
'<?php $__blaze->ensureRequired(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
1918
'<?php $__blaze->pushData([\'type\' => \'text\',\'disabled\' => $disabled]); ?> ',
2019
'<?php _'. $hash .'($__blaze, [\'type\' => \'text\',\'disabled\' => $disabled], [], [\'disabled\'], isset($this) ? $this : null); ?> ',
2120
'<?php $__blaze->popData(); ?>',
@@ -43,8 +42,7 @@
4342
$hash = Utils::hash($path);
4443

4544
expect($compiled->render())->toEqualCollapsingWhitespace(join('', [
46-
'<?php $__blaze->ensureCompiled(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
47-
'<?php require_once $__blaze->compiledPath.\'/'. $hash .'.php\'; ?> ',
45+
'<?php $__blaze->ensureRequired(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
4846
'<?php $__attrs'. $hash .' = []; ?> ',
4947
'<?php $__blaze->pushData($__attrs'. $hash .'); ?> ',
5048
'<?php $slots'. $hash .' = []; ?> ',
@@ -67,7 +65,6 @@
6765
'<?php $__resolved = $__blaze->resolve(\'flux::\' . card); ?> ',
6866
'<?php $__blaze->pushData($attributes->all()); ?> ',
6967
'<?php if ($__resolved !== false): ?> ',
70-
'<?php require_once $__blaze->compiledPath . \'/\' . $__resolved . \'.php\'; ?> ',
7168
'<?php (\'_\' . $__resolved)($__blaze, $attributes->all(), $__blaze->mergedComponentSlots(), [], isset($this) ? $this : null); ?> ',
7269
'<?php else: ?> ',
7370
'<flux:delegate-component component="card" /> ',

tests/IntegrationTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
use Illuminate\Container\Container;
44
use Illuminate\Contracts\View\Engine;
55
use Illuminate\Support\Facades\Artisan;
6+
use Illuminate\View\Component;
67
use Livewire\Blaze\Blaze;
78
use Livewire\Blaze\BlazeManager;
9+
use Livewire\Blaze\Runtime\BlazeRuntime;
810

911
beforeEach(fn () => Artisan::call('view:clear'));
1012

@@ -25,6 +27,14 @@
2527
view('mix')->render();
2628
})->throwsNoExceptions();
2729

30+
test('renders components after clearing compiled views in the same process', function () {
31+
view('mix')->render();
32+
33+
Artisan::call('view:clear');
34+
35+
view('mix')->render();
36+
})->throwsNoExceptions();
37+
2838
test('supports php engine', function () {
2939
view('php-view')->render();
3040
})->throwsNoExceptions();

tests/Memoizer/MemoizerTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
'<?php echo \Livewire\Blaze\Memoizer\Memo::get($blaze_memoized_key); ?>',
2323
'<?php else : ?>',
2424
'<?php ob_start(); ?>',
25-
'<?php $__blaze->ensureCompiled(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
26-
'<?php require_once $__blaze->compiledPath.\'/'. $hash .'.php\'; ?> ',
25+
'<?php $__blaze->ensureRequired(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
2726
'<?php $__blaze->pushData([\'src\' => $user->avatar]); ?> ',
2827
'<?php _'. $hash .'($__blaze, [\'src\' => $user->avatar], [], [\'src\'], isset($this) ? $this : null); ?> ',
2928
'<?php $__blaze->popData(); ?>',

0 commit comments

Comments
 (0)