pug-php/pug-filter-react
A Pug filter for the pug-php templating engine that lets you embed React JSX directly inside Pug templates. It compiles components and renders them to HTML server-side, letting PHP projects combine Pug markup with React UI in one streamlined workflow.
composer require <vendor>/laravel-pug (1.1.0 pulls pug-php/pug:^3.0). If you are upgrading from 1.0.x, run composer update pug-php/pug <vendor>/laravel-pug in one step so the adapter and engine versions move together.php artisan vendor:publish --provider="...PugServiceProvider". The default config is safe to start with — compiled templates land in storage/framework/views alongside Blade..pug), the engine options array passed to Pug\Pug, and the cache toggle. Everything you will tune day-to-day lives in those two places.resources/views/hello.pug next to your Blade views and return it from a route exactly as you would a Blade view:Route::get('/', fn () => view('hello', ['name' => 'Taylor']));
//- resources/views/hello.pug
doctype html
html
body
h1 Hello #{name}
php artisan view:cache and a request. If the page renders, the engine is wired correctly and you can start migrating views incrementally — Pug and Blade coexist in the same resources/views tree with no configuration.layout.blade.php and layout.pug side by side during a migration and convert leaf views first. Blade's @include('partials.nav') and Pug's include partials/nav both resolve through the same view finder, so mixed trees work — but a Pug layout cannot extend a Blade layout (or vice versa). Convert whole inheritance chains, not single files.extends/block for page shells and include for fragments. Pass data explicitly to includes with include partials/card.pug plus a - var ... prelude, or rely on the parent scope — Pug includes inherit the parent's locals, which makes accidental variable shadowing easy. Prefer explicit locals in shared partials.mixin button(label, href)) are the natural Pug analogue to Blade components and are where most day-to-day leverage sits. Define them in resources/views/mixins/ and include the file once in your layout. Mixin attributes blocks give you class/data-* pass-through without string concatenation.view(), View::make(), view composers, share(), and with() all work identically — the engine is selected by file extension. Mailables, notifications, and Mailable::view() accept .pug paths with no extra wiring, which is often the highest-value first target because email markup is repetitive.pretty, extension, paths, and cache in config/pug.php rather than instantiating Pug\Pug yourself; the adapter reads config on resolve. Register custom keywords/filters through the package's extension point (or a small service provider that resolves the engine and calls addKeyword) so they are available everywhere without repeating setup in controllers.php artisan view:cache after composer install --no-dev. Pair with php artisan view:clear on rollback. This is the single biggest runtime win — compilation is otherwise per-request work.$this->get('/')->assertSee('Hello') works regardless of engine. For assertions on markup that Pug reformats (whitespace, self-closing tags), assert on text or use assertSee(..., false) rather than exact HTML strings.Pug\Pug instance now takes an options array and several 2.x keys were removed or renamed. If you ever instantiated the engine directly, or read options out of the container, re-check that code. If you only use view(), the adapter shields you, but review any custom service provider that resolves the engine.php artisan view:clear clears compiled views, but a stale Pug cache in a custom path from your config will survive it. If a template change "does nothing," check the cache path in config/pug.php and delete it manually. In local dev, set cache => false to sidestep this entirely..editorconfig rule. Most "the engine is broken" reports are indentation..pug file throws during view(), which means a bad template can take down a route in production only when hit. Warming the cache in CI (view:cache in a test or deploy step) is the cheapest guard.#{expr} escapes, !{expr} does not. Coming from {{ }} it is easy to over-escape or, worse, use !{} on user data. Treat !{} as a deliberate, reviewable decision.@php blocks or Blade directives. You write real PHP in - code lines. Keep logic in controllers and view composers; Pug makes it tempting to inline loops that should be presenter methods.pretty on changes indentation and newlines in the rendered HTML, which can break assertSee on exact strings and inline-element spacing. Keep pretty off in production and normalize assertions."<vendor>/laravel-pug": "^1.1", "pug-php/pug": "^3.0") and upgrade them as a pair. A floating constraint on the engine is how you get a mid-sprint compile failure.How can I help you explore Laravel packages today?