Back

PhantomJS or Puppeter in AppWrite Functions

  • 0
  • Functions
50l3r
1 Apr, 2023, 19:16

Hi all,

Is there a way to be able to run puppeter or phantomjs in appwrite functions?

When testing my function locally, both with puppeter and with the html-pdf extension that phantomjs uses, it works fine, but when I run it inside a function, it throws me an error.

An example of errors:

Phantomjs

TypeScript
Error: spawn /usr/code-start/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
    at onErrorNT (node:internal/child_process:480:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)

Puppeter

TypeScript
Error: Could not find Chromium (rev. 1108766). This can occur if either
 1. you did not perform an installation before running the script (e.g. `npm install`) or
 2. your cache path is incorrectly configured (which is: /root/.cache/puppeteer).
For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
    at ChromeLauncher.resolveExecutablePath (/usr/code-start/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:127:27)
    at ChromeLauncher.executablePath (/usr/code-start/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:207:25)
    at ChromeLauncher.launch (/usr/code-start/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:93:37)
    at async /usr/code-start/dist/models/invoice.js:174:33

Thanks in advance

TL;DR
The user is asking if it's possible to run Puppeteer or PhantomJS in Appwrite functions. They have provided code examples and error messages indicating that these dependencies are not supported in the Docker image used by Appwrite. The community suggests waiting for a future version that may support this, and in the meantime, externalizing the Puppeteer functions. There is no solution provided in this thread.
safwan
1 Apr, 2023, 20:10

did you deploy the function as a fresh new function, or just an updated build to an existing function?

safwan
1 Apr, 2023, 20:11

I suggest you delete the function, and deploy a fresh build from the appwrite cli

safwan
1 Apr, 2023, 20:11

it seems like it's a simple dependency issue, and a fresh deploy should fix it

50l3r
1 Apr, 2023, 20:33

It is an existing function but I think the problem is that puppeter and phantom are not supported in the docker image that appwrite uses

Drake
1 Apr, 2023, 20:51

Yes, correct. There are OS level dependencies required which isn't supported in Appwrite functions. Here's the related issue: https://github.com/appwrite/appwrite/issues/1037. This might be achievable in the next version of our functions

50l3r
1 Apr, 2023, 20:52

Great. I'l wait and externalize the puppeter functions for the moment 🙂

Drake
1 Apr, 2023, 20:53

You might be able to hack together a solution if you include the os level dependencies in the uploaded code and reference them somehow. 🤷‍♂️

50l3r
1 Apr, 2023, 22:08

I used docker with dokku instance and create a Dockerfile like this:

50l3r
1 Apr, 2023, 22:08
TypeScript
FROM node:lts-alpine

WORKDIR /app

RUN apk update && apk add --no-cache nmap && \
    echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
    echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
    apk update && \
    apk add --no-cache \
      chromium \
      harfbuzz \
      "freetype>2.8" \
      ttf-freefont \
      nss

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

COPY package*.json ./

RUN npm install

COPY . .

CMD ["npm", "start"]
50l3r
1 Apr, 2023, 22:09

With this Procfile web: node index.js

50l3r
1 Apr, 2023, 22:09

And this is my script:

50l3r
1 Apr, 2023, 22:10
TypeScript
const express = require('express')
const bodyParser = require('body-parser')
const puppeter = require('puppeteer')

const app = express()
app.use(bodyParser.urlencoded({ extended: true }))

app.post('/', async (req, res) => {
    try {
        const html = req.body.html

        // Create a browser instance
        const browser = await puppeter.launch({
            headless: true,
            executablePath: '/usr/bin/chromium-browser',
            args: [
                '--disable-gpu',
                '--disable-setuid-sandbox',
                '--no-sandbox',
                '--no-zygote',
            ],
        })

        // Create a new page
        const page = await browser.newPage()

        await page.setContent(html, {
            waitUntil: 'networkidle0',
        })

        const pdfBuffer = await page.pdf({
            format: 'A4',
            // path: `${__dirname}/../invoice.pdf`,
            printBackground: true,
        })

        res.status(200).json({ file: pdfBuffer })
        await browser.close()
    } catch (error) {
        console.error(error)
        res.status(500).json({ error: error.message })
    }
})

app.listen(5000, function () {})
50l3r
1 Apr, 2023, 22:11

With all this I have managed to build a simple web service that through a provided html generates a pdf and sends the buffer in response to my appwrite function

50l3r
1 Apr, 2023, 22:11

I hope someone can be of help

50l3r
1 Apr, 2023, 22:12

Now, my appwrite function return a file buffer

50l3r
1 Apr, 2023, 22:12
Drake
1 Apr, 2023, 22:14

And this is hosted separate from Appwrite? And the appwrite function calls this service?

50l3r
1 Apr, 2023, 22:15

Yes

Drake
1 Apr, 2023, 22:15

I would probably write this to storage rather than returning the buffer in case it's too big and gets truncated

50l3r
1 Apr, 2023, 22:16

Yeah but in my case my backend who calls appwrite function manage the storage

50l3r
1 Apr, 2023, 22:17

I plan to use appwrite functions as microservices and be able to run universal functions from different projects

50l3r
1 Apr, 2023, 22:18

In this case, the function renders a pdf invoice based on some parameters provided

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more