diff --git a/src/gui/src/services/pdfThumbnails/README.md b/src/gui/src/services/pdfThumbnails/README.md index 83821a34f..cb7d7c05a 100644 --- a/src/gui/src/services/pdfThumbnails/README.md +++ b/src/gui/src/services/pdfThumbnails/README.md @@ -11,7 +11,12 @@ PDF.js and its fonts, CMaps, ICC profiles and WASM decoders are copied into the versioned `/dist/pdf-thumbnails/` directory during the GUI build. Deploy that directory with the GUI. `PDFJS_VERSION` must match the exact GUI dependency; the build rejects mismatches. The SDK and initial GUI bundle contain no PDF.js. -Asset requests stay on the GUI origin and begin only for an eligible PDF. +Asset requests begin only for an eligible PDF. Bundled builds load them beside +the GUI bundle, including when it is served from a CDN; unbundled development +uses `/dist/pdf-thumbnails/` on the page's origin. A cross-origin asset host must +allow CORS for the worker, modules, fonts, CMaps, ICC profiles and WASM files. +Cross-origin builds use a local Blob module worker that imports the hosted +worker, so the page's CSP must allow `blob:` workers and imports from that host. Each PDF gets a disposable module worker. PDF.js uses its loopback transport inside that worker, so termination stops both parsing and rasterization. Fonts diff --git a/src/gui/src/services/pdfThumbnails/browser.test.js b/src/gui/src/services/pdfThumbnails/browser.test.js index 4270b8660..5c1ca9050 100644 --- a/src/gui/src/services/pdfThumbnails/browser.test.js +++ b/src/gui/src/services/pdfThumbnails/browser.test.js @@ -1,6 +1,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { chromium } from '@playwright/test'; import express from 'express'; +import webpack from 'webpack'; import { mkdtemp, readFile, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; @@ -10,6 +11,8 @@ import { createPdf } from '../../../tests/fixtures/pdf.js'; let browser; let server; +let cdnServer; +let cdnOrigin; let directory; let origin; let workerMode; @@ -17,6 +20,34 @@ let workerMode; beforeAll(async () => { directory = await mkdtemp(path.join(tmpdir(), 'puter-pdf-thumbnails-')); await copyPdfThumbnailAssets(directory); + await new Promise((resolve, reject) => { + const compiler = webpack({ + mode: 'production', + entry: fileURLToPath(new URL('./index.js', import.meta.url)), + output: { + path: directory, + filename: 'bundle.js', + library: { name: 'pdfThumbnails', type: 'window' }, + }, + }); + compiler.run((error, stats) => { + compiler.close(closeError => { + if ( error || closeError ) return reject(error || closeError); + if ( stats.hasErrors() ) return reject(new Error(stats.toString())); + resolve(); + }); + }); + }); + const cdn = express(); + cdn.use((_req, res, next) => { + res.set('Access-Control-Allow-Origin', '*'); + next(); + }); + cdn.use('/assets', express.static(directory)); + cdnServer = await new Promise(resolve => { + const listener = cdn.listen(0, '127.0.0.1', () => resolve(listener)); + }); + cdnOrigin = `http://127.0.0.1:${cdnServer.address().port}`; const app = express(); app.get('/dist/pdf-thumbnails/:version/worker.js', (_req, res, next) => { if ( workerMode === 'missing' ) return res.sendStatus(404); @@ -27,6 +58,9 @@ beforeAll(async () => { // The generator's relative import into the SDK source climbs past /src, which the browser clamps to /puter-js/src. app.use('/puter-js/src', express.static(fileURLToPath(new URL('../../../../puter-js/src/', import.meta.url)))); app.use('/src', express.static(fileURLToPath(new URL('../../', import.meta.url)))); + app.get('/bundled', (req, res) => res.send(`Bundled thumbnail test + + `)); app.get('/', (_req, res) => res.send(`Thumbnail test