@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.
Files changed (2) hide show
  1. package/dist/server.js +27 -136
  2. 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 puppeteer from 'puppeteer-core';
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 blocked_domains = [
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 puppeteer.launch({
4269
+ const browser = await chromium.launch({
4383
4270
  args: [
4384
4271
  `--window-size=${width},${height}`,
4385
- ...minimal_args,
4386
- ...chromium.args
4387
- ],
4388
- defaultViewport: { width, height, deviceScaleFactor: 2 },
4389
- ignoreHTTPSErrors: true,
4390
- executablePath: await chromium.executablePath(),
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 browser.newPage();
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
- await page.setRequestInterception(true);
4399
- page.on("request", (request) => {
4400
- const url2 = request.url();
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",
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",