HTML to PDF Action - NodeJS & PHP [Open Source]

There is no special setting required to run on Mac.
It should just run like every other Wappler project.

1 Like

Any idea about the error passed below? I’ve read something (https://stackoverflow.com/questions/66070860/puppeteer-error-error-while-loading-shared-libraries-libgobject-2-0-so-0) about Docker, but I can’t solve it. Any idea? (the git proyect I clone works correctly using docker)

Failed to launch the browser process!
/opt/node_app/node_modules/puppeteer/.local-chromium/linux-869685/chrome-linux/chrome: error while loading shared libraries: libgobject-2.0.so.0: cannot open shared object file: No such file or directory

TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md

Like it says on the SO link, it was the positioning on apt-get that was the cause of issue.
You need to install some packages separately in docker to get puppeteer to run.
The docker.yml file is the one you need to setup I think to write those apt-get commands. Not sure though.

After some research I founded a tutorial to make puppeteer work using docker at https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#running-puppeteer-in-docker

Basically, I copied inside the dockerfile this code:

FROM node:12-slim

    # Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
    # Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
    # installs, work.
    RUN apt-get update \
        && apt-get install -y wget gnupg \
        && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
        && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
        && apt-get update \
        && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
          --no-install-recommends \
        && rm -rf /var/lib/apt/lists/*

    # If running Docker >= 1.13.0 use docker run's --init arg to reap zombie processes, otherwise
    # uncomment the following lines to have `dumb-init` as PID 1
    # ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
    # RUN chmod +x /usr/local/bin/dumb-init
    # ENTRYPOINT ["dumb-init", "--"]

    # Uncomment to skip the chromium download when installing puppeteer. If you do,
    # you'll need to launch puppeteer with:
    #     browser.launch({executablePath: 'google-chrome-stable'})
    # ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true

    # Install puppeteer so it's available in the container.
    RUN npm i puppeteer \
        # Add user so we don't need --no-sandbox.
        # same layer as npm install to keep re-chowned files from using up several hundred MBs more space
        && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
        && mkdir -p /home/pptruser/Downloads \
        && chown -R pptruser:pptruser /home/pptruser \
        && chown -R pptruser:pptruser /node_modules

    # Run everything after as non-privileged user.
    USER pptruser

    CMD ["google-chrome-stable"]

But after deploying and starting Docker, I’m getting this new error I can’t solve:

Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted

Any ideas?

1 Like

Can you share the complete dockerfile? I am a newbie with this stuff. Can try to help.

Found this on Google: https://github.com/jessfraz/dockerfiles/issues/350

I’m quite lost. My complete docker file is the original that Wappler creates automatically when you start a new proyect with those lines I previously copied (I’m not with my Mac right now).

After 4 hours of research, I gave up. I really don’t know how to implement the chromium and puppeteer service on the same image that runs Wappler’s web app. Maybe I should create a new image with those two services? There’s documentation and proyects to clone where you can start a Docker machine runing those services. But from what I understand, that won’t work because it would be separated from the web app, right?

I will try to deploy on my test server and see if i have any luck with it.

1 Like

Hello once again. Now with my server working with Puppeteer I wanted to know if there is any way I could use wappler’s frameworks for styling the PDF or I should do it manually?

I wanted to use these frameworks but the action crashes when executing it:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
  <script src="../js/jquery-3.5.1.slim.min.js"></script>
  <link rel="stylesheet" href="../dmxFramework7_icons/css/framework7-icons.css" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <script src="../dmxAppConnect/dmxRouting/dmxRouting.js" defer=""></script>
  <link rel="stylesheet" href="../bootstrap/5/simplex/bootstrap.min.css" />

The paths all need to be absolute.
So for jQuery, you cannot use .. /js/
Replace that with a CDN URL. Or even a full URL from your own deployed project.

Thanks, but where should I place those head parameters?

At the top of whatever Html you are passing in body field. Body does not mean html body tag. You can have head tag in the html you pass here.

1 Like

@salvuccicarlos Finally got around to trying puppeteer in Docker, and I was able to get it to work easily.
Here are the steps that might help others too. You will still have to run npm install pup... in terminal or add in packages and re-install packages from bottom toolbar first.
Although you can move that step to Dockerfile described below, I have not done that to keep the first part same as other Wappler NodeJS Extension installations.

  1. There is a file called Dockerfile for each Docker based target. This file can be found in .wappler/targets/{{target_name}}/web/Dockerfile
  2. This file usually looks like this for a local development server:
FROM wapplerio/node-14

ENV NODE_ENV development
WORKDIR /opt/node_app
COPY package.json .
RUN npm install --no-optional
CMD [ "nodemon", "--legacy-watch", "./index.js" ]
  1. To allow puppeteer to find Chromium, we need to install it at the time of Docker image creation, which is done using the file above. As per the library’s documentation, I add a few lines of code and this is what my Dockerfile looks like now:
FROM wapplerio/node-14

ENV NODE_ENV development
WORKDIR /opt/node_app
COPY package.json .
RUN npm install --no-optional
RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*
CMD [ "nodemon", "--legacy-watch", "./index.js" ]
  1. Save this, and click DEPLOY in the bottom toolbar to re-deploy the image.
  2. In the logs, you should see that it will take a bit more time than usual during deployment, since it now also runs additional RUN command for Chromium.

You will have to modify this Dockerfile file for each Docker-type target in Wappler.
I have tested this on Digital Ocean based setup Wappler provides. So I can now generate PDFs on local as well as remote dockers.

3 Likes

Thank you @sid for a detailed explanation and step-by-step solution.

May I ask you how it’s possible to use array items, for instance for multiply query results or repeats in HTML code?
For instance generate table?

Thank you in advance.

This is not in the scope of this extension.
That is part of how you create the HTML which you give to this extension as input.

The question about repeating items has been a problem with sending emails too. This is not natively supported in Wappler right now, and neither is it available as a custom extension from what I know.

The solution below is from a dev in our team, which also applies here.

@sid it’s possible to provide example of this workaround?

The link above has the code. And if you read the discussion there, you will understand the context of it.

Those who uses this solution: is it possible to mark page number on each generated PDF sheet?

Yes there is. But you will have to look at Puppeteer and mPDF documentation to see how to use.

Hi all, first time poster, long time community crawler looking for answers :joy:

After a lot of hit and miss, I’ve been able to get this working. However, I cannot seem to be able to get the styles from Bootstrap working at all. Here is my current setup (don’t mind the repeat, I’m still working on that):

My “styles” Set Value is:

<link rel="stylesheet" href="{{host}}/bootstrap/5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css" integrity="sha384-NUDU7Qr8dfscXBIhA0px/bRl3cgNrOT9l/WPm15DzH5xnBs4fL4vgRiXURs98/ID" crossorigin="anonymous">`

{{host}} resolves to http://localhost:8100

I have put the <link> tags inside <head> tags (just in case) to no avail. I’ve changed the path of the bootstrap file to /assets/bootstrap… etc. Nothing I have tried to even get some kind of styling has worked.

As you can see below, the PDF that is generated has no styling except for, if I understand how Puppeteer works correctly, the user agent stylesheet from Chromium.

Thanks in advance for any help you can provide.

This is where the issue is. You need a link here which is accessible over internet.
So, from my understanding, how Puppeteer works is by opening Chome and placing the passed HTML as a page. Here, your localhost does not exist. So only links which are accessible over internet will work. Then, whatever the final render is, is printed-as-PDF and the file is returned.
Hope this helps.