@browserless/pdf 13.6.0 → 13.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +4 -4
  2. package/src/index.js +98 -75
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@browserless/pdf",
3
3
  "description": "Convert websites to high-quality PDFs with customizable margins, background printing, and optimized scaling.",
4
4
  "homepage": "https://browserless.js.org/#/?id=pdfurl-options",
5
- "version": "13.6.0",
5
+ "version": "13.6.2",
6
6
  "main": "src",
7
7
  "author": {
8
8
  "email": "hello@microlink.io",
@@ -30,8 +30,8 @@
30
30
  "website-to-pdf"
31
31
  ],
32
32
  "dependencies": {
33
- "@browserless/goto": "13.6.0",
34
- "@browserless/screenshot": "13.6.0",
33
+ "@browserless/goto": "13.6.2",
34
+ "@browserless/screenshot": "13.6.2",
35
35
  "@kikobeats/time-span": "~1.0.12",
36
36
  "debug-logfmt": "~1.4.10",
37
37
  "p-reflect": "~2.1.0",
@@ -47,5 +47,5 @@
47
47
  "test": "exit 0"
48
48
  },
49
49
  "license": "MIT",
50
- "gitHead": "356def85cb7cfd2e5ae2e22260b9e7fd6b4a9bc1"
50
+ "gitHead": "7c7c6fee9e82050887d5499ed9dc3bac16c88c42"
51
51
  }
package/src/index.js CHANGED
@@ -1,16 +1,25 @@
1
1
  'use strict'
2
2
 
3
3
  const timeSpan = require('@kikobeats/time-span')({ format: n => Math.round(n) })
4
+ const debug = require('debug-logfmt')('browserless:pdf')
5
+ const createGoto = require('@browserless/goto')
4
6
  const pReflect = require('p-reflect')
7
+
5
8
  const {
6
9
  captureWithNavigationRetry,
7
10
  isWhiteScreenshot,
8
11
  waitForDomStability,
9
12
  resolveWaitForDom,
10
- DEFAULT_WAIT_FOR_DOM
13
+ SCREENSHOT_DEFAULT_OPTS
11
14
  } = require('@browserless/screenshot')
12
- const debug = require('debug-logfmt')('browserless:pdf')
13
- const createGoto = require('@browserless/goto')
15
+
16
+ const PDF_DEFAULT_OPTS = {
17
+ waitForDom: SCREENSHOT_DEFAULT_OPTS.waitForDom,
18
+ margin: '0.35cm',
19
+ scale: 0.65,
20
+ printBackground: true,
21
+ waitUntil: 'auto'
22
+ }
14
23
 
15
24
  const getMargin = unit => {
16
25
  if (!unit) return unit
@@ -26,83 +35,97 @@ const getMargin = unit => {
26
35
  module.exports = ({ goto, ...gotoOpts } = {}) => {
27
36
  goto = goto || createGoto(gotoOpts)
28
37
 
29
- return function pdf (page) {
30
- return async (
31
- url,
32
- {
33
- margin = '0.35cm',
34
- scale = 0.65,
35
- printBackground = true,
36
- waitUntil = 'auto',
37
- waitForDom = DEFAULT_WAIT_FOR_DOM,
38
- ...opts
39
- } = {}
40
- ) => {
41
- let pdfBuffer
42
- const waitForDomOpts = resolveWaitForDom(waitForDom)
43
-
44
- const generatePdf = page =>
45
- captureWithNavigationRetry(
38
+ // Render an already-prepared page to a PDF buffer. Split out from the load so
39
+ // a single load can be reused across page-range chunks (microlink-api's
40
+ // parallel renderer) without re-navigating.
41
+ const render = (page, opts = {}) => {
42
+ const {
43
+ margin = PDF_DEFAULT_OPTS.margin,
44
+ scale = PDF_DEFAULT_OPTS.scale,
45
+ printBackground = PDF_DEFAULT_OPTS.printBackground,
46
+ waitUntil,
47
+ waitForDom,
48
+ ...rest
49
+ } = opts
50
+ return captureWithNavigationRetry(
51
+ () => page.pdf({ ...rest, margin: getMargin(margin), printBackground, scale }),
52
+ { page, goto, timeout: goto.timeouts.action(rest.timeout) }
53
+ )
54
+ }
55
+
56
+ // Navigate `page` to `url` and wait until it is ready to print: DOM stability
57
+ // plus, in `auto` mode, a screenshot poll that re-waits while the first paint
58
+ // is still blank.
59
+ const prepare = async (page, url, opts = {}) => {
60
+ const {
61
+ margin,
62
+ scale,
63
+ printBackground,
64
+ waitUntil = PDF_DEFAULT_OPTS.waitUntil,
65
+ waitForDom = PDF_DEFAULT_OPTS.waitForDom,
66
+ ...rest
67
+ } = opts
68
+ const waitForDomOpts = resolveWaitForDom(waitForDom)
69
+
70
+ const waitForDomStabilityResult = async page => {
71
+ if (!waitForDomOpts) return
72
+
73
+ const result = await pReflect(page.evaluate(waitForDomStability, waitForDomOpts))
74
+ debug(
75
+ 'waitForDomStability',
76
+ result.isRejected
77
+ ? { ...waitForDomOpts, error: result.reason.message || result.reason }
78
+ : { ...waitForDomOpts, ...result.value }
79
+ )
80
+ }
81
+
82
+ if (waitUntil !== 'auto') {
83
+ await goto(page, { ...rest, url, waitUntil })
84
+ await waitForDomStabilityResult(page)
85
+ return
86
+ }
87
+
88
+ await goto(page, { ...rest, url, waitUntil, waitUntilAuto })
89
+ async function waitUntilAuto (page) {
90
+ await waitForDomStabilityResult(page)
91
+ const timeout = goto.timeouts.action(rest.timeout)
92
+ let isWhite = false
93
+ let retry = -1
94
+
95
+ const timePdf = timeSpan()
96
+
97
+ do {
98
+ ++retry
99
+ const screenshotTime = timeSpan()
100
+ const screenshot = await captureWithNavigationRetry(
46
101
  () =>
47
- page.pdf({
48
- ...opts,
49
- margin: getMargin(margin),
50
- printBackground,
51
- scale
102
+ page.screenshot({
103
+ ...rest,
104
+ optimizeForSpeed: true,
105
+ type: 'jpeg',
106
+ quality: 30
52
107
  }),
53
- { page, goto, timeout: goto.timeouts.action(opts.timeout) }
108
+ { page, goto, timeout }
54
109
  )
110
+ isWhite = await isWhiteScreenshot(screenshot)
111
+ if (isWhite) await goto.waitUntilAuto(page, { timeout: rest.timeout })
112
+ debug('retry', { waitUntil, isWhite, retry, duration: screenshotTime() })
113
+ } while (isWhite && timePdf() < timeout)
55
114
 
56
- const waitForDomStabilityResult = async page => {
57
- if (!waitForDomOpts) return
58
-
59
- const result = await pReflect(page.evaluate(waitForDomStability, waitForDomOpts))
60
- debug(
61
- 'waitForDomStability',
62
- result.isRejected
63
- ? { ...waitForDomOpts, error: result.reason.message || result.reason }
64
- : { ...waitForDomOpts, ...result.value }
65
- )
66
- }
115
+ debug({ waitUntil, isWhite, timeout, duration: require('pretty-ms')(timePdf()) })
116
+ }
117
+ }
67
118
 
68
- if (waitUntil !== 'auto') {
69
- await goto(page, { ...opts, url, waitUntil })
70
- await waitForDomStabilityResult(page)
71
- pdfBuffer = await generatePdf(page)
72
- } else {
73
- await goto(page, { ...opts, url, waitUntil, waitUntilAuto })
74
- async function waitUntilAuto (page) {
75
- await waitForDomStabilityResult(page)
76
- const timeout = goto.timeouts.action(opts.timeout)
77
- let isWhite = false
78
- let retry = -1
79
-
80
- const timePdf = timeSpan()
81
-
82
- do {
83
- ++retry
84
- const screenshotTime = timeSpan()
85
- const screenshot = await captureWithNavigationRetry(
86
- () =>
87
- page.screenshot({
88
- ...opts,
89
- optimizeForSpeed: true,
90
- type: 'jpeg',
91
- quality: 30
92
- }),
93
- { page, goto, timeout }
94
- )
95
- isWhite = await isWhiteScreenshot(screenshot)
96
- if (isWhite) await goto.waitUntilAuto(page, { timeout: opts.timeout })
97
- debug('retry', { waitUntil, isWhite, retry, duration: screenshotTime() })
98
- } while (isWhite && timePdf() < timeout)
99
-
100
- debug({ waitUntil, isWhite, timeout, duration: require('pretty-ms')(timePdf()) })
101
- }
102
- pdfBuffer = await generatePdf(page)
119
+ const pdf =
120
+ page =>
121
+ async (url, opts = {}) => {
122
+ await prepare(page, url, opts)
123
+ return render(page, opts)
103
124
  }
104
125
 
105
- return pdfBuffer
106
- }
107
- }
126
+ pdf.prepare = prepare
127
+ pdf.render = render
128
+ return pdf
108
129
  }
130
+
131
+ module.exports.DEFAULT_OPTS = PDF_DEFAULT_OPTS