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

duncan3dc/blade

duncan3dc/blade brings Laravel's Blade templating engine to any PHP project without Laravel. Render views with familiar Blade syntax, directives, layouts, includes, and caching, making it easy to add clean, reusable templates to standalone apps, scripts, or legacy codebases.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer alongside the framework-agnostic PSR dependencies:

composer require duncan3dc/blade

Two directories are required up front: one for your .blade.php views and one for the compiled PHP cache. Create both before the first render — the package does not create them for you:

mkdir -p resources/views storage/blade-cache

The minimum viable bootstrap is the BladeInstance constructor (views path, then cache path):

use duncan3dc\Laravel\BladeInstance;

$blade = new BladeInstance(
    __DIR__ . '/resources/views',
    __DIR__ . '/storage/blade-cache'
);

echo $blade->render('hello', ['name' => 'World']);

A working resources/views/hello.blade.php:

Hello, {{ $name }}!

Look first at the BladeInstance class in the repo — it is the only public surface you need. From there the underlying classes (Illuminate\View\Factory, Illuminate\View\FileViewFinder, Illuminate\View\Compilers\BladeCompiler) are what you'll be reaching into for anything beyond basic rendering.

Best first use case: transactional HTML emails or a lightweight static site generator, where you want layouts, sections, and escaping without dragging in Eloquent, routing, and the HTTP kernel.

Implementation Patterns

Layouts and partials. Standard Blade semantics work unchanged — @extends, @section, @yield, @include, @each, @push/@stack:

{{-- layouts/app.blade.php --}}
<html><body>@yield('content')</body></html>

{{-- pages/home.blade.php --}}
@extends('layouts.app')
@section('content')
    @include('partials.header', ['title' => $title])
@endsection

Choosing between render, display, and make. render() returns a string (good for emails, writing to disk, tests). display() echoes directly (good for controllers). make() returns an Illuminate\View\View if you need with(), nest(), or to inspect data before rendering.

$view = $blade->make('report', compact('rows'));
$view->with('generatedAt', now());
echo $view->render();

Global data via share(). Anything that appears on every template — config, site name, current user — should be shared once in the bootstrap rather than threaded through every render call:

$blade->share('siteName', config('app.name'));

Composers for view-specific data. Register closures (or class-based composers) so a partial can request data lazily instead of the caller assembling it:

$blade->composer('partials.nav', function ($view) use ($container) {
    $view->with('links', $container->getMainNav());
});

Class-based composers behave exactly as in Laravel; they receive the View in compose().

Custom directives. Laravel's full directive set isn't present, so register what you need. The callback returns the literal PHP/Blade string:

$blade->directive('money', function ($expression) {
    return "<?php echo number_format($expression, 2); ?>";
});

Rendering a string without a file. Useful for user-editable snippets or mail bodies stored in a DB column:

echo $blade->renderString('Hi {{ $name }}', ['name' => 'Ada']);

Framework integration. This package is a natural fit as the view layer inside Slim, Laminas, a WordPress theme, or a custom MVC kernel. The pattern is always the same: build one BladeInstance in your container (singleton) and inject it into controllers/services. Do not instantiate it per request if you can avoid it — the constructor wires up the finder and factory.

Namespaced views for package-style template distribution:

$blade->addNamespace('mail', __DIR__ . '/vendor/emails/views');
echo $blade->render('mail::welcome', $data);

Gotchas and Tips

  • Cache directory permissions will bite you first. The most common error is a failed to open stream or "Please provide a valid cache path" — both are almost always a missing directory or missing write permission. Log the constructor's cache path at boot to confirm what's actually in use.

  • Compiled templates persist across renders. In development, edit the view and the stale compiled file may still run if timestamps confuse the compiler (e.g. file copied with old mtime). Clear the cache directory on deploy/dev-reload; it is safe to rm -rf cache/*. In production, treat the cache dir as disposable but never clear it mid-request.

  • Line numbers in stack traces point at compiled PHP, not your Blade file. When you see compiled-xxxx.php in an exception, open that file — the class name and line are correct but the line number is off by the number of injected echo statements in the surrounding block. Map back mentally or search the compiled file for a fragment of your template.

  • Laravel helpers are absent. route(), asset(), url(), old(), csrf_field(), __(), @csrf, @auth, @can, @vite, and @livewire do not exist. You get "Call to undefined function" or "unknown directive" errors. The fix is either to function_exists-guard real helpers in your bootstrap, or register shim directives:

    $blade->directive('asset', fn ($expr) => "<?php echo '/assets/' . ltrim($expr, '/'); ?>");
    
  • No service container means no facades. Do not copy-paste Laravel templates that rely on Auth::user() or config() — those facades aren't registered. Share the data via $blade->share() or compose it in a view composer instead.

  • Escaping still applies. {{ $userInput }} is HTML-escaped; {!! $html !!} is raw. The latter is the most common XSS vector in a non-Laravel app that "just needs to render some rich text". Prefer a sanitizer on write, not on render.

  • Extension points worth knowing. $blade->getCompiler() exposes the BladeCompiler for advanced tweaking (custom escapes, precompiled extensions). $blade->getContainer() returns the lightweight container, useful for registering bindings consumed by class-based composers. $blade->directive() and $blade->composer() are the two extension points you'll use in 95% of cases.

  • Performance profile. First render of a view compiles and caches it; subsequent renders are effectively include of cached PHP. If a page feels slow, check whether the cache directory is being written (or cleared) on every request — that turns every render into a compile.

  • Testing. In PHPUnit, constructing a fresh BladeInstance per test with a sys_get_temp_dir() cache is fast enough and isolates state between tests. Just don't share a cache directory across test workers running in parallel.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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