1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.addJob = addJob;
|
7 | exports.removeJob = removeJob;
|
8 | exports.launchBrowserIfNeeded = launchBrowserIfNeeded;
|
9 | exports.closeBrowser = closeBrowser;
|
10 | exports.restartBrowser = restartBrowser;
|
11 | exports.browserIsRunning = browserIsRunning;
|
12 | exports.getOpenBrowserPage = getOpenBrowserPage;
|
13 | exports.closeBrowserPage = closeBrowserPage;
|
14 |
|
15 | var _puppeteer = _interopRequireDefault(require("puppeteer"));
|
16 |
|
17 | var _debug = _interopRequireDefault(require("debug"));
|
18 |
|
19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
20 |
|
21 | const debuglog = (0, _debug.default)('penthouse:browser');
|
22 |
|
23 | let browser = null;
|
24 | let _browserLaunchPromise = null;
|
25 | let reusableBrowserPages = [];
|
26 |
|
27 |
|
28 | let ongoingJobs = 0;
|
29 |
|
30 | function addJob() {
|
31 | ongoingJobs = ongoingJobs + 1;
|
32 | }
|
33 |
|
34 | function removeJob() {
|
35 | ongoingJobs = ongoingJobs - 1;
|
36 | }
|
37 |
|
38 | const DEFAULT_PUPPETEER_LAUNCH_ARGS = ['--disable-setuid-sandbox', '--no-sandbox', '--ignore-certificate-errors'
|
39 |
|
40 |
|
41 |
|
42 | ];
|
43 |
|
44 | async function launchBrowserIfNeeded({
|
45 | getBrowser,
|
46 | width,
|
47 | height
|
48 | }) {
|
49 | if (browser) {
|
50 | return;
|
51 | }
|
52 |
|
53 | const usingCustomGetBrowser = getBrowser && typeof getBrowser === 'function';
|
54 |
|
55 | if (usingCustomGetBrowser && !_browserLaunchPromise) {
|
56 | debuglog('using browser provided via getBrowser option');
|
57 | _browserLaunchPromise = Promise.resolve(getBrowser());
|
58 | }
|
59 |
|
60 | if (!_browserLaunchPromise) {
|
61 | debuglog('no browser instance, launching new browser..');
|
62 | _browserLaunchPromise = _puppeteer.default.launch({
|
63 | args: DEFAULT_PUPPETEER_LAUNCH_ARGS,
|
64 | ignoreHTTPSErrors: true,
|
65 | defaultViewport: {
|
66 | width,
|
67 | height
|
68 | }
|
69 | });
|
70 | }
|
71 |
|
72 | _browserLaunchPromise.then(async browser => {
|
73 | debuglog('browser ready');
|
74 | const browserPages = await browser.pages();
|
75 |
|
76 | if (browserPages.length > 0) {
|
77 | debuglog('re-using the page browser launched with');
|
78 | browserPages.forEach(Page => {
|
79 | if (!reusableBrowserPages.includes(Page)) {
|
80 | Page.notSetupForPenthouse = true;
|
81 | reusableBrowserPages.push(Page);
|
82 | } else {
|
83 | debuglog('ignoring browser page already inside reusableBrowserPages');
|
84 | }
|
85 | });
|
86 | }
|
87 |
|
88 | return browser;
|
89 | });
|
90 |
|
91 | browser = await _browserLaunchPromise;
|
92 | _browserLaunchPromise = null;
|
93 | }
|
94 |
|
95 | async function closeBrowser({
|
96 | forceClose,
|
97 | unstableKeepBrowserAlive
|
98 | }) {
|
99 | if (browser && (forceClose || !unstableKeepBrowserAlive)) {
|
100 | if (ongoingJobs > 0) {
|
101 | debuglog('keeping browser open as ongoingJobs: ' + ongoingJobs);
|
102 | } else if (browser && browser.close) {
|
103 | browser.close();
|
104 | browser = null;
|
105 | _browserLaunchPromise = null;
|
106 | debuglog('closed browser');
|
107 | }
|
108 | }
|
109 | }
|
110 |
|
111 | async function restartBrowser({
|
112 | getBrowser,
|
113 | width,
|
114 | height
|
115 | }) {
|
116 | let browserPages;
|
117 |
|
118 | if (browser) {
|
119 | browserPages = await browser.pages();
|
120 | }
|
121 |
|
122 | debuglog('restartBrowser called' + browser && browserPages && '\n_browserPagesOpen: ' + browserPages.length);
|
123 |
|
124 |
|
125 | if (_browserLaunchPromise) {
|
126 |
|
127 | await _browserLaunchPromise;
|
128 |
|
129 | } else if (!getBrowser) {
|
130 | console.log('now restarting chrome after crash');
|
131 | browser = null;
|
132 | await launchBrowserIfNeeded({
|
133 | width,
|
134 | height
|
135 | });
|
136 | }
|
137 | }
|
138 |
|
139 | async function browserIsRunning() {
|
140 | try {
|
141 |
|
142 | await browser.version();
|
143 | return true;
|
144 | } catch (e) {
|
145 | return false;
|
146 | }
|
147 | }
|
148 |
|
149 | async function getOpenBrowserPage() {
|
150 | const browserPages = await browser.pages();
|
151 |
|
152 | if (reusableBrowserPages.length > 0) {
|
153 | debuglog('re-using browser page for generateCriticalCss, remaining at: ' + browserPages.length);
|
154 | const reusedPage = reusableBrowserPages.pop();
|
155 | let reused = true;
|
156 |
|
157 |
|
158 | if (reusedPage.notSetupForPenthouse) {
|
159 | reused = false;
|
160 |
|
161 | delete reusedPage.notSetupForPenthouse;
|
162 | }
|
163 |
|
164 | return Promise.resolve({
|
165 | page: reusedPage,
|
166 | reused
|
167 | });
|
168 | }
|
169 |
|
170 | debuglog('adding browser page for generateCriticalCss, before adding was: ' + browserPages.length);
|
171 | return browser.newPage().then(page => {
|
172 | return {
|
173 | page
|
174 | };
|
175 | });
|
176 | }
|
177 |
|
178 | async function closeBrowserPage({
|
179 | page,
|
180 | error,
|
181 | unstableKeepBrowserAlive,
|
182 | unstableKeepOpenPages
|
183 | }) {
|
184 | if (!browser || !page) {
|
185 | return;
|
186 | }
|
187 |
|
188 | const browserPages = await browser.pages();
|
189 | debuglog('remove (maybe) browser page for generateCriticalCss, before removing was: ' + browserPages.length);
|
190 | const badErrors = ['Target closed', 'Page crashed'];
|
191 |
|
192 | if (page && !(error && badErrors.some(badError => error.toString().indexOf(badError) > -1))) {
|
193 |
|
194 |
|
195 | try {
|
196 |
|
197 |
|
198 |
|
199 | if (unstableKeepBrowserAlive) {
|
200 | if (unstableKeepOpenPages !== 'all' && browserPages.length > unstableKeepOpenPages) {
|
201 | page.close();
|
202 | } else {
|
203 | debuglog('saving page for re-use, instead of closing');
|
204 |
|
205 | if (error) {
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 | debuglog('Reset page first..');
|
212 | await page.goto('about:blank').then(() => {
|
213 | debuglog('... page reset DONE');
|
214 | });
|
215 | }
|
216 |
|
217 | reusableBrowserPages.push(page);
|
218 | }
|
219 | } else {
|
220 | debuglog('now try to close browser page');
|
221 | await page.close();
|
222 | }
|
223 | } catch (err) {
|
224 | debuglog('failed to close browser page (ignoring)');
|
225 | }
|
226 | }
|
227 | } |
\ | No newline at end of file |