Blaze

repository·main·Indexed 20 days ago

https://github.com/livewire/blaze

A high-performance replacement for anonymous Blade components in Laravel that optimizes rendering by compiling templates into optimized PHP functions. It features three levels of optimization: the default Function Compiler, Runtime Memoization for repeated components without slots, and Compile-Time Folding for maximum performance with static HTML. Blaze includes a debug mode and profiler to visualize rendering times and component performance via flame chart traces.

Tokens
7.9K
Snippets
30
Records
39
Agent score
72%

What's inside livewire/blaze

  1. Blaze optimization strategies

    main

    Blaze provides three levels of optimization. The Function Compiler is the default and is safe for almost all use cases. Advanced strategies provide higher performance but require more care.

    StrategyParameterDefaultBest For
    Function CompilercompiletrueGeneral use
    Runtime MemoizationmemofalseRepeated components (e.g. icons, avatars)
    Compile-Time FoldingfoldfalseMaximum performance (static HTML)

    Important Notes:

    • Memoization only works on components without slots.
    • Folding is the most aggressive optimization; it turns the component into static HTML at compile time, meaning it ceases to exist at runtime. Use with caution.
  2. How Blaze folding works

    main

    Blaze achieves high performance by 'folding' components: pre-rendering them during compilation and embedding the resulting static HTML directly into your templates. This eliminates runtime overhead.

    Key Concepts

    • Static HTML Output: Folding produces static HTML. All internal logic, conditions, and dynamic content are baked in at compile time.
    • The Risk of Folding: Because logic is baked in, components that rely on dynamic data might behave incorrectly if folded. You must ensure components are suitable for folding or configure Blaze to abort folding when necessary.
    • Global State Warning: Never fold components that use global state. If a component accesses data via helpers, facades, or Blade directives that aren't passed in as props, the folded output will be incorrect. Blaze attempts to detect this, but you must be vigilant.
  3. Configure safe and unsafe parameters for @blaze(fold: true)

    main

    When using fold: true, you must tell Blaze how to handle dynamic values for props, slots, and attributes to prevent breaking the component.

    safe parameter

    Use safe for @props that are passed through to the output without internal logic/transformation. This allows folding to proceed even when the caller passes a dynamic expression.

    unsafe parameter

    Use unsafe for values that are used in internal logic (e.g., match, if, switch) or if the component inspects slot content or the attribute bag. When a value marked unsafe receives a dynamic input, folding is aborted for that instance.

    Target Values

    ValueTarget
    *All props, attributes, and slots
    slotThe default slot
    [name]A specific prop, attribute, or named slot
    attributesAll attributes not defined in @props
    {{-- Marking a prop as safe for pass-through --}}
    @blaze(fold: true, safe: ['level'])
    
    {{-- Marking a slot as unsafe because logic depends on it --}}
    @blaze(fold: true, unsafe: ['slot'])
    
    {{-- Marking the attribute bag as unsafe --}}
    @blaze(fold: true, unsafe: ['attributes'])
  4. Avoid folding components with global state

    main

    Components that access the following types of global state internally must not be marked with fold: true. Using these patterns inside a folded component will produce incorrect results because the state is captured at compile time rather than runtime.

    CategoryExamples
    DatabaseUser::get()
    Authenticationauth()->check(), @auth, @guest
    Sessionsession('key')
    Requestrequest()->path(), request()->is()
    Validation$errors->has(), $errors->first()
    Timenow(), Carbon::now()
    Security@csrf

    Note: Passing global state into a component via attributes or slots is generally safe, as it treats the data as a prop rather than internal global access.

  5. Use the Blaze Profiler

    main

    The Blaze profiler allows you to visualize component rendering performance via a flame chart trace.

    Workflow:

    1. Enable debug mode (via Blaze::debug() or BLAZE_DEBUG=true).
    2. Open the debug overlay and click the Open Profiler button to open a separate window.
    3. Navigate to the URL you wish to profile in your main window.
    4. Refresh the profiler window to load the trace for the current page.

    The trace displays every component rendered during the request, its duration, nesting depth, and the optimization strategy used (compiled, folded, memoized, or blade).

    NOTE

    The profiler requires a functional cache store. If CACHE_STORE is set to array or the cache is unreachable, the profiler will not work.

  6. Install Blaze via Composer

    main

    Install Blaze as a drop-in replacement for anonymous Blade components to speed up rendering by compiling templates into optimized PHP functions. If you are using Flux UI, Blaze is ready to go immediately after installation with no extra configuration.

    composer require livewire/blaze:^1.0
  7. Enable folding and memoization in Blaze 1.0

    main

    In Blaze 1.0, you can explicitly enable folding and memoization using two methods:

    1. Using the @blaze directive

    Pass boolean arguments directly to the directive in your Blade templates:

    @blaze(fold: true, memo: true)

    2. Using Blaze::optimize() in a Service Provider

    You can configure optimizations for entire directories globally. This is useful for applying different strategies to different parts of your view tree (e.g., applying fold to components but memo to icons).

    Blaze::optimize()
        ->in(resource_path('views/components'))
        ->in(resource_path('views/components/ui'), fold: true)
        ->in(resource_path('views/components/icons'), memo: true);
  8. Optimize entire directories with Blaze::optimize()

    main

    To enable Blaze for many components at once, call Blaze::optimize() within your AppServiceProvider's boot method. This allows you to target specific directories and apply different optimization strategies per folder.

    Key features:

    • Use ->in(path) to target a directory.
    • Use compile: false to exclude a subdirectory.
    • Pass optimization parameters like memo: true or fold: true to the in() method.
    • Component-level @blaze directives will override these directory-level settings.

    Note: After enabling Blaze, you must clear your compiled views using php artisan view:clear.

    use Livewire\
    Blaze\Blaze;
    
    public function boot(): void
    {
        // Optimize specific directories
        Blaze::optimize()->in(resource_path('views/components'));
    
        // Optimize with specific strategies
        Blaze::optimize()
            ->in(resource_path('views/components/icons'), memo: true)
            ->in(resource_path('views/components/cards'), fold: true);
    
        // Exclude subdirectories
        Blaze::optimize()
            ->in(resource_path('views/components'))
            ->in(resource_path('views/components/legacy'), compile: false);
    }
  9. Use Runtime Memoization for repeated components

    main

    Runtime Memoization caches the output of a component based on its name and the props passed to it. This is ideal for elements like icons or avatars that appear many times with the same properties.

    Constraint: Memoization only works on components that do not use slots.

    @blaze(memo: true)
    
    @props(['name'])
    
    <x-dynamic-component :component="'icon-' . $name" />
  10. Verify component safety before using @blaze(fold: true)

    main

    Compile-time folding pre-renders components during Blade compilation, embedding static HTML directly into the parent template. This eliminates runtime overhead but can cause bugs if the component relies on dynamic global state.

    Do NOT fold a component if it accesses any of the following:

    • Database: DB::, ::where(), ::find(), ::get(), etc.
    • Auth: auth(), @auth, @guest, Auth::, or $user from auth.
    • Session: session(), Session::.
    • Request: request(), Request::, $request.
    • Validation: $errors, @error.
    • Time: now(), Carbon::, today(), time().
    • CSRF: @csrf, csrf_token().
    • URL state: url()->current(), request()->path(), etc.
    • Config/Env: config(), env() (if values change between requests).
    • Cache: Cache::, cache().
    • App state: app(), resolve(), App::.

    Exception: If only a small section requires global state, use @unblaze with a scope to exclude that specific part from the folding process.

    @blaze(fold: true)
    
    @props(['name', 'label'])
    
    <div class="container">
        <label>{{ $label }}</label>
        <input name="{{ $name }}">
    
        @unblaze(scope: ['name' => $name])
            @if($errors->has($scope['name']))
                {{ $errors->first($scope['name']) }}
            @endif
        @endunblaze
    </div>
  11. Analyze Props, Slots, and Attributes for folding safety

    main

    Props Analysis

    • Static props: (e.g., color="red") are safe to fold.
    • Dynamic pass-through props: (e.g., :level="$isFeatured ? 1 : 2") are safe ONLY IF marked with safe: ['prop_name'].
    • Dynamic non-pass-through props: (e.g., :color="$deleting ? 'red' : 'blue'" where color is used in a match statement) CANNOT be folded.

    Slot Analysis

    • Default slot: Generally safe as they are treated as pass-through.
    • Slots used in logic: If you use $slot->hasActualContent() or $slot->isEmpty(), you MUST mark the slot as unsafe: ['slot'].
    • Named slots in logic: If a named slot (e.g., footer) is inspected via logic, mark it unsafe: ['footer'].

    Attribute Bag Analysis

    If the component reads attributes via $attributes->get() and uses them in logic (rather than just merging them), mark attributes or the specific attribute name as unsafe.