@browserless/pdf 13.6.3 → 13.6.5
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.
- package/package.json +4 -4
- package/src/index.js +43 -18
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.
|
|
5
|
+
"version": "13.6.5",
|
|
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.
|
|
34
|
-
"@browserless/screenshot": "13.6.
|
|
33
|
+
"@browserless/goto": "13.6.5",
|
|
34
|
+
"@browserless/screenshot": "13.6.5",
|
|
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": "
|
|
50
|
+
"gitHead": "679c9a8f0db8a6a98bb54fd3d19532ea8a64d76b"
|
|
51
51
|
}
|
package/src/index.js
CHANGED
|
@@ -22,10 +22,13 @@ const PDF_DEFAULT_OPTS = {
|
|
|
22
22
|
waitUntil: 'auto'
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Share of the
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
|
|
25
|
+
// Share of the phase's load allowance the readiness gate may consume in `auto`
|
|
26
|
+
// mode. Pages observed settling in 0.6-3.3s (a hydrating document is the slow
|
|
27
|
+
// end), so a quarter of the allowance — ~3.9s at the default request budget —
|
|
28
|
+
// covers them with margin while keeping the cap well short of the render's
|
|
29
|
+
// share. The gate returns as soon as the page is quiet, so this bounds only a
|
|
30
|
+
// page that never settles.
|
|
31
|
+
const READY_BUDGET_RATIO = 0.25
|
|
29
32
|
|
|
30
33
|
// Minimum visible characters for the text fast path. Matches the counting cap
|
|
31
34
|
// in `waitForReady`'s snapshot, which stops walking text nodes once reached —
|
|
@@ -97,35 +100,57 @@ module.exports = ({ goto, ...gotoOpts } = {}) => {
|
|
|
97
100
|
return
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
// Surfaced to the caller: a page whose readiness could not be confirmed
|
|
104
|
+
// (`timedOut`) is a poor one to keep rendering on, so a caller reusing this
|
|
105
|
+
// load across page-ranges can choose a fresh context instead.
|
|
106
|
+
let readiness
|
|
107
|
+
|
|
100
108
|
await goto(page, { ...rest, url, waitUntil, waitUntilAuto })
|
|
101
|
-
|
|
109
|
+
return readiness
|
|
110
|
+
|
|
111
|
+
async function waitUntilAuto (page, { timeout: autoTimeout } = {}) {
|
|
102
112
|
await waitForDomStabilityResult(page)
|
|
103
113
|
const timeout = goto.timeouts.action(rest.timeout)
|
|
104
|
-
// One action budget shared by the readiness gate and the screenshot poll,
|
|
105
|
-
// so worst-case prepare stays within a single `timeout` instead of one
|
|
106
|
-
// per stage.
|
|
107
|
-
const elapsed = timeSpan()
|
|
108
114
|
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
// The readiness gate waits for a page to settle — page-load work, not a
|
|
116
|
+
// small action. Budgeting it from `timeouts.action` (timeout/11) gave it
|
|
117
|
+
// ~1.2s while a hydrating document needs 2-3s, so it timed out on every
|
|
118
|
+
// tall page and the zero-capture fast path never fired. Budget it from
|
|
119
|
+
// the load allowance goto actually assigned to this phase; the gate
|
|
120
|
+
// returns as soon as the page is quiet, so this is a cap, not a cost.
|
|
121
|
+
const readyTime = timeSpan()
|
|
122
|
+
const ready = await waitForReady(page, {
|
|
123
|
+
timeout: Math.round((autoTimeout ?? timeout) * READY_BUDGET_RATIO)
|
|
124
|
+
})
|
|
125
|
+
readiness = ready
|
|
126
|
+
debug('ready', { ...ready, duration: readyTime() })
|
|
127
|
+
|
|
128
|
+
// The blank-page poll keeps its own action budget, measured from here so
|
|
129
|
+
// a slow gate cannot starve it.
|
|
130
|
+
const elapsed = timeSpan()
|
|
116
131
|
|
|
117
132
|
// Fast path: the page settled with real painted content in a document
|
|
118
133
|
// taller than the viewport — a visibly rendered image (not a tracking
|
|
119
134
|
// pixel), or enough visible text with webfonts loaded (a pending
|
|
120
135
|
// `font-display: block` font renders text invisible, exactly when a
|
|
121
|
-
// capture would be white) —
|
|
136
|
+
// capture would be white) — and that content is not `covered` by an
|
|
137
|
+
// opaque viewport-filling layer (a fixed white loading overlay passes
|
|
138
|
+
// every other DOM signal while a capture stays white): skip the
|
|
122
139
|
// screenshot poll. Height and viewport come from the same in-page
|
|
123
140
|
// snapshot (`page.viewport()` is null under `defaultViewport: null`),
|
|
124
141
|
// and an unknown viewport skips the fast path rather than dropping the
|
|
125
142
|
// taller-than-viewport guard. A gate that timed out never settled, so
|
|
126
143
|
// don't trust its partial snapshot: fall through to the blank check.
|
|
127
144
|
const painted = ready.painted > 0 || (ready.text >= TEXT_PAINTED_MIN && ready.fonts)
|
|
128
|
-
if (
|
|
145
|
+
if (
|
|
146
|
+
!ready.timedOut &&
|
|
147
|
+
painted &&
|
|
148
|
+
!ready.covered &&
|
|
149
|
+
ready.viewport > 0 &&
|
|
150
|
+
ready.height > ready.viewport
|
|
151
|
+
) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
129
154
|
|
|
130
155
|
// Otherwise fall back to the screenshot poll — re-wait while the first
|
|
131
156
|
// paint is still blank — to keep the blank-SPA protection. The page has
|