Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added prefer_local_executable: true option so that users are able to install chrome-headless-render-pdf and puppeteer locally #61

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/assets
/_build
/deps
erl_crash.dump
Expand Down
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ In development: While this usually works, it unfortunately leads to
pdf_generator to be compiled all the time again and again due to my bad Makefile
skills. Help is very much appreciated.

Eventually, if you are using Phoenix and you would like to have your npm packages installed localy, within the `/assets/node_modules` directory, simply run `npm install chrome-headless-render-pdf puppeteer` within `assets/node_modules` and pass `prefer_local_executable: true`
option when generating the PDF like this:

```Elixir
PdfGenerator.generate({:url, "http://some-url.com"}, generator: :chrome, prefer_local_executable: true)
```

# Try it out

Pass some HTML to PdfGenerator.generate:
Expand Down Expand Up @@ -114,11 +121,11 @@ html_works_too = "<html><body><h1>I need Docker, baby docker is what I need!"
{:ok, filename} = PdfGenerator.generate html_works_too, generator: :chrome, no_sandbox: true, page_size: "letter"
```

# System prerequisites
# System prerequisites

It's either
It's either

* wkhtmltopdf or
* wkhtmltopdf or

* nodejs (for Chrome-headless/Puppeteer)

Expand All @@ -132,18 +139,18 @@ those generated with wkhtmltopdf.

### global install (great for Docker images)

Run `npm -g install chrome-headless-render-pdf puppeteer`.
Run `npm -g install chrome-headless-render-pdf puppeteer`.

This requires [nodejs](https://nodejs.org), of course. This will install a
recent chromium and chromedriver to run Chrome in headless mode and use this
browser and its API to print PDFs globally on your machine.

If you prefer a project-local install, use the `compile: "make chrome"` option
in your mixfile's dependency-line.

On some machines, this doesn't install Chromium and fails. Here's how to get
this running on Ubuntu 18:

```bash
DEBIAN_FRONTEND=noninteractive PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=TRUE \
apt-get install -y chromium-chromedriver \
Expand All @@ -153,34 +160,34 @@ DEBIAN_FRONTEND=noninteractive PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=TRUE \
### local install

Run `make priv/node_modules`. This requires both `nodejs` (insallation see
above) and `make`.
above) and `make`.

Or, run `cd priv && npm install`

## wkhtmltopdf

2. Download wkhtmltopdf and place it in your $PATH. Current binaries can be
found here: http://wkhtmltopdf.org/downloads.html

For the impatient (Ubuntu 18.04 Bionic Beaver):

```
apt-get -y install xfonts-base xfonts-75dpi \
&& wget https://downloads.wkhtmltopdf.org/0.12/0.12.5/wkhtmltox_0.12.5-1.bionic_amd64.deb \
&& dpkg -i wkhtmltox_0.12.5-1.bionic_amd64.deb
```

For other distributions, refer to http://wkhtmltopdf.org/downloads.html – For
example, replace `bionic` with `xenial` if you're on Ubuntu 16.04.

## optional dependencies

3. _optional:_ Install `xvfb` (shouldn't be required with the binary mentioned above):

To use other wkhtmltopdf executables comiled with an unpatched Qt on systems
without an X window server installed, please install `xvfb-run` from your
repository (on Debian/Ubuntu: `sudo apt-get install xvfb`).

I haven't heard any feedback of people using this feature since a while since
the wkhtmltopdf projects ships ready-made binaries. I will deprecate this
starting in `0.6.0` since, well, YAGNI.
Expand Down Expand Up @@ -222,7 +229,7 @@ config :pdf_generator,

- `edit_password`: requires `pdftk`, set password for edit permissions on PDF

- `shell_params`: pass custom parameters to `wkhtmltopdf`. **CAUTION: BEWARE OF SHELL INJECTIONS!**
- `shell_params`: pass custom parameters to `wkhtmltopdf` or `chrome-headless-render-pdf`. **CAUTION: BEWARE OF SHELL INJECTIONS!**

- `command_prefix`: prefix `wkhtmltopdf` with some command or a command with options
(e.g. `xvfb-run -a`, `sudo` ..)
Expand All @@ -231,7 +238,7 @@ config :pdf_generator,

## Contribution; how to run tests

You're more than welcome ot submit patches. Please run `mix test` to ensure at bit of stability. Tests require a full-fledged environment, with all of `wkhtmltopdf`, `xvfb` and `chrome-headless-render-pdf` available path. Also make to to have run `npm install` in the app's base directory (will install chrome-headless-render-pdf non-globally in there). With all these installed, `mix test` should run smoothly.
You're more than welcome to submit patches. Please run `mix test` to ensure at bit of stability. Tests require a full-fledged environment, with all of `wkhtmltopdf`, `xvfb` and `chrome-headless-render-pdf` available path. Also make to to have run `npm install` in the app's base directory (will install chrome-headless-render-pdf non-globally in there). With all these installed, `mix test` should run smoothly.

_Hint_: Getting `:enoent` errors ususally means that chrome or xvfb couldn't be run. Yes, this should output a nicer error.

Expand Down Expand Up @@ -295,6 +302,6 @@ file a report.

# Contributing

Contributions (Issues, PRs…) are more than welcome. Please ave a quick read at
the [Contribution tips](./CONTRIBUTING.md), though. It's basically about scope
Contributions (Issues, PRs…) are more than welcome. Please ave a quick read at
the [Contribution tips](./CONTRIBUTING.md), though. It's basically about scope
and kindness.
12 changes: 9 additions & 3 deletions lib/pdf_generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,15 @@ defmodule PdfGenerator do
node_executable = PdfGenerator.PathAgent.get.node_path
disable_sandbox = Application.get_env(:pdf_generator, :disable_chrome_sandbox) || options[:no_sandbox]

# needs `make priv/node_modules` to be run when building
priv_dir = :code.priv_dir(:pdf_generator) |> to_string()
js_file = "#{priv_dir}/node_modules/chrome-headless-render-pdf/dist/cli/chrome-headless-render-pdf.js"
dir =
if options[:prefer_local_executable] do
Path.expand("assets")
else
# needs `make priv/node_modules` to be run when building
:code.priv_dir(:pdf_generator) |> to_string()
end

js_file = "#{dir}/node_modules/chrome-headless-render-pdf/dist/cli/chrome-headless-render-pdf.js"

{executable, executable_args} =
if options[:prefer_system_executable] && is_binary(chrome_executable) do
Expand Down
6 changes: 6 additions & 0 deletions test/pdf_generator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ defmodule PdfGeneratorTest do
assert result |> File.read! |> String.slice(0, 6) == "%PDF-1"
end

test "chrome-headless from URL, with local installation of chrome-hedless-render-pdf and puppeteer" do
{status, result} = PdfGenerator.generate({:url, "http://google.com"}, generator: :chrome, prefer_local_executable: true)
assert status == :ok
assert result |> File.read! |> String.slice(0, 6) == "%PDF-1"
end

test "chrome's no-sandbox option doesn't crash" do
{_status, result} = PdfGenerator.generate({:url, "http://google.com"}, generator: :chrome, disable_chrome_sandbox: true)
assert result |> File.read! |> String.slice(0, 6) == "%PDF-1"
Expand Down