Skip to content

Tokenizer parses component tags inside PHP comments #22

@jdlien

Description

@jdlien

Summary

Blaze's Tokenizer incorrectly parses component-like strings (<flux:...>, <x-...>) that appear inside PHP comments, causing corrupted compiled output and PHP parse errors.

Environment

  • livewire/blaze: v1.0.0-beta.1
  • livewire/flux: v2.x
  • livewire/flux-pro: v2.x
  • Laravel: v12.x
  • PHP: 8.5.1

Affected Component

The bug is triggered by vendor/livewire/flux/stubs/resources/views/flux/modal/index.blade.php which contains:

// Support <flux:modal ... @close="?"> syntax...
// Support <flux:modal ... @cancel="?"> syntax...

These are PHP comments documenting a syntax feature, but Blaze's tokenizer treats them as actual component tags.

Root Cause

Location: vendor/livewire/blaze/src/Tokenizer/Tokenizer.php

The handleTextState() method (lines 85-162) scans for component prefixes (flux:, x:, x-) without tracking whether it's currently inside:

  • PHP comments (// ... or /* ... */)
  • PHP strings
  • Compiled PHP blocks (<?php ... ?>)
protected function handleTextState(): State
{
    $char = $this->current();

    if ($char === '<') {
        // ... checks for component patterns without context awareness
        if ($prefixInfo = $this->matchComponentOpen()) {
            // This matches even inside PHP comments!
            ...
        }
    }
}

The Bug Flow

  1. Blaze processes flux/modal/index.blade.php which has @blaze directive
  2. The Tokenizer scans the compiled Blade output
  3. It encounters the PHP comment: // Support <flux:modal ... @close="?"> syntax...
  4. The tokenizer sees <flux:modal and starts parsing it as a real component
  5. This produces malformed PHP output where HTML is inserted into PHP code blocks
  6. PHP throws: syntax error, unexpected token "<", expecting end of file

Compiled Output Analysis

The corrupted compiled view shows the problem clearly:

// Support <ui-modal ...="..." data-flux-modal>

    <dialog
        wire:ignore.self
        class="p-6..." wire:close="?"
                        x-data
                    x-on:modal-show.document="..."
            > syntax...
if ($attributes['@close'] ?? null) {

The tokenizer:

  1. Saw <flux:modal in the comment
  2. Tried to render/fold it as a real component
  3. Injected <dialog> HTML directly into PHP code
  4. Mixed PHP code with HTML, breaking syntax

Minimal Reproduction

{{-- blaze-bug-repro.blade.php --}}
@blaze

@props([
    'test' => null,
])

@php
// This comment has a component: <flux:button variant="primary"/>
$foo = 'bar';
@endphp

<div {{ $attributes }}>
    {{ $slot }}
</div>

Any component with @blaze that contains a PHP comment referencing a component-like string will trigger this bug.

Suggested Fix

The Tokenizer needs context awareness. Options:

Option 1: Skip PHP blocks entirely

Before tokenizing, strip or mark PHP blocks (<?php ... ?>) as non-parseable regions.

Option 2: Track parser state

Maintain a state stack that knows when the parser is inside:

  • PHP code blocks
  • PHP comments (single-line // and multi-line /* */)
  • PHP strings

Option 3: Pre-process to escape component-like strings in PHP contexts

Before tokenization, escape component patterns that appear inside PHP comments/strings.

Workaround

Currently, the only workaround is to remove Blaze:

composer remove livewire/blaze
php artisan view:clear
php artisan cache:clear

Additional Notes

There are deprecation warnings about ReflectionProperty::setAccessible() but these are a separate issue:

Method ReflectionProperty::setAccessible() is deprecated since 8.5

This is in Blaze's codebase and should be addressed for PHP 8.5+ compatibility, but is not the cause of the compilation bug.

Files Examined

  • /vendor/livewire/blaze/src/Tokenizer/Tokenizer.php - Root cause
  • /vendor/livewire/blaze/src/Folder/Folder.php - Folding logic
  • /vendor/livewire/flux/stubs/resources/views/flux/modal/index.blade.php - Trigger component
  • /storage/framework/views/41e4f911aa753b471035b4b72be67899.php - Corrupted output

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions