3

I would like to use the Spatie/Browsershot library on my Laravel10 project but can't quite figure out how to make it work on a Docker environnement.

Error Output (Spatie\Browsershot\Exceptions\CouldNotTakeBrowsershot)

For some reason Chrome did not write a file at `example.pdf`. Command ======= [] Output ======

Controller Method (to test the library)

public function getPDF()
{
    return Browsershot::html('<h1>Hello world!!</h1>')->save('example.pdf');
}

// same result with:

public function getPDF()
{
    return Browsershot::html('<h1>Hello world!!</h1>')
        ->setRemoteInstance('chrome', 9222)
        ->save('example.pdf');
}

docker-compose.yml

version: '3'
services:
  phpfpm:
    container_name: '${APP_NAME}'
    build:
      args:
        user: '${WWWUSER}'
        uid: '${WWWGROUP}'
      context: ./docker
      dockerfile: Dockerfile
    working_dir: /var/www/html
    volumes:
      - ./:/var/www/html
    networks:
      - network_project
    depends_on:
      - mariadb
    restart: unless-stopped

  chrome:
    image: 'zenika/alpine-chrome:80'
    entrypoint: ["chromium-browser", "--headless", "--disable-gpu", "--disable-software-rasterizer", "--disable-dev-shm-usage", "--no-sandbox", "--remote-debugging-address=0.0.0.0", "--remote-debugging-port=9222"]
    ports:
      - "9222:9222"
    networks:
      - network_project

  nginx:
    image: nginx:latest
    networks:
      - network_project
    depends_on:
      - mariadb
    ports:
      - '127.0.0.1:${APP_PORT}:80'
    volumes:
      - ./docker/nginx/tkt.conf:/etc/nginx/conf.d/default.conf
      - ./:/var/www/html
    links:
      - phpfpm
    restart: unless-stopped

  redis:
    image: 'redis:alpine'
    ports:
      - '127.0.0.1:${FORWARD_REDIS_PORT:-6379}:6379'
    volumes:
      - 'redis_volume:/data'
    networks:
      - network_project
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      retries: 3
      timeout: 5s
    restart: unless-stopped

  mariadb:
    image: 'mariadb:10.7.4'
    ports:
      - '127.0.0.1:${FORWARD_DB_PORT:-3306}:3306'
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
      MYSQL_DATABASE: '${DB_DATABASE}'
      MYSQL_USER: '${DB_USERNAME}'
      MYSQL_PASSWORD: '${DB_PASSWORD}'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    volumes:
      - 'mariadb_volume:/var/lib/mysql'
    networks:
      - network_project
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping" ]
    restart: unless-stopped

  mailhog:
    image: mailhog/mailhog
    networks:
      - network_project
    ports:
      - "1025:1025"
      - "8025:8025"
    restart: unless-stopped

networks:
  network_project:
    driver: bridge
volumes:
  mariadb_volume:
    driver: local
  redis_volume:
    driver: local

More context

I have puppeteer.js installed (npm install -g puppeteer) also as chromium (npm install chromium).

My app is running

  • Laravel 10 (php 8.2)
  • InertiaJS

1 Answers1

3

I want to share my solution, which may be useful to someone.

1)First of all, we need update docker-compose.yml (we will add chromium service-container) :

chromium:
  image: zenika/alpine-chrome
  command:
    [
      chromium-browser,
      "--headless",
      "--disable-gpu",
      "--remote-debugging-address=0.0.0.0",
      "--remote-debugging-port=9222",
    ]
  cap_add:
    - SYS_ADMIN
  volumes:
    - tmpfiles:/tmp
  ports:
    - "9222:9222"
  networks:
    sail:
      ipv4_address: 172.22.0.100

2)The chromium service-container use a static IP, so we need to update our sail network:

networks:
  sail:
    ipam:
      driver: default
      config:
        - subnet: "172.22.0.1/24"

3)In the next step, you should update volumes:

volumes:
    tmpfiles:
        driver: local

4)Don't forget add this volume to your service-container with laravel:

services:
    laravel.test:  # Here will be name of your service-container
        ...
         volumes:
            - 'tmpfiles:/tmp' # This line
            - '.:/var/www/html'
        ...
    
         depends_on:
         - chromium # This line too

Item 5: Rebuild docker

# Step 1: Stop the containers
./vendor/bin/sail down

# Step 2: Rebuild the containers without cache
./vendor/bin/sail build --no-cache

# Step 3: Start the containers
./vendor/bin/sail up

Thats all, now you can use browsershot like this

$bs = Browsershot::html($html)
            ->format('A4')
            ->showBackground()
            ->margins(10, 10, 10, 10);
if (config('browser-shot.HOST')) {
    $bs->setRemoteInstance(config('browser-shot.HOST'), '9222')
        ->waitUntilNetworkIdle();
}

return $bs->pdf();

for convenience, i have created browser-shot.php in config directory

<?php

return [
    'PATH_CHROME' => env('PATH_CHROME'),
    'PATH_NODE_MODULES' => env('PATH_NODE_MODULES'),
    'HOST' => env('BROWSERSHOT_CHROMIUM_HOST', '127.0.0.1'),
    'NODE' => env('NODE', '/usr/bin/node'),
    'NPM' => env('NPM', '/usr/bin/npm'),
];

Don't forget add this line to your env file

BROWSERSHOT_CHROMIUM_HOST=172.22.0.100

ArtemPD
  • 31
  • 1
  • 5