docs / Blade & parity
Blade & parity
Views are compiled, not interpreted. The reference is the real Laravel renderer running on PHP 8.3, and the comparison is bytes.
What compiles
| Blade | verdict | note |
|---|---|---|
| @extends, @section, @yield | compiles | the sections travel to the layout, not just the child view |
| @if, @elseif, @else, @unless | compiles | |
| @foreach, @for, @while, @forelse | compiles | |
| @switch, @match | compiles | |
| ternary, ?:, ??, ??=, isset, empty | compiles | evaluated with PHP's own rules for a missing value |
| {{ }} and {!! !!} | compiles | escaping matches e(), not a regex approximation |
| __('key') | compiles | translations are dumped at build time from your lang/. Other translation helpers are not compiled yet and fail loud. |
| @vite, @fonts | compiles | a runtime shim reads the build manifest — the hashed URLs are the real ones |
| @php blocks | restricted | a subset; anything outside it is a build error, never a silent difference |
| <x-…> components, slots | fails loud | they compile to a view runtime the edge does not carry → a port, or inline the partial |
| custom directives | not compiled yet | a directive outside the documented set fails the build; inline the markup or move the work into the view |
What parity means here
The build does not “look right” — it compares, in two places. The Blade corpus transpiles each case through the CLI, imports the emitted module and byte-compares the rendered output against an expectation file that the real Laravel app on PHP 8.3.30 produced. The shadow harness goes further and diffs a whole request — status, headers and body — between the PHP app and the compiled worker. The corpus is 55/55 today, and a divergence fails CI rather than becoming a footnote.
$ npm run test:corpus
55/55 blade cases byte-identical vs PHP 8.3.30Two things follow from that. First, the compiled view must reproduce PHP's string and number formatting, not JavaScript's — the runtime carries the PHP behaviours (sprintf,number_format, json_encode, DateTime) deliberately. Second, a Blade construct that cannot be reproduced has exactly one honest answer: the build stops.
Sharing the layout
A layout is a view too. @extends with @section/@yield is compiled as a function that renders the child's sections at the point the layout yields them, in the same order Laravel does. Nested includes (@include,@includeIf) resolve at build time; a view that does not exist is a build error, not an empty string.
Working locally
Blade stays Blade in development: the same files, the same artisan, the same hot reload. There is no second template language and no “edge flavour” of your views. The compiled form only exists inside dist/.
Source: README.md §Compiles today; MAP.md §5 §6b; COMPILED.md — repository ba1e9a5