Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
10f534d
Refactor Utils calls
ganyicz Feb 28, 2026
c5b2a5b
Remove parseAttributesArrayToRuntimeArrayString
ganyicz Feb 28, 2026
6c77b28
Add DirectiveCompiler
ganyicz Feb 28, 2026
dc66f98
Delete parseAttributeStringToArray usage
ganyicz Feb 28, 2026
d18223f
Remove Utils:: parseAttributeStringToArray
ganyicz Feb 28, 2026
7f4f03c
Fix imports
ganyicz Feb 28, 2026
ce9dcdb
Move attribute preprocessing to Parser
ganyicz Feb 28, 2026
afe89e9
Update ComponentSource to accept path
ganyicz Feb 28, 2026
602e5a1
Add failing test
ganyicz Feb 28, 2026
bc37a90
Refactor BladeService to an instance
ganyicz Feb 28, 2026
43bb269
Add tests
ganyicz Feb 28, 2026
e868467
Extract isolated rendering from BladeService
ganyicz Mar 1, 2026
83faf5e
Refactor
ganyicz Mar 1, 2026
607cc92
Refactor
ganyicz Mar 1, 2026
ef70625
Refactor
ganyicz Mar 1, 2026
3c8f164
Refactor
ganyicz Mar 1, 2026
9366f76
Refactor
ganyicz Mar 1, 2026
6d12865
Refactor
ganyicz Mar 1, 2026
efa5018
Refactor
ganyicz Mar 1, 2026
1ddfa2c
Refactor
ganyicz Mar 1, 2026
dffb7e8
Refactor tests
ganyicz Mar 1, 2026
f65b4aa
Fix DirectiveCompiler
ganyicz Mar 1, 2026
8b723dd
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 2, 2026
be6b5c5
Test CI
ganyicz Mar 2, 2026
7ff4d3b
Test CI
ganyicz Mar 2, 2026
badecc5
Test CI
ganyicz Mar 2, 2026
c3620dc
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 2, 2026
ed808b2
Test CI
ganyicz Mar 2, 2026
cbcf408
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 2, 2026
e669dcb
Test CI
ganyicz Mar 2, 2026
1e83681
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 2, 2026
5d95d28
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 2, 2026
0b19f0c
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 3, 2026
52e873b
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 3, 2026
d72bf52
Merge branch 'main' into filip/blade-compiler-refactor
ganyicz Mar 4, 2026
93349fd
Fix merge conflicts
ganyicz Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions src/BladeRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

namespace Livewire\Blaze;

use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\File;
use Illuminate\View\Compilers\BladeCompiler;
use Livewire\Blaze\Runtime\BlazeRuntime;
use ReflectionClass;

/**
* Handles isolated Blade rendering used during compile-time folding.
*/
class BladeRenderer
{
public function __construct(
protected BladeCompiler $blade,
protected Factory $factory,
protected BlazeRuntime $runtime,
protected BlazeManager $manager,
) {}

/**
* Get the temporary cache directory path used during isolated rendering.
*/
public function getTemporaryCachePath(): string
{
return config('view.compiled').'/blaze';
}

/**
* Render a Blade template string in isolation by freezing and restoring compiler state.
*/
public function render(string $template): string
{
$temporaryCachePath = $this->getTemporaryCachePath();

File::ensureDirectoryExists($temporaryCachePath);

$restoreFactory = $this->freezeObjectProperties($this->factory, [
'renderCount' => 0,
'renderedOnce' => [],
'sections' => [],
'sectionStack' => [],
'pushes' => [],
'prepends' => [],
'pushStack' => [],
'componentStack' => [],
'componentData' => [],
'currentComponentData' => [],
'slots' => [],
'slotStack' => [],
'fragments' => [],
'fragmentStack' => [],
'loopsStack' => [],
'translationReplacements' => [],
]);

$restoreCompiler = $this->freezeObjectProperties($this->blade, [
'cachePath' => $temporaryCachePath,
'rawBlocks' => [],
'footer' => [],
'prepareStringsForCompilationUsing' => [
function ($input) {
if (Unblaze::hasUnblaze($input)) {
$input = Unblaze::processUnblazeDirectives($input);
};

$input = $this->manager->compileForFolding($input, $this->blade->getPath());

return $input;
},
],
'path' => null,
'forElseCounter' => 0,
'firstCaseInSwitch' => true,
'lastSection' => null,
'lastFragment' => null,
]);

$restoreRuntime = $this->freezeObjectProperties($this->runtime, [
'compiled' => [],
'paths' => [],
'compiledPath' => $temporaryCachePath,
'dataStack' => [],
'slotsStack' => [],
]);

try {
$this->manager->startFolding();

$result = $this->blade->render($template, deleteCachedView: true);
} finally {
$restoreCompiler();
$restoreFactory();
$restoreRuntime();

$this->manager->stopFolding();
}

$result = Unblaze::replaceUnblazePrecompiledDirectives($result);

return $result;
}

/**
* Delete the temporary cache directory created during isolated rendering.
*/
public function deleteTemporaryCacheDirectory(): void
{
File::deleteDirectory($this->getTemporaryCachePath());
}

/**
* Snapshot object properties and return a restore closure to revert them.
*/
protected function freezeObjectProperties(object $object, array $properties)
{
$reflection = new ReflectionClass($object);

$frozen = [];

foreach ($properties as $key => $value) {
$name = is_numeric($key) ? $value : $key;

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

$frozen[$name] = $property->getValue($object);

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

return function () use ($reflection, $object, $frozen) {
foreach ($frozen as $name => $value) {
$property = $reflection->getProperty($name);
$property->setValue($object, $value);
}
};
}
}
Loading