Skip to content

Optimize large form rendering#19550

Merged
danharrin merged 26 commits into
4.12-betafrom
worktree-form-perf
May 3, 2026
Merged

Optimize large form rendering#19550
danharrin merged 26 commits into
4.12-betafrom
worktree-form-perf

Conversation

@danharrin
Copy link
Copy Markdown
Member

No description provided.

@danharrin danharrin added this to the v4 milestone Mar 23, 2026
@danharrin danharrin added the task label Mar 23, 2026
@github-project-automation github-project-automation Bot moved this to Todo in Roadmap Mar 23, 2026
Signed-off-by: Dan Harrin <git@danharrin.com>
@danharrin danharrin changed the base branch from 4.x to 4.12-beta May 3, 2026 17:43
@danharrin danharrin marked this pull request as ready for review May 3, 2026 18:42
@danharrin danharrin merged commit a2f6157 into 4.12-beta May 3, 2026
46 checks passed
@danharrin danharrin deleted the worktree-form-perf branch May 3, 2026 19:01
@github-project-automation github-project-automation Bot moved this from Todo to Done in Roadmap May 3, 2026
@danharrin
Copy link
Copy Markdown
Member Author

Test file for ref

<?php

use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
use Filament\Tests\Fixtures\Livewire\Livewire;
use Filament\Tests\TestCase;
use Illuminate\Support\MessageBag;
use Illuminate\Support\ViewErrorBag;

use function Filament\Tests\livewire;

uses(TestCase::class);

it('measures render performance', function (): void {
    view()->share('errors', (new ViewErrorBag)->put('default', new MessageBag));

    $cases = [
        'TextInput' => RenderPerformanceTextInput::class,
        'Select' => RenderPerformanceSelect::class,
        'FileUpload' => RenderPerformanceFileUpload::class,
        'Repeater (10 items, 2 fields)' => RenderPerformanceRepeater::class,
        'Checkbox' => RenderPerformanceCheckbox::class,
    ];

    $iterations = 100;
    $results = [];

    foreach ($cases as $label => $class) {
        $test = livewire($class);
        $instance = $test->instance();
        $schema = $instance->getSchema('form');

        $schema->toHtml();

        $start = hrtime(true);

        for ($i = 0; $i < $iterations; $i++) {
            $schema->toHtml();
        }

        $totalMs = (hrtime(true) - $start) / 1_000_000;
        $results[$label] = $totalMs / $iterations;
    }

    $width = max(array_map('strlen', array_keys($results)));

    echo "\n";
    echo "Render performance (avg ms per render, {$iterations} iterations):\n";
    echo str_repeat('-', $width + 16) . "\n";

    foreach ($results as $label => $avgMs) {
        echo str_pad($label, $width + 2) . number_format($avgMs, 3) . " ms\n";
    }

    echo str_repeat('-', $width + 16) . "\n";

    expect(true)->toBeTrue();
});

class RenderPerformanceTextInput extends Livewire
{
    public function form(Schema $form): Schema
    {
        return $form->components([
            TextInput::make('text'),
        ]);
    }
}

class RenderPerformanceSelect extends Livewire
{
    public function form(Schema $form): Schema
    {
        return $form->components([
            Select::make('select')
                ->options([
                    'one' => 'One',
                    'two' => 'Two',
                    'three' => 'Three',
                ]),
        ]);
    }
}

class RenderPerformanceFileUpload extends Livewire
{
    public function form(Schema $form): Schema
    {
        return $form->components([
            FileUpload::make('file'),
        ]);
    }
}

class RenderPerformanceRepeater extends Livewire
{
    public function form(Schema $form): Schema
    {
        return $form->components([
            Repeater::make('items')
                ->schema([
                    TextInput::make('title'),
                    TextInput::make('description'),
                ])
                ->default(array_fill(0, 10, [
                    'title' => 'Title',
                    'description' => 'Description',
                ])),
        ]);
    }
}

class RenderPerformanceCheckbox extends Livewire
{
    public function form(Schema $form): Schema
    {
        return $form->components([
            Checkbox::make('checkbox'),
        ]);
    }
}
  ┌────────────────────────────────┬────────────┬───────────────────┬─────────┬──────────┐
  │           Component            │ 4.x median │ table-perf median │    Δ    │ % faster │
  ├────────────────────────────────┼────────────┼───────────────────┼─────────┼──────────┤
  │ TextInput                      │ 0.729      │ 0.044             │ −0.685  │ 94%      │
  ├────────────────────────────────┼────────────┼───────────────────┼─────────┼──────────┤
  │ Select                         │ 0.819      │ 0.050             │ −0.769  │ 94%      │
  ├────────────────────────────────┼────────────┼───────────────────┼─────────┼──────────┤
  │ FileUpload                     │ 0.743      │ 0.081             │ −0.662  │ 89%      │
  ├────────────────────────────────┼────────────┼───────────────────┼─────────┼──────────┤
  │ Repeater (10 items × 2 fields) │ 31.754     │ 3.431             │ −28.323 │ 89%      │
  ├────────────────────────────────┼────────────┼───────────────────┼─────────┼──────────┤
  │ Checkbox                       │ 0.449*     │ 0.028             │ −0.421  │ 94%      │
  └────────────────────────────────┴────────────┴───────────────────┴─────────┴──────────┘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant