Skip to content

Fix optimize class-based view rendered as empty output - #212

Closed
ghabriel25 wants to merge 2 commits into
livewire:mainfrom
ghabriel25:fix/blaze-optimize-class-based-view
Closed

Fix optimize class-based view rendered as empty output#212
ghabriel25 wants to merge 2 commits into
livewire:mainfrom
ghabriel25:fix/blaze-optimize-class-based-view

Conversation

@ghabriel25

@ghabriel25 ghabriel25 commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Prevents Blaze::optimize()->in() from wrapping views that belong to class-based components, which previously caused those components to render as empty output with no exception.

Problem

When a directory is optimized via Blaze::optimize()->in(...), every Blade file under that path is compiled and wrapped into a Blaze function. Class-based components do not go through the Blaze runtime — they render via Component::render() → the view engine → PhpEngine::evaluatePath(), which simply requires the compiled file and captures its output.

The Blaze wrapper only defines a function; nothing calls it. Result:

{{-- resources/views/components/alert.blade.php --}}
<div>{{ $message }}</div>
// After Blaze wrap
<?php
if (!function_exists('_…')):
function _…($__blaze, $__data = [], ...) {
    // …
    echo ltrim(ob_get_clean());
} endif;
BLAZE_ENABLED=false  →  <div>hello</div>
BLAZE_ENABLED=true   →  (empty string, 200, no exception)

This is especially easy to hit because Laravel’s make:component (class-based) writes the view into resources/views/components — the same path the README uses as the example for directory optimization.

Solution

Skip the Blaze wrap when the view path is the conventional view of a class-based component.

  1. BladeService::isClassBasedComponentView(string $path): bool

    • Normalizes separators
    • Requires a /components/ segment
    • Derives the component name (forms/input.blade.phpforms.input)
    • Delegates to the existing hasClassBasedComponent() (same resolution order as Laravel’s ComponentTagCompiler)
  2. Wrap guard in BlazeManager::compile() (and the folding compile path for consistency):

$shouldWrap = $path
    && ($directives->blaze() || $this->config->shouldCompile($path))
    && ! $this->blade->isClassBasedComponentView($path);

The class-based check is absolute: even an explicit @blaze on a class-based view is ignored. Class-based components remain unsupported; this only stops poisoning their normal Blade path.
Anonymous components in the same optimized directory are unaffected and still get compiled/wrapped as before.

Changes

  • src/BladeService.php — add isClassBasedComponentView()
  • src/BlazeManager.php — skip wrap for class-based component views in compile() and compileForFolding()
  • tests/BladeServiceTest.php — unit tests for detection (class-based vs anonymous, nested names)
  • tests/BlazeManagerTest.php — integration test: optimize directory containing a class-based view and assert correct HTML
  • Workbench Alert component + fixture updated to a real class-based component (render() returns view('components.alert'))

Fixes: #210

@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Benchmark Result: Default

Attempt Blade Blaze Change
#1 190.32ms 10.98ms 94.2%
#2 188.83ms 11.08ms 94.1%
#3 193.03ms 11.03ms 94.3%
#4 * 194.17ms 11.10ms 94.3%
#5 189.76ms 10.98ms 94.2%
#6 189.94ms 11.06ms 94.2%
#7 188.66ms 10.99ms 94.2%
#8 188.48ms 11.03ms 94.1%
#9 186.75ms 10.99ms 94.1%
#10 190.77ms 11.00ms 94.2%
Snapshot 188.75ms 10.99ms 94.2%
Result 189.76ms (~) 11.00ms (~) 94.2% (~)

Median of 10 attempts (* = outlier, excluded from result), 5000 iterations x 10 rounds, 25.91s total

To run a specific benchmark, comment /benchmark <name>
attributes, aware, class, default, forwarding, merge, named-slots, no-attributes, slot, compilation

@ghabriel25

Copy link
Copy Markdown
Contributor Author

Closing in favor #213

@ghabriel25 ghabriel25 closed this Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimizing directory with Blaze::optimize()->in() renders class-based templates as empty output

1 participant