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

Html2Media Laravel Package

institut-agro-ead/html2media

A Laravel/PHP package for converting HTML into media such as images or PDFs. Generate visual assets from Blade views or raw markup via a simple, configurable API—useful for reports, thumbnails, social cards, and automated document generation.

View on GitHub
Deep Wiki
Context7

Getting Started

html2media is a thin Laravel wrapper around HTML → media conversion (PDF and images), with a fluent call-site API and a config file for output defaults. The day-to-day value is that you stop shelling out to headless Chrome or wkhtmltopdf and express “turn this Blade view into a PDF” in framework idioms.

Minimal steps:

  1. Install and publish config:

    composer require institut-agro-ead/html2media
    php artisan vendor:publish --tag=html2media-config
    
  2. Read config/html2media.php first — this is where file name, orientation, margins, paper size, output format/quality, and (critically, per v1.0.3) the rerender/print behaviour live. Most surprises are config keys, not code.

  3. Check the service provider for the binding and any facade alias, so you know whether to inject a class or call a facade.

  4. First use case — an invoice PDF from a Blade view:

    use InstitutAgroEad\Html2Media\Facades\Html2Media;
    
    Route::get('/invoices/{invoice}/pdf', function (Invoice $invoice) {
        return Html2Media::view('invoices.pdf', ['invoice' => $invoice])
            ->filename("invoice-{$invoice->number}.pdf")
            ->orientation('portrait')
            ->download();
    });
    

If that returns a PDF, you have the whole core loop. If you use Filament, register/see the action integration next — that's the second surface area worth wiring early.

Implementation Patterns

Blade view as the primary source of truth. Treat the PDF template as a normal Blade view under resources/views/pdf/ and pass data in like any other view. This keeps print layouts reviewable, diffable, and testable with the same tooling as web views. Reserve raw-HTML strings for content that is already rendered elsewhere (rich-text fields, generated tables).

Three delivery modes, one builder. The package distinguishes download vs print (and image export). Model this explicitly in your controller:

$doc = Html2Media::view('invoices.pdf', compact('invoice'));

return match ($request->query('mode')) {
    'print'    => $doc->print(),      // browser print / inline
    'preview'  => $doc->image(),      // thumbnail
    default    => $doc->download(),   // attachment
};

Per-document overrides, not global config. Keep config/html2media.php as the safe default and set orientation, margins, filename, and format at the call site. Different documents legitimately want different layouts; encoding that in config turns into constant churn.

Filament action pattern. For admin panels, wrap generation in a Filament action whose closure builds the payload at click time (not at mount time) so you render current row state:

Action::make('downloadPdf')
    ->action(fn (Invoice $record) => Html2Media::view('invoices.pdf', ['invoice' => $record])
        ->filename("invoice-{$record->number}.pdf")
        ->download());

Don't precompute a closure over stale Eloquent state; pass the record and let the action resolve it.

Queue heavy documents. Large templates (many line items, embedded images) are CPU/memory heavy. Dispatch a job, write the file to a disk (Storage::disk('invoices')->put(...)), then notify or expose a signed URL. This also dodges request timeouts.

Centralize behind an adapter. v1.0.x is still stabilising (the 1.0.3 patch fixes rerender behaviour). Wrap Html2Media in a small DocumentRenderer service so an upgrade or API shift touches one class, not every controller and Filament resource.

Testing. Assert on the artifact, not the implementation: response content type, non-empty binary, and a snapshot of the HTML passed to the converter. A cheap smoke test that renders your two highest-value documents will catch silent regressions where a template still “works” but produces a blank or truncated PDF.

Gotchas and Tips

  • v1.0.3’s “forcing print content to rerender” is the headline fix — verify it actually fires. The classic failure mode with a force-refresh flag is that it’s read at construction time, so calling it after a first render has no effect. Either rerender before the first render in a request or rebuild the renderer instance. Log or dd() inside the path to confirm the forced branch executed — the visible output looks the same either way.
  • Rerender is not global invalidation. Forcing one document to rebuild won’t flush compiled Blade views, PDFs already on disk, or CDN copies. Trace each layer of your output path (view cache → intermediate HTML → final binary) and invalidate what you actually rely on.
  • Config caching. php artisan config:cache in production means edits to html2media.php (orientation, margins, rerender behaviour) won‘t take effect until you re-run it. If toggling a setting changes nothing, this is almost always why.
  • Compiled views are a separate cache. If output is stale even after a forced rerender, run php artisan view:clear to distinguish template compilation from package caching.
  • Asset URLs and images. Relative asset() paths require a correct APP_URL in the environment doing the rendering (queues included). For logos and fonts, prefer absolute URLs or inlined base64 — a headless renderer on a worker has no browser context and will silently drop unresolvable resources.
  • CSS support depends on the underlying engine. If the package delegates to headless Chrome, modern layout mostly works; if it wraps another engine, flexbox/grid may degrade. Test the actual PDF, not the browser preview — a layout that looks fine in dev tools can collapse on paper.
  • Long-lived workers. Under Octane/queues, don’t register the converter as a singleton if it caches state internally, or always rerender at the start of each job. Shared state across requests is a classic source of “yesterday’s invoice” bugs.
  • Concurrency on shared output paths. Two simultaneous generations writing to the same filename can race. If you write to a deterministic path, wrap it in Cache::lock(...).
  • Memory and timeouts. Large documents blow memory_limit and PHP execution time rather than failing gracefully. Push to a queue and set an explicit timeout on the job before you discover this in production.
  • Version pinning. At 1.0.x with active patch releases, pin ("institut-agro-ead/html2media": "1.0.*") and keep the adapter thin. The rerender fix signals active maintenance and ongoing churn — budget for a minor upgrade when it lands.
  • No automated verification = added risk. If you can’t assert on the rendered artifact in CI, adopting any print layer trades a build problem for a silent-output problem. Add the smoke test before you scale usage.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route