Skip to content

Implement BladeOne render engine #145

@alexander-zierhut

Description

@alexander-zierhut

See: https://github.com/EFTEC/BladeOne

This is going to be our next render engine.

BladeOne (eftec/bladeone) is the pragmatic standalone Blade. A single ~5–6k-LOC PHP file, zero Composer dependencies beyond ext-json, ~8.1M installs, v4.19.1 shipped September 2025, regular 2025 releases. As long as you instantiate via new BladeOne(...) and never touch the optional BladeOne::$instance accessor, the engine is genuinely instance-scoped and two instances coexist safely. It supports @php … @endphp, @if/@foreach/@switch, @extends/@yield/@section, @push/@stack, @class/@style, and the legacy @component('navbar', [...]) … @slot('title') … @endslot … @endcomponent system with named slots.

We need a working file cache for this. We should use the PSR for this.

Example code to establish a render engine pipeline:

interface Renderer {
    public function supports(string $viewPath): bool;
    public function render(string $viewPath, array $opt): string;
}

trait CanRenderView {
    /** @var Renderer[] */
    private array $renderers = [];

    public function registerRenderer(Renderer $r): void {
        $this->renderers[] = $r;
    }

    public function render(string $viewPath, array $opt = []): string {
        $opt = $this->buildOpt($opt); // existing: response/request/root/host/user/title
        $opt['e'] = fn($v) => htmlspecialchars((string)$v, ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8');
        $opt['component'] = $this->makeComponentInvoker($opt);
        $opt['generateResourceLink'] = $this->generateResourceLinkFor($opt);
        $opt['layout_essentials_body'] = $this->layoutEssentialsBody($opt);
        $opt['layout_essentials_head'] = $this->layoutEssentialsHead($opt);

        foreach ($this->renderers as $r) {
            if ($r->supports($viewPath)) {
                $body = $r->render($viewPath, $opt);
                return $this->wrapInLayout($body, $opt);
            }
        }
        return $this->renderClosureArray($viewPath, $opt); // existing path, unchanged
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions