Replace the webpack+acorn transform with a Babel plugin

This commit converts the pdfjsdev-loader transform into a Babel plugin,
to skip a AST->string->AST round-trip.

Before this commit, the webpack build process was:
1. Babel parses the code
2. Babel transforms the AST
3. Babel generates the code
4. Acorn parses the code
5. pdfjsdev-loader transforms the AST
6. @javascript-obfuscator/escodegen generates the code
7. Webpack parses the file
8. Webpack concatenates the files

After this commit, it is reduced to:
1. Babel parses the code
2. Babel transforms the AST
3. babel-plugin-pdfjs-preprocessor transforms the AST
4. Babel generates the code
5. Webpack parses the file
6. Webpack concatenates the files

This change improves the build time by ~25% (tested on MacBook Air M2):
- `gulp lib`: 3.4s to 2.6s
- `gulp dist`: 36s to 29s
- `gulp generic`: 5.5s to 4.0s
- `gulp mozcentral`: 4.7s to 3.2s

The new Babel plugin doesn't support the `saveComments` option of
pdfjsdev-loader, and it just always discards comments. Even though
pdfjsdev-loader supported multiple values for that option, it was
effectively ignored due to `acorn` dropping comments by default.
This commit is contained in:
Nicolò Ribaudo 2024-01-22 18:33:31 +01:00
parent f5bb9bc21b
commit f724ae98a1
No known key found for this signature in database
GPG Key ID: AAFDA9101C58F338
16 changed files with 287 additions and 479 deletions

View File

@ -1,347 +1,241 @@
import * as acorn from "acorn"; import { types as t, transformSync } from "@babel/core";
import escodegen from "@javascript-obfuscator/escodegen";
import fs from "fs"; import fs from "fs";
import path from "path"; import { join as joinPaths } from "path";
import vm from "vm"; import vm from "vm";
const PDFJS_PREPROCESSOR_NAME = "PDFJSDev"; const PDFJS_PREPROCESSOR_NAME = "PDFJSDev";
const ROOT_PREFIX = "$ROOT/"; const ROOT_PREFIX = "$ROOT/";
const ACORN_ECMA_VERSION = 2022;
function isLiteral(obj, value) {
return obj.type === "Literal" && obj.value === value;
}
function isPDFJSPreprocessor(obj) { function isPDFJSPreprocessor(obj) {
return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME; return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;
} }
function evalWithDefines(code, defines, loc) { function evalWithDefines(code, defines) {
if (!code || !code.trim()) { if (!code || !code.trim()) {
throw new Error("No JavaScript expression given"); throw new Error("No JavaScript expression given");
} }
return vm.runInNewContext(code, defines, { displayErrors: false }); return vm.runInNewContext(code, defines, { displayErrors: false });
} }
function handlePreprocessorAction(ctx, actionName, args, loc) { function handlePreprocessorAction(ctx, actionName, args, path) {
try { try {
let arg; const arg = args[0];
switch (actionName) { switch (actionName) {
case "test": case "test":
arg = args[0]; if (!t.isStringLiteral(arg)) {
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
throw new Error("No code for testing is given"); throw new Error("No code for testing is given");
} }
const isTrue = !!evalWithDefines(arg.value, ctx.defines); return !!evalWithDefines(arg.value, ctx.defines);
return { type: "Literal", value: isTrue, loc };
case "eval": case "eval":
arg = args[0]; if (!t.isStringLiteral(arg)) {
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
throw new Error("No code for eval is given"); throw new Error("No code for eval is given");
} }
const result = evalWithDefines(arg.value, ctx.defines); const result = evalWithDefines(arg.value, ctx.defines);
if ( if (
typeof result === "boolean" || typeof result === "boolean" ||
typeof result === "string" || typeof result === "string" ||
typeof result === "number" typeof result === "number" ||
typeof result === "object"
) { ) {
return { type: "Literal", value: result, loc }; return result;
}
if (typeof result === "object") {
const parsedObj = acorn.parse("(" + JSON.stringify(result) + ")", {
ecmaVersion: ACORN_ECMA_VERSION,
});
parsedObj.body[0].expression.loc = loc;
return parsedObj.body[0].expression;
} }
break; break;
case "json": case "json":
arg = args[0]; if (!t.isStringLiteral(arg)) {
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
throw new Error("Path to JSON is not provided"); throw new Error("Path to JSON is not provided");
} }
let jsonPath = arg.value; let jsonPath = arg.value;
if (jsonPath.indexOf(ROOT_PREFIX) === 0) { if (jsonPath.startsWith(ROOT_PREFIX)) {
jsonPath = path.join( jsonPath = joinPaths(
ctx.rootPath, ctx.rootPath,
jsonPath.substring(ROOT_PREFIX.length) jsonPath.substring(ROOT_PREFIX.length)
); );
} }
const jsonContent = fs.readFileSync(jsonPath).toString(); return JSON.parse(fs.readFileSync(jsonPath, "utf8"));
const parsedJSON = acorn.parse("(" + jsonContent + ")", {
ecmaVersion: ACORN_ECMA_VERSION,
});
parsedJSON.body[0].expression.loc = loc;
return parsedJSON.body[0].expression;
} }
throw new Error("Unsupported action"); throw new Error("Unsupported action");
} catch (e) { } catch (e) {
throw new Error( throw path.buildCodeFrameError(
"Could not process " + "Could not process " +
PDFJS_PREPROCESSOR_NAME + PDFJS_PREPROCESSOR_NAME +
"." + "." +
actionName + actionName +
" at " +
JSON.stringify(loc) +
"\n" +
e.name +
": " + ": " +
e.message e.message
); );
} }
} }
function postprocessNode(ctx, node) { function babelPluginPDFJSPreprocessor(babel, ctx) {
switch (node.type) { return {
case "ExportNamedDeclaration": name: "babel-plugin-pdfjs-preprocessor",
case "ImportDeclaration": manipulateOptions({ parserOpts }) {
if ( parserOpts.attachComment = false;
node.source && },
node.source.type === "Literal" && visitor: {
ctx.map && "ExportNamedDeclaration|ImportDeclaration": ({ node }) => {
ctx.map[node.source.value] if (node.source && ctx.map?.[node.source.value]) {
) { node.source.value = ctx.map[node.source.value];
const newValue = ctx.map[node.source.value]; }
node.source.value = node.source.raw = newValue; },
} "IfStatement|ConditionalExpression": {
break; exit(path) {
case "IfStatement": const { node } = path;
if (isLiteral(node.test, true)) { if (t.isBooleanLiteral(node.test)) {
// if (true) stmt1; => stmt1 // if (true) stmt1; => stmt1
return node.consequent; // if (false) stmt1; else stmt2; => stmt2
} else if (isLiteral(node.test, false)) { path.replaceWith(
// if (false) stmt1; else stmt2; => stmt2 node.test.value === true
return node.alternate || { type: "EmptyStatement", loc: node.loc }; ? node.consequent
} : node.alternate || t.emptyStatement()
break;
case "ConditionalExpression":
if (isLiteral(node.test, true)) {
// true ? stmt1 : stmt2 => stmt1
return node.consequent;
} else if (isLiteral(node.test, false)) {
// false ? stmt1 : stmt2 => stmt2
return node.alternate;
}
break;
case "UnaryExpression":
if (node.operator === "typeof" && isPDFJSPreprocessor(node.argument)) {
// typeof PDFJSDev => 'object'
return { type: "Literal", value: "object", loc: node.loc };
}
if (
node.operator === "!" &&
node.argument.type === "Literal" &&
typeof node.argument.value === "boolean"
) {
// !true => false, !false => true
return { type: "Literal", value: !node.argument.value, loc: node.loc };
}
break;
case "LogicalExpression":
switch (node.operator) {
case "&&":
if (isLiteral(node.left, true)) {
return node.right;
}
if (isLiteral(node.left, false)) {
return node.left;
}
break;
case "||":
if (isLiteral(node.left, true)) {
return node.left;
}
if (isLiteral(node.left, false)) {
return node.right;
}
break;
}
break;
case "BinaryExpression":
switch (node.operator) {
case "==":
case "===":
case "!=":
case "!==":
if (
node.left.type === "Literal" &&
node.right.type === "Literal" &&
typeof node.left.value === typeof node.right.value
) {
// folding two literals == and != check
switch (typeof node.left.value) {
case "string":
case "boolean":
case "number":
const equal = node.left.value === node.right.value;
return {
type: "Literal",
value: (node.operator[0] === "=") === equal,
loc: node.loc,
};
}
}
break;
}
break;
case "CallExpression":
if (
node.callee.type === "MemberExpression" &&
isPDFJSPreprocessor(node.callee.object) &&
node.callee.property.type === "Identifier"
) {
// PDFJSDev.xxxx(arg1, arg2, ...) => transform
const action = node.callee.property.name;
return handlePreprocessorAction(ctx, action, node.arguments, node.loc);
}
// require('string')
if (
node.callee.type === "Identifier" &&
node.callee.name === "require" &&
node.arguments.length === 1 &&
node.arguments[0].type === "Literal" &&
ctx.map &&
ctx.map[node.arguments[0].value]
) {
const requireName = node.arguments[0];
requireName.value = requireName.raw = ctx.map[requireName.value];
}
break;
case "BlockStatement":
let subExpressionIndex = 0;
while (subExpressionIndex < node.body.length) {
switch (node.body[subExpressionIndex].type) {
case "EmptyStatement":
// Removing empty statements from the blocks.
node.body.splice(subExpressionIndex, 1);
continue;
case "BlockStatement":
// Block statements inside a block are moved to the parent one.
const subChildren = node.body[subExpressionIndex].body;
Array.prototype.splice.apply(node.body, [
subExpressionIndex,
1,
...subChildren,
]);
subExpressionIndex += Math.max(subChildren.length - 1, 0);
continue;
case "ReturnStatement":
case "ThrowStatement":
// Removing dead code after return or throw.
node.body.splice(
subExpressionIndex + 1,
node.body.length - subExpressionIndex - 1
); );
break;
}
subExpressionIndex++;
}
break;
case "FunctionDeclaration":
case "FunctionExpression":
const block = node.body;
if (
block.body.length > 0 &&
block.body.at(-1).type === "ReturnStatement" &&
!block.body.at(-1).argument
) {
// Function body ends with return without arg -- removing it.
block.body.pop();
}
break;
}
return node;
}
function fixComments(ctx, node) {
if (!ctx.saveComments) {
return;
}
// Fixes double comments in the escodegen output.
delete node.trailingComments;
// Removes ESLint and other service comments.
if (node.leadingComments) {
const CopyrightRegExp = /\bcopyright\b/i;
const BlockCommentRegExp = /^\s*(globals|eslint|falls through)\b/;
const LineCommentRegExp = /^\s*eslint\b/;
let i = 0;
while (i < node.leadingComments.length) {
const type = node.leadingComments[i].type;
const value = node.leadingComments[i].value;
if (ctx.saveComments === "copyright") {
// Remove all comments, except Copyright notices and License headers.
if (!(type === "Block" && CopyrightRegExp.test(value))) {
node.leadingComments.splice(i, 1);
continue;
}
} else if (
(type === "Block" && BlockCommentRegExp.test(value)) ||
(type === "Line" && LineCommentRegExp.test(value))
) {
node.leadingComments.splice(i, 1);
continue;
}
i++;
}
}
}
function traverseTree(ctx, node) {
// generic node processing
for (const i in node) {
const child = node[i];
if (typeof child === "object" && child !== null && child.type) {
const result = traverseTree(ctx, child);
if (result !== child) {
node[i] = result;
}
} else if (Array.isArray(child)) {
child.forEach(function (childItem, index) {
if (
typeof childItem === "object" &&
childItem !== null &&
childItem.type
) {
const result = traverseTree(ctx, childItem);
if (result !== childItem) {
child[index] = result;
} }
},
},
UnaryExpression(path) {
const { node } = path;
if (node.operator === "typeof" && isPDFJSPreprocessor(node.argument)) {
// typeof PDFJSDev => 'object'
path.replaceWith(t.stringLiteral("object"));
return;
} }
}); if (node.operator === "!" && t.isBooleanLiteral(node.argument)) {
} // !true => false, !false => true
} path.replaceWith(t.booleanLiteral(!node.argument.value));
}
},
LogicalExpression: {
exit(path) {
const { node } = path;
if (!t.isBooleanLiteral(node.left)) {
return;
}
node = postprocessNode(ctx, node) || node; switch (node.operator) {
case "&&":
// true && expr => expr
// false && expr => false
path.replaceWith(
node.left.value === true ? node.right : node.left
);
break;
case "||":
// true || expr => true
// false || expr => expr
path.replaceWith(
node.left.value === true ? node.left : node.right
);
break;
}
},
},
BinaryExpression: {
exit(path) {
const { node } = path;
switch (node.operator) {
case "==":
case "===":
case "!=":
case "!==":
if (t.isLiteral(node.left) && t.isLiteral(node.right)) {
// folding == and != check that can be statically evaluated
const { confident, value } = path.evaluate();
if (confident) {
path.replaceWith(t.booleanLiteral(value));
}
}
}
},
},
CallExpression(path) {
const { node } = path;
if (
t.isMemberExpression(node.callee) &&
isPDFJSPreprocessor(node.callee.object) &&
t.isIdentifier(node.callee.property) &&
!node.callee.computed
) {
// PDFJSDev.xxxx(arg1, arg2, ...) => transform
const action = node.callee.property.name;
const result = handlePreprocessorAction(
ctx,
action,
node.arguments,
path
);
path.replaceWith(t.inherits(t.valueToNode(result), path.node));
}
fixComments(ctx, node); // require('string')
return node; if (
} t.isIdentifier(node.callee, { name: "require" }) &&
node.arguments.length === 1 &&
t.isStringLiteral(node.arguments[0]) &&
ctx.map?.[node.arguments[0].value]
) {
const requireName = node.arguments[0];
requireName.value = requireName.raw = ctx.map[requireName.value];
}
},
BlockStatement: {
// Visit node in post-order so that recursive flattening
// of blocks works correctly.
exit(path) {
const { node } = path;
function preprocessPDFJSCode(ctx, code) { let subExpressionIndex = 0;
const format = ctx.format || { while (subExpressionIndex < node.body.length) {
indent: { switch (node.body[subExpressionIndex].type) {
style: " ", case "EmptyStatement":
// Removing empty statements from the blocks.
node.body.splice(subExpressionIndex, 1);
continue;
case "BlockStatement":
// Block statements inside a block are flattened
// into the parent one.
const subChildren = node.body[subExpressionIndex].body;
node.body.splice(subExpressionIndex, 1, ...subChildren);
subExpressionIndex += Math.max(subChildren.length - 1, 0);
continue;
case "ReturnStatement":
case "ThrowStatement":
// Removing dead code after return or throw.
node.body.splice(
subExpressionIndex + 1,
node.body.length - subExpressionIndex - 1
);
break;
}
subExpressionIndex++;
}
},
},
Function: {
exit(path) {
if (!t.isBlockStatement(path.node.body)) {
// Arrow function with expression body
return;
}
const { body } = path.node.body;
if (
body.length > 0 &&
t.isReturnStatement(body.at(-1), { argument: null })
) {
// Function body ends with return without arg -- removing it.
body.pop();
}
},
},
}, },
}; };
const parseOptions = {
ecmaVersion: ACORN_ECMA_VERSION,
locations: true,
sourceFile: ctx.sourceFile,
sourceType: "module",
};
const codegenOptions = {
format,
parse(input) {
return acorn.parse(input, { ecmaVersion: ACORN_ECMA_VERSION });
},
sourceMap: ctx.sourceMap,
sourceMapWithCode: ctx.sourceMap,
};
const syntax = acorn.parse(code, parseOptions);
traverseTree(ctx, syntax);
return escodegen.generate(syntax, codegenOptions);
} }
export { preprocessPDFJSCode }; function preprocessPDFJSCode(ctx, content) {
return transformSync(content, {
configFile: false,
plugins: [[babelPluginPDFJSPreprocessor, ctx]],
}).code;
}
export { babelPluginPDFJSPreprocessor, preprocessPDFJSCode };

View File

@ -1,10 +1,10 @@
function test() { function test() {
"test"; "test";
"1"; "1";
"2"; "2";
"3"; "3";
if ("test") { if ("test") {
"5"; "5";
} }
"4"; "4";
} }

View File

@ -1,17 +1,17 @@
function f1() { function f1() {
"1"; "1";
"2"; "2";
} }
function f2() { function f2() {
"1"; "1";
"2"; "2";
} }
function f3() { function f3() {
if ("1") { if ("1") {
"1"; "1";
} }
"2"; "2";
if ("3") { if ("3") {
"4"; "4";
} }
} }

View File

@ -10,6 +10,6 @@ var i = true;
var j = false; var j = false;
var k = false; var k = false;
var l = true; var l = true;
var m = '1' === true; var m = false;
var n = false; var n = false;
var o = true; var o = true;

View File

@ -1,13 +1,21 @@
function f1() { function f1() {}
}
function f2() { function f2() {
return 1; return 1;
} }
function f3() { function f3() {
var i = 0; var i = 0;
throw "test"; throw "test";
} }
function f4() { function f4() {
var i = 0; var i = 0;
} }
var obj = {
method1() {},
method2() {}
};
class C {
method1() {}
method2() {}
}
var arrow1 = () => {};
var arrow2 = () => {};

View File

@ -23,3 +23,15 @@ function f4() {
var j = 0; var j = 0;
} }
var obj = {
method1() { return; var i = 0; },
method2() { return; },
};
class C {
method1() { return; var i = 0; }
method2() { return; }
}
var arrow1 = () => { return; var i = 0; };
var arrow2 = () => { return; };

View File

@ -3,11 +3,17 @@ var b = true;
var c = true; var c = true;
var d = false; var d = false;
var e = true; var e = true;
var f = 'text'; var f = "text";
var g = { var g = {
"obj": { "i": 1 }, obj: {
"j": 2 i: 1
},
j: 2
};
var h = {
test: "test"
}; };
var h = { 'test': 'test' };
var i = '0'; var i = '0';
var j = { "i": 1 }; var j = {
i: 1
};

View File

@ -1 +1 @@
{ 'test': 'test' } { "test": "test" }

View File

@ -1,17 +1,17 @@
if ('test') { if ('test') {
"1"; "1";
} }
{ {
"1"; "1";
} }
{ {
"1"; "1";
} }
; ;
{ {
"2"; "2";
} }
; ;
if ('1') { if ('1') {
"1"; "1";
} }

View File

@ -1,7 +1,5 @@
import { Test } from 'import-name'; import { Test } from "import-name";
import { Test2 } from './non-alias'; import { Test2 } from './non-alias';
export { export { Test3 } from "import-name";
Test3 var Imp = require("import-name");
} from 'import-name';
var Imp = require('import-name');
var Imp2 = require('./non-alias'); var Imp2 = require('./non-alias');

View File

@ -42,6 +42,12 @@ files.forEach(function (expectationFilename) {
if (out !== expectation) { if (out !== expectation) {
errors++; errors++;
// Allow regenerating the expected output using
// OVERWRITE=true node ./external/builder/test-fixtures.mjs
if (process.env.OVERWRITE) {
fs.writeFileSync(expectationFilename, out + "\n");
}
console.log("Assertion failed for " + inFilename); console.log("Assertion failed for " + inFilename);
console.log("--------------------------------------------------"); console.log("--------------------------------------------------");
console.log("EXPECTED:"); console.log("EXPECTED:");

View File

@ -1,7 +1,7 @@
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { preprocessPDFJSCode } from "./preprocessor2.mjs"; import { preprocessPDFJSCode } from "./babel-plugin-pdfjs-preprocessor.mjs";
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -48,6 +48,12 @@ files.forEach(function (expectationFilename) {
if (out !== expectation) { if (out !== expectation) {
errors++; errors++;
// Allow regenerating the expected output using
// OVERWRITE=true node ./external/builder/test-fixtures_esprima.mjs
if (process.env.OVERWRITE) {
fs.writeFileSync(expectationFilename, out + "\n");
}
console.log("Assertion failed for " + inFilename); console.log("Assertion failed for " + inFilename);
console.log("--------------------------------------------------"); console.log("--------------------------------------------------");
console.log("EXPECTED:"); console.log("EXPECTED:");

View File

@ -1,41 +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.
*/
import path from "path";
import { preprocessPDFJSCode } from "../builder/preprocessor2.mjs";
export default function (source) {
// Options must be specified, ignoring request if not.
if (!this.query || typeof this.query !== "object") {
return source;
}
this.cacheable();
const filePath = this.resourcePath;
const context = this.rootContext;
const sourcePath = path.relative(context, filePath).split(path.sep).join("/");
const ctx = Object.create(this.query);
ctx.sourceMap = true;
ctx.sourceFile = sourcePath;
const callback = this.callback;
const sourceAndMap = preprocessPDFJSCode(ctx, source);
const map = sourceAndMap.map.toJSON();
// escodegen does not embed source -- setting map's sourcesContent.
map.sourcesContent = [source];
callback(null, sourceAndMap.code, map);
return undefined;
}

View File

@ -14,6 +14,10 @@
*/ */
/* eslint-env node */ /* eslint-env node */
import {
babelPluginPDFJSPreprocessor,
preprocessPDFJSCode,
} from "./external/builder/babel-plugin-pdfjs-preprocessor.mjs";
import { exec, spawn, spawnSync } from "child_process"; import { exec, spawn, spawnSync } from "child_process";
import autoprefixer from "autoprefixer"; import autoprefixer from "autoprefixer";
import babel from "@babel/core"; import babel from "@babel/core";
@ -30,7 +34,6 @@ import postcssDirPseudoClass from "postcss-dir-pseudo-class";
import postcssDiscardComments from "postcss-discard-comments"; import postcssDiscardComments from "postcss-discard-comments";
import postcssNesting from "postcss-nesting"; import postcssNesting from "postcss-nesting";
import { preprocess } from "./external/builder/builder.mjs"; import { preprocess } from "./external/builder/builder.mjs";
import { preprocessPDFJSCode } from "./external/builder/preprocessor2.mjs";
import rename from "gulp-rename"; import rename from "gulp-rename";
import replace from "gulp-replace"; import replace from "gulp-replace";
import rimraf from "rimraf"; import rimraf from "rimraf";
@ -209,10 +212,11 @@ function createWebpackConfig(
const isModule = output.library?.type === "module"; const isModule = output.library?.type === "module";
const skipBabel = bundleDefines.SKIP_BABEL; const skipBabel = bundleDefines.SKIP_BABEL;
// `core-js`, see https://github.com/zloirock/core-js/issues/514, const babelExcludeRegExp = [
// should be excluded from processing. // `core-js`, see https://github.com/zloirock/core-js/issues/514,
const babelExcludes = ["node_modules[\\\\\\/]core-js"]; // should be excluded from processing.
const babelExcludeRegExp = new RegExp(`(${babelExcludes.join("|")})`); /node_modules[\\/]core-js/,
];
const babelPresets = skipBabel const babelPresets = skipBabel
? undefined ? undefined
@ -227,7 +231,15 @@ function createWebpackConfig(
}, },
], ],
]; ];
const babelPlugins = []; const babelPlugins = [
[
babelPluginPDFJSPreprocessor,
{
rootPath: __dirname,
defines: bundleDefines,
},
],
];
const plugins = []; const plugins = [];
if (!disableLicenseHeader) { if (!disableLicenseHeader) {
@ -335,14 +347,6 @@ function createWebpackConfig(
targets: BABEL_TARGETS, targets: BABEL_TARGETS,
}, },
}, },
{
loader: path.join(__dirname, "external/webpack/pdfjsdev-loader.mjs"),
options: {
rootPath: __dirname,
saveComments: false,
defines: bundleDefines,
},
},
], ],
}, },
// Avoid shadowing actual Node.js variables with polyfills, by disabling // Avoid shadowing actual Node.js variables with polyfills, by disabling
@ -463,7 +467,6 @@ function createSandboxExternal(defines) {
const licenseHeader = fs.readFileSync("./src/license_header.js").toString(); const licenseHeader = fs.readFileSync("./src/license_header.js").toString();
const ctx = { const ctx = {
saveComments: false,
defines, defines,
}; };
return gulp return gulp
@ -1572,13 +1575,15 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
} }
function preprocessLib(content) { function preprocessLib(content) {
const skipBabel = bundleDefines.SKIP_BABEL; const skipBabel = bundleDefines.SKIP_BABEL;
content = preprocessPDFJSCode(ctx, content);
content = babel.transform(content, { content = babel.transform(content, {
sourceType: "module", sourceType: "module",
presets: skipBabel presets: skipBabel
? undefined ? undefined
: [["@babel/preset-env", { loose: false, modules: false }]], : [["@babel/preset-env", { loose: false, modules: false }]],
plugins: [babelPluginReplaceNonWebpackImport], plugins: [
babelPluginReplaceNonWebpackImport,
[babelPluginPDFJSPreprocessor, ctx],
],
targets: BABEL_TARGETS, targets: BABEL_TARGETS,
}).code; }).code;
content = content.replaceAll( content = content.replaceAll(
@ -1589,7 +1594,6 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
} }
const ctx = { const ctx = {
rootPath: __dirname, rootPath: __dirname,
saveComments: false,
defines: bundleDefines, defines: bundleDefines,
map: { map: {
"pdfjs-lib": "../pdf.js", "pdfjs-lib": "../pdf.js",

95
package-lock.json generated
View File

@ -13,9 +13,7 @@
"@babel/runtime": "^7.23.8", "@babel/runtime": "^7.23.8",
"@fluent/bundle": "^0.18.0", "@fluent/bundle": "^0.18.0",
"@fluent/dom": "^0.9.0", "@fluent/dom": "^0.9.0",
"@javascript-obfuscator/escodegen": "2.3.0",
"@jazzer.js/core": "^2.1.0", "@jazzer.js/core": "^2.1.0",
"acorn": "^8.11.3",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",
@ -2330,33 +2328,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@javascript-obfuscator/escodegen": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@javascript-obfuscator/escodegen/-/escodegen-2.3.0.tgz",
"integrity": "sha512-QVXwMIKqYMl3KwtTirYIA6gOCiJ0ZDtptXqAv/8KWLG9uQU2fZqTVy7a/A5RvcoZhbDoFfveTxuGxJ5ibzQtkw==",
"dev": true,
"dependencies": {
"@javascript-obfuscator/estraverse": "^5.3.0",
"esprima": "^4.0.1",
"esutils": "^2.0.2",
"optionator": "^0.8.1"
},
"engines": {
"node": ">=6.0"
},
"optionalDependencies": {
"source-map": "~0.6.1"
}
},
"node_modules/@javascript-obfuscator/estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@javascript-obfuscator/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-SxIFtV5/wlXYS7G3zLVj7CddLolX8Bm/hr68fiyNL3MyG2k4FwF9B5Z5GTpVLhw2EELYNwyoYBvFlR4gGnQPdw==",
"dev": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/@jazzer.js/bug-detectors": { "node_modules/@jazzer.js/bug-detectors": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/@jazzer.js/bug-detectors/-/bug-detectors-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@jazzer.js/bug-detectors/-/bug-detectors-2.1.0.tgz",
@ -9954,19 +9925,6 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"dev": true,
"dependencies": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/liftoff": { "node_modules/liftoff": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
@ -13347,6 +13305,7 @@
}, },
"node_modules/npm/node_modules/lodash._baseindexof": { "node_modules/npm/node_modules/lodash._baseindexof": {
"version": "3.1.0", "version": "3.1.0",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -13362,16 +13321,19 @@
}, },
"node_modules/npm/node_modules/lodash._bindcallback": { "node_modules/npm/node_modules/lodash._bindcallback": {
"version": "3.0.1", "version": "3.0.1",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/npm/node_modules/lodash._cacheindexof": { "node_modules/npm/node_modules/lodash._cacheindexof": {
"version": "3.0.2", "version": "3.0.2",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/npm/node_modules/lodash._createcache": { "node_modules/npm/node_modules/lodash._createcache": {
"version": "3.1.2", "version": "3.1.2",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -13386,6 +13348,7 @@
}, },
"node_modules/npm/node_modules/lodash._getnative": { "node_modules/npm/node_modules/lodash._getnative": {
"version": "3.9.1", "version": "3.9.1",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -13403,6 +13366,7 @@
}, },
"node_modules/npm/node_modules/lodash.restparam": { "node_modules/npm/node_modules/lodash.restparam": {
"version": "3.6.1", "version": "3.6.1",
"dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
@ -15878,23 +15842,6 @@
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=",
"dev": true "dev": true
}, },
"node_modules/optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"dev": true,
"dependencies": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/ordered-read-streams": { "node_modules/ordered-read-streams": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
@ -16665,15 +16612,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true,
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
@ -19913,18 +19851,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"dev": true,
"dependencies": {
"prelude-ls": "~1.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/type-fest": { "node_modules/type-fest": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
@ -20997,15 +20923,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/word-wrap": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/wordwrap": { "node_modules/wordwrap": {
"version": "0.0.2", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",

View File

@ -7,9 +7,7 @@
"@babel/runtime": "^7.23.8", "@babel/runtime": "^7.23.8",
"@fluent/bundle": "^0.18.0", "@fluent/bundle": "^0.18.0",
"@fluent/dom": "^0.9.0", "@fluent/dom": "^0.9.0",
"@javascript-obfuscator/escodegen": "2.3.0",
"@jazzer.js/core": "^2.1.0", "@jazzer.js/core": "^2.1.0",
"acorn": "^8.11.3",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",