diff --git a/gulpfile.mjs b/gulpfile.mjs index 6a4d51b03..a99a104bc 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -362,10 +362,6 @@ function createWebpackConfig( // V8 chokes on very long sequences, work around that. sequences: false, }, - mangle: { - // Ensure that the `tweakWebpackOutput` function works. - reserved: ["__webpack_exports__"], - }, keep_classnames: true, keep_fnames: true, module: isModule, @@ -463,13 +459,6 @@ function checkChromePreferencesFile(chromePrefsPath, webPrefs) { return ret; } -function tweakWebpackOutput(jsName) { - return replace( - /((?:\s|,)__webpack_exports__)(?:\s?)=(?:\s?)({};)/gm, - (match, p1, p2) => `${p1} = globalThis.${jsName} = ${p2}` - ); -} - function createMainBundle(defines) { const mainFileConfig = createWebpackConfig(defines, { filename: defines.MINIFIED ? "pdf.min.mjs" : "pdf.mjs", @@ -479,8 +468,7 @@ function createMainBundle(defines) { }); return gulp .src("./src/pdf.js", { encoding: false }) - .pipe(webpack2Stream(mainFileConfig)) - .pipe(tweakWebpackOutput("pdfjsLib")); + .pipe(webpack2Stream(mainFileConfig)); } function createScriptingBundle(defines, extraOptions = undefined) { @@ -548,8 +536,7 @@ function createSandboxBundle(defines, extraOptions = undefined) { return gulp .src("./src/pdf.sandbox.js", { encoding: false }) - .pipe(webpack2Stream(sandboxFileConfig)) - .pipe(tweakWebpackOutput("pdfjsSandbox")); + .pipe(webpack2Stream(sandboxFileConfig)); } function createWorkerBundle(defines) { @@ -561,8 +548,7 @@ function createWorkerBundle(defines) { }); return gulp .src("./src/pdf.worker.js", { encoding: false }) - .pipe(webpack2Stream(workerFileConfig)) - .pipe(tweakWebpackOutput("pdfjsWorker")); + .pipe(webpack2Stream(workerFileConfig)); } function createWebBundle(defines, options) { @@ -610,8 +596,7 @@ function createComponentsBundle(defines) { }); return gulp .src("./web/pdf_viewer.component.js", { encoding: false }) - .pipe(webpack2Stream(componentsFileConfig)) - .pipe(tweakWebpackOutput("pdfjsViewer")); + .pipe(webpack2Stream(componentsFileConfig)); } function createImageDecodersBundle(defines) { @@ -625,8 +610,7 @@ function createImageDecodersBundle(defines) { }); return gulp .src("./src/pdf.image_decoders.js", { encoding: false }) - .pipe(webpack2Stream(componentsFileConfig)) - .pipe(tweakWebpackOutput("pdfjsImageDecoders")); + .pipe(webpack2Stream(componentsFileConfig)); } function createCMapBundle() { diff --git a/package-lock.json b/package-lock.json index 5f3d8950c..22ced23e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,7 @@ "ttest": "^4.0.0", "typescript": "^5.8.3", "vinyl": "^3.0.0", - "webpack": "^5.98.0", + "webpack": "^5.99.5", "webpack-stream": "^7.0.0", "yargs": "^17.7.2" }, @@ -12388,9 +12388,9 @@ } }, "node_modules/webpack": { - "version": "5.98.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", - "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "version": "5.99.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.5.tgz", + "integrity": "sha512-q+vHBa6H9qwBLUlHL4Y7L0L1/LlyBKZtS9FHNCQmtayxjI5RKC9yD8gpvLeqGv5lCQp1Re04yi0MF40pf30Pvg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 323d3ba3f..27eee246d 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "ttest": "^4.0.0", "typescript": "^5.8.3", "vinyl": "^3.0.0", - "webpack": "^5.98.0", + "webpack": "^5.99.5", "webpack-stream": "^7.0.0", "yargs": "^17.7.2" }, diff --git a/src/display/api.js b/src/display/api.js index a223d5e6f..e210118b3 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -2136,6 +2136,13 @@ class PDFWorker { ); }; } + + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { + this._resetGlobalState = () => { + this.#isWorkerDisabled = false; + delete globalThis.pdfjsWorker; + }; + } } constructor({ diff --git a/src/pdf.image_decoders.js b/src/pdf.image_decoders.js index 633d51105..2631f46f7 100644 --- a/src/pdf.image_decoders.js +++ b/src/pdf.image_decoders.js @@ -29,6 +29,18 @@ const pdfjsVersion = const pdfjsBuild = typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0; +globalThis.pdfjsImageDecoders = { + getVerbosityLevel, + Jbig2Error, + Jbig2Image, + JpegError, + JpegImage, + JpxError, + JpxImage, + setVerbosityLevel, + VerbosityLevel, +}; + export { getVerbosityLevel, Jbig2Error, diff --git a/src/pdf.js b/src/pdf.js index e9a1b974c..2a3acbaaf 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -93,6 +93,59 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING || GENERIC")) { }; } +globalThis.pdfjsLib = { + AbortException, + AnnotationEditorLayer, + AnnotationEditorParamsType, + AnnotationEditorType, + AnnotationEditorUIManager, + AnnotationLayer, + AnnotationMode, + AnnotationType, + build, + ColorPicker, + createValidAbsoluteUrl, + DOMSVGFactory, + DrawLayer, + FeatureTest, + fetchData, + getDocument, + getFilenameFromUrl, + getPdfFilenameFromUrl, + getUuid, + getXfaPageViewport, + GlobalWorkerOptions, + ImageKind, + InvalidPDFException, + isDataScheme, + isPdfFile, + isValidExplicitDest, + MathClamp, + noContextMenu, + normalizeUnicode, + OPS, + OutputScale, + PasswordResponses, + PDFDataRangeTransport, + PDFDateString, + PDFWorker, + PermissionFlag, + PixelsPerInch, + RenderingCancelledException, + ResponseException, + setLayerDimensions, + shadow, + SignatureExtractor, + stopEvent, + SupportedImageMimeTypes, + TextLayer, + TouchManager, + Util, + VerbosityLevel, + version, + XfaLayer, +}; + export { AbortException, AnnotationEditorLayer, diff --git a/src/pdf.sandbox.js b/src/pdf.sandbox.js index 79cb05ec1..4752f9f59 100644 --- a/src/pdf.sandbox.js +++ b/src/pdf.sandbox.js @@ -145,4 +145,8 @@ function QuickJSSandbox() { return ModuleLoader().then(module => new Sandbox(window, module)); } +globalThis.pdfjsSandbox = { + QuickJSSandbox, +}; + export { QuickJSSandbox }; diff --git a/src/pdf.worker.js b/src/pdf.worker.js index 900c0b02a..5d6bdf0aa 100644 --- a/src/pdf.worker.js +++ b/src/pdf.worker.js @@ -22,4 +22,8 @@ const pdfjsVersion = const pdfjsBuild = typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0; +globalThis.pdfjsWorker = { + WorkerMessageHandler, +}; + export { WorkerMessageHandler }; diff --git a/test/unit/pdf.image_decoders_spec.js b/test/unit/pdf.image_decoders_spec.js index d12210e3d..ebd583fd3 100644 --- a/test/unit/pdf.image_decoders_spec.js +++ b/test/unit/pdf.image_decoders_spec.js @@ -22,6 +22,18 @@ import { Jbig2Error, Jbig2Image } from "../../src/core/jbig2.js"; import { JpegError, JpegImage } from "../../src/core/jpg.js"; import { JpxError, JpxImage } from "../../src/core/jpx.js"; +const expectedAPI = Object.freeze({ + getVerbosityLevel, + Jbig2Error, + Jbig2Image, + JpegError, + JpegImage, + JpxError, + JpxImage, + setVerbosityLevel, + VerbosityLevel, +}); + describe("pdfimage_api", function () { it("checks that the *official* PDF.js-image decoders API exposes the expected functionality", async function () { // eslint-disable-next-line no-unsanitized/method @@ -33,16 +45,10 @@ describe("pdfimage_api", function () { // The imported Object contains an (automatically) inserted Symbol, // hence we copy the data to allow using a simple comparison below. - expect({ ...pdfimageAPI }).toEqual({ - getVerbosityLevel, - Jbig2Error, - Jbig2Image, - JpegError, - JpegImage, - JpxError, - JpxImage, - setVerbosityLevel, - VerbosityLevel, - }); + expect({ ...pdfimageAPI }).toEqual(expectedAPI); + + expect(Object.keys(globalThis.pdfjsImageDecoders).sort()).toEqual( + Object.keys(expectedAPI).sort() + ); }); }); diff --git a/test/unit/pdf.worker_spec.js b/test/unit/pdf.worker_spec.js index f90498662..b02fc6746 100644 --- a/test/unit/pdf.worker_spec.js +++ b/test/unit/pdf.worker_spec.js @@ -13,9 +13,20 @@ * limitations under the License. */ +import { PDFWorker } from "../../src/display/api.js"; import { WorkerMessageHandler } from "../../src/core/worker.js"; +const expectedAPI = Object.freeze({ + WorkerMessageHandler, +}); + describe("pdfworker_api", function () { + afterEach(function () { + // Avoid interfering with other unit-tests, since `globalThis.pdfjsWorker` + // being defined will impact loading and usage of the worker. + PDFWorker._resetGlobalState(); + }); + it("checks that the *official* PDF.js-worker API exposes the expected functionality", async function () { // eslint-disable-next-line no-unsanitized/method const pdfworkerAPI = await import( @@ -26,8 +37,10 @@ describe("pdfworker_api", function () { // The imported Object contains an (automatically) inserted Symbol, // hence we copy the data to allow using a simple comparison below. - expect({ ...pdfworkerAPI }).toEqual({ - WorkerMessageHandler, - }); + expect({ ...pdfworkerAPI }).toEqual(expectedAPI); + + expect(Object.keys(globalThis.pdfjsWorker).sort()).toEqual( + Object.keys(expectedAPI).sort() + ); }); }); diff --git a/test/unit/pdf_spec.js b/test/unit/pdf_spec.js index 184afaecb..714753502 100644 --- a/test/unit/pdf_spec.js +++ b/test/unit/pdf_spec.js @@ -135,6 +135,10 @@ describe("pdfjs_api", function () { // The imported Object contains an (automatically) inserted Symbol, // hence we copy the data to allow using a simple comparison below. expect({ ...pdfjsAPI }).toEqual(expectedAPI); + + expect(Object.keys(globalThis.pdfjsLib).sort()).toEqual( + Object.keys(expectedAPI).sort() + ); }); }); diff --git a/test/unit/pdf_viewer.component_spec.js b/test/unit/pdf_viewer.component_spec.js index 1785a4959..a511a353f 100644 --- a/test/unit/pdf_viewer.component_spec.js +++ b/test/unit/pdf_viewer.component_spec.js @@ -39,35 +39,41 @@ import { StructTreeLayerBuilder } from "../../web/struct_tree_layer_builder.js"; import { TextLayerBuilder } from "../../web/text_layer_builder.js"; import { XfaLayerBuilder } from "../../web/xfa_layer_builder.js"; +const expectedAPI = Object.freeze({ + AnnotationLayerBuilder, + DownloadManager, + EventBus, + FindState, + GenericL10n, + LinkTarget, + parseQueryString, + PDFFindController, + PDFHistory, + PDFLinkService, + PDFPageView, + PDFScriptingManager, + PDFSinglePageViewer, + PDFViewer, + ProgressBar, + RenderingStates, + ScrollMode, + SimpleLinkService, + SpreadMode, + StructTreeLayerBuilder, + TextLayerBuilder, + XfaLayerBuilder, +}); + describe("pdfviewer_api", function () { it("checks that the *official* PDF.js-viewer API exposes the expected functionality", async function () { const pdfviewerAPI = await import("../../web/pdf_viewer.component.js"); // The imported Object contains an (automatically) inserted Symbol, // hence we copy the data to allow using a simple comparison below. - expect({ ...pdfviewerAPI }).toEqual({ - AnnotationLayerBuilder, - DownloadManager, - EventBus, - FindState, - GenericL10n, - LinkTarget, - parseQueryString, - PDFFindController, - PDFHistory, - PDFLinkService, - PDFPageView, - PDFScriptingManager, - PDFSinglePageViewer, - PDFViewer, - ProgressBar, - RenderingStates, - ScrollMode, - SimpleLinkService, - SpreadMode, - StructTreeLayerBuilder, - TextLayerBuilder, - XfaLayerBuilder, - }); + expect({ ...pdfviewerAPI }).toEqual(expectedAPI); + + expect(Object.keys(globalThis.pdfjsViewer).sort()).toEqual( + Object.keys(expectedAPI).sort() + ); }); }); diff --git a/web/pdf_viewer.component.js b/web/pdf_viewer.component.js index e3f9e8db8..fca58eb3b 100644 --- a/web/pdf_viewer.component.js +++ b/web/pdf_viewer.component.js @@ -46,6 +46,31 @@ const pdfjsVersion = const pdfjsBuild = typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0; +globalThis.pdfjsViewer = { + AnnotationLayerBuilder, + DownloadManager, + EventBus, + FindState, + GenericL10n, + LinkTarget, + parseQueryString, + PDFFindController, + PDFHistory, + PDFLinkService, + PDFPageView, + PDFScriptingManager, + PDFSinglePageViewer, + PDFViewer, + ProgressBar, + RenderingStates, + ScrollMode, + SimpleLinkService, + SpreadMode, + StructTreeLayerBuilder, + TextLayerBuilder, + XfaLayerBuilder, +}; + export { AnnotationLayerBuilder, DownloadManager,