From 927e50f5d48a67e76f2a51c112ea5a98867822fe Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 28 Sep 2023 13:00:10 +0200 Subject: [PATCH] [api-major] Output JavaScript modules in the builds (issue 10317) At this point in time all browsers, and also Node.js, support standard `import`/`export` statements and we can now finally consider outputting modern JavaScript modules in the builds.[1] In order for this to work we can *only* use proper `import`/`export` statements throughout the main code-base, and (as expected) our Node.js support made this much more complicated since both the official builds and the GitHub Actions-based tests must keep working.[2] One remaining issue is that the `pdf.scripting.js` file cannot be built as a JavaScript module, since doing so breaks PDF scripting. Note that my initial goal was to try and split these changes into a couple of commits, however that unfortunately didn't really work since it turned out to be difficult for smaller patches to work correctly and pass (all) tests that way.[3] This is a classic case of every change requiring a couple of other changes, with each of those changes requiring further changes in turn and the size/scope quickly increasing as a result. One possible "issue" with these changes is that we'll now only output JavaScript modules in the builds, which could perhaps be a problem with older tools. However it unfortunately seems far too complicated/time-consuming for us to attempt to support both the old and modern module formats, hence the alternative would be to do "nothing" here and just keep our "old" builds.[4] --- [1] The final blocker was module support in workers in Firefox, which was implemented in Firefox 114; please see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility [2] It's probably possible to further improve/simplify especially the Node.js-specific code, but it does appear to work as-is. [3] Having partially "broken" patches, that fail tests, as part of the commit history is *really not* a good idea in general. [4] Outputting JavaScript modules was first requested almost five years ago, see issue 10317, and nowadays there *should* be much better support for JavaScript modules in various tools. --- external/dist/webpack.js | 5 +- gulpfile.mjs | 218 +++++++++++----------- src/display/api.js | 51 +---- src/display/display_utils.js | 24 --- src/display/node_stream.js | 15 +- src/display/node_utils.js | 70 +++++-- src/pdf.js | 2 - src/pdf.worker.entry.js | 2 +- test/driver.js | 2 +- test/test_slave.html | 4 +- test/unit/api_spec.js | 11 +- test/unit/jasmine-boot.js | 2 +- test/unit/pdf_spec.js | 9 +- test/unit/scripting_spec.js | 9 +- web/app.js | 5 +- web/app_options.js | 8 +- web/generic_scripting.js | 17 +- web/pdfjs.js | 2 - web/viewer-geckoview.html | 2 +- web/viewer-snippet-chrome-extension.html | 2 +- web/viewer-snippet-firefox-extension.html | 2 +- web/viewer-snippet.html | 2 +- web/viewer.html | 4 +- 23 files changed, 227 insertions(+), 241 deletions(-) diff --git a/external/dist/webpack.js b/external/dist/webpack.js index 03704cdd4..9b9447208 100644 --- a/external/dist/webpack.js +++ b/external/dist/webpack.js @@ -15,11 +15,12 @@ "use strict"; -const pdfjs = require("./build/pdf.js"); +const pdfjs = require("./build/pdf.mjs"); if (typeof window !== "undefined" && "Worker" in window) { pdfjs.GlobalWorkerOptions.workerPort = new Worker( - new URL("./build/pdf.worker.js", import.meta.url) + new URL("./build/pdf.worker.mjs", import.meta.url), + { type: "module" } ); } diff --git a/gulpfile.mjs b/gulpfile.mjs index d47533cbc..cc2624d19 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -201,6 +201,7 @@ function createWebpackConfig( !bundleDefines.LIB && !bundleDefines.TESTING && !disableSourceMaps; + const isModule = output.library?.type === "module"; const skipBabel = bundleDefines.SKIP_BABEL; // `core-js`, see https://github.com/zloirock/core-js/issues/514, @@ -216,7 +217,9 @@ function createWebpackConfig( { corejs: "3.32.2", shippedProposals: true, useBuiltIns: "usage" }, ], ]; - const babelPlugins = ["@babel/plugin-transform-modules-commonjs"]; + const babelPlugins = isModule + ? [] + : ["@babel/plugin-transform-modules-commonjs"]; const plugins = []; if (!disableLicenseHeader) { @@ -225,8 +228,7 @@ function createWebpackConfig( ); } - const experiments = - output.library?.type === "module" ? { outputModule: true } : undefined; + const experiments = isModule ? { outputModule: true } : undefined; // Required to expose e.g., the `window` object. output.globalObject = "globalThis"; @@ -296,7 +298,11 @@ function createWebpackConfig( } return { - mode: "none", + mode: "production", + optimization: { + mangleExports: false, + minimize: false, + }, experiments, output, performance: { @@ -388,14 +394,28 @@ function checkChromePreferencesFile(chromePrefsPath, webPrefs) { return ret; } -function replaceWebpackRequire() { - // Produced bundles can be rebundled again, avoid collisions (e.g. in api.js) - // by renaming __webpack_require__ to something else. - return replace("__webpack_require__", "__w_pdfjs_require__"); -} +function tweakWebpackOutput(jsName) { + const replacer = ["__non_webpack_import__\\("]; -function replaceNonWebpackImport() { - return replace("__non_webpack_import__", "import"); + if (jsName) { + replacer.push( + " __webpack_exports__ = {};", + " __webpack_exports__ = await __webpack_exports__;" + ); + } + const regex = new RegExp(`(${replacer.join("|")})`, "gm"); + + return replace(regex, match => { + switch (match) { + case "__non_webpack_import__(": + return "import(/* webpackIgnore: true */ "; + case " __webpack_exports__ = {};": + return ` __webpack_exports__ = globalThis.${jsName} = {};`; + case " __webpack_exports__ = await __webpack_exports__;": + return ` __webpack_exports__ = globalThis.${jsName} = await __webpack_exports__;`; + } + return match; + }); } function addGlobalExports(amdName, jsName) { @@ -423,21 +443,16 @@ function addGlobalExports(amdName, jsName) { } function createMainBundle(defines) { - const mainAMDName = "pdfjs-dist/build/pdf"; - const mainOutputName = "pdf.js"; - const mainFileConfig = createWebpackConfig(defines, { - filename: mainOutputName, - library: mainAMDName, - libraryTarget: "umd", - umdNamedDefine: true, + filename: "pdf.mjs", + library: { + type: "module", + }, }); return gulp .src("./src/pdf.js") .pipe(webpack2Stream(mainFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) - .pipe(addGlobalExports(mainAMDName, "pdfjsLib")); + .pipe(tweakWebpackOutput("pdfjsLib")); } function createScriptingBundle(defines, extraOptions = undefined) { @@ -457,8 +472,6 @@ function createScriptingBundle(defines, extraOptions = undefined) { return gulp .src("./src/pdf.scripting.js") .pipe(webpack2Stream(scriptingFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) .pipe(addGlobalExports(scriptingAMDName, "pdfjsScripting")); } @@ -489,9 +502,6 @@ function createTemporaryScriptingBundle(defines, extraOptions = undefined) { } function createSandboxBundle(defines, extraOptions = undefined) { - const sandboxAMDName = "pdfjs-dist/build/pdf.sandbox"; - const sandboxOutputName = "pdf.sandbox.js"; - const scriptingPath = TMP_DIR + "pdf.scripting.js"; // Insert the source as a string to be `eval`-ed in the sandbox. const sandboxDefines = builder.merge(defines, { @@ -502,10 +512,10 @@ function createSandboxBundle(defines, extraOptions = undefined) { const sandboxFileConfig = createWebpackConfig( sandboxDefines, { - filename: sandboxOutputName, - library: sandboxAMDName, - libraryTarget: "umd", - umdNamedDefine: true, + filename: "pdf.sandbox.mjs", + library: { + type: "module", + }, }, extraOptions ); @@ -513,36 +523,30 @@ function createSandboxBundle(defines, extraOptions = undefined) { return gulp .src("./src/pdf.sandbox.js") .pipe(webpack2Stream(sandboxFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) - .pipe(addGlobalExports(sandboxAMDName, "pdfjsSandbox")); + .pipe(tweakWebpackOutput("pdfjsSandbox")); } function createWorkerBundle(defines) { - const workerAMDName = "pdfjs-dist/build/pdf.worker"; - const workerOutputName = "pdf.worker.js"; - const workerFileConfig = createWebpackConfig(defines, { - filename: workerOutputName, - library: workerAMDName, - libraryTarget: "umd", - umdNamedDefine: true, + filename: "pdf.worker.mjs", + library: { + type: "module", + }, }); return gulp .src("./src/pdf.worker.js") .pipe(webpack2Stream(workerFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) - .pipe(addGlobalExports(workerAMDName, "pdfjsWorker")); + .pipe(tweakWebpackOutput("pdfjsWorker")); } function createWebBundle(defines, options) { - const viewerOutputName = "viewer.js"; - const viewerFileConfig = createWebpackConfig( defines, { - filename: viewerOutputName, + filename: "viewer.mjs", + library: { + type: "module", + }, }, { defaultPreferencesDir: options.defaultPreferencesDir, @@ -551,17 +555,19 @@ function createWebBundle(defines, options) { return gulp .src("./web/viewer.js") .pipe(webpack2Stream(viewerFileConfig)) - .pipe(replaceNonWebpackImport()); + .pipe(tweakWebpackOutput()); } function createGVWebBundle(defines, options) { - const viewerOutputName = "viewer-geckoview.js"; defines = builder.merge(defines, { GECKOVIEW: true }); const viewerFileConfig = createWebpackConfig( defines, { - filename: viewerOutputName, + filename: "viewer-geckoview.mjs", + library: { + type: "module", + }, }, { defaultPreferencesDir: options.defaultPreferencesDir, @@ -570,43 +576,33 @@ function createGVWebBundle(defines, options) { return gulp .src("./web/viewer-geckoview.js") .pipe(webpack2Stream(viewerFileConfig)) - .pipe(replaceNonWebpackImport()); + .pipe(tweakWebpackOutput()); } function createComponentsBundle(defines) { - const componentsAMDName = "pdfjs-dist/web/pdf_viewer"; - const componentsOutputName = "pdf_viewer.js"; - const componentsFileConfig = createWebpackConfig(defines, { - filename: componentsOutputName, - library: componentsAMDName, - libraryTarget: "umd", - umdNamedDefine: true, + filename: "pdf_viewer.mjs", + library: { + type: "module", + }, }); return gulp .src("./web/pdf_viewer.component.js") .pipe(webpack2Stream(componentsFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) - .pipe(addGlobalExports(componentsAMDName, "pdfjsViewer")); + .pipe(tweakWebpackOutput("pdfjsViewer")); } function createImageDecodersBundle(defines) { - const imageDecodersAMDName = "pdfjs-dist/image_decoders/pdf.image_decoders"; - const imageDecodersOutputName = "pdf.image_decoders.js"; - const componentsFileConfig = createWebpackConfig(defines, { - filename: imageDecodersOutputName, - library: imageDecodersAMDName, - libraryTarget: "umd", - umdNamedDefine: true, + filename: "pdf.image_decoders.mjs", + library: { + type: "module", + }, }); return gulp .src("./src/pdf.image_decoders.js") .pipe(webpack2Stream(componentsFileConfig)) - .pipe(replaceWebpackRequire()) - .pipe(replaceNonWebpackImport()) - .pipe(addGlobalExports(imageDecodersAMDName, "pdfjsImageDecoders")); + .pipe(tweakWebpackOutput("pdfjsImageDecoders")); } function createCMapBundle() { @@ -1161,15 +1157,15 @@ function buildMinified(defines, dir) { } async function parseMinified(dir) { - const pdfFile = fs.readFileSync(dir + "/build/pdf.js").toString(); + const pdfFile = fs.readFileSync(dir + "build/pdf.mjs").toString(); const pdfWorkerFile = fs - .readFileSync(dir + "/build/pdf.worker.js") + .readFileSync(dir + "build/pdf.worker.mjs") .toString(); const pdfSandboxFile = fs - .readFileSync(dir + "/build/pdf.sandbox.js") + .readFileSync(dir + "build/pdf.sandbox.mjs") .toString(); const pdfImageDecodersFile = fs - .readFileSync(dir + "/image_decoders/pdf.image_decoders.js") + .readFileSync(dir + "image_decoders/pdf.image_decoders.mjs") .toString(); console.log(); @@ -1183,41 +1179,42 @@ async function parseMinified(dir) { }, keep_classnames: true, keep_fnames: true, + module: true, }; fs.writeFileSync( - dir + "/build/pdf.min.js", + dir + "build/pdf.min.mjs", (await minify(pdfFile, options)).code ); fs.writeFileSync( - dir + "/build/pdf.worker.min.js", + dir + "build/pdf.worker.min.mjs", (await minify(pdfWorkerFile, options)).code ); fs.writeFileSync( - dir + "/build/pdf.sandbox.min.js", + dir + "build/pdf.sandbox.min.mjs", (await minify(pdfSandboxFile, options)).code ); fs.writeFileSync( - dir + "image_decoders/pdf.image_decoders.min.js", + dir + "image_decoders/pdf.image_decoders.min.mjs", (await minify(pdfImageDecodersFile, options)).code ); console.log(); console.log("### Cleaning js files"); - fs.unlinkSync(dir + "/build/pdf.js"); - fs.unlinkSync(dir + "/build/pdf.worker.js"); - fs.unlinkSync(dir + "/build/pdf.sandbox.js"); + fs.unlinkSync(dir + "build/pdf.mjs"); + fs.unlinkSync(dir + "build/pdf.worker.mjs"); + fs.unlinkSync(dir + "build/pdf.sandbox.mjs"); - fs.renameSync(dir + "/build/pdf.min.js", dir + "/build/pdf.js"); - fs.renameSync(dir + "/build/pdf.worker.min.js", dir + "/build/pdf.worker.js"); + fs.renameSync(dir + "build/pdf.min.mjs", dir + "build/pdf.mjs"); + fs.renameSync(dir + "build/pdf.worker.min.mjs", dir + "build/pdf.worker.mjs"); fs.renameSync( - dir + "/build/pdf.sandbox.min.js", - dir + "/build/pdf.sandbox.js" + dir + "build/pdf.sandbox.min.mjs", + dir + "build/pdf.sandbox.mjs" ); fs.renameSync( - dir + "/image_decoders/pdf.image_decoders.min.js", - dir + "/image_decoders/pdf.image_decoders.js" + dir + "image_decoders/pdf.image_decoders.min.mjs", + dir + "image_decoders/pdf.image_decoders.mjs" ); } @@ -1859,8 +1856,8 @@ gulp.task( packageJson().pipe(gulp.dest(TYPESTEST_DIR)), gulp .src([ - GENERIC_DIR + "build/pdf.js", - GENERIC_DIR + "build/pdf.worker.js", + GENERIC_DIR + "build/pdf.mjs", + GENERIC_DIR + "build/pdf.worker.mjs", SRC_DIR + "pdf.worker.entry.js", ]) .pipe(gulp.dest(TYPESTEST_DIR + "build/")), @@ -2153,7 +2150,7 @@ function packageJson() { const npmManifest = { name: DIST_NAME, version: VERSION, - main: "build/pdf.js", + main: "build/pdf.mjs", types: "types/src/pdf.d.ts", description: DIST_DESCRIPTION, keywords: DIST_KEYWORDS, @@ -2171,7 +2168,6 @@ function packageJson() { https: false, url: false, }, - format: "amd", // to not allow system.js to choose 'cjs' repository: { type: "git", url: DIST_REPO_URL, @@ -2230,49 +2226,49 @@ gulp.task( .pipe(gulp.dest(DIST_DIR)), gulp .src([ - GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js", - GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js.map", + GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.mjs", + GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.mjs.map", SRC_DIR + "pdf.worker.entry.js", ]) .pipe(gulp.dest(DIST_DIR + "build/")), gulp .src([ - GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js", - GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js.map", + GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.mjs", + GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.mjs.map", SRC_DIR + "pdf.worker.entry.js", ]) .pipe(gulp.dest(DIST_DIR + "legacy/build/")), gulp - .src(MINIFIED_DIR + "build/pdf.js") - .pipe(rename("pdf.min.js")) + .src(MINIFIED_DIR + "build/pdf.mjs") + .pipe(rename("pdf.min.mjs")) .pipe(gulp.dest(DIST_DIR + "build/")), gulp - .src(MINIFIED_DIR + "build/pdf.worker.js") - .pipe(rename("pdf.worker.min.js")) + .src(MINIFIED_DIR + "build/pdf.worker.mjs") + .pipe(rename("pdf.worker.min.mjs")) .pipe(gulp.dest(DIST_DIR + "build/")), gulp - .src(MINIFIED_DIR + "build/pdf.sandbox.js") - .pipe(rename("pdf.sandbox.min.js")) + .src(MINIFIED_DIR + "build/pdf.sandbox.mjs") + .pipe(rename("pdf.sandbox.min.mjs")) .pipe(gulp.dest(DIST_DIR + "build/")), gulp - .src(MINIFIED_DIR + "image_decoders/pdf.image_decoders.js") - .pipe(rename("pdf.image_decoders.min.js")) + .src(MINIFIED_DIR + "image_decoders/pdf.image_decoders.mjs") + .pipe(rename("pdf.image_decoders.min.mjs")) .pipe(gulp.dest(DIST_DIR + "image_decoders/")), gulp - .src(MINIFIED_LEGACY_DIR + "build/pdf.js") - .pipe(rename("pdf.min.js")) + .src(MINIFIED_LEGACY_DIR + "build/pdf.mjs") + .pipe(rename("pdf.min.mjs")) .pipe(gulp.dest(DIST_DIR + "legacy/build/")), gulp - .src(MINIFIED_LEGACY_DIR + "build/pdf.worker.js") - .pipe(rename("pdf.worker.min.js")) + .src(MINIFIED_LEGACY_DIR + "build/pdf.worker.mjs") + .pipe(rename("pdf.worker.min.mjs")) .pipe(gulp.dest(DIST_DIR + "legacy/build/")), gulp - .src(MINIFIED_LEGACY_DIR + "build/pdf.sandbox.js") - .pipe(rename("pdf.sandbox.min.js")) + .src(MINIFIED_LEGACY_DIR + "build/pdf.sandbox.mjs") + .pipe(rename("pdf.sandbox.min.mjs")) .pipe(gulp.dest(DIST_DIR + "legacy/build/")), gulp - .src(MINIFIED_LEGACY_DIR + "image_decoders/pdf.image_decoders.js") - .pipe(rename("pdf.image_decoders.min.js")) + .src(MINIFIED_LEGACY_DIR + "image_decoders/pdf.image_decoders.mjs") + .pipe(rename("pdf.image_decoders.min.mjs")) .pipe(gulp.dest(DIST_DIR + "legacy/image_decoders/")), gulp .src(COMPONENTS_DIR + "**/*", { base: COMPONENTS_DIR }) diff --git a/src/display/api.js b/src/display/api.js index 14382074f..2d3837b25 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -51,7 +51,6 @@ import { DOMStandardFontDataFactory, isDataScheme, isValidFetchUrl, - loadScript, PageViewport, RenderingCancelledException, StatTimer, @@ -1986,14 +1985,13 @@ const PDFWorkerUtil = { fakeWorkerId: 0, }; if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { - // eslint-disable-next-line no-undef - if (isNodeJS && typeof __non_webpack_require__ === "function") { + if (isNodeJS) { // Workers aren't supported in Node.js, force-disabling them there. PDFWorkerUtil.isWorkerDisabled = true; GlobalWorkerOptions.workerSrc ||= PDFJSDev.test("LIB") ? "../pdf.worker.js" - : "./pdf.worker.js"; + : "./pdf.worker.mjs"; } // Check if URLs have the same origin. For non-HTTP based URLs, returns false. @@ -2126,11 +2124,7 @@ class PDFWorker { ); } - const worker = - typeof PDFJSDev === "undefined" && - !workerSrc.endsWith("/build/pdf.worker.js") - ? new Worker(workerSrc, { type: "module" }) - : new Worker(workerSrc); + const worker = new Worker(workerSrc, { type: "module" }); const messageHandler = new MessageHandler("main", "worker", worker); const terminateEarly = () => { worker.removeEventListener("error", onWorkerError); @@ -2312,40 +2306,15 @@ class PDFWorker { // Loads worker code into the main-thread. static get _setupFakeWorkerGlobal() { const loader = async () => { - const mainWorkerMessageHandler = this.#mainThreadWorkerMessageHandler; - - if (mainWorkerMessageHandler) { + if (this.#mainThreadWorkerMessageHandler) { // The worker was already loaded using e.g. a ` - + + diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index f569a6dd2..0396325c0 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -56,6 +56,8 @@ import { GlobalImageCache } from "../../src/core/image_utils.js"; import { GlobalWorkerOptions } from "../../src/display/worker_options.js"; import { Metadata } from "../../src/display/metadata.js"; +const WORKER_SRC = "../../build/generic/build/pdf.worker.mjs"; + describe("api", function () { const basicApiFileName = "basicapi.pdf"; const basicApiFileLength = 105779; // bytes @@ -914,7 +916,8 @@ describe("api", function () { } GlobalWorkerOptions.workerPort = new Worker( - new URL("../../build/generic/build/pdf.worker.js", window.location) + new URL(WORKER_SRC, window.location), + { type: "module" } ); const loadingTask1 = getDocument(basicApiGetDocumentParams); @@ -934,7 +937,8 @@ describe("api", function () { } GlobalWorkerOptions.workerPort = new Worker( - new URL("../../build/generic/build/pdf.worker.js", window.location) + new URL(WORKER_SRC, window.location), + { type: "module" } ); const loadingTask1 = getDocument(basicApiGetDocumentParams); @@ -963,7 +967,8 @@ describe("api", function () { } GlobalWorkerOptions.workerPort = new Worker( - new URL("../../build/generic/build/pdf.worker.js", window.location) + new URL(WORKER_SRC, window.location), + { type: "module" } ); const loadingTask = getDocument(basicApiGetDocumentParams); diff --git a/test/unit/jasmine-boot.js b/test/unit/jasmine-boot.js index 96d48558d..5852ae6da 100644 --- a/test/unit/jasmine-boot.js +++ b/test/unit/jasmine-boot.js @@ -108,7 +108,7 @@ async function initializePDFJS(callback) { ); } // Configure the worker. - GlobalWorkerOptions.workerSrc = "../../build/generic/build/pdf.worker.js"; + GlobalWorkerOptions.workerSrc = "../../build/generic/build/pdf.worker.mjs"; callback(); } diff --git a/test/unit/pdf_spec.js b/test/unit/pdf_spec.js index 413b9708d..d647f5ced 100644 --- a/test/unit/pdf_spec.js +++ b/test/unit/pdf_spec.js @@ -49,7 +49,6 @@ import { getXfaPageViewport, isDataScheme, isPdfFile, - loadScript, noContextMenu, PDFDateString, PixelsPerInch, @@ -88,7 +87,6 @@ const expectedAPI = Object.freeze({ InvalidPDFException, isDataScheme, isPdfFile, - loadScript, MissingPDFException, noContextMenu, normalizeUnicode, @@ -132,10 +130,9 @@ describe("web_pdfjsLib", function () { if (isNodeJS) { pending("loadScript is not supported in Node.js."); } - await loadScript( - "../../build/generic/build/pdf.js", - /* removeScriptElement = */ true - ); + const apiPath = "../../build/generic/build/pdf.mjs"; + await import(apiPath); + const webPdfjsLib = await import("../../web/pdfjs.js"); expect(Object.keys(webPdfjsLib).sort()).toEqual( diff --git a/test/unit/scripting_spec.js b/test/unit/scripting_spec.js index bfcc10a56..dbeb58d9b 100644 --- a/test/unit/scripting_spec.js +++ b/test/unit/scripting_spec.js @@ -13,9 +13,7 @@ * limitations under the License. */ -import { loadScript } from "../../src/display/display_utils.js"; - -const sandboxBundleSrc = "../../build/generic/build/pdf.sandbox.js"; +const sandboxBundleSrc = "../../build/generic/build/pdf.sandbox.mjs"; describe("Scripting", function () { let sandbox, send_queue, test_id, ref, windowAlert; @@ -53,8 +51,9 @@ describe("Scripting", function () { const command = "alert"; send_queue.set(command, { command, value }); }; - const promise = loadScript(sandboxBundleSrc).then(() => { - return window.pdfjsSandbox.QuickJSSandbox(); + // eslint-disable-next-line no-unsanitized/method + const promise = import(sandboxBundleSrc).then(pdfjsSandbox => { + return pdfjsSandbox.QuickJSSandbox(); }); sandbox = { createSandbox(data) { diff --git a/web/app.js b/web/app.js index 560fb784b..d5675e578 100644 --- a/web/app.js +++ b/web/app.js @@ -44,7 +44,6 @@ import { InvalidPDFException, isDataScheme, isPdfFile, - loadScript, MissingPDFException, PDFWorker, PromiseCapability, @@ -2264,10 +2263,10 @@ async function loadFakeWorker() { GlobalWorkerOptions.workerSrc ||= AppOptions.get("workerSrc"); if (typeof PDFJSDev === "undefined") { - window.pdfjsWorker = await import("pdfjs/pdf.worker.js"); + globalThis.pdfjsWorker = await import("pdfjs/pdf.worker.js"); return; } - await loadScript(PDFWorker.workerSrc); + await __non_webpack_import__(PDFWorker.workerSrc); // eslint-disable-line no-undef } async function loadPDFBug(self) { diff --git a/web/app_options.js b/web/app_options.js index 13de98898..e461f3910 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -300,8 +300,8 @@ const defaultOptions = { typeof PDFJSDev === "undefined" ? "../src/pdf.worker.js" : PDFJSDev.test("MOZCENTRAL") - ? "resource://pdf.js/build/pdf.worker.js" - : "../build/pdf.worker.js", + ? "resource://pdf.js/build/pdf.worker.mjs" + : "../build/pdf.worker.mjs", kind: OptionKind.WORKER, }, }; @@ -325,8 +325,8 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { /** @type {string} */ value: typeof PDFJSDev === "undefined" - ? "../build/dev-sandbox/pdf.sandbox.js" - : "../build/pdf.sandbox.js", + ? "../build/dev-sandbox/pdf.sandbox.mjs" + : "../build/pdf.sandbox.mjs", kind: OptionKind.VIEWER, }; } else if (PDFJSDev.test("CHROME")) { diff --git a/web/generic_scripting.js b/web/generic_scripting.js index 0c0aa8024..8b7f33305 100644 --- a/web/generic_scripting.js +++ b/web/generic_scripting.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { getPdfFilenameFromUrl, loadScript } from "pdfjs-lib"; +import { getPdfFilenameFromUrl } from "pdfjs-lib"; async function docProperties(pdfDocument) { const url = "", @@ -41,11 +41,16 @@ async function docProperties(pdfDocument) { class GenericScripting { constructor(sandboxBundleSrc) { - this._ready = loadScript( - sandboxBundleSrc, - /* removeScriptElement = */ true - ).then(() => { - return window.pdfjsSandbox.QuickJSSandbox(); + this._ready = new Promise((resolve, reject) => { + const sandbox = + typeof PDFJSDev === "undefined" + ? import(sandboxBundleSrc) // eslint-disable-line no-unsanitized/method + : __non_webpack_import__(sandboxBundleSrc); // eslint-disable-line no-undef + sandbox + .then(pdfjsSandbox => { + resolve(pdfjsSandbox.QuickJSSandbox()); + }) + .catch(reject); }); } diff --git a/web/pdfjs.js b/web/pdfjs.js index cb9f39d74..3ca9b5490 100644 --- a/web/pdfjs.js +++ b/web/pdfjs.js @@ -35,7 +35,6 @@ const { InvalidPDFException, isDataScheme, isPdfFile, - loadScript, MissingPDFException, noContextMenu, normalizeUnicode, @@ -81,7 +80,6 @@ export { InvalidPDFException, isDataScheme, isPdfFile, - loadScript, MissingPDFException, noContextMenu, normalizeUnicode, diff --git a/web/viewer-geckoview.html b/web/viewer-geckoview.html index 6f42a2f56..b6ebd15d6 100644 --- a/web/viewer-geckoview.html +++ b/web/viewer-geckoview.html @@ -76,7 +76,7 @@ See https://github.com/adobe-type-tools/cmap-resources - + diff --git a/web/viewer-snippet-chrome-extension.html b/web/viewer-snippet-chrome-extension.html index dcf2ed598..6cd81812e 100644 --- a/web/viewer-snippet-chrome-extension.html +++ b/web/viewer-snippet-chrome-extension.html @@ -1,4 +1,4 @@ - + diff --git a/web/viewer-snippet-firefox-extension.html b/web/viewer-snippet-firefox-extension.html index c7c416d50..aa6cf5d9b 100644 --- a/web/viewer-snippet-firefox-extension.html +++ b/web/viewer-snippet-firefox-extension.html @@ -1,2 +1,2 @@ - + diff --git a/web/viewer-snippet.html b/web/viewer-snippet.html index f0bea7080..56864bf67 100644 --- a/web/viewer-snippet.html +++ b/web/viewer-snippet.html @@ -1,3 +1,3 @@ - + diff --git a/web/viewer.html b/web/viewer.html index 95382b727..0b0d9d152 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -44,9 +44,9 @@ See https://github.com/adobe-type-tools/cmap-resources - + - +