@scullyio/scully-plugin-playwright
Version:
The playwright renderer is utilizing the [playwright](https://playwright.dev/) engine to render your pages.
171 lines • 7.99 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.playwrightRenderer = exports.playwrightRender = exports.title404 = void 0;
const tslib_1 = require("tslib");
const scully_1 = require("@scullyio/scully");
const cli_options_1 = require("@scullyio/scully/src/lib/utils/cli-options");
const fs_extra_1 = require("fs-extra");
const jsonc_1 = require("jsonc");
const path_1 = require("path");
const plugins_scully_plugin_playwright_utils_1 = require("./plugins-scully-plugin-playwright-utils");
let version = '0.0.0';
try {
const pkg = path_1.join(__dirname, '../../../package.json');
version = jsonc_1.jsonc.parse(fs_extra_1.readFileSync(pkg).toString()).version || '0.0.0';
}
catch (e) {
// this is only for internals builds
}
exports.title404 = '404 - URL not provided in the app Scully is serving';
const errorredPages = new Map();
exports.playwrightRender = 'playwrightRender';
const playwrightRenderer = (route) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const path = route.rawRoute
? route.rawRoute
: scully_1.scullyConfig.hostUrl
? `${scully_1.scullyConfig.hostUrl}${route.route}`
: `http${cli_options_1.ssl ? 's' : ''}://${scully_1.scullyConfig.hostName}:${scully_1.scullyConfig.appPort}${route.route}`;
let pageHtml;
let browser;
let page;
try {
browser = yield plugins_scully_plugin_playwright_utils_1.launchedBrowser().catch((e) => {
scully_1.logError('Playwright died?', e);
return Promise.reject(e);
});
// open a new page
page = yield browser.newPage();
let resolve;
const pageReady = new Promise((r) => (resolve = r));
if (scully_1.scullyConfig.ignoreResourceTypes && scully_1.scullyConfig.ignoreResourceTypes.length > 0) {
yield page.route('**/*', (route) => checkIfRequestShouldBeIgnored.bind(route.request));
// eslint-disable-next-line no-inner-declarations
function checkIfRequestShouldBeIgnored(request) {
if (scully_1.scullyConfig.ignoreResourceTypes.includes(request.resourceType())) {
request.abort();
}
else {
request.continue();
}
}
}
/** this will be called from the browser, but runs in node */
yield page.exposeFunction('pageRenderReady', () => {
resolve();
});
windowSet(page, 'scullyVersion', version);
if (route.config && route.config.manualIdleCheck) {
route.exposeToPage = route.exposeToPage || {};
route.exposeToPage.manualIdle = true;
}
if (scully_1.scullyConfig.inlineStateOnly) {
route.injectToPage = route.injectToPage || {};
route.injectToPage.inlineStateOnly = true;
}
if (route.exposeToPage !== undefined) {
windowSet(page, 'ScullyIO-exposed', route.exposeToPage);
}
if (route.injectToPage !== undefined) {
windowSet(page, 'ScullyIO-injected', route.injectToPage);
}
/** Inject this into the running page, runs in browser */
yield page.addInitScript(() => {
/** set "running" mode */
window['ScullyIO'] = 'running';
window.addEventListener('AngularReady', () => {
window['pageRenderReady']();
});
});
// enter url in page
yield page.goto(path);
yield Promise.race([pageReady, plugins_scully_plugin_playwright_utils_1.waitForIt(25 * 1000)]);
/** when done, add in some scully content. */
yield page.evaluate(() => {
const head = document.head;
/** add a small script tag to set "generated" mode */
const d = document.createElement('script');
d.innerHTML = `window['ScullyIO']='generated';`;
if (window['ScullyIO-injected']) {
/** and add the injected data there too. */
d.innerHTML += `window['ScullyIO-injected']=${JSON.stringify(window['ScullyIO-injected'])};`;
}
const m = document.createElement('meta');
m.name = 'generator';
m.content = `Scully ${window['scullyVersion']}`;
head.appendChild(d);
head.insertBefore(m, head.firstChild);
/** inject the scully version into the body attribute */
document.body.setAttribute('scully-version', window['scullyVersion']);
});
pageHtml = yield page.content();
/** Check for undefined content and re-try */
if ([undefined, null, '', 'undefined', 'null'].includes(pageHtml)) {
throw new Error(`Route "${route.route}" render to ${path}`);
}
const firstTitle = yield page.evaluate(() => {
const d = document.querySelector('h1');
return (d && d.innerText) || '';
});
if (firstTitle === exports.title404) {
scully_1.logWarn(`Route "${scully_1.yellow(route.route)}" not provided by angular app`);
}
/** save thumbnail to disk code */
if (scully_1.scullyConfig.thumbnails) {
const file = path_1.join(scully_1.scullyConfig.outDir, route.route, '/thumbnail.jpg');
scully_1.createFolderFor(file);
yield page.screenshot({ path: file });
}
/**
* when the browser is shown, use a 2 minute timeout, otherwise
* wait for page-read || timeout @ 25 seconds.
*/
if (cli_options_1.showBrowser) {
page.evaluate("console.log('\\n\\n------------------------------\\nScully is done, page left open for 120 seconds for inspection\\n------------------------------\\n\\n')");
//* don't close the browser, but leave it open for inspection for 120 secs
plugins_scully_plugin_playwright_utils_1.waitForIt(1200 * 1000).then(() => page.close());
}
else {
// await page.close();
page.close();
}
}
catch (err) {
const { message } = err;
// tslint:disable-next-line: no-unused-expression
page && typeof page.close === 'function' && (yield page.close());
scully_1.logWarn(`Playwright error while rendering "${scully_1.yellow(route.route)}"`, err, ' we will retry rendering this page up to 3 times.');
if (message && message.includes('closed')) {
/** signal the launched to relaunch playwright, as it has likely died here. */
//TODO:c
plugins_scully_plugin_playwright_utils_1.reLaunch('closed');
// return playwrightRender(route);
}
if (errorredPages.has(route.route) && errorredPages.get(route.route) > 2) {
scully_1.logError(`Playwright error while rendering "${scully_1.yellow(route.route)}"`, err, ' we retried rendering this page 3 times.');
/** we tried this page before, something is really off. Exit stage left. */
//TODO:
// captureException(err);
process.exit(15);
}
else {
const count = errorredPages.get(route.route) || 0;
errorredPages.set(route.route, count + 1);
/** give it a couple of secs */
yield plugins_scully_plugin_playwright_utils_1.waitForIt(3 * 1000);
/** retry! */
return exports.playwrightRenderer(route);
}
}
// logWarn(`done with page ${path}`);
return pageHtml;
});
exports.playwrightRenderer = playwrightRenderer;
const windowSet = (page, name, value) => page.addInitScript(`
Object.defineProperty(window, '${name}', {
get() {
return JSON.parse('${JSON.stringify(value)}')
}
})
`);
scully_1.registerPlugin('scullySystem', exports.playwrightRender, exports.playwrightRenderer);
//# sourceMappingURL=plugins-scully-plugin-playwright.js.map
;