wnx/sidecar-browsershot
Run Spatie Browsershot on AWS Lambda via Sidecar in Laravel. Generate PDFs/screenshots without installing Node, Puppeteer, or Chrome on your server—headless Chrome runs in a deployed Lambda function. Includes config publishing and Sidecar deploy workflow.
Installation
composer require wnx/sidecar-browsershot
Ensure your Laravel app is configured for Sidecar (check sidecar.php config).
Basic Usage
Register the Browsershot Sidecar function in app/Providers/SidecarServiceProvider.php:
public function registerFunctions()
{
return [
\Wnx\SidecarBrowsershot\Functions\Browsershot::class,
];
}
First Lambda Invocation
Use the sidecar facade to trigger Browsershot:
use Wnx\Sidecar\Facades\Sidecar;
$html = '<h1>Hello, Browsershot!</h1>';
$path = Sidecar::call('browsershot', [
'html' => $html,
'filename' => 'output.png',
]);
src/Functions/Browsershot.php – Core logic.config/sidecar-browsershot.php – Default settings.$pdfPath = Sidecar::call('browsershot', [
'html' => view('invoice')->render(),
'format' => 'pdf',
'options' => [
'margin-top' => '1cm',
'margin-right' => '1cm',
'margin-bottom' => '1cm',
'margin-left' => '1cm',
],
]);
$url = 'https://example.com/blog/post-123';
$imagePath = Sidecar::call('browsershot', [
'url' => $url,
'filename' => 'post-123.png',
'width' => 1200,
'height' => 630,
]);
Use Laravel Queues to offload heavy rendering:
use Illuminate\Support\Facades\Queue;
Queue::push(function () {
Sidecar::call('browsershot', [
'html' => $this->generateComplexReport(),
'filename' => "report_{$this->reportId}.pdf",
]);
});
Cache results or process outputs (e.g., upload to S3):
$result = Sidecar::call('browsershot', [
'html' => $html,
'filename' => 'temp.png',
'returnAs' => 'base64', // Return as base64 string
]);
Storage::disk('s3')->put("images/{$filename}.png", base64_decode($result));
Environment-Specific Config:
Override sidecar-browsershot.php in config/ for Lambda-specific settings (e.g., timeout, memory).
'timeout' => env('AWS_LAMBDA_TIMEOUT', 30), // Seconds
'memory' => env('AWS_LAMBDA_MEMORY', 1024), // MB
Error Handling:
Wrap calls in try-catch to handle Lambda timeouts or Browsershot failures:
try {
$path = Sidecar::call('browsershot', [...]);
} catch (\Wnx\Sidecar\Exceptions\SidecarException $e) {
Log::error("Browsershot failed: " . $e->getMessage());
// Fallback to a static image or retry logic
}
Blade Views: Pass Blade views directly:
$html = view('emails.report', ['data' => $reportData])->render();
Sidecar::call('browsershot', ['html' => $html, 'format' => 'pdf']);
Lambda Timeouts:
'timeout' => 60, // Increase if needed
'memory' => 3008, // 3GB for heavy pages
Task timed out errors.Headless Chrome Limits:
/tmp is ephemeral (512MB–10GB). Large outputs may fail.returnAs => 'base64' to avoid writing to disk, or clean /tmp post-execution:
// In your Sidecar function (extend Browsershot)
public function handle()
{
$result = parent::handle();
if (file_exists($this->filename)) {
unlink($this->filename);
}
return $result;
}
CORS/Network Issues:
curl in Lambda to verify connectivity:
exec('curl -I https://example.com', $output, $return);
Font/Resource Loading:
$html = '<style>@font-face { src: url("data:font/woff2;base64,...); }</style>';
Local Testing:
Use sidecar:test to simulate Lambda locally:
php artisan sidecar:test browsershot --html="<h1>Test</h1>"
Logging:
Enable Sidecar logging in sidecar.php:
'logging' => [
'enabled' => true,
'channel' => 'single',
],
Common Errors:
| Error | Cause | Solution |
|---|---|---|
Failed to execute process |
Missing Chrome binary | Ensure Lambda layer has Chrome installed. |
Connection refused |
Port 3000 not exposed | Use puppeteer-executable-path config. |
ENOSPC |
Disk full (/tmp) |
Increase Lambda ephemeral storage. |
TimeoutException |
Slow page load | Increase timeout or optimize HTML. |
Custom Headless Chrome Flags:
Extend the Browsershot function to pass flags:
// In your Sidecar function
protected function getChromeFlags(): array
{
return [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage', // Bypass `/dev/shm` limits
'--disable-gpu',
];
}
Post-Processing: Chain Sidecar functions for multi-step workflows:
$pdfPath = Sidecar::call('browsershot', ['html' => $html, 'format' => 'pdf']);
$optimizedPath = Sidecar::call('optimize-pdf', ['file' => $pdfPath]);
Shared Storage: Mount an EFS volume to Lambda for persistent storage of Chrome binaries or caches:
// sidecar-browsershot.php
'chrome_binary_path' => '/mnt/efs/chrome-linux/chrome',
Retry Logic: Implement exponential backoff for transient failures:
use Wnx\Sidecar\Facades\Sidecar;
$maxRetries = 3;
$retryDelay = 1000; // ms
for ($i = 0; $i < $maxRetries; $i++) {
try {
return Sidecar::call('browsershot', [...]);
} catch (\Exception $e) {
if ($i === $maxRetries - 1) throw $e;
usleep($retryDelay * (2 ** $i));
}
}
How can I help you explore Laravel packages today?