prerender
Advanced tools
| diff --git a/lib/browsers/chrome.js b/lib/browsers/chrome.js | ||
| index d3bb913..080da16 100644 | ||
| --- a/lib/browsers/chrome.js | ||
| +++ b/lib/browsers/chrome.js | ||
| @@ -17,6 +17,7 @@ const CaptureScreenshotTimedOut = 'CaptureScreenshotTimedOut'; | ||
| const UnableToCaptureScreenshot = 'UnableToCaptureScreenshot'; | ||
| const PrintPdfTimedOut = 'PrintPdfTimedOut'; | ||
| const UnableToCapturePdf = 'UnableToCapturePdf'; | ||
| +const NoExecutionContext = 'NoExecutionContext'; | ||
| chrome.name = 'Chrome'; | ||
| @@ -33,6 +34,9 @@ chrome.spawn = function (options) { | ||
| } | ||
| this.chromeChild = spawn(location, this.options.chromeFlags || [ | ||
| + // this.chromeChild = spawn('/usr/bin/taskset', [ | ||
| + // '-c', '1', | ||
| + // location, | ||
| '--headless', | ||
| '--disable-gpu', | ||
| '--remote-debugging-port=' + this.options.browserDebuggingPort, | ||
| @@ -162,6 +166,7 @@ chrome.openTab = function (options) { | ||
| tab.prerender = options; | ||
| tab.prerender.errors = []; | ||
| tab.prerender.requests = {}; | ||
| + console.log("Cleanup 1"); | ||
| tab.prerender.numRequestsInFlight = 0; | ||
| return this.setUpEvents(tab); | ||
| @@ -203,18 +208,37 @@ chrome.setUpEvents = async function (tab) { | ||
| Network, | ||
| Emulation, | ||
| Log, | ||
| - Console | ||
| + Console, | ||
| + Runtime, | ||
| } = tab; | ||
| + | ||
| + | ||
| await Promise.all([ | ||
| DOM.enable(), | ||
| Page.enable(), | ||
| Security.enable(), | ||
| Network.enable(), | ||
| Log.enable(), | ||
| - Console.enable() | ||
| + Console.enable(), | ||
| + Runtime.enable(), | ||
| ]); | ||
| + Runtime.executionContextCreated((event) => { | ||
| + if ( event.context | ||
| + && event.context.auxData | ||
| + && (!tab.defaultExecutionContext | ||
| + || (tab.prerender.mainFrame && event.context.auxData.frameId == tab.prerender.mainFrame.id))) { | ||
| + tab.defaultExecutionContext = event.context; | ||
| + } | ||
| + }); | ||
| + | ||
| + Page.frameNavigated((event) => { | ||
| + if (!tab.prerender.mainFrame) { | ||
| + tab.prerender.mainFrame = event.frame; | ||
| + } | ||
| + }) | ||
| + | ||
| //hold onto info that could be used later if saving a HAR file | ||
| tab.prerender.pageLoadInfo = { | ||
| url: tab.prerender.url, | ||
| @@ -260,6 +284,8 @@ chrome.setUpEvents = async function (tab) { | ||
| }, 1000); | ||
| }); | ||
| + Network.requestServedFromCache((e) => console.log("served from cache", e)); | ||
| + | ||
| Security.certificateError(({ eventId }) => { | ||
| Security.handleCertificateError({ | ||
| eventId, | ||
| @@ -274,6 +300,7 @@ chrome.setUpEvents = async function (tab) { | ||
| tab.prerender.requests[params.requestId] = params.request.url; | ||
| if (tab.prerender.logRequests || this.options.logRequests) util.log('+', tab.prerender.numRequestsInFlight, params.request.url); | ||
| + util.log(`Request to ${params.request.url}, ${tab.prerender.numRequestsInFlight}`); | ||
| if (!tab.prerender.initialRequestId) { | ||
| util.log(`Initial request to ${params.request.url}`); | ||
| tab.prerender.initialRequestId = params.requestId; | ||
| @@ -297,6 +324,7 @@ chrome.setUpEvents = async function (tab) { | ||
| //during a redirect, we don't get the responseReceived event for the original request, | ||
| //so lets decrement the number of requests in flight here. | ||
| //the original requestId is also reused for the redirected request | ||
| + console.log('R1'); | ||
| tab.prerender.numRequestsInFlight--; | ||
| let redirectEntry = tab.prerender.pageLoadInfo.entries[params.requestId]; | ||
| @@ -343,6 +371,7 @@ chrome.setUpEvents = async function (tab) { | ||
| } | ||
| if (params.type === "EventSource") { | ||
| + console.log('Response 1'); | ||
| tab.prerender.numRequestsInFlight--; | ||
| tab.prerender.lastRequestReceivedAt = new Date().getTime(); | ||
| if (tab.prerender.logRequests || this.options.logRequests) util.log('-', tab.prerender.numRequestsInFlight, tab.prerender.requests[params.requestId]); | ||
| @@ -365,6 +394,7 @@ chrome.setUpEvents = async function (tab) { | ||
| util.log(`Initial request finished ${request}`); | ||
| } | ||
| + console.log('Loading finished 1', tab.prerender.numRequestsInFlight); | ||
| tab.prerender.numRequestsInFlight--; | ||
| tab.prerender.lastRequestReceivedAt = new Date().getTime(); | ||
| @@ -384,6 +414,7 @@ chrome.setUpEvents = async function (tab) { | ||
| //all outstanding requests will fire this event | ||
| Network.loadingFailed((params) => { | ||
| if (tab.prerender.requests[params.requestId]) { | ||
| + console.log("Loading failed 1"); | ||
| tab.prerender.numRequestsInFlight--; | ||
| if (tab.prerender.logRequests || this.options.logRequests) util.log('-', tab.prerender.numRequestsInFlight, tab.prerender.requests[params.requestId]); | ||
| delete tab.prerender.requests[params.requestId]; | ||
| @@ -481,6 +512,11 @@ chrome.loadUrlThenWaitForPageLoadEvent = function (tab, url, onNavigated) { | ||
| if (!finished) { | ||
| finished = true; | ||
| util.log('page timed out', tab.prerender.url); | ||
| + // console.log( | ||
| + // JSON.stringify( | ||
| + // tab.prerender.pageLoadInfo.entries, null, 2 | ||
| + // ) | ||
| + // ); | ||
| const timeoutStatusCode = tab.prerender.timeoutStatusCode || this.options.timeoutStatusCode; | ||
| if (timeoutStatusCode) { | ||
| @@ -501,6 +537,7 @@ chrome.loadUrlThenWaitForPageLoadEvent = function (tab, url, onNavigated) { | ||
| let width = parseInt(tab.prerender.width, 10) || 1440; | ||
| let height = parseInt(tab.prerender.height, 10) || 718; | ||
| + console.log(` == width: ${width}, height: ${height}`); | ||
| Emulation.setDeviceMetricsOverride({ | ||
| width: width, | ||
| screenWidth: width, | ||
| @@ -561,6 +598,7 @@ chrome.checkIfPageIsDoneLoading = function (tab) { | ||
| expression: 'window.prerenderReady' | ||
| }).then((result) => { | ||
| let prerenderReady = result && result.result && result.result.value; | ||
| + console.log("prerenderReady", prerenderReady); | ||
| let shouldWaitForPrerenderReady = typeof prerenderReady == 'boolean'; | ||
| let waitAfterLastRequest = tab.prerender.waitAfterLastRequest || this.options.waitAfterLastRequest; | ||
| @@ -574,6 +612,14 @@ chrome.checkIfPageIsDoneLoading = function (tab) { | ||
| tab.prerender.lastRequestReceivedAt < ((new Date()).getTime() - waitAfterLastRequest) | ||
| const timeSpentAfterFirstPrerenderReady = (tab.prerender.firstPrerenderReadyTime && (new Date().getTime() - tab.prerender.firstPrerenderReadyTime)) || 0; | ||
| + try { | ||
| + console.log(` == CHECK IF PAGE DONE LOADING doneLoading: ${doneLoading}`); | ||
| + console.log(` == CHECK IF PAGE DONE LOADING numRequestsInFlight: ${tab.prerender.numRequestsInFlight}`); | ||
| + console.log(` == CHECK IF PAGE DONE LOADING waitAfterLastRequest: ${waitAfterLastRequest}`); | ||
| + console.log(` == SHOULD WAIT FOR PRERENDER READY: ${shouldWaitForPrerenderReady}`); | ||
| + } catch (e) { | ||
| + console.log("c error", e); | ||
| + } | ||
| resolve( | ||
| (!shouldWaitForPrerenderReady && doneLoading) || | ||
| @@ -636,7 +682,10 @@ const getHtmlWithShadowDomFunction = () => { | ||
| const attributeNames = htmlNode.getAttributeNames(); | ||
| const attrStringList = attributeNames.map((attributeName) => (`${attributeName}="${htmlNode.getAttribute(attributeName)}"`)) | ||
| - return '<!DOCTYPE html>'+'<html '+ attrStringList.join(' ') +'>'+innerText+'</html>'; | ||
| + return `<!DOCTYPE html> | ||
| + <html ${attrStringList.join(' ')}> | ||
| + ${innerText} | ||
| + </html>`; | ||
| } | ||
| chrome.parseHtmlFromPage = function (tab) { | ||
| @@ -654,10 +703,19 @@ chrome.parseHtmlFromPage = function (tab) { | ||
| ? getHtmlWithShadowDomFunction.toString() | ||
| : getHtmlFunction.toString(); | ||
| - tab.Runtime.evaluate({ | ||
| - expression: "document.firstElementChild.outerHTML" | ||
| - }).then((resp) => { | ||
| + if (!tab.defaultExecutionContext) { | ||
| + util.log('No default exectution context found. Can\'t evaluate page. ', tab.prerender.url); | ||
| + tab.prerender.statusCode = 504; | ||
| + tab.prerender.errors.push(NoExecutionContext); | ||
| + reject(); | ||
| + } | ||
| + tab.Runtime.callFunctionOn({ | ||
| + expression: getHtmlFunctionText, | ||
| + functionDeclaration: getHtmlFunctionText, | ||
| + executionContextId: tab.defaultExecutionContext.id, | ||
| + userGesture: true | ||
| + }).then((resp) => { | ||
| tab.prerender.content = resp.result.value; | ||
| if (tab.prerender.content === undefined) { | ||
| tab.prerender.statusCode = 504; |
| diff --git a/lib/browsers/chrome.js b/lib/browsers/chrome.js | ||
| index 2568daa..7afc61d 100644 | ||
| --- a/lib/browsers/chrome.js | ||
| +++ b/lib/browsers/chrome.js | ||
| @@ -32,7 +32,9 @@ chrome.spawn = function (options) { | ||
| return reject(); | ||
| } | ||
| - this.chromeChild = spawn(location, this.options.chromeFlags || [ | ||
| + this.chromeChild = spawn('/usr/bin/taskset', [ | ||
| + '-c', '1', | ||
| + location, | ||
| '--headless', | ||
| '--disable-gpu', | ||
| '--remote-debugging-port=' + this.options.browserDebuggingPort, |
+3
-0
@@ -5,2 +5,5 @@ # Change Log | ||
| ## 5.20.0 - 2022-05-06 | ||
| - If a request made during rendering gets a 5XX response the render process will be marked as dirty | ||
| ## 5.19.0 - 2022-03-23 | ||
@@ -7,0 +10,0 @@ - Ability to parse content from the shadow DOM |
@@ -351,2 +351,6 @@ const CDP = require('chrome-remote-interface'); | ||
| } | ||
| if (params.response && params.response.status >= 500 && params.response.status < 600) { // 5XX | ||
| tab.prerender.dirtyRender = true; | ||
| } | ||
| }); | ||
@@ -353,0 +357,0 @@ |
+1
-1
@@ -5,3 +5,3 @@ { | ||
| "description": "Service to prerender Javascript rendered pages for SEO", | ||
| "version": "5.19.0", | ||
| "version": "5.20.0", | ||
| "license": "MIT", | ||
@@ -8,0 +8,0 @@ "repository": { |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 19 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 19 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
98755
9.45%23
9.52%1616
0.19%