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.
This commit is contained in:
Jonas Jenwald 2022-04-03 11:51:49 +02:00
parent 7c8a92da77
commit 8fa73dbfab
3 changed files with 41 additions and 27 deletions

View File

@ -327,6 +327,10 @@ function replaceWebpackRequire() {
return replace("__webpack_require__", "__w_pdfjs_require__"); return replace("__webpack_require__", "__w_pdfjs_require__");
} }
function replaceNonWebpackImport() {
return replace("__non_webpack_import__", "import");
}
function replaceJSRootName(amdName, jsName) { function replaceJSRootName(amdName, jsName) {
// Saving old-style JS module name. // Saving old-style JS module name.
return replace( return replace(
@ -349,6 +353,7 @@ function createMainBundle(defines) {
.src("./src/pdf.js") .src("./src/pdf.js")
.pipe(webpack2Stream(mainFileConfig)) .pipe(webpack2Stream(mainFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe(replaceJSRootName(mainAMDName, "pdfjsLib")); .pipe(replaceJSRootName(mainAMDName, "pdfjsLib"));
} }
@ -370,6 +375,7 @@ function createScriptingBundle(defines, extraOptions = undefined) {
.src("./src/pdf.scripting.js") .src("./src/pdf.scripting.js")
.pipe(webpack2Stream(scriptingFileConfig)) .pipe(webpack2Stream(scriptingFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe( .pipe(
replace( replace(
'root["' + scriptingAMDName + '"] = factory()', 'root["' + scriptingAMDName + '"] = factory()',
@ -428,6 +434,7 @@ function createSandboxBundle(defines, extraOptions = undefined) {
.src("./src/pdf.sandbox.js") .src("./src/pdf.sandbox.js")
.pipe(webpack2Stream(sandboxFileConfig)) .pipe(webpack2Stream(sandboxFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe(replaceJSRootName(sandboxAMDName, "pdfjsSandbox")); .pipe(replaceJSRootName(sandboxAMDName, "pdfjsSandbox"));
} }
@ -445,6 +452,7 @@ function createWorkerBundle(defines) {
.src("./src/pdf.worker.js") .src("./src/pdf.worker.js")
.pipe(webpack2Stream(workerFileConfig)) .pipe(webpack2Stream(workerFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe(replaceJSRootName(workerAMDName, "pdfjsWorker")); .pipe(replaceJSRootName(workerAMDName, "pdfjsWorker"));
} }
@ -460,7 +468,10 @@ function createWebBundle(defines, options) {
defaultPreferencesDir: options.defaultPreferencesDir, 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) { function createComponentsBundle(defines) {
@ -477,6 +488,7 @@ function createComponentsBundle(defines) {
.src("./web/pdf_viewer.component.js") .src("./web/pdf_viewer.component.js")
.pipe(webpack2Stream(componentsFileConfig)) .pipe(webpack2Stream(componentsFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe(replaceJSRootName(componentsAMDName, "pdfjsViewer")); .pipe(replaceJSRootName(componentsAMDName, "pdfjsViewer"));
} }
@ -494,6 +506,7 @@ function createImageDecodersBundle(defines) {
.src("./src/pdf.image_decoders.js") .src("./src/pdf.image_decoders.js")
.pipe(webpack2Stream(componentsFileConfig)) .pipe(webpack2Stream(componentsFileConfig))
.pipe(replaceWebpackRequire()) .pipe(replaceWebpackRequire())
.pipe(replaceNonWebpackImport())
.pipe(replaceJSRootName(imageDecodersAMDName, "pdfjsImageDecoders")); .pipe(replaceJSRootName(imageDecodersAMDName, "pdfjsImageDecoders"));
} }
@ -1427,12 +1440,14 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
// __non_webpack_require__ has to be used. // __non_webpack_require__ has to be used.
// In this target, we don't create a bundle, so we have to replace the // In this target, we don't create a bundle, so we have to replace the
// occurrences of __non_webpack_require__ ourselves. // occurrences of __non_webpack_require__ ourselves.
function babelPluginReplaceNonWebPackRequire(babel) { function babelPluginReplaceNonWebpackImports(babel) {
return { return {
visitor: { visitor: {
Identifier(curPath, state) { Identifier(curPath, state) {
if (curPath.node.name === "__non_webpack_require__") { if (curPath.node.name === "__non_webpack_require__") {
curPath.replaceWith(babel.types.identifier("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, regenerator: true,
}, },
], ],
babelPluginReplaceNonWebPackRequire, babelPluginReplaceNonWebpackImports,
], ],
}).code; }).code;
const removeCjsSrc = const removeCjsSrc =

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/* globals PDFBug, Stats */
import { import {
animationStarted, animationStarted,
@ -254,6 +253,7 @@ const PDFViewerApplication = {
_docStats: null, _docStats: null,
_wheelUnusedTicks: 0, _wheelUnusedTicks: 0,
_idleCallbacks: new Set(), _idleCallbacks: new Set(),
_PDFBug: null,
// Called once when the document is loaded. // Called once when the document is loaded.
async initialize(appConfig) { async initialize(appConfig) {
@ -847,10 +847,8 @@ const PDFViewerApplication = {
this.findBar?.reset(); this.findBar?.reset();
this.toolbar.reset(); this.toolbar.reset();
this.secondaryToolbar.reset(); this.secondaryToolbar.reset();
this._PDFBug?.cleanup();
if (typeof PDFBug !== "undefined") {
PDFBug.cleanup();
}
await Promise.all(promises); await Promise.all(promises);
}, },
@ -2126,22 +2124,23 @@ async function loadFakeWorker() {
async function initPDFBug(enabledTabs) { async function initPDFBug(enabledTabs) {
const { debuggerScriptPath, mainContainer } = PDFViewerApplication.appConfig; 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); PDFBug.init({ OPS }, mainContainer, enabledTabs);
PDFViewerApplication._PDFBug = PDFBug;
} }
function reportPageStatsPDFBug({ pageNumber }) { function reportPageStatsPDFBug({ pageNumber }) {
if (typeof Stats === "undefined" || !Stats.enabled) { if (!globalThis.Stats?.enabled) {
return; return;
} }
const pageView = PDFViewerApplication.pdfViewer.getPageView( const pageView = PDFViewerApplication.pdfViewer.getPageView(
/* index = */ pageNumber - 1 /* index = */ pageNumber - 1
); );
const pageStats = pageView?.pdfPage?.stats; globalThis.Stats.add(pageNumber, pageView?.pdfPage?.stats);
if (!pageStats) {
return;
}
Stats.add(pageNumber, pageStats);
} }
function webViewerInitialized() { function webViewerInitialized() {

View File

@ -13,10 +13,9 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict"; let opMap;
// eslint-disable-next-line no-var const FontInspector = (function FontInspectorClosure() {
var FontInspector = (function FontInspectorClosure() {
let fonts; let fonts;
let active = false; let active = false;
const fontAttribute = "data-font-name"; const fontAttribute = "data-font-name";
@ -154,12 +153,8 @@ var FontInspector = (function FontInspectorClosure() {
}; };
})(); })();
let opMap;
// Manages all the page steppers. // Manages all the page steppers.
// const StepperManager = (function StepperManagerClosure() {
// eslint-disable-next-line no-var
var StepperManager = (function StepperManagerClosure() {
let steppers = []; let steppers = [];
let stepperDiv = null; let stepperDiv = null;
let stepperControls = null; let stepperControls = null;
@ -451,8 +446,7 @@ const Stepper = (function StepperClosure() {
return Stepper; return Stepper;
})(); })();
// eslint-disable-next-line no-var const Stats = (function Stats() {
var Stats = (function Stats() {
let stats = []; let stats = [];
function clear(node) { function clear(node) {
node.textContent = ""; // Remove any `node` contents from the DOM. node.textContent = ""; // Remove any `node` contents from the DOM.
@ -510,7 +504,7 @@ var Stats = (function Stats() {
})(); })();
// Manages all the debugging tools. // Manages all the debugging tools.
window.PDFBug = (function PDFBugClosure() { const PDFBug = (function PDFBugClosure() {
const panelWidth = 300; const panelWidth = 300;
const buttons = []; const buttons = [];
let activePanel = null; let activePanel = null;
@ -562,13 +556,13 @@ window.PDFBug = (function PDFBugClosure() {
container.style.right = panelWidth + "px"; container.style.right = panelWidth + "px";
// Initialize all the debugging tools. // 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 panel = document.createElement("div");
const panelButton = document.createElement("button"); const panelButton = document.createElement("button");
panelButton.textContent = tool.name; panelButton.textContent = tool.name;
panelButton.addEventListener("click", event => { panelButton.addEventListener("click", event => {
event.preventDefault(); event.preventDefault();
this.selectPanel(i); this.selectPanel(tool);
}); });
controls.appendChild(panelButton); controls.appendChild(panelButton);
panels.appendChild(panel); panels.appendChild(panel);
@ -609,3 +603,9 @@ window.PDFBug = (function PDFBugClosure() {
}, },
}; };
})(); })();
globalThis.FontInspector = FontInspector;
globalThis.StepperManager = StepperManager;
globalThis.Stats = Stats;
export { PDFBug };