Skip to content

Commit 298d721

Browse files
Merge pull request #18051 from Snuffleupagus/NodePackages
[api-minor] Re-factor how Node.js packages/polyfills are loaded (issue 17245)
2 parents 761abc7 + 9418ed1 commit 298d721

File tree

7 files changed

+103
-73
lines changed

7 files changed

+103
-73
lines changed

gulpfile.mjs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,8 @@ function checkChromePreferencesFile(chromePrefsPath, webPrefs) {
445445

446446
function tweakWebpackOutput(jsName) {
447447
const replacer = [
448-
" __webpack_exports__ = {};",
449-
",__webpack_exports__={};",
450-
" __webpack_exports__ = await __webpack_exports__;",
451-
"\\(__webpack_exports__=await __webpack_exports__\\)",
448+
" __webpack_exports__ = {};", // Normal builds.
449+
",__webpack_exports__={};", // Minified builds.
452450
];
453451
const regex = new RegExp(`(${replacer.join("|")})`, "gm");
454452

@@ -458,10 +456,6 @@ function tweakWebpackOutput(jsName) {
458456
return ` __webpack_exports__ = globalThis.${jsName} = {};`;
459457
case ",__webpack_exports__={};":
460458
return `,__webpack_exports__=globalThis.${jsName}={};`;
461-
case " __webpack_exports__ = await __webpack_exports__;":
462-
return ` __webpack_exports__ = globalThis.${jsName} = await (globalThis.${jsName}Promise = __webpack_exports__);`;
463-
case "(__webpack_exports__=await __webpack_exports__)":
464-
return `(__webpack_exports__=globalThis.${jsName}=await (globalThis.${jsName}Promise=__webpack_exports__))`;
465459
}
466460
return match;
467461
});

src/display/api.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
NodeCanvasFactory,
5959
NodeCMapReaderFactory,
6060
NodeFilterFactory,
61+
NodePackages,
6162
NodeStandardFontDataFactory,
6263
} from "display-node_utils";
6364
import { CanvasGraphics } from "./canvas.js";
@@ -2094,6 +2095,14 @@ class PDFWorker {
20942095
* @type {Promise<void>}
20952096
*/
20962097
get promise() {
2098+
if (
2099+
typeof PDFJSDev !== "undefined" &&
2100+
PDFJSDev.test("GENERIC") &&
2101+
isNodeJS
2102+
) {
2103+
// Ensure that all Node.js packages/polyfills have loaded.
2104+
return Promise.all([NodePackages.promise, this._readyCapability.promise]);
2105+
}
20972106
return this._readyCapability.promise;
20982107
}
20992108

src/display/node_stream.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,23 @@
1313
* limitations under the License.
1414
*/
1515

16-
import {
17-
AbortException,
18-
assert,
19-
isNodeJS,
20-
MissingPDFException,
21-
} from "../shared/util.js";
16+
import { AbortException, assert, MissingPDFException } from "../shared/util.js";
2217
import {
2318
extractFilenameFromHeader,
2419
validateRangeRequestCapabilities,
2520
} from "./network_utils.js";
21+
import { NodePackages } from "./node_utils.js";
2622

2723
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
2824
throw new Error(
2925
'Module "./node_stream.js" shall not be used with MOZCENTRAL builds.'
3026
);
3127
}
3228

33-
let fs, http, https, url;
34-
if (isNodeJS) {
35-
// Native packages.
36-
fs = await __non_webpack_import__("fs");
37-
http = await __non_webpack_import__("http");
38-
https = await __non_webpack_import__("https");
39-
url = await __non_webpack_import__("url");
40-
}
41-
4229
const fileUriRegex = /^file:\/\/\/[a-zA-Z]:\//;
4330

4431
function parseUrl(sourceUrl) {
32+
const url = NodePackages.get("url");
4533
const parsedUrl = url.parse(sourceUrl);
4634
if (parsedUrl.protocol === "file:" || parsedUrl.host) {
4735
return parsedUrl;
@@ -347,11 +335,13 @@ class PDFNodeStreamFullReader extends BaseFullReader {
347335

348336
this._request = null;
349337
if (this._url.protocol === "http:") {
338+
const http = NodePackages.get("http");
350339
this._request = http.request(
351340
createRequestOptions(this._url, stream.httpHeaders),
352341
handleResponse
353342
);
354343
} else {
344+
const https = NodePackages.get("https");
355345
this._request = https.request(
356346
createRequestOptions(this._url, stream.httpHeaders),
357347
handleResponse
@@ -394,11 +384,13 @@ class PDFNodeStreamRangeReader extends BaseRangeReader {
394384

395385
this._request = null;
396386
if (this._url.protocol === "http:") {
387+
const http = NodePackages.get("http");
397388
this._request = http.request(
398389
createRequestOptions(this._url, this._httpHeaders),
399390
handleResponse
400391
);
401392
} else {
393+
const https = NodePackages.get("https");
402394
this._request = https.request(
403395
createRequestOptions(this._url, this._httpHeaders),
404396
handleResponse
@@ -423,6 +415,7 @@ class PDFNodeStreamFsFullReader extends BaseFullReader {
423415
path = path.replace(/^\//, "");
424416
}
425417

418+
const fs = NodePackages.get("fs");
426419
fs.promises.lstat(path).then(
427420
stat => {
428421
// Setting right content length.
@@ -453,6 +446,7 @@ class PDFNodeStreamFsRangeReader extends BaseRangeReader {
453446
path = path.replace(/^\//, "");
454447
}
455448

449+
const fs = NodePackages.get("fs");
456450
this._setReadableStream(fs.createReadStream(path, { start, end: end - 1 }));
457451
}
458452
}

src/display/node_utils.js

Lines changed: 77 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,56 +27,90 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
2727
);
2828
}
2929

30-
let fs, canvas, path2d;
3130
if (isNodeJS) {
32-
// Native packages.
33-
fs = await __non_webpack_import__("fs");
34-
// Optional, third-party, packages.
35-
try {
36-
canvas = await __non_webpack_import__("canvas");
37-
} catch {}
38-
try {
39-
path2d = await __non_webpack_import__("path2d");
40-
} catch {}
41-
}
31+
// eslint-disable-next-line no-var
32+
var packageCapability = Promise.withResolvers();
33+
// eslint-disable-next-line no-var
34+
var packageMap = null;
4235

43-
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("SKIP_BABEL")) {
44-
(function checkDOMMatrix() {
45-
if (globalThis.DOMMatrix || !isNodeJS) {
46-
return;
47-
}
48-
const DOMMatrix = canvas?.DOMMatrix;
36+
const loadPackages = async () => {
37+
// Native packages.
38+
const fs = await __non_webpack_import__("fs"),
39+
http = await __non_webpack_import__("http"),
40+
https = await __non_webpack_import__("https"),
41+
url = await __non_webpack_import__("url");
4942

50-
if (DOMMatrix) {
51-
globalThis.DOMMatrix = DOMMatrix;
52-
} else {
53-
warn("Cannot polyfill `DOMMatrix`, rendering may be broken.");
43+
// Optional, third-party, packages.
44+
let canvas, path2d;
45+
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("SKIP_BABEL")) {
46+
try {
47+
canvas = await __non_webpack_import__("canvas");
48+
} catch {}
49+
try {
50+
path2d = await __non_webpack_import__("path2d");
51+
} catch {}
5452
}
55-
})();
5653

57-
(function checkPath2D() {
58-
if (globalThis.Path2D || !isNodeJS) {
59-
return;
60-
}
61-
const CanvasRenderingContext2D = canvas?.CanvasRenderingContext2D;
62-
const applyPath2DToCanvasRenderingContext =
63-
path2d?.applyPath2DToCanvasRenderingContext;
64-
const Path2D = path2d?.Path2D;
65-
66-
if (
67-
CanvasRenderingContext2D &&
68-
applyPath2DToCanvasRenderingContext &&
69-
Path2D
70-
) {
71-
applyPath2DToCanvasRenderingContext(CanvasRenderingContext2D);
72-
globalThis.Path2D = Path2D;
73-
} else {
74-
warn("Cannot polyfill `Path2D`, rendering may be broken.");
54+
return new Map(Object.entries({ fs, http, https, url, canvas, path2d }));
55+
};
56+
57+
loadPackages().then(
58+
map => {
59+
packageMap = map;
60+
packageCapability.resolve();
61+
62+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("SKIP_BABEL")) {
63+
return;
64+
}
65+
if (!globalThis.DOMMatrix) {
66+
const DOMMatrix = map.get("canvas")?.DOMMatrix;
67+
68+
if (DOMMatrix) {
69+
globalThis.DOMMatrix = DOMMatrix;
70+
} else {
71+
warn("Cannot polyfill `DOMMatrix`, rendering may be broken.");
72+
}
73+
}
74+
if (!globalThis.Path2D) {
75+
const CanvasRenderingContext2D =
76+
map.get("canvas")?.CanvasRenderingContext2D;
77+
const applyPath2DToCanvasRenderingContext =
78+
map.get("path2d")?.applyPath2DToCanvasRenderingContext;
79+
const Path2D = map.get("path2d")?.Path2D;
80+
81+
if (
82+
CanvasRenderingContext2D &&
83+
applyPath2DToCanvasRenderingContext &&
84+
Path2D
85+
) {
86+
applyPath2DToCanvasRenderingContext(CanvasRenderingContext2D);
87+
globalThis.Path2D = Path2D;
88+
} else {
89+
warn("Cannot polyfill `Path2D`, rendering may be broken.");
90+
}
91+
}
92+
},
93+
reason => {
94+
warn(`loadPackages: ${reason}`);
95+
96+
packageMap = new Map();
97+
packageCapability.resolve();
7598
}
76-
})();
99+
);
100+
}
101+
102+
class NodePackages {
103+
static get promise() {
104+
return packageCapability.promise;
105+
}
106+
107+
static get(name) {
108+
return packageMap?.get(name);
109+
}
77110
}
78111

79112
const fetchData = function (url) {
113+
const fs = NodePackages.get("fs");
80114
return fs.promises.readFile(url).then(data => new Uint8Array(data));
81115
};
82116

@@ -87,6 +121,7 @@ class NodeCanvasFactory extends BaseCanvasFactory {
87121
* @ignore
88122
*/
89123
_createCanvas(width, height) {
124+
const canvas = NodePackages.get("canvas");
90125
return canvas.createCanvas(width, height);
91126
}
92127
}
@@ -113,5 +148,6 @@ export {
113148
NodeCanvasFactory,
114149
NodeCMapReaderFactory,
115150
NodeFilterFactory,
151+
NodePackages,
116152
NodeStandardFontDataFactory,
117153
};

src/display/stubs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
const NodeCanvasFactory = null;
1717
const NodeCMapReaderFactory = null;
1818
const NodeFilterFactory = null;
19+
const NodePackages = null;
1920
const NodeStandardFontDataFactory = null;
2021
const PDFFetchStream = null;
2122
const PDFNetworkStream = null;
@@ -25,6 +26,7 @@ export {
2526
NodeCanvasFactory,
2627
NodeCMapReaderFactory,
2728
NodeFilterFactory,
29+
NodePackages,
2830
NodeStandardFontDataFactory,
2931
PDFFetchStream,
3032
PDFNetworkStream,

test/unit/clitests_helper.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
setVerbosityLevel,
1919
VerbosityLevel,
2020
} from "../../src/shared/util.js";
21+
import { NodePackages } from "../../src/display/node_utils.js";
2122

2223
// Sets longer timeout, similar to `jasmine-boot.js`.
2324
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
@@ -29,6 +30,9 @@ if (!isNodeJS) {
2930
);
3031
}
3132

33+
// Ensure that all Node.js packages/polyfills have loaded.
34+
await NodePackages.promise;
35+
3236
// Reduce the amount of console "spam", by ignoring `info`/`warn` calls,
3337
// when running the unit-tests in Node.js/Travis.
3438
setVerbosityLevel(VerbosityLevel.ERRORS);

web/pdfjs.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
* limitations under the License.
1414
*/
1515

16-
// Ensure that the viewer waits for the library to complete loading,
17-
// to avoid breaking e.g. the standalone viewer components (see issue 17228).
18-
if (
19-
(typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) &&
20-
!globalThis.pdfjsLib
21-
) {
22-
await globalThis.pdfjsLibPromise;
23-
}
24-
2516
const {
2617
AbortException,
2718
AnnotationEditorLayer,

0 commit comments

Comments
 (0)