Skip to content

Artisan developer guide

The Artisan package has two linked responsibilities: rendering Hypertext Markup Language (HTML) through Chrome and importing the resulting Portable Document Format (PDF) page into a NextPDF document. When you debug issues, keep the Chrome, parser, and importer boundaries separate.

Use this guide when you write renderer integrations, long-lived workers, parser diagnostics, or tests for nextpdf/artisan.

LayerOwned byResponsibilityDo not put here
ApplicationApplicationAuthorize HTML generation and choose renderer configuration.Browser process management.
HTML policyApplication and packageReject unsafe or oversized HTML before rendering.Tenant authorization or business decisions.
Chrome renderernextpdf/artisanRender HTML into a standalone PDF produced by Chrome.General PDF repair or arbitrary PDF editing.
Parser/importernextpdf/artisanParse the rendered PDF and import one page as a form XObject.Full PDF conformance validation.
Core enginenextpdf/nextpdfPlace imported form objects and write the final document.Chrome DevTools Protocol (CDP) lifecycle.
StageBehaviorDeveloper action
Config creationChromeRendererConfig defines the binary, timeout, Cascading Style Sheets (CSS), input-size, and sandbox behavior.Use environment-specific configuration instead of hard-coded runtime guesses.
Renderer creationChromeHtmlRenderer owns a BrowserPool.Reuse the renderer inside a worker, then close it during shutdown.
HTML validationSecurity policy checks size and wraps the document in default CSS.Validate caller authorization before this stage.
Chrome printCDP renders a standalone PDF.Keep external resources blocked unless a reviewed policy allows them.
PDF parsePdfReader::parse() reads xref data, pages, objects, resources, and revisions.Treat parser failures as render failures unless diagnostics are the goal.
Page importPageImporter::import() extracts page content, media box, resources, and embedded objects.Import page 0 unless the workflow deliberately chooses another page.
PathPurpose
app/Pdf/Renderers/*Application wrapper around ChromeHtmlRenderer.
app/Pdf/Templates/*HTML template rendering and data transfer object (DTO)-to-view mapping.
app/Pdf/Policies/*HTML size, resource, and tenant rendering policy.
tests/Pdf/Renderer/*Renderer smoke tests with small HTML fixtures.
tests/Pdf/Parser/*Parser fixtures for imported Chrome output.

Keep template rendering separate from browser rendering. Pass the renderer final HTML and a known page width.

<?php
use NextPDF\Artisan\ChromeHtmlRenderer;
use NextPDF\Artisan\ChromeRendererConfig;
use NextPDF\Artisan\PageImporter;
use NextPDF\Parser\PdfReader;
$renderer = new ChromeHtmlRenderer(new ChromeRendererConfig(
renderTimeout: 30,
maxHtmlSize: 1_000_000,
));
$result = $renderer->render($html, widthPt: 595.28);
$reader = new PdfReader($result->getPdfData());
$reader->parse();
$form = (new PageImporter())->import($reader);

Create one renderer per worker process or per request scope. Reuse it to avoid repeated Chrome startup cost. Close it explicitly to prevent process leaks during worker shutdown.

<?php
final class InvoiceChromeRenderer
{
public function __construct(
private readonly ChromeHtmlRenderer $renderer,
) {}
public function renderInvoice(string $html): string
{
return $this->renderer
->render($html, widthPt: 595.28)
->getPdfData();
}
public function close(): void
{
$this->renderer->close();
}
}

Use the parser application programming interfaces (APIs) when Chrome output fails to import. Keep diagnostics read-only, and avoid mutating parser state after a successful import.

Diagnostic questionAPI to useExpected signal
Does the file parse?PdfReader::parse()Throws for invalid PDF structure.
Does page 0 exist?PdfReader::getPage(0)Returns a PdfObject.
Is there content?PdfReader::getPageContentStream($page)Non-empty content stream.
Are resources present?PdfReader::getPageResources($page)Resource dictionary array.
Are there incremental revisions?PdfReader::getRevisionCount()Count greater than one.
Which object failed?PdfTokenizer::getOffset() and parser exception context.Byte offset for fixture reduction.
Extension pointUse it forConstraint
ChromeRendererConfig::fromArray()Framework configuration mapping.Unknown or mistyped optional values fall back to defaults.
HtmlSecurityPolicyInterfaceParse-layer HTML policy.Does not replace transport, process, or authorization controls.
LoggerInterfaceRender and browser diagnostics.Do not log HTML content by default.
BrowserPoolLong-lived Chrome process reuse.Must be closed on worker shutdown.
PageImporterEmbedding a parsed external page.Reader must be parsed first.
Parser classesDiagnostics and imported Chrome output.Not a general PDF repair toolkit.
  1. Reproduce the HTML fragment in a minimal render test.
  2. Validate maxHtmlSize, default CSS, and Chrome binary path.
  3. Render with a fixed width in points.
  4. Parse the returned PDF bytes with PdfReader::parse().
  5. Import page 0 unless the workflow deliberately chooses another page.
  6. Add fixture tests for the smallest HTML that reproduces each failure.
  7. Close the renderer in worker shutdown hooks.
FailureWhere it should be handledRecommended response
Chrome binary missingDeployment check and renderer construction path.Fail readiness before accepting render traffic.
Oversize HTMLHTML policy.Reject before starting Chrome.
Browser timeoutRenderer boundary.Fail the render, and record template name, size, width, and timeout.
Parser failureImport boundary.Store a small sanitized fixture for debugging when policy allows it.
Browser process leakWorker lifecycle.Close on shutdown and restart after controlled render counts.
ConcernDefaultWhen to override
Render timeout30 seconds.Increase for measured, bounded documents only.
Max HTML size5,000,000 bytes.Lower for public endpoints.
SandboxEnabled.Disable only when container constraints require it, and the host is isolated.
HeightAuto when heightPt <= 0.Use fixed height for strict layout contracts.
External resourcesBlocked by renderer policy.Allow only through a reviewed resource policy.
  • Render tests cover representative HTML and CSS.
  • Security tests cover oversize HTML and blocked resource attempts.
  • Import tests assert the returned form object has content, media box, and resources.
  • Parser tests cover cross-reference (xref) table, xref stream, object stream, and malformed fixture cases.
  • Worker tests call close() and verify no browser process remains.
  • Performance tests record render time by template and content size.