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

Blade Laravel Package

jenssegers/blade

Use Laravel's Blade templating engine as a standalone package outside of Laravel. jenssegers/blade wraps the Blade compiler in a simple, lightweight API, letting any PHP project render .blade.php views with caching, layouts, sections, includes, and custom directives—without pulling in the full frame...

View on GitHub
Deep Wiki
Context7

Getting Started

Install into a Composer/PSR-4 project and let Composer resolve the Illuminate view stack:

composer require jenssegers/blade:^2.0
composer show illuminate/view   # know which Laravel major you actually got

Two directories are the entire configuration: where .blade.php files live, and where compiled PHP is cached.

use Jenssegers\Blade\Blade;

$blade = new Blade(__DIR__.'/views', __DIR__.'/cache/views');
echo $blade->render('emails.welcome', ['name' => 'Ada']);

Look first at: the constructor (view path(s) + compile cache path), then render(), then the handful of extension methods you will actually use — share(), composer(), directive(), exists(), addNamespace(), make(). That is the whole public surface: no kernel, no service provider, no app(). Everything else you will ever need lives on the underlying Illuminate\View\Factory/BladeCompiler, and you have to reach for it deliberately.

First real use case: transactional email or a PDF invoice. Both are "render a string and hand it to something else," which is exactly the shape this package is good at.

$html = $blade->render('mail.order-shipped', ['order' => $order]);
$mailer->sendHtml($to, 'Your order shipped', $html);

Do the spike on one template you already ship. If it renders identically to the legacy output (diff the HTML, don't just eyeball it), you have your proof and your first snapshot test in one go.

Before writing a second template, wrap it. This is the single highest-leverage thing you will do on day one:

final class TemplateRenderer
{
    public function __construct(private \Jenssegers\Blade\Blade $blade) {}

    public function render(string $view, array $data = []): string
    {
        return $this->blade->render($view, $data);
    }
}

That class turns a single-maintainer dependency into a replaceable implementation detail, and it is the cheapest insurance you will buy on this package. Everything downstream — swap to illuminate/view, move to full Laravel, or replace with Twig — becomes a change to one file.

Implementation Patterns

Bootstrap once, inject everywhere. Construct Blade in your front controller or DI container as a singleton. Never new Blade(...) inside a loop or per-request handler; each instance re-registers the engine resolver and compiler, and the compiled-template cache lookup is the only thing standing between you and recompiling on every call.

Use multiple view paths for layering. The first argument accepts an array, and the finder takes the first match. That gives you per-tenant or per-theme overrides essentially for free:

$blade = new Blade(
    [__DIR__."/views/tenants/{$tenant}", __DIR__.'/views'],
    $cachePath
);

Namespaces for partial libraries. Share a partials/ tree across services with addNamespace('ui', '/shared/views') and then @include('ui::button'). This is how you get "one design system, several services" without copy-pasting partials.

Globals via share(), per-view data via the render call. Share the boring stuff once (app name, locale, current year, brand color, base URL for a self-built url() helper) and reserve the second argument for the view's actual contract. Keeping globals in one bootstrap file makes it obvious what every template implicitly assumes.

Composers for anything cross-cutting. Prefer a composer over stuffing data at each call site:

$blade->composer('mail.*', fn ($view) => $view->with('supportEmail', $cfg));

Composers receive the Illuminate\View\View instance, so with()/getData() are available. This keeps a mail directory from each independently re-fetching config, and gives you one place to change when a piece of shared context moves.

Custom directives sparingly, and only for presentation. A money formatter is fine:

$blade->directive('money', fn ($expr) => "<?php echo number_format((float) ($expr), 2); ?>");

Every directive you add is a directive that must be re-registered in any future Laravel app, and is code that escapes snapshot tests unless exercised. Keep the list short and colocate it in one bootstrap file.

Escaping is intact — treat {!! !!} as a code-review flag. {{ $x }} compiles to e($x) and illuminate/support ships the helper, so auto-escaping works exactly as in Laravel. Your XSS surface is now entirely the raw-output blocks and the data you allow into them. Grep for {!! in CI and require an explicit reason for each.

Render once, reuse the string. For batch work, build the HTML once per distinct payload, then loop over recipients sending the same string — do not re-render per row. Push bulk generation onto a queue and write PDFs/HTML to disk or object storage rather than rendering inline in a web request.

Snapshot-test the output. Fix the data (including dates and money), render, and assert the HTML against a fixture. That test is what makes the eventual swap to illuminate/view or full Laravel a contained change rather than a rewrite, and it is the only reliable guard against silent drift when the Illuminate tree moves underneath you.

Warm the cache on deploy. Render your highest-traffic templates during deploy (a small CLI script calling render() with dummy data) and clear the compiled directory as part of the release. Cold cache is the slow path; stale cache is the wrong-output path. Doing both in a defined order removes the ambiguity.

Gotchas and Tips

The compile cache directory is the number one first-render failure. Recent Illuminate versions will mkdir for you, but with the deploying user's ownership and default umask — which is not necessarily the PHP-FPM user. Create it explicitly, chmod it, and assert writability at boot (fail fast with a clear message, not an exception deep inside a view). Never point two deployments (blue/green, multiple containers on a shared volume) at the same cache directory; the mtime comparison across hosts is not trustworthy.

Stale compiled templates are silent. Blade invalidates by comparing template mtime to compiled-file mtime. docker COPY, rsync without -t, and NFS clock skew all break that assumption — you edit a template, deploy, and get last week's markup with no error. If your build process doesn't preserve mtimes deterministically, clear the compiled directory on every deploy rather than trusting mtime.

A large slice of Laravel's template vocabulary does not exist here. Missing helpers: route(), url(), asset(), config(), csrf_field(), old(), __()/trans(), env(). Missing directives: @csrf, @vite, @livewire, @inertia. Worse, several directives compile cleanly and then throw at render time — @auth, @guest, @can, @cannot, @env, @lang, and @error compile to auth(), app('gate'), app('translator'), or a shared $errors bag that is never bound. These are runtime failures, not parse errors, so they surface only when that branch executes. Test every branch of a template, not just the happy path — a @auth inside an email footer will pass every render until someone triggers the logged-in variant.

Inject your own container if you need resolution. The constructor accepts an Illuminate\Container\Container. Pass your own and pre-bind the services your directives rely on. Do not assume global app() resolves to your container unless your pinned version says so — verify it, don't hope. If you find yourself needing app() inside templates, that is a signal the logic belongs in the composer or the adapter instead.

Reach the compiler when directives aren't enough. Component namespaces, anonymous component paths, and compileString() for rendering a template stored in a database column all live on the BladeCompiler, not on the wrapper. Access it through the compiler accessor on Blade or supply a preconfigured container. Note that compileString() + eval is off the supported path and a poor fit for anything user-authored. Blade is not a hostile-input sandbox; if that requirement appears, re-evaluate against Twig's sandbox rather than extending this.

Errors are exceptions, so catch them at the boundary. A missing view throws InvalidArgumentException; compile and runtime failures surface as Illuminate\View\ViewException. Catch in your TemplateRenderer, log the view name and the keys of the data array (never the values — they may contain PII), and return a fallback. Decide before production what a rendering failure means for an email: a queued retry, or a degraded plaintext message? Guessing under incident pressure is how you ship a blank confirmation email.

Pin the whole Illuminate tree and audit it. Run composer why illuminate/view before adopting, and run composer update --dry-run against Laravel majors deliberately rather than inheriting them on a routine update. Upstream drift, not this package's own code, is the compatibility risk — the 2.0.1 release being essentially "support for Laravel 11" tells you the maintenance model is reactive. Assign a named owner and a cadence for re-checking, or this quietly becomes unowned infrastructure.

Don't install it next to a real Laravel app. It adds risk and buys nothing there; use the framework engine. Conversely, keep templates free of custom directives where you can — that is what lets the same .blade.php files move into Laravel later untouched. The portability of the template files is the real long-term value; protect it.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console