Joan Drago Mateu
Joan Drago Mateu

Reputation: 13

Unable to deploy a firebase function using Typescript and Puppeteer

This is my first time working with Firebase functions. I can make my function work locally, getting the scraped data that I want with Puppeteer. However I can not deploy this function to Firebase, because of the following error:

 Function failed on loading user code. Error message: Code in file lib/index.js can't be 
    loaded. Is there a syntax error in your code? Detailed stack trace: TypeError 
    [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function
    at promisify (internal/util.js:214:11)
    at Object.<anonymous> (/srv/node_modules/extract-zip/index.js:11:18)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/srv/node_modules/puppeteer/lib/BrowserFetcher.js:21:17)

The index.ts file where I export my function is the following:

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import urls from "./data/urls";
import scraper from "./scraper";

admin.initializeApp();

exports.data = functions
  .runWith({ timeoutSeconds: 30, memory: "1GB" })
  .region("europe-west1")
  .https.onRequest(async (req, res) => {
    try {
      const products = await Promise.all(urls.map((url) => scraper(url)));
      res.send(products);
    } catch (e) {
      console.log(e);
    }
  });
`

Scraper file

export default async function scraper(url: string) {
  const browser = await puppeteer.launch({
    headless: true,
    args: ["--no-sandbox"],
  });
  const page = await browser.newPage();
  await page.goto(url);
  await page.waitFor(3000);

  const title = await page.$eval(
    "#productTitle",
    (el) => (el as HTMLElement).innerText
  );
  const image = await page.$eval("#landingImage", (img) =>
    img.getAttribute("src")
  );
  let price;

  if ((await page.$("#price_inside_buybox")) !== null) {
    price = await page.$eval(
      "#price_inside_buybox",
      (el) => (el as HTMLElement).innerText
    );
  } else {
    price = "precio segunda";
  }

  const res = {
    title,
    image,
    price,
  };

  await browser.close();
  return res; // TODO somehow get the promotions
}

Upvotes: 1

Views: 964

Answers (3)

Joshua Okpako
Joshua Okpako

Reputation: 51

I had the same problem but I realized that it is because puppeteer no longer uses node 8 from version 3 onward as described on their version 3.0.0 release https://github.com/puppeteer/puppeteer/releases/tag/v3.0.0

To fix the issue, you need to change your node version in the package.json file in your functions folder. You need to change it from this

"engines": {
"node": "8"
 },

to

"engines": {
"node": "10"
}

Upvotes: 4

Joan Drago Mateu
Joan Drago Mateu

Reputation: 13

Thanks Berry, that worked for me. We will wait until the issue with version 3 is fixed.

Upvotes: 0

Berry Goudswaard
Berry Goudswaard

Reputation: 36

I had the exact same problem and solved it by reverting back to [email protected]

If you don't use 3.x.x specific feature, this is the workaround until the issue is fixed.

Upvotes: 2

Related Questions