جافاسكريبت - Puppeteer انتظار تحميل الصفحة و setTimeout لا يعمل في دوال Firebase السحابية
أحاول تحميل صفحة أستضيفها على Firebase وتحويلها إلى PDF باستخدام Puppeteer.
تعمل بشكل جيد مع صفحة HTML فقط.
الآن أحصل على البيانات من Firebase وأعرضها في صفحتي، لذلك أحتاج إلى انتظار تحميل الصفحة بالكامل قبل أن أتمكن من إنشاء ملف PDF.
هذا يعمل بشكل جيد عند الاختبار محليًا باستخدام محاكي Firebase npm run serve.
ومع ذلك، لا يعمل في وظائف السحابة، فالانتظار يستمر حتى تنتهي مهلة الدالة.
تسجل السجلات waitFor وبعد فترة Function execution took 120002 ms, finished with status: 'timeout'.
جربت الكثير من الأمور ولا أعرف ماذا أفعل، وأبدأ أعتقد أنه قد يكون خطأً في وظائف السحابة.
import * as functions from 'firebase-functions';
// tslint:disable-next-line:no-duplicate-imports
import { VALID_MEMORY_OPTIONS } from 'firebase-functions';
// import * as puppeteer from 'puppeteer';
const runtimeOpts = {
timeoutSeconds: 120,
memory: VALID_MEMORY_OPTIONS[4],
};
// const cors = require('cors')({ origin: true });
export const generatePDF = functions
.runWith(runtimeOpts)
// .region('europe-west1')
.https.onRequest(async (request: any, response: any) => {
// cors(request, response, async () => {
console.log(7);
const hostname = request.hostname;
let url = '';
if (hostname === 'localhost') {
url = 'http://localhost:5000';
} else {
url = 'https://myapp.firebaseapp.com';
}
const puppeteer = require('puppeteer');
console.log('launch puppeteer');
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
// debug: {headless: false}
console.log('new page');
const page = await browser.newPage();
console.log('goto');
await page
.goto(`${url}/report/A3p71Fl5GD98Sjks5BJg`)
.catch((error: any) => {
console.log(error);
return response.send('Timeout1');
});
console.log('waitFor');
// await page.waitFor(10000).catch((error: any) => {
// console.log(error);
// return response.send('Timeout2');
// });
await new Promise(resolve => setTimeout(resolve, 5000));
// await page.waitForNavigation({
// waitUntil: 'networkidle0',
// });
// Wait for element to render
// await page.waitForSelector('#end');
// await page.waitFor(10000);
console.log('create pdf');
const pdf = await page.pdf({
format: 'A4',
});
console.log('close browser');
await browser.close();
// response.setHeader('Content-Disposition', 'attachment; filename=customfilename.pdf');
response.setHeader('Content-Disposition', 'filename=customfilename.pdf');
return response.type('application/pdf').send(pdf);
// });
});
export const helloWorld = functions.https.onRequest(
async (request: any, response: any) => {
await new Promise(resolve => setTimeout(resolve, 5000));
response.send('Hello from Firebase!');
},
);
// function delay(ms: number) {
// return new Promise(resolve => setTimeout(resolve, ms));
// }
ملف package.json:
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "8"
},
"main": "lib/index.js",
"dependencies": {
"cors": "^2.8.5",
"firebase-admin": "^8.7.0",
"firebase-functions": "^3.3.0",
"puppeteer": "^2.0.0"
},
"devDependencies": {
"tslint": "^5.12.0",
"typescript": "^3.6.3"
},
"private": true
}
tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017",
"lib": ["dom"]
},
"compileOnSave": true,
"include": ["src"]
}
الإجابة رقم 1
يجب عليك استيراد puppeteer خارج الدالة الخاصة بك، حتى تتمكن firebase من إعادة استخدامه. أيضًا لا تحتاج إلى إنشاء مهلات، لكن يمكنك استخدام await page.waitFor(5000); بدلاً من ذلك. حاولت إنشاء مثال minimal لحالة الاستخدام الخاصة بك. إذا واجهت أخطاءً، يرجى الذهاب إلى وحدة تحكم وظائف firebase الخاصة بك وفحص السجلات، يجب أن تخبرك بما هو الخطأ.
هناك أيضًا احتمال أنك لم تقم بتمكين الفوترة في حساب Firebase الخاص بك - في هذه الحالة لا يمكن لوظيفتك الوصول إلى المضيفين من جهات خارجية.
import * as functions from 'firebase-functions';
import * as puppeteer from 'puppeteer';
export const generatePDF = functions
.runWith({ timeoutSeconds: 30, memory: "1GB" })
.https.onRequest(async (request, response) => {
const url = 'https://www.yoururl.com/';
const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.goto(url);
await page.waitFor(5000);
const pdf = await page.pdf({
format: 'A4',
});
await browser.close();
response.setHeader('Content-Disposition', 'filename=customfilename.pdf');
return response.type('application/pdf').send(pdf);
});
