diff --git a/external/dist/lib/README.md b/external/dist/lib/README.md index 8f44cd646833d6..9d6a89d7f4f346 100644 --- a/external/dist/lib/README.md +++ b/external/dist/lib/README.md @@ -3,5 +3,5 @@ pre-built library as found in e.g. the `/build`, `/web`, and `/image_decoders` folders in the root of this repository. Please note that the "lib" build target exists mostly to enable unit-testing in -Node.js/Travis, and that you'll need to handle e.g. any Node.js dependencies -yourself if using the files in this folder. +Node.js/Travis, and that you'll need to handle e.g. any necessary polyfills +and/or Node.js dependencies yourself if using the files in this folder. diff --git a/gulpfile.js b/gulpfile.js index c8f3fc98661bb6..5ccc6f40b52116 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1150,92 +1150,105 @@ gulp.task("jsdoc", function(done) { }); }); +function buildLib(defines, dir) { + // 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 + // occurences of __non_webpack_require__ ourselves. + function babelPluginReplaceNonWebPackRequire(babel) { + return { + visitor: { + Identifier(curPath, state) { + if (curPath.node.name === "__non_webpack_require__") { + curPath.replaceWith(babel.types.identifier("require")); + } + }, + }, + }; + } + function preprocess(content) { + var skipBabel = + bundleDefines.SKIP_BABEL || /\/\*\s*no-babel-preset\s*\*\//.test(content); + content = preprocessor2.preprocessPDFJSCode(ctx, content); + content = babel.transform(content, { + sourceType: "module", + presets: skipBabel ? undefined : ["@babel/preset-env"], + plugins: [ + "@babel/plugin-transform-modules-commonjs", + [ + "@babel/plugin-transform-runtime", + { + helpers: false, + regenerator: true, + }, + ], + babelPluginReplaceNonWebPackRequire, + ], + }).code; + var removeCjsSrc = /^(var\s+\w+\s*=\s*(_interopRequireDefault\()?require\(".*?)(?:\/src)(\/[^"]*"\)\)?;)$/gm; + content = content.replace(removeCjsSrc, (all, prefix, interop, suffix) => { + return prefix + suffix; + }); + return licenseHeaderLibre + content; + } + var babel = require("@babel/core"); + var versionInfo = getVersionJSON(); + var bundleDefines = builder.merge(defines, { + BUNDLE_VERSION: versionInfo.version, + BUNDLE_BUILD: versionInfo.commit, + TESTING: process.env["TESTING"] === "true", + }); + var ctx = { + rootPath: __dirname, + saveComments: false, + defines: bundleDefines, + map: { + "pdfjs-lib": "../pdf", + }, + }; + var licenseHeaderLibre = fs + .readFileSync("./src/license_header_libre.js") + .toString(); + var preprocessor2 = require("./external/builder/preprocessor2.js"); + return merge([ + gulp.src( + [ + "src/{core,display,shared}/*.js", + "!src/shared/{cffStandardStrings,fonts_utils}.js", + "src/{pdf,pdf.worker}.js", + ], + { base: "src/" } + ), + gulp.src( + ["examples/node/domstubs.js", "web/*.js", "!web/{pdfjs,viewer}.js"], + { base: "." } + ), + gulp.src("test/unit/*.js", { base: "." }), + ]) + .pipe(transform("utf8", preprocess)) + .pipe(gulp.dest(dir)); +} + gulp.task( "lib", gulp.series("buildnumber", "default_preferences", function() { - // 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 - // occurences of __non_webpack_require__ ourselves. - function babelPluginReplaceNonWebPackRequire(babel) { - return { - visitor: { - Identifier(curPath, state) { - if (curPath.node.name === "__non_webpack_require__") { - curPath.replaceWith(babel.types.identifier("require")); - } - }, - }, - }; - } - function preprocess(content) { - var skipBabel = - bundleDefines.SKIP_BABEL || - /\/\*\s*no-babel-preset\s*\*\//.test(content); - content = preprocessor2.preprocessPDFJSCode(ctx, content); - content = babel.transform(content, { - sourceType: "module", - presets: skipBabel ? undefined : ["@babel/preset-env"], - plugins: [ - "@babel/plugin-transform-modules-commonjs", - [ - "@babel/plugin-transform-runtime", - { - helpers: false, - regenerator: true, - }, - ], - babelPluginReplaceNonWebPackRequire, - ], - }).code; - var removeCjsSrc = /^(var\s+\w+\s*=\s*(_interopRequireDefault\()?require\(".*?)(?:\/src)(\/[^"]*"\)\)?;)$/gm; - content = content.replace( - removeCjsSrc, - (all, prefix, interop, suffix) => { - return prefix + suffix; - } - ); - return licenseHeaderLibre + content; - } - var babel = require("@babel/core"); - var versionInfo = getVersionJSON(); - var bundleDefines = builder.merge(DEFINES, { + var defines = builder.merge(DEFINES, { GENERIC: true, LIB: true }); + + return buildLib(defines, "build/lib/"); + }) +); + +gulp.task( + "lib-es5", + gulp.series("buildnumber", "default_preferences", function() { + var defines = builder.merge(DEFINES, { GENERIC: true, LIB: true, - BUNDLE_VERSION: versionInfo.version, - BUNDLE_BUILD: versionInfo.commit, - TESTING: process.env["TESTING"] === "true", + SKIP_BABEL: false, }); - var ctx = { - rootPath: __dirname, - saveComments: false, - defines: bundleDefines, - map: { - "pdfjs-lib": "../pdf", - }, - }; - var licenseHeaderLibre = fs - .readFileSync("./src/license_header_libre.js") - .toString(); - var preprocessor2 = require("./external/builder/preprocessor2.js"); - return merge([ - gulp.src( - [ - "src/{core,display,shared}/*.js", - "!src/shared/{cffStandardStrings,fonts_utils}.js", - "src/{pdf,pdf.worker}.js", - ], - { base: "src/" } - ), - gulp.src( - ["examples/node/domstubs.js", "web/*.js", "!web/{pdfjs,viewer}.js"], - { base: "." } - ), - gulp.src("test/unit/*.js", { base: "." }), - ]) - .pipe(transform("utf8", preprocess)) - .pipe(gulp.dest("build/lib/")); + + return buildLib(defines, "build/lib-es5/"); }) ); @@ -1371,7 +1384,7 @@ gulp.task("baseline", function(done) { gulp.task( "unittestcli", - gulp.series("testing-pre", "lib", function(done) { + gulp.series("testing-pre", "lib-es5", function(done) { var options = [ "node_modules/jasmine/bin/jasmine", "JASMINE_CONFIG_PATH=test/unit/clitests.json", diff --git a/src/core/worker.js b/src/core/worker.js index 34e5a824c3f3d2..879e98a61cb462 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -136,6 +136,20 @@ var WorkerMessageHandler = { "; thus breaking e.g. `for...in` iteration of `Array`s." ); } + + // Ensure that (primarily) Node.js users won't accidentally attempt to use + // a non-translated build of the library, since that would quickly fail + // anyway because of missing polyfills (such as e.g. `ReadableStream). + if ( + (typeof PDFJSDev === "undefined" || PDFJSDev.test("SKIP_BABEL")) && + typeof ReadableStream === "undefined" + ) { + throw new Error( + "The browser/environment lacks native support for critical " + + "functionality used by the PDF.js library (e.g. `ReadableStream`); " + + "please use an ES5-compatible build instead." + ); + } } var docId = docParams.docId; diff --git a/src/shared/compatibility.js b/src/shared/compatibility.js index 78373c4d12f1dc..93fee9bd145e95 100644 --- a/src/shared/compatibility.js +++ b/src/shared/compatibility.js @@ -14,11 +14,9 @@ */ /* eslint no-var: error */ -// Skip compatibility checks for modern builds (unless we're running the -// unit-tests in Node.js/Travis) and if we already ran the module. +// Skip compatibility checks for modern builds and if we already ran the module. if ( - (typeof PDFJSDev === "undefined" || - PDFJSDev.test("!SKIP_BABEL || (LIB && TESTING)")) && + (typeof PDFJSDev === "undefined" || !PDFJSDev.test("SKIP_BABEL")) && (typeof globalThis === "undefined" || !globalThis._pdfjsCompatibilityChecked) ) { // Provides support for globalThis in legacy browsers. diff --git a/test/unit/clitests.json b/test/unit/clitests.json index c11109675b1ede..4e22992c4eb836 100644 --- a/test/unit/clitests.json +++ b/test/unit/clitests.json @@ -1,5 +1,5 @@ { - "spec_dir": "build/lib/test/unit", + "spec_dir": "build/lib-es5/test/unit", "helpers": [ "clitests_helper.js"