From 8fa73dbfabac988ea3226a3aca20b46ba9dabfaf Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 3 Apr 2022 11:51:49 +0200 Subject: [PATCH] Convert `web/debugger.js` to a *basic* module The various functionality in `web/debugger.js` is currently *indirectly* added to the global scope, since that's how `var` works when it's used outside of any functions/closures. Given how this functionality is being accessed/used, not just in the viewer but also in the API and textLayer, simply converting the entire file to a module isn't trivial[1]. However, we can at least export the `PDFBug`-part properly and then `import` that dynamically in the viewer. Also, to improve the code a little bit, we're now *explicitly* exporting the necessary functionality globally. According to MDN, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility, all the browsers that we now support have dynamic `imports` implementations. --- [1] We could probably pass around references to the necessary functionality, but given how this is being used I'm just not sure it's worth the effort. Also, adding *official* support for these viewer-specific debugging tools in the API feels both unnecessary and unfortunate. --- gulpfile.js | 21 ++++++++++++++++++--- web/app.js | 21 ++++++++++----------- web/debugger.js | 26 +++++++++++++------------- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index f8f405882..b09069667 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -327,6 +327,10 @@ function replaceWebpackRequire() { return replace("__webpack_require__", "__w_pdfjs_require__"); } +function replaceNonWebpackImport() { + return replace("__non_webpack_import__", "import"); +} + function replaceJSRootName(amdName, jsName) { // Saving old-style JS module name. return replace( @@ -349,6 +353,7 @@ function createMainBundle(defines) { .src("./src/pdf.js") .pipe(webpack2Stream(mainFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe(replaceJSRootName(mainAMDName, "pdfjsLib")); } @@ -370,6 +375,7 @@ function createScriptingBundle(defines, extraOptions = undefined) { .src("./src/pdf.scripting.js") .pipe(webpack2Stream(scriptingFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe( replace( 'root["' + scriptingAMDName + '"] = factory()', @@ -428,6 +434,7 @@ function createSandboxBundle(defines, extraOptions = undefined) { .src("./src/pdf.sandbox.js") .pipe(webpack2Stream(sandboxFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe(replaceJSRootName(sandboxAMDName, "pdfjsSandbox")); } @@ -445,6 +452,7 @@ function createWorkerBundle(defines) { .src("./src/pdf.worker.js") .pipe(webpack2Stream(workerFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe(replaceJSRootName(workerAMDName, "pdfjsWorker")); } @@ -460,7 +468,10 @@ function createWebBundle(defines, options) { defaultPreferencesDir: options.defaultPreferencesDir, } ); - return gulp.src("./web/viewer.js").pipe(webpack2Stream(viewerFileConfig)); + return gulp + .src("./web/viewer.js") + .pipe(webpack2Stream(viewerFileConfig)) + .pipe(replaceNonWebpackImport()); } function createComponentsBundle(defines) { @@ -477,6 +488,7 @@ function createComponentsBundle(defines) { .src("./web/pdf_viewer.component.js") .pipe(webpack2Stream(componentsFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe(replaceJSRootName(componentsAMDName, "pdfjsViewer")); } @@ -494,6 +506,7 @@ function createImageDecodersBundle(defines) { .src("./src/pdf.image_decoders.js") .pipe(webpack2Stream(componentsFileConfig)) .pipe(replaceWebpackRequire()) + .pipe(replaceNonWebpackImport()) .pipe(replaceJSRootName(imageDecodersAMDName, "pdfjsImageDecoders")); } @@ -1427,12 +1440,14 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) { // __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) { + function babelPluginReplaceNonWebpackImports(babel) { return { visitor: { Identifier(curPath, state) { if (curPath.node.name === "__non_webpack_require__") { curPath.replaceWith(babel.types.identifier("require")); + } else if (curPath.node.name === "__non_webpack_import__") { + curPath.replaceWith(babel.types.identifier("import")); } }, }, @@ -1454,7 +1469,7 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) { regenerator: true, }, ], - babelPluginReplaceNonWebPackRequire, + babelPluginReplaceNonWebpackImports, ], }).code; const removeCjsSrc = diff --git a/web/app.js b/web/app.js index d5c0febae..490528066 100644 --- a/web/app.js +++ b/web/app.js @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFBug, Stats */ import { animationStarted, @@ -254,6 +253,7 @@ const PDFViewerApplication = { _docStats: null, _wheelUnusedTicks: 0, _idleCallbacks: new Set(), + _PDFBug: null, // Called once when the document is loaded. async initialize(appConfig) { @@ -847,10 +847,8 @@ const PDFViewerApplication = { this.findBar?.reset(); this.toolbar.reset(); this.secondaryToolbar.reset(); + this._PDFBug?.cleanup(); - if (typeof PDFBug !== "undefined") { - PDFBug.cleanup(); - } await Promise.all(promises); }, @@ -2126,22 +2124,23 @@ async function loadFakeWorker() { async function initPDFBug(enabledTabs) { const { debuggerScriptPath, mainContainer } = PDFViewerApplication.appConfig; - await loadScript(debuggerScriptPath); + const { PDFBug } = + typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") + ? await import(debuggerScriptPath) // eslint-disable-line no-unsanitized/method + : await __non_webpack_import__(debuggerScriptPath); // eslint-disable-line no-undef PDFBug.init({ OPS }, mainContainer, enabledTabs); + + PDFViewerApplication._PDFBug = PDFBug; } function reportPageStatsPDFBug({ pageNumber }) { - if (typeof Stats === "undefined" || !Stats.enabled) { + if (!globalThis.Stats?.enabled) { return; } const pageView = PDFViewerApplication.pdfViewer.getPageView( /* index = */ pageNumber - 1 ); - const pageStats = pageView?.pdfPage?.stats; - if (!pageStats) { - return; - } - Stats.add(pageNumber, pageStats); + globalThis.Stats.add(pageNumber, pageView?.pdfPage?.stats); } function webViewerInitialized() { diff --git a/web/debugger.js b/web/debugger.js index 2a7de20c3..696d98c77 100644 --- a/web/debugger.js +++ b/web/debugger.js @@ -13,10 +13,9 @@ * limitations under the License. */ -"use strict"; +let opMap; -// eslint-disable-next-line no-var -var FontInspector = (function FontInspectorClosure() { +const FontInspector = (function FontInspectorClosure() { let fonts; let active = false; const fontAttribute = "data-font-name"; @@ -154,12 +153,8 @@ var FontInspector = (function FontInspectorClosure() { }; })(); -let opMap; - // Manages all the page steppers. -// -// eslint-disable-next-line no-var -var StepperManager = (function StepperManagerClosure() { +const StepperManager = (function StepperManagerClosure() { let steppers = []; let stepperDiv = null; let stepperControls = null; @@ -451,8 +446,7 @@ const Stepper = (function StepperClosure() { return Stepper; })(); -// eslint-disable-next-line no-var -var Stats = (function Stats() { +const Stats = (function Stats() { let stats = []; function clear(node) { node.textContent = ""; // Remove any `node` contents from the DOM. @@ -510,7 +504,7 @@ var Stats = (function Stats() { })(); // Manages all the debugging tools. -window.PDFBug = (function PDFBugClosure() { +const PDFBug = (function PDFBugClosure() { const panelWidth = 300; const buttons = []; let activePanel = null; @@ -562,13 +556,13 @@ window.PDFBug = (function PDFBugClosure() { container.style.right = panelWidth + "px"; // Initialize all the debugging tools. - for (const [i, tool] of this.tools.entries()) { + for (const tool of this.tools) { const panel = document.createElement("div"); const panelButton = document.createElement("button"); panelButton.textContent = tool.name; panelButton.addEventListener("click", event => { event.preventDefault(); - this.selectPanel(i); + this.selectPanel(tool); }); controls.appendChild(panelButton); panels.appendChild(panel); @@ -609,3 +603,9 @@ window.PDFBug = (function PDFBugClosure() { }, }; })(); + +globalThis.FontInspector = FontInspector; +globalThis.StepperManager = StepperManager; +globalThis.Stats = Stats; + +export { PDFBug };