0

I am trying to make Spatie Browsershot work on Windows with XAMPP. First of all I installed puppeteer:

npm install -g puppeteer

At first I wanted to output the result directly to the browser, so I had the following code in the controller:

use Spatie\Browsershot\Browsershot;

    public function createPDFWithBrowsershot(Request $request)
    {
        Browsershot::html('<h1>Test</h1>')->pdf();
    }

But then I get the following error:

The command "node ^"C:^\xampp^\htdocs^\my_project^\vendor^\spatie^\browsershot^\src/../bin/browser.js^ ..."

So then I tried to do the following (though not sure it's a good option for Windows, but it did make the above error disappear):

    public function createPDFWithBrowsershot(Request $request)
    {
        Browsershot::html('<h1>Test</h1>')->setNodeBinary('PATH %~dp0;%PATH%;')->pdf();
    }

And the error above disappeared, however the page was blank.

So instead of trying to output the PDF to the browser, I tried to save it as a pdf file:

    public function createPDFWithBrowsershot(Request $request)
    {
        $save_to_file = 'C:/pdfs/file.pdf';
        Browsershot::html('<h1>Test</h1>')->setNodeBinary('PATH %~dp0;%PATH%;')->savePdf($save_to_file);
    }

But I got a new error:

For some reason Chrome did not write a file at C:/pdfs/file.pdf. Command ======= [] Output ======

I also tried several other paths:

 $save_to_file = 'C:\pdfs\file.pdf';

or

$save_to_file = storage_path('pdfs/file.pdf');

But I get the same error.

I even tried uninstalling the global puppeteer and installing it only in my project:

npm install puppeteer

And even installing chromium:

npm install chromium

Nothing makes it work

Why?

apokryfos
  • 38,771
  • 9
  • 70
  • 114
pileup
  • 1
  • 2
  • 18
  • 45

1 Answers1

0

It's sometimes hard to config Spatie BrowserShot, harder to send it in production (you will have to setup you prod environment and it can be a pain). Here is the config i use locally on my windows 10, hope it will help you :

My Spatie BrowserShot version in composer.json

"spatie/browsershot": "^3.56",

My puppeteer version in package.json

"puppeteer": "^15.1.1",

The controller which recieve the Illuminate\Http\Request from frontend

public function handleRequest(Request $request)
 {
   if ($request->has('print')) 
   {
     $view = view('view.to.render', [
       'parameter' => $parameter
     ])->render();
    
     $name = 'name_of_my.pdf';
    
     Browsershot::html($view)
     ->addChromiumArguments([
     'font-render-hinting' => 'none',
     'allow-running-insecure-content',
     'autoplay-policy' => 'user-gesture-required',
     'disable-component-update',
     'disable-domain-reliability',
     'disable-features' => 'AudioServiceOutOfProcess,IsolateOrigins,site-per-process',
     'disable-print-preview',
     'disable-setuid-sandbox',
     'disable-site-isolation-trials',
     'disable-speech-api',
     'disable-web-security',
     'disable-setuid-sandbox',
     'disable-dev-shm-usage',
     'disk-cache-size' => 33554432,
     'enable-features' => 'SharedArrayBuffer',
     'hide-scrollbars',
     'ignore-gpu-blocklist',
     'in-process-gpu',
     'mute-audio',
     'no-default-browser-check',
     'no-pings',
     'no-sandbox',
     'no-zygote',
     'use-gl' => 'swiftshader',
     'window-size' => '1920,1080',
     'single-process'
     ])
     ->timeout(120000)
     ->waitUntilNetworkIdle()
     ->scale('0.8')
     ->format('a4')
     ->landscape()
     ->save(public_path('downloads').'/'.$name);
   }
   else {
     // do other stuff
   }
 }

The template you use has to hide some elements in order to be "printable", here an exemple

@php $is_print = request()->has('print') ? true : false @endphp

<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Title</title>

        @if (! $is_print)
            <meta name="csrf-token" content="{{ csrf_token() }}">

            <link rel="stylesheet" href="{{ asset('path-to-file.css') }}">
        @endif
    </head>

    <body>
        <div id="app">
            @if (! $is_print)
                <!-- here the stuff you display to the user -->
            @endif

            <!-- here the stuff you display only in the PDF -->
        </div>

        <script src="{{ asset('path-to-file.js') }}"></script>
    </body>
</html>

EDIT in production, you will have to set the paths for the chrome standalone and the node modules, here is mine in linux machine

->setChromePath('/usr/bin/google-chrome')
->setNodeModulePath('/usr/lib/node_modules')
jurandou
  • 100
  • 6