js-phpize/js-phpize-phug
JS-PHPize for Phug brings JavaScript-style expressions into Pug templates compiled to PHP. Write familiar JS syntax in your server-side views while Phug renders them as PHP, making template logic more expressive and easier to reuse.
This package is the glue between two libraries: JsPhpize (transpiles JavaScript expressions to PHP at compile time) and Phug (a Pug template engine for PHP). In practice it lets you keep writing Pug templates the way a front-end developer would — with JS expressions, var, ternaries, JS-style operators — while rendering them server-side in PHP.
Minimal setup:
composer require js-phpize/js-phpize-phug
Then register the adapter as a Phug module/extension on the renderer:
use Phug\Renderer;
$renderer = new Renderer([
'paths' => [__DIR__ . '/views'],
'cache_dir' => __DIR__ . '/cache',
'modules' => [\JsPhpize\JsPhpizePhug::class], // adapter entry point
]);
echo $renderer->renderFile('profile.pug', ['user' => $user]);
And in views/profile.pug:
- var discount = user.isPremium ? 0.2 : 0
- var price = product.price * (1 - discount)
h1= user.name
p= price
Where to look first:
src/ directory if the README is thin; the adapter is usually a small class that registers JsPhpize as a Phug compiler/filter module.First real use case: you have a Pug template written for Node/Pug (or you want to write one that way) and you need to render it from PHP without rewriting every - var x = ... line into PHP. This package is the fastest path to that, and it also works well when front-end devs own the templates and PHP devs own the data.
Register the adapter once at bootstrap, not per render. Phug resolves modules when the renderer is constructed, so build a single Renderer (or a container-bound singleton) and reuse it. Creating a renderer per request re-parses options and defeats the compiled-template cache.
// bootstrap / service provider
$container->singleton(Renderer::class, fn () => new Renderer([
'paths' => [resource_path('views')],
'cache_dir' => storage_path('framework/views/phug'),
'modules' => [\JsPhpize\JsPhpizePhug::class],
'debug' => env('APP_DEBUG'),
]));
Keep statements in - and output in =. The idiomatic split still applies. Use - var x = ... for variables and = expr / #{expr} for output. This makes it obvious which lines are passed through JsPhpize versus treated as plain Pug text.
- var items = cart.items.filter(function (i) { return i.qty > 0; })
ul
each item in items
li= item.name + ' × ' + item.qty
Share data, don't embed data. Pass PHP arrays/objects via the second argument to renderFile and treat them as the JS scope. Avoid putting business logic in the template; use it only for presentation-level expressions (formatting, ternaries, arithmetic, small loops).
$renderer->renderFile('cart.pug', [
'cart' => $cart->toArray(),
'user' => $auth->user(),
]);
Mixing PHP and JS is possible but should be a deliberate boundary. Some projects use JS expressions for the template logic and PHP for helper calls injected into scope (e.g. $formatMoney as a closure). Keep that boundary consistent; don't alternate styles within a single template file.
Framework integration. Wire the renderer into your app's view layer (Laravel, Slim, Symfony, or plain PHP). Because Phug compiles to PHP and caches, the runtime cost after the first render is just executing generated PHP — comparable to Twig/Blade.
Compile-then-inspect workflow. During development, render the template and open the compiled file in cache_dir. The generated PHP is the exact translation JsPhpize produced; it is the single most useful debugging artifact. Enable debug so cache is regenerated on template change.
+ on mixed types, == vs ===, undefined vs null, truthiness of "0", and array key handling all behave differently than you might expect. JsPhpize emulates JS where it can, but always test expressions that mix types.function () {} and string concatenation..toUpperCase(), .map(), .reduce(), .toFixed() depend on JsPhpize's method stubs. If a method silently produces wrong output, rewrite it as a plain expression or call a PHP helper injected into scope..pug. Always include the compiled path in stack traces when reporting bugs.js-phpize, phug, and this adapter together in composer.json, and read the diff on upgrades.How can I help you explore Laravel packages today?