Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pug Filter Stylus Laravel Package

pug-php/pug-filter-stylus

Adds Stylus stylesheet support to Pug templates in PHP, so you can write Stylus inside your .pug files and have it compiled automatically. A small filter plugin for the pug-php renderer—install it, register the filter, and keep styles alongside your markup.

View on GitHub
Deep Wiki
Context7

Getting Started

What this package does: it registers .pug as a view engine with Laravel's view finder, so view('emails.welcome') will happily resolve resources/views/emails/welcome.pug. Templates are compiled to cached PHP, so at runtime you get normal Laravel view behaviour with Pug syntax on top. Release 2.1.0 widens the dependency to allow pug-php 3, which means you can now run the wrapper against the current engine line (PHP 7+ only) instead of being pinned to pug-php 2.

Minimal steps:

composer require pug/laravel
php artisan vendor:publish --provider="Pug\PugServiceProvider"   # config/pug.php

Auto-discovery handles the service provider on modern Laravel; on older 5.x apps register Pug\PugServiceProvider manually in config/app.php.

Then drop a file in place and render it:

//- resources/views/hello.pug
doctype html
html
  body
    h1 Hello #{name}
Route::get('/hello', fn () => view('hello', ['name' => 'Taylor']));

The extension is configurable (pug.extension), and both hello.pug and hello.blade.php can coexist — resolution order is what the config says, so be deliberate if you have same-named files.

Where to look first: config/pug.php. That single file controls the extension, the compiled-template cache path, and the option array passed straight through to the underlying Pug\Pug instance. Most "why is it doing that?" questions end there.

Best first use case: don't port your app shell. Pick a high-churn, low-risk corner — transactional emails, notification templates, or a static marketing/legal page. Those are self-contained, easy to eyeball, and give you a feel for the syntax tax before you commit anything load-bearing. If the team doesn't already know Pug, converting a single mailable is a good two-hour spike that either sells the approach or kills it cheaply.

Implementation Patterns

Layouts replace @extends/@section:

//- layouts/app.pug
doctype html
html
  head
    title #{title ?? 'App'}
  body
    block content
//- dashboard.pug
extends layouts/app
block content
  h1 Dashboard

include/mixin cover partials and reusable UI. Mixins are the closest thing to Blade components and are the main reason teams stay with Pug — argument-driven markup with no @props ceremony. If you need class-based components with slots and attribute bags, keep those in Blade; don't rebuild them in Pug.

Data passing is identical to Blade. view(), View::share(), view composers, $errors, old() — all unchanged, because the compiled output is a plain PHP view. That also means @csrf, @auth and friends are not available; use csrf_field() / auth()->check() in an expression instead.

Incremental adoption is the sane pattern. Run Pug for emails and static pages, Blade for anything Livewire/Inertia touches. Livewire components must be Blade; don't try to fight that.

Mailables and PDFs are the sweet spot:

public function build()
{
    return $this->view('emails.receipt')->with(['order' => $this->order]);
}

Same for laravel-snappy / dompdf HTML sources — Pug's indentation-heavy markup is genuinely nicer for table-based email layouts than nested Blade divs.

Deployment: compiled templates live in the cache path from config/pug.php. Add php artisan view:clear to your deploy script — and be aware php artisan view:cache (Laravel 8+) does not know about .pug files, so your Pug templates get compiled lazily on first request after deploy. On a multi-server setup, either pre-warm with a request or accept the first-hit cost.

Config sketch for production:

// config/pug.php
'extension' => '.pug',
'basedir'   => resource_path('views'),
'options'   => [
    'cache'  => env('APP_ENV') === 'production',
    'pretty' => false,
],

basedir matters: without it, include/extends paths resolve unpredictably once templates live in subdirectories. Set it explicitly and use paths relative to resources/views.

Extension point: custom keywords/filters go in the options array (custom_keywords, etc.) or via a small service provider that rebinds the Pug\Pug instance. This is the escape hatch for domain-specific helpers — e.g. a +money($amount) mixin is usually enough, but a real keyword is there if you need it.

Gotchas and Tips

Upgrading to 2.1.0 / pug-php 3. This is the headline change and it is potentially breaking for anyone with a hand-tuned options array:

  • pug-php 3 requires PHP 7.0+ and drops the 5.x line. Check your CI matrix before bumping.
  • Several options were renamed or tightened (prettyprint → pretty is the common one). If you set legacy keys in config/pug.php, they may now be silently ignored — which looks like "my output formatting changed for no reason."
  • The php expression language is the default; if you were relying on JS-flavoured expressions you may see new errors.
  • Because 2.1.0 only widens the constraint, composer update can pull pug-php 3 underneath you on an existing app. Pin explicitly (pug/laravel:^2.1 pug-php/pug:^3) and re-render every template in a branch rather than discovering it in production.

Errors point at the wrong line. Compile failures reference the generated PHP, not your .pug source. Keep pretty => true in local so the compiled file in the cache directory is readable, then open it and diff against your template. A source-mapped error message is still a wish, not a feature.

Indentation is the syntax. Tabs vs spaces, or one stray space in an if block, produces either a compile error or — worse — silently wrong nesting that renders fine in dev and breaks when a conditional branch flips. Enforce a linter (pug-lint from npm works on the markup even though the engine is PHP) and an .editorconfig.

Escaping differs from Blade and it bites. #{ } escapes, !{ } does not. Teams habituated to {{ }} vs {!! !!} will interpolate user data unescaped at least once. Grep for !{ in review; treat it like {!! !!}.

You cannot mix Blade into a Pug file. No @if, no @include, no {{ }}. Raw PHP can be embedded with - lines (- $total = array_sum($items)), which is useful but is also how a template quietly becomes a controller.

Pug ≠ pug.js. The syntax is shared, but the expression language is PHP and JS-only constructs (loops with JS semantics, JS closures, Object.keys) won't work. Designers porting a Pug mockup from a Node project will hit this wall — worth saying out loud up front, because it's the most common source of "this package is broken" frustration.

Testing works normally. assertViewHas, assertSee, assertViewIs all behave, since it's a regular view render. Snapshot-test one or two compiled outputs after a pug-php major bump; that's the cheapest way to catch the option-renaming class of regression.

Don't rewrite the whole app. Pug is a genuine ergonomics win for markup-heavy, logic-light templates and a genuine liability everywhere else. The teams that get value from this package scope it to emails, PDFs and static pages, and leave Blade to do the application's job.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle