@cloudcannon/suite
Version:
A suite of gulp tools to manage static sites on CloudCannon
159 lines (132 loc) • 4.83 kB
JavaScript
const through = require("through2").obj,
//exec = require('await-exec'),
log = require("fancy-log"),
c = require('ansi-colors'),
fs = require('fs-extra'),
path = require("path"),
timeout = ms => new Promise(res => setTimeout(res, ms)),
merge = require("merge-img");
module.exports = function (screenshotter, tagmap) {
return through(async function(file, enc, cb) {
log(`Launching browser`)
await screenshotter.launchBrowser();
log(`Launching server`)
let serverUrl = await screenshotter.launchServer();
let srcPath = path.join(process.cwd(), screenshotter.options.path);
let urlPath = path.relative(srcPath, file.path);
log(`Launching page`)
let page = await screenshotter.loadPage(serverUrl, urlPath, {
name: "desktop",
width: 1920,
height: 1080
});
if (!page) {
log(`No page, shutting down browser and server`);
await screenshotter.shutdownServer();
await screenshotter.shutdownBrowser();
return cb();
}
log(`Finding data-i18n tags`)
const tags = await page.evaluate(() => {
const i18ntags = Array.from(document.querySelectorAll('[data-i18n]'))
return i18ntags.map(i18ntag => {
let tagObj = {};
tagObj.content = i18ntag.innerHTML;
tagObj.type = i18ntag.tagName.toLowerCase();
tagObj.i18n = i18ntag.getAttribute('data-i18n');
let range = document.createRange();
range.selectNodeContents(i18ntag);
let rect = range.getBoundingClientRect();
if (!rect) {
rect = i18ntag.getBoundingClientRect();
}
tagObj.top = rect.top;
tagObj.right = rect.right;
tagObj.bottom = rect.bottom;
tagObj.left = rect.left;
return tagObj;
});
}).catch(e => console.error(e));
log(`Formatting data-i18n tags`)
tags.forEach(i18ntag => {
tagmap[i18ntag.i18n] = tagmap[i18ntag.i18n] || {pages: [], content: []};
let formatUrl = urlPath.replace(/index\.html/, '');
formatUrl = formatUrl.replace(/^\//, '');
tagmap[i18ntag.i18n].pages.push({url: formatUrl, type: i18ntag.type});
if (tagmap[i18ntag.i18n].content.indexOf(i18ntag.content) < 0) {
tagmap[i18ntag.i18n].content.push(i18ntag.content);
}
});
log(`Taking screenshot`);
if (screenshotter.options.delay) {
log(`Waiting ${screenshotter.options.delay}ms`);
await timeout(screenshotter.options.delay);
}
let screenshotOptions = {encoding: (screenshotter.options.base64 ? "base64" : "binary")};
log(`Finding page size`);
const { width, height } = await Promise.race([
page.evaluate(function() {
const body = document.querySelector('body');
const boundingBox = body.getBoundingClientRect();
return {width: boundingBox.width, height: boundingBox.height};
}).catch(e => log.error(e)),
new Promise(function(resolve) {
setTimeout(function() {resolve(false);}, 2000);
})
]);
if (!width || !height) {
log(`Couldn't find page dimensions in time, shutting down browser and server`);
await screenshotter.shutdownServer();
await screenshotter.shutdownBrowser();
return cb();
}
let segmentHeight = 4000;
let numSegments = Math.ceil(height / segmentHeight);
screenshotOptions.clip = {
x: 0,
y: 0,
width,
height: segmentHeight
};
log(`Taking screenshot in ${numSegments} parts, at ${width}px by ${height}px total`);
let screenshot;
for (let n = 0; n < numSegments; n++) {
screenshotOptions.clip.y = Math.min(segmentHeight * n, height);
screenshotOptions.clip.height = Math.min(screenshotOptions.clip.height, height - screenshotOptions.clip.y);
const screenshotBottom = await page.screenshot(screenshotOptions);
if (screenshot) {
screenshot = await merge([screenshot, screenshotBottom], { direction: true });
} else {
screenshot = screenshotBottom;
}
}
log(c.greenBright(`Screenshot completed ${page.url()} ✓`));
log(`Page closing`);
await page.close();
log(`Page closed`);
log(`Shutting down browser and server`);
await screenshotter.shutdownServer();
await screenshotter.shutdownBrowser();
log(`Ensuring directory`);
let shotDir = path.join(screenshotter.options.dest, urlPath);
await fs.ensureDir(path.dirname(shotDir));
if (screenshot) {
log(`Outputting image`);
if (numSegments > 1) {
await screenshot.write(shotDir.replace(/html$/, 'png'), (error) => {
if (error)console.log(error);
});
} else {
await fs.writeFile(shotDir.replace(/html$/, 'png'), screenshot, (error) => {
if(error)console.log(error);
});
}
//await fs.ensureDir(shotDir.replace(/html$/, 'tiles/'));
//await exec(`convert ${shotDir.replace(/html$/, 'png')} -crop 240x240 ${shotDir.replace(/html$/, 'tiles')}/tile%d.png`);
}
log(`Outputting json`);
await fs.writeFile(shotDir.replace(/html$/, 'json'), JSON.stringify([...tags], null, 2));
this.push(file);
cb();
});
};