@datawheel/bespoke 0.6.0-rc.4 → 0.6.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.js +26 -144
- package/package.json +2 -3
package/dist/server.js
CHANGED
|
@@ -26,8 +26,7 @@ import * as allIcons from '@tabler/icons-react';
|
|
|
26
26
|
import NextCors from 'nextjs-cors';
|
|
27
27
|
import imageType from 'image-type';
|
|
28
28
|
import formidable from 'formidable';
|
|
29
|
-
import
|
|
30
|
-
import puppeteer2 from 'puppeteer';
|
|
29
|
+
import { chromium } from 'playwright-chromium';
|
|
31
30
|
import DomParser from 'dom-parser';
|
|
32
31
|
import path from 'path';
|
|
33
32
|
import axiosRetry from 'axios-retry';
|
|
@@ -4221,114 +4220,6 @@ function endpointUpdateMyDataFactory(operations) {
|
|
|
4221
4220
|
}
|
|
4222
4221
|
}, []);
|
|
4223
4222
|
}
|
|
4224
|
-
async function generatePDF(path2) {
|
|
4225
|
-
const width = 1920;
|
|
4226
|
-
const height = 1080;
|
|
4227
|
-
const maxTimeoutPerPage = 0;
|
|
4228
|
-
try {
|
|
4229
|
-
const browser = await puppeteer.launch({
|
|
4230
|
-
args: [
|
|
4231
|
-
`--window-size=${width},${height}`,
|
|
4232
|
-
"--start-fullscreen"
|
|
4233
|
-
],
|
|
4234
|
-
defaultViewport: { width, height },
|
|
4235
|
-
headless: "shell",
|
|
4236
|
-
ignoreHTTPSErrors: true
|
|
4237
|
-
});
|
|
4238
|
-
const url = new URL(path2);
|
|
4239
|
-
const searchParams = new URLSearchParams(url.search);
|
|
4240
|
-
searchParams.set("print", "true");
|
|
4241
|
-
url.search = searchParams.toString();
|
|
4242
|
-
const page = await browser.newPage();
|
|
4243
|
-
await page.goto(url.toString(), { waitUntil: "networkidle0", timeout: maxTimeoutPerPage });
|
|
4244
|
-
await page.waitForSelector("#bespoke-report", { timeout: maxTimeoutPerPage });
|
|
4245
|
-
await page.evaluate(async () => {
|
|
4246
|
-
await new Promise((resolve) => {
|
|
4247
|
-
const scrollInterval = setInterval(() => {
|
|
4248
|
-
window.scrollBy(0, window.innerHeight);
|
|
4249
|
-
}, 100);
|
|
4250
|
-
const checkNetworkActivity = () => {
|
|
4251
|
-
const activeRequests = performance.getEntriesByType("resource").filter((entry) => entry.duration === 0);
|
|
4252
|
-
return activeRequests.length === 0;
|
|
4253
|
-
};
|
|
4254
|
-
const checkInterval = setInterval(() => {
|
|
4255
|
-
if (checkNetworkActivity()) {
|
|
4256
|
-
clearInterval(scrollInterval);
|
|
4257
|
-
clearInterval(checkInterval);
|
|
4258
|
-
resolve();
|
|
4259
|
-
}
|
|
4260
|
-
}, 1e3);
|
|
4261
|
-
});
|
|
4262
|
-
});
|
|
4263
|
-
const pdf = await page.pdf({
|
|
4264
|
-
displayHeaderFooter: true,
|
|
4265
|
-
footerTemplate: `
|
|
4266
|
-
<div
|
|
4267
|
-
style="
|
|
4268
|
-
color: lightgray; border-top: solid lightgray 1px; font-size: 10px;
|
|
4269
|
-
padding-top: 5px; text-align: center; width: 100%;
|
|
4270
|
-
"
|
|
4271
|
-
>
|
|
4272
|
-
<p>Page <span class="pageNumber" /> of <span class="totalPages" /></p>
|
|
4273
|
-
</div>`,
|
|
4274
|
-
format: "A4",
|
|
4275
|
-
// Letter,Legal,Tabloid,Ledger,A0,A1,A2,A3,A4,A5,A6
|
|
4276
|
-
headerTemplate: `
|
|
4277
|
-
<div
|
|
4278
|
-
style="
|
|
4279
|
-
color: lightgray; border-bottom: solid lightgray 1px; font-size: 10px;
|
|
4280
|
-
padding-bottom: 5px; text-align: center; width: 100%;
|
|
4281
|
-
"
|
|
4282
|
-
>
|
|
4283
|
-
<p class="url" />
|
|
4284
|
-
</div>`,
|
|
4285
|
-
// height: `${height}px`,
|
|
4286
|
-
landscape: false,
|
|
4287
|
-
margin: {
|
|
4288
|
-
bottom: 70,
|
|
4289
|
-
// minimum required for footer msg to display
|
|
4290
|
-
left: 20,
|
|
4291
|
-
right: 20,
|
|
4292
|
-
top: 70
|
|
4293
|
-
// minimum required for header msg to display
|
|
4294
|
-
},
|
|
4295
|
-
omitBackground: true,
|
|
4296
|
-
pageRanges: "",
|
|
4297
|
-
// All
|
|
4298
|
-
// path: "./test.pdf" // Path to save the file
|
|
4299
|
-
preferCSSPageSize: false,
|
|
4300
|
-
// Give any CSS @page size declared in the page priority over what is declared in the width or height or format option.
|
|
4301
|
-
printBackground: true,
|
|
4302
|
-
scale: 1,
|
|
4303
|
-
// From 0.1 to 2
|
|
4304
|
-
tagged: false,
|
|
4305
|
-
// Generate tagged (accessible) PDF.
|
|
4306
|
-
timeout: 0
|
|
4307
|
-
// width: `${width}px`,
|
|
4308
|
-
});
|
|
4309
|
-
await browser.close();
|
|
4310
|
-
return pdf.toString("base64");
|
|
4311
|
-
} catch (error) {
|
|
4312
|
-
console.error("Error generating PDF:", error);
|
|
4313
|
-
throw error;
|
|
4314
|
-
}
|
|
4315
|
-
}
|
|
4316
|
-
function endpointDownloadReport() {
|
|
4317
|
-
return endpoint("POST", "pdf", async (req, res) => {
|
|
4318
|
-
const { slugs, path: path2 } = req.body;
|
|
4319
|
-
if (!slugs || !path2) {
|
|
4320
|
-
throw new BackendError(400, "Missing path parameter in request.");
|
|
4321
|
-
} else {
|
|
4322
|
-
const url = new URL(path2, req.headers["origin"]);
|
|
4323
|
-
const pdf = await generatePDF(url);
|
|
4324
|
-
return {
|
|
4325
|
-
ok: true,
|
|
4326
|
-
status: 200,
|
|
4327
|
-
data: pdf
|
|
4328
|
-
};
|
|
4329
|
-
}
|
|
4330
|
-
});
|
|
4331
|
-
}
|
|
4332
4223
|
var minimal_args = [
|
|
4333
4224
|
"--autoplay-policy=user-gesture-required",
|
|
4334
4225
|
"--disable-background-networking",
|
|
@@ -4368,56 +4259,47 @@ var minimal_args = [
|
|
|
4368
4259
|
"--disable-dev-shm-usage",
|
|
4369
4260
|
"--no-sandbox"
|
|
4370
4261
|
];
|
|
4371
|
-
var
|
|
4372
|
-
"google-analytics.com",
|
|
4373
|
-
"googletagmanager.com"
|
|
4374
|
-
];
|
|
4262
|
+
var TIME = "playwright";
|
|
4375
4263
|
async function generateImage(path2, section, format = "png", transparent = false) {
|
|
4376
4264
|
const width = 1366;
|
|
4377
4265
|
const height = 768;
|
|
4378
4266
|
const maxTimeoutPerPage = 0;
|
|
4379
|
-
console.time(
|
|
4267
|
+
console.time(TIME);
|
|
4380
4268
|
try {
|
|
4381
|
-
const browser = await
|
|
4269
|
+
const browser = await chromium.launch({
|
|
4270
|
+
executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
|
|
4382
4271
|
args: [
|
|
4383
4272
|
`--window-size=${width},${height}`,
|
|
4384
4273
|
...minimal_args
|
|
4385
|
-
]
|
|
4386
|
-
defaultViewport: { width, height, deviceScaleFactor: 2 },
|
|
4387
|
-
ignoreHTTPSErrors: true,
|
|
4388
|
-
headless: true
|
|
4274
|
+
]
|
|
4389
4275
|
});
|
|
4390
|
-
|
|
4276
|
+
const context = await browser.newContext({
|
|
4277
|
+
viewport: { width, height },
|
|
4278
|
+
deviceScaleFactor: 2
|
|
4279
|
+
});
|
|
4280
|
+
console.timeLog(TIME, "Browser started");
|
|
4391
4281
|
const url = new URL(path2);
|
|
4392
4282
|
const searchParams = new URLSearchParams(url.search);
|
|
4393
4283
|
url.search = searchParams.toString();
|
|
4394
|
-
const page = await
|
|
4395
|
-
console.timeLog(
|
|
4284
|
+
const page = await context.newPage();
|
|
4285
|
+
console.timeLog(TIME, "Creating page");
|
|
4396
4286
|
await page.addStyleTag({ content: ".bespoke-Section-container{ padding: 1rem !important }" });
|
|
4397
|
-
|
|
4398
|
-
page.
|
|
4399
|
-
|
|
4400
|
-
if (blocked_domains.some((domain) => url2.includes(domain))) {
|
|
4401
|
-
request.abort();
|
|
4402
|
-
} else {
|
|
4403
|
-
request.continue();
|
|
4404
|
-
}
|
|
4405
|
-
});
|
|
4406
|
-
console.timeLog("puppeteer", "Setting request interceptor");
|
|
4407
|
-
await page.goto(url.toString(), { waitUntil: "networkidle0", timeout: maxTimeoutPerPage });
|
|
4408
|
-
console.timeLog("puppeteer", "Navigated to page");
|
|
4287
|
+
console.timeLog(TIME, "Setting request interceptor");
|
|
4288
|
+
await page.goto(url.toString(), { timeout: maxTimeoutPerPage });
|
|
4289
|
+
console.timeLog(TIME, "Navigated to page");
|
|
4409
4290
|
await page.waitForSelector("#bespoke-report", { timeout: maxTimeoutPerPage });
|
|
4410
|
-
console.timeLog(
|
|
4291
|
+
console.timeLog(TIME, "Selector detected");
|
|
4292
|
+
await page.waitForLoadState("networkidle");
|
|
4411
4293
|
if (transparent) {
|
|
4412
4294
|
await page.$eval(`.bespoke-Section-${section}`, (el) => el["style"].background = "transparent");
|
|
4413
4295
|
await page.evaluate(() => document.body.style.background = "transparent");
|
|
4414
|
-
console.timeLog(
|
|
4296
|
+
console.timeLog(TIME, "Added transparent background");
|
|
4415
4297
|
}
|
|
4416
4298
|
if (format === "svg") {
|
|
4417
4299
|
const element = await page.$(".d3plus-viz");
|
|
4418
4300
|
const svg = await element?.evaluate((el) => el.outerHTML);
|
|
4419
|
-
console.timeLog(
|
|
4420
|
-
console.timeEnd(
|
|
4301
|
+
console.timeLog(TIME, "Finishing SVG");
|
|
4302
|
+
console.timeEnd(TIME);
|
|
4421
4303
|
await browser.close();
|
|
4422
4304
|
return svg?.replace(/ {4}|[\t\n\r]/gm, "");
|
|
4423
4305
|
} else {
|
|
@@ -4426,15 +4308,15 @@ async function generateImage(path2, section, format = "png", transparent = false
|
|
|
4426
4308
|
type: "png",
|
|
4427
4309
|
omitBackground: true
|
|
4428
4310
|
});
|
|
4429
|
-
console.timeLog(
|
|
4430
|
-
console.timeEnd(
|
|
4311
|
+
console.timeLog(TIME, "Finishing PNG");
|
|
4312
|
+
console.timeEnd(TIME);
|
|
4431
4313
|
await browser.close();
|
|
4432
4314
|
return screenshot;
|
|
4433
4315
|
}
|
|
4434
4316
|
} catch (error) {
|
|
4435
4317
|
console.error("Error generating Image:", error);
|
|
4436
|
-
console.timeLog(
|
|
4437
|
-
console.timeEnd(
|
|
4318
|
+
console.timeLog(TIME, "Finishing with error");
|
|
4319
|
+
console.timeEnd(TIME);
|
|
4438
4320
|
throw error;
|
|
4439
4321
|
}
|
|
4440
4322
|
}
|
|
@@ -4560,7 +4442,7 @@ function getEndpointMap(db) {
|
|
|
4560
4442
|
endpointRevalidateReportFactory(api),
|
|
4561
4443
|
endpointRevalidateUrlFactory(),
|
|
4562
4444
|
endpointReadPrivateBlocksFactory(api),
|
|
4563
|
-
endpointDownloadReport(),
|
|
4445
|
+
// endpointDownloadReport(),
|
|
4564
4446
|
endpointExportImage(),
|
|
4565
4447
|
endpointListIconsFactory(api, "tabler"),
|
|
4566
4448
|
endpointReadIconFactory(api, "tabler"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datawheel/bespoke",
|
|
3
|
-
"version": "0.6.0-rc.
|
|
3
|
+
"version": "0.6.0-rc.6",
|
|
4
4
|
"description": "Content management system for creating automated data reports",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -103,9 +103,8 @@
|
|
|
103
103
|
"nextjs-cors": "^2.1.1",
|
|
104
104
|
"normalizr": "^3.6.2",
|
|
105
105
|
"pg": "^8.7.3",
|
|
106
|
+
"playwright-chromium": "^1.44.1",
|
|
106
107
|
"pretty-format": "^28.1.1",
|
|
107
|
-
"puppeteer": "^22.10.0",
|
|
108
|
-
"puppeteer-core": "^22.10.0",
|
|
109
108
|
"react": "^18.2.0",
|
|
110
109
|
"react-clipboard.js": "^2.0.16",
|
|
111
110
|
"react-dom": "^18.2.0",
|