@datawheel/bespoke 0.6.0-rc.3 → 0.6.0-rc.5
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 +27 -136
- 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 chromium from '@sparticuz/chromium';
|
|
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,116 +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
|
-
chromium.setHeadlessMode = true;
|
|
4333
|
-
chromium.setGraphicsMode = false;
|
|
4334
4223
|
var minimal_args = [
|
|
4335
4224
|
"--autoplay-policy=user-gesture-required",
|
|
4336
4225
|
"--disable-background-networking",
|
|
@@ -4370,49 +4259,47 @@ var minimal_args = [
|
|
|
4370
4259
|
"--disable-dev-shm-usage",
|
|
4371
4260
|
"--no-sandbox"
|
|
4372
4261
|
];
|
|
4373
|
-
var
|
|
4374
|
-
"google-analytics.com",
|
|
4375
|
-
"googletagmanager.com"
|
|
4376
|
-
];
|
|
4262
|
+
var TIME = "playwright";
|
|
4377
4263
|
async function generateImage(path2, section, format = "png", transparent = false) {
|
|
4378
4264
|
const width = 1366;
|
|
4379
4265
|
const height = 768;
|
|
4380
4266
|
const maxTimeoutPerPage = 0;
|
|
4267
|
+
console.time(TIME);
|
|
4381
4268
|
try {
|
|
4382
|
-
const browser = await
|
|
4269
|
+
const browser = await chromium.launch({
|
|
4383
4270
|
args: [
|
|
4384
4271
|
`--window-size=${width},${height}`,
|
|
4385
|
-
...minimal_args
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
headless: chromium.headless
|
|
4272
|
+
...minimal_args
|
|
4273
|
+
]
|
|
4274
|
+
});
|
|
4275
|
+
const context = await browser.newContext({
|
|
4276
|
+
viewport: { width, height },
|
|
4277
|
+
deviceScaleFactor: 2
|
|
4392
4278
|
});
|
|
4279
|
+
console.timeLog(TIME, "Browser started");
|
|
4393
4280
|
const url = new URL(path2);
|
|
4394
4281
|
const searchParams = new URLSearchParams(url.search);
|
|
4395
4282
|
url.search = searchParams.toString();
|
|
4396
|
-
const page = await
|
|
4283
|
+
const page = await context.newPage();
|
|
4284
|
+
console.timeLog(TIME, "Creating page");
|
|
4397
4285
|
await page.addStyleTag({ content: ".bespoke-Section-container{ padding: 1rem !important }" });
|
|
4398
|
-
|
|
4399
|
-
page.
|
|
4400
|
-
|
|
4401
|
-
if (blocked_domains.some((domain) => url2.includes(domain))) {
|
|
4402
|
-
request.abort();
|
|
4403
|
-
} else {
|
|
4404
|
-
request.continue();
|
|
4405
|
-
}
|
|
4406
|
-
});
|
|
4407
|
-
await page.goto(url.toString(), { waitUntil: "networkidle0", timeout: maxTimeoutPerPage });
|
|
4286
|
+
console.timeLog(TIME, "Setting request interceptor");
|
|
4287
|
+
await page.goto(url.toString(), { timeout: maxTimeoutPerPage });
|
|
4288
|
+
console.timeLog(TIME, "Navigated to page");
|
|
4408
4289
|
await page.waitForSelector("#bespoke-report", { timeout: maxTimeoutPerPage });
|
|
4290
|
+
console.timeLog(TIME, "Selector detected");
|
|
4291
|
+
await page.waitForLoadState("networkidle");
|
|
4409
4292
|
if (transparent) {
|
|
4410
4293
|
await page.$eval(`.bespoke-Section-${section}`, (el) => el["style"].background = "transparent");
|
|
4411
4294
|
await page.evaluate(() => document.body.style.background = "transparent");
|
|
4295
|
+
console.timeLog(TIME, "Added transparent background");
|
|
4412
4296
|
}
|
|
4413
4297
|
if (format === "svg") {
|
|
4414
4298
|
const element = await page.$(".d3plus-viz");
|
|
4415
4299
|
const svg = await element?.evaluate((el) => el.outerHTML);
|
|
4300
|
+
console.timeLog(TIME, "Finishing SVG");
|
|
4301
|
+
console.timeEnd(TIME);
|
|
4302
|
+
await browser.close();
|
|
4416
4303
|
return svg?.replace(/ {4}|[\t\n\r]/gm, "");
|
|
4417
4304
|
} else {
|
|
4418
4305
|
const element = await page.$(".bespoke-Section-container");
|
|
@@ -4420,11 +4307,15 @@ async function generateImage(path2, section, format = "png", transparent = false
|
|
|
4420
4307
|
type: "png",
|
|
4421
4308
|
omitBackground: true
|
|
4422
4309
|
});
|
|
4310
|
+
console.timeLog(TIME, "Finishing PNG");
|
|
4311
|
+
console.timeEnd(TIME);
|
|
4423
4312
|
await browser.close();
|
|
4424
4313
|
return screenshot;
|
|
4425
4314
|
}
|
|
4426
4315
|
} catch (error) {
|
|
4427
4316
|
console.error("Error generating Image:", error);
|
|
4317
|
+
console.timeLog(TIME, "Finishing with error");
|
|
4318
|
+
console.timeEnd(TIME);
|
|
4428
4319
|
throw error;
|
|
4429
4320
|
}
|
|
4430
4321
|
}
|
|
@@ -4550,7 +4441,7 @@ function getEndpointMap(db) {
|
|
|
4550
4441
|
endpointRevalidateReportFactory(api),
|
|
4551
4442
|
endpointRevalidateUrlFactory(),
|
|
4552
4443
|
endpointReadPrivateBlocksFactory(api),
|
|
4553
|
-
endpointDownloadReport(),
|
|
4444
|
+
// endpointDownloadReport(),
|
|
4554
4445
|
endpointExportImage(),
|
|
4555
4446
|
endpointListIconsFactory(api, "tabler"),
|
|
4556
4447
|
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.5",
|
|
4
4
|
"description": "Content management system for creating automated data reports",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"@mantine/prism": "^6.0.19",
|
|
53
53
|
"@monaco-editor/react": "^4.4.5",
|
|
54
54
|
"@reduxjs/toolkit": "^1.8.4",
|
|
55
|
-
"@sparticuz/chromium": "^123.0.1",
|
|
56
55
|
"@tabler/icons-react": "^2.15.0",
|
|
57
56
|
"@tiptap/extension-hard-break": "^2.2.2",
|
|
58
57
|
"@tiptap/extension-history": "^2.2.2",
|
|
@@ -104,8 +103,8 @@
|
|
|
104
103
|
"nextjs-cors": "^2.1.1",
|
|
105
104
|
"normalizr": "^3.6.2",
|
|
106
105
|
"pg": "^8.7.3",
|
|
106
|
+
"playwright-chromium": "^1.44.1",
|
|
107
107
|
"pretty-format": "^28.1.1",
|
|
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",
|