Skip to content

Commit d188bad

Browse files
committed
Expose .create method
1 parent 263e355 commit d188bad

File tree

4 files changed

+241
-215
lines changed

4 files changed

+241
-215
lines changed

src/browserless.js

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
'use strict'
2+
3+
const createTempFile = require('create-temp-file2')
4+
const extractDomain = require('extract-domain')
5+
const puppeteer = require('puppeteer')
6+
const debug = require('debug')('browserless')
7+
8+
const { getDevice } = require('./devices')
9+
const isTracker = require('./is-tracker')
10+
11+
const WAIT_UNTIL = ['networkidle2', 'load', 'domcontentloaded']
12+
13+
const EVALUATE_TEXT = page => page.evaluate(() => document.body.innerText)
14+
15+
const EVALUATE_HTML = page => page.content()
16+
17+
const isEmpty = val => val == null || !(Object.keys(val) || val).length
18+
19+
const isExternalUrl = (domainOne, domainTwo) => domainOne !== domainTwo
20+
21+
module.exports = launchOpts => {
22+
let browser = puppeteer.launch(launchOpts)
23+
24+
const newPage = () =>
25+
Promise.resolve(browser).then(browser => browser.newPage())
26+
27+
const goto = async (
28+
page,
29+
{
30+
url,
31+
abortTrackers,
32+
abortTypes,
33+
waitFor,
34+
waitUntil,
35+
userAgent,
36+
viewport,
37+
args
38+
}
39+
) => {
40+
await page.setRequestInterception(true)
41+
let reqCount = { abort: 0, continue: 0 }
42+
43+
page.on('request', req => {
44+
const resourceUrl = req.url()
45+
46+
const resourceType = req.resourceType()
47+
48+
if (abortTypes.includes(resourceType)) {
49+
debug(`abort:${resourceType}:${++reqCount.abort}`, resourceUrl)
50+
return req.abort()
51+
}
52+
53+
const urlDomain = extractDomain(url)
54+
const resourceDomain = extractDomain(resourceUrl)
55+
const isExternal = isExternalUrl(urlDomain, resourceDomain)
56+
57+
if (abortTrackers && isExternal && isTracker(resourceDomain)) {
58+
debug(`abort:tracker:${++reqCount.abort}`, resourceUrl)
59+
return req.abort()
60+
}
61+
62+
debug(`continue:${resourceType}:${++reqCount.continue}`, resourceUrl)
63+
return req.continue()
64+
})
65+
66+
if (userAgent) await page.setUserAgent(userAgent)
67+
if (viewport) await page.setViewport(viewport)
68+
const response = await page.goto(url, Object.assign({ waitUntil }, args))
69+
if (waitFor) await page.waitFor(waitFor)
70+
debug(reqCount)
71+
return response
72+
}
73+
74+
const evaluate = fn => async (url, opts = {}) => {
75+
const {
76+
abortTrackers = true,
77+
abortTypes = ['image', 'media', 'stylesheet', 'font'],
78+
waitFor = 0,
79+
waitUntil = WAIT_UNTIL,
80+
userAgent,
81+
viewport,
82+
...args
83+
} = opts
84+
85+
const page = await newPage()
86+
const response = await goto(page, {
87+
url,
88+
abortTrackers,
89+
abortTypes,
90+
waitFor,
91+
waitUntil,
92+
userAgent,
93+
viewport,
94+
args
95+
})
96+
97+
const content = await fn(page, response)
98+
await page.close()
99+
return content
100+
}
101+
102+
const screenshot = async (url, opts = {}) => {
103+
const {
104+
abortTypes = [],
105+
device: deviceName = 'macbook pro 13',
106+
tmpOpts,
107+
type = 'png',
108+
userAgent,
109+
viewport,
110+
waitFor = 0,
111+
waitUntil = WAIT_UNTIL,
112+
...args
113+
} = opts
114+
115+
const tempFile = createTempFile(Object.assign({ ext: `.${type}` }, tmpOpts))
116+
const { path } = tempFile
117+
118+
const { userAgent: deviceUserAgent, viewport: deviceViewport } = getDevice(
119+
deviceName
120+
)
121+
122+
const page = await newPage()
123+
124+
await goto(page, {
125+
userAgent: isEmpty(userAgent) ? deviceUserAgent : userAgent,
126+
viewport: Object.assign({}, deviceViewport, viewport),
127+
url,
128+
abortTypes,
129+
waitFor,
130+
waitUntil,
131+
args
132+
})
133+
134+
await page.screenshot(Object.assign({ path, type }, args))
135+
136+
await page.close()
137+
return Promise.resolve(tempFile)
138+
}
139+
140+
const pdf = async (url, opts = {}) => {
141+
const {
142+
abortTrackers = false,
143+
abortTypes = [],
144+
device: deviceName = 'macbook pro 13',
145+
format = 'A4',
146+
margin = {
147+
top: '0.25cm',
148+
right: '0.25cm',
149+
bottom: '0.25cm',
150+
left: '0.25cm'
151+
},
152+
media = 'screen',
153+
printBackground = true,
154+
scale = 0.65,
155+
tmpOpts,
156+
userAgent,
157+
viewport,
158+
waitFor = 0,
159+
waitUntil = WAIT_UNTIL,
160+
...args
161+
} = opts
162+
163+
const tempFile = createTempFile(Object.assign({ ext: `.pdf` }, tmpOpts))
164+
const { path } = tempFile
165+
166+
const { userAgent: deviceUserAgent, viewport: deviceViewport } = getDevice(
167+
deviceName
168+
)
169+
170+
const page = await newPage()
171+
172+
await page.emulateMedia(media)
173+
174+
await goto(page, {
175+
userAgent: isEmpty(userAgent) ? deviceUserAgent : userAgent,
176+
viewport: Object.assign({}, deviceViewport, viewport),
177+
url,
178+
abortTrackers,
179+
abortTypes,
180+
waitFor,
181+
waitUntil,
182+
args
183+
})
184+
185+
await page.pdf(
186+
Object.assign(
187+
{
188+
margin,
189+
path,
190+
format,
191+
printBackground,
192+
scale
193+
},
194+
args
195+
)
196+
)
197+
198+
await page.close()
199+
return Promise.resolve(tempFile)
200+
}
201+
202+
return {
203+
browser,
204+
html: evaluate(EVALUATE_HTML),
205+
text: evaluate(EVALUATE_TEXT),
206+
evaluate,
207+
pdf,
208+
screenshot,
209+
page: newPage,
210+
goto
211+
}
212+
}

src/create.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict'
2+
3+
const browserless = require('.')
4+
5+
module.exports = opts =>
6+
browserless({
7+
ignoreHTTPSErrors: true,
8+
args: [
9+
'--disable-notifications',
10+
'--disable-offer-store-unmasked-wallet-cards',
11+
'--disable-offer-upload-credit-cards',
12+
'--disable-setuid-sandbox',
13+
'--enable-async-dns',
14+
'--enable-simple-cache-backend',
15+
'--enable-tcp-fast-open',
16+
'--media-cache-size=33554432',
17+
'--no-default-browser-check',
18+
'--no-pings',
19+
'--no-sandbox',
20+
'--no-zygote',
21+
'--prerender-from-omnibox=disabled',
22+
'--single-process'
23+
],
24+
...opts
25+
})

src/devices/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ const devices = puppeteerDevices.concat(customDevices)
88
const getDevice = deviceName =>
99
devices.find(device => device.name.toLowerCase() === deviceName.toLowerCase())
1010

11-
module.exports.devices = devices
11+
module.exports = devices
1212
module.exports.getDevice = getDevice

0 commit comments

Comments
 (0)