/
pdf-core.js
114 lines (95 loc) · 2.79 KB
/
pdf-core.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const puppeteer = require('puppeteer');
const BPromise = require('bluebird');
const _ = require('lodash');
const logger = require('../util/logger')(__filename);
async function render(_opts = {}) {
const opts = _.merge({
scrollPage: false,
emulateScreenMedia: true,
viewport: {
width: 1600,
height: 1200,
},
goto: {
waitUntil: 'networkidle',
networkIdleTimeout: 2000,
},
pdf: {
format: 'A4',
printBackground: true,
}
}, _opts);
if (_.get(_opts, 'pdf.width') && _.get(_opts, 'pdf.height')) {
// pdf.format always overrides width and height, so we must delete it
// when user explicitly wants to set width and height
opts.pdf.format = undefined;
}
logger.info(`Rendering with opts: ${JSON.stringify(opts, null, 2)}`);
const browser = await puppeteer.launch({
headless: true,
args: ['--disable-gpu', '--no-sandbox', '--disable-setuid-sandbox'],
});
const page = await browser.newPage();
page.on('console', (...args) => logger.info('PAGE LOG:', ...args));
page.on('error', (err) => {
logger.error(`Error event emitted: ${err}`);
logger.error(err.stack);
browser.close();
});
let data;
try {
logger.info('Set browser viewport..');
await page.setViewport(opts.viewport);
if (opts.emulateScreenMedia) {
logger.info('Emulate @media screen..');
await page.emulateMedia('screen');
}
logger.info(`Goto url ${opts.url} ..`);
await page.goto(opts.url, opts.goto);
if (_.isNumber(opts.waitFor) || _.isString(opts.waitFor)) {
logger.info(`Wait for ${opts.waitFor} ..`);
await page.waitFor(opts.waitFor);
}
if (opts.scrollPage) {
logger.info(`Scroll page ..`);
await scrollPage(page);
}
logger.info(`Render PDF ..`);
data = await page.pdf(opts.pdf);
} catch (err) {
logger.error(`Error when rendering page: ${err}`);
logger.error(err.stack);
throw err;
} finally {
logger.info('Closing browser..');
await browser.close();
}
return data;
}
async function scrollPage(page) {
// Scroll to page end to trigger lazy loading elements
return await page.evaluate(() => {
const scrollInterval = 100;
const scrollStep = Math.floor(window.innerHeight / 2);
const bottomThreshold = 400;
function bottomPos() {
return window.pageYOffset + window.innerHeight;
}
return new Promise((resolve, reject) => {
function scrollDown() {
window.scrollBy(0, scrollStep);
if (document.body.scrollHeight - bottomPos() < bottomThreshold) {
window.scrollTo(0, 0);
setTimeout(resolve, 500);
return;
}
setTimeout(scrollDown, scrollInterval);
}
setTimeout(reject, 30000);
scrollDown();
});
});
}
module.exports = {
render,
};