From 3220bbfd5c74487cdf65c3c429fc381910ba64f0 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 1 Nov 2020 23:06:40 +0100 Subject: [PATCH] [WIP] Remove SystemJS usage, in development mode, from the worker *Please note:* Unfortunately this can't land until https://bugzilla.mozilla.org/show_bug.cgi?id=1247687 is fixed in Firefox. (The patch has, however, been successfully tested in Google Chrome 87.) This removes the final piece of SystemJS usage from the PDF.js library, thus allowing a fair bit of clean-up, and we now use *only* native `import`/`export` statements everywhere in development mode. --- .eslintrc | 1 - external/systemjs/plugin-babel-cached.js | 149 ----------------------- package-lock.json | 12 -- package.json | 2 - src/core/.eslintrc | 13 -- src/display/api.js | 25 ++-- src/pdf.worker.js | 6 +- src/shared/.eslintrc | 13 -- src/worker_loader.js | 32 ----- systemjs.config.js | 96 --------------- web/app.js | 2 +- web/app_options.js | 2 +- 12 files changed, 18 insertions(+), 335 deletions(-) delete mode 100644 external/systemjs/plugin-babel-cached.js delete mode 100644 src/core/.eslintrc delete mode 100644 src/shared/.eslintrc delete mode 100644 src/worker_loader.js delete mode 100644 systemjs.config.js diff --git a/.eslintrc b/.eslintrc index 1289674834b003..7e2f5abca29023 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,7 +26,6 @@ "globals": { "PDFJSDev": false, "exports": false, - "SystemJS": false, }, "rules": { diff --git a/external/systemjs/plugin-babel-cached.js b/external/systemjs/plugin-babel-cached.js deleted file mode 100644 index 518dfa4ce696f5..00000000000000 --- a/external/systemjs/plugin-babel-cached.js +++ /dev/null @@ -1,149 +0,0 @@ -/* Copyright 2017 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* eslint-disable no-var */ - -var babel = require("plugin-babel"); - -var cacheExpiration = 60 /* min */ * 60 * 1000; -var dbVersion = 1; -var dbName = "babelcache"; -var dbCacheTable = "translated"; -var dbPromise; - -function getDb() { - if (!dbPromise) { - dbPromise = new Promise(function (resolve, reject) { - var request = indexedDB.open(dbName, dbVersion); - request.onupgradeneeded = function () { - var db = request.result; - db.createObjectStore(dbCacheTable, { keyPath: "address" }); - }; - request.onsuccess = function () { - var db = request.result; - resolve(db); - }; - request.onerror = function () { - console.warn("getDb: " + request.error); - reject(request.error); - }; - }); - } - return dbPromise; -} - -function storeCache(address, hashCode, translated, format) { - return getDb().then(function (db) { - var tx = db.transaction(dbCacheTable, "readwrite"); - var store = tx.objectStore(dbCacheTable); - store.put({ - address, - hashCode, - translated, - expires: Date.now() + cacheExpiration, - format, - }); - return new Promise(function (resolve, reject) { - tx.oncomplete = function () { - resolve(); - }; - tx.onerror = function () { - resolve(); - }; - }); - }); -} - -function loadCache(address, hashCode) { - return getDb().then(function (db) { - var tx = db.transaction(dbCacheTable, "readonly"); - var store = tx.objectStore(dbCacheTable); - var getAddress = store.get(address); - return new Promise(function (resolve, reject) { - tx.oncomplete = function () { - var found = getAddress.result; - var isValid = - found && found.hashCode === hashCode && Date.now() < found.expires; - resolve( - isValid - ? { - translated: found.translated, - format: found.format, - } - : null - ); - }; - tx.onerror = function () { - resolve(null); - }; - }); - }); -} - -var encoder = new TextEncoder("utf-8"); -function sha256(str) { - var buffer = encoder.encode(str); - return crypto.subtle.digest("SHA-256", buffer).then(function (hash) { - var data = new Int32Array(hash); - return ( - data[0].toString(36) + - "-" + - data[1].toString(36) + - "-" + - data[2].toString(36) + - "-" + - data[3].toString(36) - ); - }); -} - -exports.translate = function (load, opt) { - var savedHashCode, babelTranslateError; - return sha256(load.source) - .then(function (hashCode) { - savedHashCode = hashCode; - return loadCache(load.address, hashCode); - }) - .then( - function (cache) { - if (cache) { - load.metadata.format = cache.format; - return cache.translated; - } - return babel.translate.call(this, load, opt).then( - function (translated) { - return storeCache( - load.address, - savedHashCode, - translated, - load.metadata.format - ).then(function () { - return translated; - }); - }, - function (reason) { - throw (babelTranslateError = reason); - } - ); - }.bind(this) - ) - .catch( - function (reason) { - if (babelTranslateError) { - throw babelTranslateError; - } - return babel.translate.call(this, load, opt); - }.bind(this) - ); -}; diff --git a/package-lock.json b/package-lock.json index fa457a166b7c1f..61923ac84c555a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16941,18 +16941,6 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, - "systemjs": { - "version": "0.21.6", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-0.21.6.tgz", - "integrity": "sha512-R+5S9eV9vcQgWOoS4D87joZ4xkFJHb19ZsyKY07D1+VBDE9bwYcU+KXE0r5XlDA8mFoJGyuWDbfrNoh90JsA8g==", - "dev": true - }, - "systemjs-plugin-babel": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/systemjs-plugin-babel/-/systemjs-plugin-babel-0.0.25.tgz", - "integrity": "sha512-RMKSizWWlw4+IpDB385ugxn7Owd9W+HEtjYDQ6yO1FpsnER/vk6FbXRweUF+mvRi6EHgk8vDdUdtui7ReDwX3w==", - "dev": true - }, "table": { "version": "6.0.7", "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", diff --git a/package.json b/package.json index 9f8e1a6765101f..e0c1315987f7d1 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,6 @@ "stylelint": "^13.12.0", "stylelint-config-prettier": "^8.0.2", "stylelint-prettier": "^1.2.0", - "systemjs": "^0.21.6", - "systemjs-plugin-babel": "^0.0.25", "terser": "^5.6.0", "through2": "^4.0.2", "ttest": "^3.0.0", diff --git a/src/core/.eslintrc b/src/core/.eslintrc deleted file mode 100644 index c1831d3880daf2..00000000000000 --- a/src/core/.eslintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 2017, - }, - - "extends": [ - "../../.eslintrc" - ], - - "env": { - "es2017": true, - }, -} diff --git a/src/display/api.js b/src/display/api.js index 690193adebfcb8..ee1fa8152e7ed1 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -1763,11 +1763,10 @@ const PDFWorker = (function PDFWorkerClosure() { // Workers aren't supported in Node.js, force-disabling them there. isWorkerDisabled = true; - if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("LIB")) { - fallbackWorkerSrc = "../pdf.worker.js"; - } else { - fallbackWorkerSrc = "./pdf.worker.js"; - } + fallbackWorkerSrc = + typeof PDFJSDev !== "undefined" && PDFJSDev.test("LIB") + ? "../pdf.worker.js" + : "./pdf.worker.js"; } else if (typeof document === "object" && "currentScript" in document) { const pdfjsFilePath = document.currentScript?.src; if (pdfjsFilePath) { @@ -1793,13 +1792,11 @@ const PDFWorker = (function PDFWorkerClosure() { } function getMainThreadWorkerMessageHandler() { - let mainWorkerMessageHandler; try { - mainWorkerMessageHandler = globalThis.pdfjsWorker?.WorkerMessageHandler; + return globalThis.pdfjsWorker?.WorkerMessageHandler || null; } catch (ex) { - /* Ignore errors. */ + return null; // Ignore errors. } - return mainWorkerMessageHandler || null; } // Loads worker code into main thread. @@ -1817,7 +1814,7 @@ const PDFWorker = (function PDFWorkerClosure() { return mainWorkerMessageHandler; } if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) { - const worker = await import("pdfjs/core/worker.js"); + const worker = await import("pdfjs/pdf.worker.js"); return worker.WorkerMessageHandler; } if ( @@ -1944,9 +1941,11 @@ const PDFWorker = (function PDFWorkerClosure() { ); } - // Some versions of FF can't create a worker on localhost, see: - // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 - const worker = new Worker(workerSrc); + const worker = + (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) && + !workerSrc.endsWith("/build/pdf.worker.js") + ? new Worker(workerSrc, { type: "module" }) + : new Worker(workerSrc); const messageHandler = new MessageHandler("main", "worker", worker); const terminateEarly = () => { worker.removeEventListener("error", onWorkerError); diff --git a/src/pdf.worker.js b/src/pdf.worker.js index ee44edd7e2746b..900c0b02a16381 100644 --- a/src/pdf.worker.js +++ b/src/pdf.worker.js @@ -16,8 +16,10 @@ import { WorkerMessageHandler } from "./core/worker.js"; /* eslint-disable-next-line no-unused-vars */ -const pdfjsVersion = PDFJSDev.eval("BUNDLE_VERSION"); +const pdfjsVersion = + typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_VERSION") : void 0; /* eslint-disable-next-line no-unused-vars */ -const pdfjsBuild = PDFJSDev.eval("BUNDLE_BUILD"); +const pdfjsBuild = + typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0; export { WorkerMessageHandler }; diff --git a/src/shared/.eslintrc b/src/shared/.eslintrc deleted file mode 100644 index c1831d3880daf2..00000000000000 --- a/src/shared/.eslintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 2017, - }, - - "extends": [ - "../../.eslintrc" - ], - - "env": { - "es2017": true, - }, -} diff --git a/src/worker_loader.js b/src/worker_loader.js deleted file mode 100644 index 12b807a44a8573..00000000000000 --- a/src/worker_loader.js +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; - -// Patch importScripts to work around a bug in WebKit and Chrome 48-. -// See https://crbug.com/572225 and https://webkit.org/b/153317. -self.importScripts = (function (importScripts) { - return function () { - setTimeout(function () {}, 0); - return importScripts.apply(this, arguments); - }; -})(importScripts); - -importScripts("../node_modules/systemjs/dist/system.js"); -importScripts("../systemjs.config.js"); - -SystemJS.import("pdfjs/core/worker.js").then(function () { - // Worker is loaded at this point. -}); diff --git a/systemjs.config.js b/systemjs.config.js deleted file mode 100644 index a4a02bc0feb87b..00000000000000 --- a/systemjs.config.js +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright 2017 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* eslint-disable no-var */ - -"use strict"; - -(function () { - var baseLocation; - if (typeof document !== "undefined") { - baseLocation = new URL("./", document.currentScript.src); - } else if (typeof location !== "undefined") { - // Probably worker -- walking subfolders until we will reach root. - baseLocation = location; - while (baseLocation.href.includes("/src/")) { - baseLocation = new URL("..", baseLocation); - } - } else { - throw new Error("Cannot configure SystemJS"); - } - - var PluginBabelPath = "node_modules/systemjs-plugin-babel/plugin-babel.js"; - var SystemJSPluginBabelPath = - "node_modules/systemjs-plugin-babel/systemjs-babel-browser.js"; - var PluginBabelCachePath = "external/systemjs/plugin-babel-cached.js"; - - var isCachingPossible = - typeof indexedDB !== "undefined" && - typeof TextEncoder !== "undefined" && - typeof crypto !== "undefined" && - typeof crypto.subtle !== "undefined"; - - // When we create a bundle, webpack is run on the source and it will replace - // require with __webpack_require__. When we want to use the real require, - // __non_webpack_require__ has to be used. - // In this target, we don't create a bundle, so we have to replace the - // occurrences of __non_webpack_require__ ourselves. - function babelPluginReplaceNonWebPackRequire(babel) { - return { - visitor: { - Identifier(path, state) { - if (path.node.name === "__non_webpack_require__") { - path.replaceWith(babel.types.identifier("require")); - } - }, - }, - }; - } - - SystemJS.config({ - packages: { - "": { - defaultExtension: "js", - }, - }, - paths: { - pdfjs: new URL("src", baseLocation).href, - "pdfjs-web": new URL("web", baseLocation).href, - "pdfjs-test": new URL("test", baseLocation).href, - "pdfjs-lib": new URL("src/pdf", baseLocation).href, - "core-js": new URL("node_modules/core-js", baseLocation).href, - "web-streams-polyfill": new URL( - "node_modules/web-streams-polyfill", - baseLocation - ).href, - }, - meta: { - "*": { - scriptLoad: false, - esModule: true, - babelOptions: { - env: false, - plugins: [babelPluginReplaceNonWebPackRequire], - }, - }, - }, - map: { - "plugin-babel": new URL(PluginBabelPath, baseLocation).href, - "systemjs-babel-build": new URL(SystemJSPluginBabelPath, baseLocation) - .href, - "plugin-babel-cached": new URL(PluginBabelCachePath, baseLocation).href, - }, - transpiler: isCachingPossible ? "plugin-babel-cached" : "plugin-babel", - }); -})(); diff --git a/web/app.js b/web/app.js index 6bdcaef9808318..f1be7aa0590d18 100644 --- a/web/app.js +++ b/web/app.js @@ -2137,7 +2137,7 @@ async function loadFakeWorker() { GlobalWorkerOptions.workerSrc = AppOptions.get("workerSrc"); } if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) { - window.pdfjsWorker = await import("pdfjs/core/worker.js"); + window.pdfjsWorker = await import("pdfjs/pdf.worker.js"); return undefined; } return loadScript(PDFWorker.getWorkerSrc()); diff --git a/web/app_options.js b/web/app_options.js index f88932034c75b5..18f0fe8ca2cf84 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -240,7 +240,7 @@ const defaultOptions = { /** @type {string} */ value: typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") - ? "../src/worker_loader.js" + ? "../src/pdf.worker.js" : "../build/pdf.worker.js", kind: OptionKind.WORKER, },