Skip to content

Start building your next app or website — with AI, right in your browser.

Visit devdojo.com
Docs
Pocketknife

Open Source 02 / 34

Pocketknife

Pocketknife is the portable Blade — a Go engine that safely renders a subset of Laravel Blade as static HTML, paired with a Laravel package that renders the identical files in a real app. It's the engine behind DevDojo Sites.

Pocketknife is the portable Blade — a Go engine that statically renders a closed subset of Laravel's Blade templating language, paired with a Composer package (devdojo/pocketknife) that makes the identical files render in a real Laravel application. One project, two renderers, one contract: everything the static renderer supports produces byte-identical output through real Blade. It's the engine behind DevDojo Sites, and it's built in the same open-source spirit as the rest of the toolbox, with a standalone public release (thedevdojo/pocketknife) on the roadmap.

Why it exists

A DevDojo site and a Laravel app are meant to be points on one dial, not two products. Blade is the language at both ends — a site's pages are .blade.php files in a Laravel-shaped folder structure — so turning a site into an app should move zero files.

The catch is serving. Real Blade compiles to arbitrary PHP, so it can never run multi-tenant on shared static infrastructure. Pocketknife resolves that with a no-eval Go renderer for a well-defined Blade subset: it parses templates into an AST and renders them itself — it never executes PHP, never evals, and never panics on user input. Blade syntax becomes safe to serve at the static tier, and anything the subset doesn't cover isn't an error — it's a tier signal: "this needs your site running as a full app."

What's in the box

Part What it is
The Go engine Scanner, parser, renderer, and expression evaluator for the Blade subset. Byte-faithful to your HTML — everything outside the dialect passes through verbatim.
The devdojo/pocketknife package The Laravel half: renders the same site tree natively in any Laravel app, with the same data bindings — and can serve it as live pages.
The conformance suite Language-agnostic fixture cases rendered by the Go engine and by real Blade, byte-diffed in CI. Real Laravel is the oracle — anything the two renderers can't agree on doesn't ship in the subset.
The CLI pocketknife compile (a JSON stdin/stdout protocol for host applications) and pocketknife lint (diagnostics for a whole site tree).

The dialect at a glance

The subset reads like everyday Blade — the full grammar, with exact behavior, is in the Sites syntax reference:

  • Echoes{{ $expr }} (escaped, exactly Laravel's e()), {!! $expr !!} (raw), {{-- comments --}} (removed).
  • Control flow@if / @elseif / @else, @foreach (with $loop), @break / @continue with optional conditions.
  • Components<x-sections.hero heading="…"/> resolving under resources/views/components/, @props defaults, bound attributes (:plans="$plans"), default and named slots. Layouts are ordinary components wrapping {{ $slot }}.
  • Expressions — variables, $post->title, $items[0], ??, comparisons and boolean logic, with PHP's truthiness and loose-equality rules faithfully reproduced.
  • Dataresources/data/site.json binds as $site, JSON collections bind by filename, and markdown content folders become collections with rendered content.
  • Assets@vite(['resources/css/site.css']) renders a static projection: the Tailwind v4 CDN plus your CSS entry inlined. The same line switches to real Vite output once the site runs as an app with built assets.

Two deliberate strictnesses: undefined variables are build errors (real Blade throws at runtime; rendering silent blanks would hide typos), with ?? as the sanctioned default pattern — and every diagnostic carries a file, line, and column.

Tier signals, not failures

Valid Blade outside the subset — @auth, @php, function calls, $attributes — is never silently dropped and never crashes the build. It renders literally in the output and is reported as a structured app-tier diagnostic, with the construct named. Hosts like Sites surface these as an upgrade prompt: this page needs your site running as an application. That's the dial working as designed — write real Blade freely, and the engine tells you which tier it belongs to.

The Laravel package

Because .blade.php is Laravel's native Blade extension, a Pocketknife site needs zero configuration to render in a real app — copy a page into resources/views/ and it just works. The devdojo/pocketknife package adds the rest of the contract:

  • Registers the site's view and component roots (your app's own views always win).
  • Binds the data contract — $site, collections, and content collections — from resources/data/.
  • Provides the static-projection @vite while the app has no built assets, then steps aside for real Vite.
  • Optionally serves the site tree as live pages: a fallback route renders each page as native Blade and serves public/** assets, GET/HEAD only, with app routes always taking precedence.

That serving mode is what powers connecting a Laravel app to Sites: your app pulls the site's Blade source and renders it natively — real templates, not exported HTML.

Where it fits

Every Sites compile — builder previews, the published site, exports, and the AI's build-loop lint — runs through the Pocketknife engine, so what you see in the builder is exactly what ships. And because the conformance suite pins the engine to real Blade byte-for-byte, the site you build today is a Laravel app waiting to be switched on. For the wider toolbox, see the open source overview.

© 2026 DevDojo Edit this page