@browserless/screenshot 10.8.0 → 10.9.1
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/LICENSE.md +0 -0
- package/package.json +9 -8
- package/src/index.js +114 -33
- package/src/pretty/index.js +0 -2
package/LICENSE.md
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@browserless/screenshot",
|
|
3
3
|
"description": "Take a clean screenshot of any website",
|
|
4
4
|
"homepage": "https://browserless.js.org/#/?id=screenshoturl-options",
|
|
5
|
-
"version": "10.
|
|
5
|
+
"version": "10.9.1",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"author": {
|
|
8
8
|
"email": "hello@microlink.io",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"screenshot"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@browserless/goto": "^10.
|
|
31
|
+
"@browserless/goto": "^10.9.1",
|
|
32
32
|
"@kikobeats/time-span": "~1.0.8",
|
|
33
33
|
"debug-logfmt": "~1.4.0",
|
|
34
34
|
"got": "~11.8.6",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"svg-gradient": "~1.0.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@browserless/test": "^10.
|
|
48
|
+
"@browserless/test": "^10.9.0",
|
|
49
49
|
"ava": "5",
|
|
50
50
|
"cheerio": "latest"
|
|
51
51
|
},
|
|
@@ -56,14 +56,15 @@
|
|
|
56
56
|
"scripts",
|
|
57
57
|
"src"
|
|
58
58
|
],
|
|
59
|
+
"scripts": {
|
|
60
|
+
"coverage": "exit 0",
|
|
61
|
+
"test": "ava"
|
|
62
|
+
},
|
|
59
63
|
"license": "MIT",
|
|
60
64
|
"ava": {
|
|
61
65
|
"serial": true,
|
|
62
66
|
"timeout": "2m",
|
|
63
67
|
"workerThreads": false
|
|
64
68
|
},
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
"test": "ava"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
69
|
+
"gitHead": "be10f67b4113601686e30986e164158ceb6f32be"
|
|
70
|
+
}
|
package/src/index.js
CHANGED
|
@@ -32,16 +32,80 @@ const waitForImagesOnViewport = page =>
|
|
|
32
32
|
)
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
const waitForDomStability = ({ idle, timeout } = {}) =>
|
|
36
|
+
new Promise(resolve => {
|
|
37
|
+
if (!document.body) return resolve({ status: 'no-body' })
|
|
38
|
+
|
|
39
|
+
let lastChange = performance.now()
|
|
40
|
+
const observer = new window.MutationObserver(() => {
|
|
41
|
+
lastChange = performance.now()
|
|
42
|
+
})
|
|
43
|
+
observer.observe(document.body, {
|
|
44
|
+
childList: true,
|
|
45
|
+
subtree: true,
|
|
46
|
+
attributes: false,
|
|
47
|
+
characterData: false
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const deadline = performance.now() + timeout
|
|
51
|
+
|
|
52
|
+
;(function check () {
|
|
53
|
+
const now = performance.now()
|
|
54
|
+
if (now - lastChange >= idle) {
|
|
55
|
+
observer.disconnect()
|
|
56
|
+
return resolve({ status: 'idle' })
|
|
57
|
+
}
|
|
58
|
+
if (now >= deadline) {
|
|
59
|
+
observer.disconnect()
|
|
60
|
+
return resolve({ status: 'timeout' })
|
|
61
|
+
}
|
|
62
|
+
window.requestAnimationFrame(check)
|
|
63
|
+
})()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const scrollFullPageToLoadContent = async (page, timeout) => {
|
|
67
|
+
const debug = require('debug-logfmt')('browserless:goto')
|
|
68
|
+
|
|
69
|
+
const duration = debug.duration()
|
|
70
|
+
const result = await page.evaluate(waitForDomStability, {
|
|
71
|
+
idle: timeout / 2 / 2,
|
|
72
|
+
timeout: timeout / 2
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
duration('waitForDomStability', result)
|
|
76
|
+
|
|
77
|
+
await page.evaluate(
|
|
78
|
+
timeout =>
|
|
79
|
+
new Promise(resolve => {
|
|
80
|
+
let currentScrollPosition = 0
|
|
81
|
+
const scrollStep = Math.floor(window.innerHeight)
|
|
82
|
+
const pageHeight = document.body.scrollHeight
|
|
83
|
+
const totalSteps = Math.ceil(pageHeight / scrollStep)
|
|
84
|
+
const stepDelay = timeout / 2 / totalSteps
|
|
85
|
+
const scrollNext = async () => {
|
|
86
|
+
if (currentScrollPosition >= pageHeight) {
|
|
87
|
+
resolve()
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
window.scrollBy(0, scrollStep)
|
|
91
|
+
currentScrollPosition += scrollStep
|
|
92
|
+
setTimeout(scrollNext, stepDelay)
|
|
93
|
+
}
|
|
94
|
+
scrollNext()
|
|
95
|
+
}),
|
|
96
|
+
timeout
|
|
97
|
+
)
|
|
98
|
+
await page.evaluate(() => window.scrollTo(0, 0))
|
|
99
|
+
}
|
|
100
|
+
|
|
35
101
|
const waitForElement = async (page, element) => {
|
|
36
102
|
const screenshotOpts = {}
|
|
37
|
-
|
|
38
103
|
if (element) {
|
|
39
104
|
await page.waitForSelector(element, { visible: true })
|
|
40
105
|
screenshotOpts.clip = await page.$eval(element, getBoundingClientRect)
|
|
41
106
|
screenshotOpts.fullPage = false
|
|
42
107
|
return screenshotOpts
|
|
43
108
|
}
|
|
44
|
-
|
|
45
109
|
return screenshotOpts
|
|
46
110
|
}
|
|
47
111
|
|
|
@@ -51,35 +115,58 @@ module.exports = ({ goto, ...gotoOpts }) => {
|
|
|
51
115
|
return function screenshot (page) {
|
|
52
116
|
return async (
|
|
53
117
|
url,
|
|
54
|
-
{
|
|
55
|
-
element,
|
|
56
|
-
codeScheme = 'atom-dark',
|
|
57
|
-
overlay: overlayOpts = {},
|
|
58
|
-
waitUntil = 'auto',
|
|
59
|
-
...opts
|
|
60
|
-
} = {}
|
|
118
|
+
{ codeScheme = 'atom-dark', overlay: overlayOpts = {}, waitUntil = 'auto', ...opts } = {}
|
|
61
119
|
) => {
|
|
62
120
|
let screenshot
|
|
63
121
|
let response
|
|
64
122
|
|
|
65
|
-
const beforeScreenshot = response => {
|
|
66
|
-
const timeout = goto.timeouts.action(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
123
|
+
const beforeScreenshot = async (page, response, { element, fullPage = false } = {}) => {
|
|
124
|
+
const timeout = goto.timeouts.action(opts.timeout)
|
|
125
|
+
|
|
126
|
+
let screenshotOpts = {}
|
|
127
|
+
const tasks = [
|
|
128
|
+
{
|
|
129
|
+
fn: () => page.evaluate('document.fonts.ready'),
|
|
130
|
+
debug: 'beforeScreenshot:fontsReady'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
fn: () => waitForImagesOnViewport(page),
|
|
134
|
+
debug: 'beforeScreenshot:waitForImagesOnViewport'
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
if (codeScheme && response) {
|
|
139
|
+
tasks.push({
|
|
140
|
+
fn: () => waitForPrism(page, response, { codeScheme, ...opts }),
|
|
141
|
+
debug: 'beforeScreenshot:waitForPrism'
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (fullPage) {
|
|
146
|
+
tasks.push({
|
|
147
|
+
fn: () => scrollFullPageToLoadContent(page, timeout, goto),
|
|
148
|
+
debug: 'beforeScreenshot:scrollFullPageToLoadContent'
|
|
149
|
+
})
|
|
150
|
+
} else if (element) {
|
|
151
|
+
tasks.push({
|
|
152
|
+
fn: async () => {
|
|
153
|
+
screenshotOpts = await waitForElement(page, element)
|
|
76
154
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
155
|
+
debug: 'beforeScreenshot:waitForElement'
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await Promise.all(
|
|
160
|
+
tasks.map(({ fn, ...opts }) =>
|
|
161
|
+
goto.run({
|
|
162
|
+
fn: fn(),
|
|
163
|
+
...opts,
|
|
164
|
+
timeout: fullPage ? timeout * 2 : timeout
|
|
165
|
+
})
|
|
166
|
+
)
|
|
82
167
|
)
|
|
168
|
+
|
|
169
|
+
return screenshotOpts
|
|
83
170
|
}
|
|
84
171
|
|
|
85
172
|
const takeScreenshot = async opts => {
|
|
@@ -98,19 +185,13 @@ module.exports = ({ goto, ...gotoOpts }) => {
|
|
|
98
185
|
|
|
99
186
|
if (waitUntil !== 'auto') {
|
|
100
187
|
;({ response } = await goto(page, { ...opts, url, waitUntil }))
|
|
101
|
-
const
|
|
102
|
-
waitForElement(page, element),
|
|
103
|
-
beforeScreenshot(response)
|
|
104
|
-
])
|
|
188
|
+
const screenshotOpts = await beforeScreenshot(page, response, opts)
|
|
105
189
|
screenshot = await page.screenshot({ ...opts, ...screenshotOpts })
|
|
106
190
|
debug('screenshot', { waitUntil, duration: timeScreenshot() })
|
|
107
191
|
} else {
|
|
108
192
|
;({ response } = await goto(page, { ...opts, url, waitUntil, waitUntilAuto }))
|
|
109
193
|
async function waitUntilAuto (page, { response }) {
|
|
110
|
-
const
|
|
111
|
-
waitForElement(page, element),
|
|
112
|
-
beforeScreenshot(response)
|
|
113
|
-
])
|
|
194
|
+
const screenshotOpts = await beforeScreenshot(page, response, opts)
|
|
114
195
|
const { isWhite } = await takeScreenshot({ ...opts, ...screenshotOpts })
|
|
115
196
|
debug('screenshot', { waitUntil, isWhite, duration: timeScreenshot() })
|
|
116
197
|
}
|
package/src/pretty/index.js
CHANGED
|
@@ -32,8 +32,6 @@ const JSONParse = input => {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
module.exports = async (page, response, { timeout, codeScheme, styles, scripts, modules }) => {
|
|
35
|
-
if (!response || !codeScheme) return
|
|
36
|
-
|
|
37
35
|
let [theme, content, prism] = await Promise.all([getTheme(codeScheme), response.text(), getPrism])
|
|
38
36
|
|
|
39
37
|
if (isHtmlContent(content)) return
|