124 lines
3.1 KiB
JavaScript
124 lines
3.1 KiB
JavaScript
/*
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
Author Tobias Koppers @sokra
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const { UsageState } = require("../ModuleGraph");
|
|
const { numberToIdentifier } = require("../Template");
|
|
const { assignDeterministicIds } = require("../ids/IdHelpers");
|
|
const {
|
|
concatComparators,
|
|
compareSelect,
|
|
compareStringsNumeric
|
|
} = require("../util/comparators");
|
|
|
|
/** @typedef {import("../Compiler")} Compiler */
|
|
/** @typedef {import("../ModuleGraph").ExportsInfo} ExportsInfo */
|
|
|
|
const OBJECT = [];
|
|
const ARRAY = [];
|
|
|
|
/**
|
|
* @param {ExportsInfo} exportsInfo exports info
|
|
* @param {boolean} canBeArray can be exports info point to an array
|
|
* @returns {boolean} mangle is possible
|
|
*/
|
|
const canMangle = (exportsInfo, canBeArray) => {
|
|
if (exportsInfo.otherExportsInfo.used !== UsageState.Unused) return false;
|
|
let hasSomethingToMangle = false;
|
|
const empty = canBeArray ? ARRAY : OBJECT;
|
|
for (const exportInfo of exportsInfo.exports) {
|
|
if (exportInfo.name in empty) {
|
|
return false;
|
|
}
|
|
if (exportInfo.canMangle === true) {
|
|
hasSomethingToMangle = true;
|
|
}
|
|
}
|
|
return hasSomethingToMangle;
|
|
};
|
|
|
|
const comparator = concatComparators(
|
|
// Sort used before unused fields
|
|
compareSelect(
|
|
e => e.used !== false,
|
|
(a, b) => (a === b ? 0 : a ? -1 : 1)
|
|
),
|
|
// Sort by name
|
|
compareSelect(e => e.name, compareStringsNumeric)
|
|
);
|
|
|
|
/**
|
|
* @param {ExportsInfo} exportsInfo exports info
|
|
* @param {boolean} canBeArray can be exports info point to an array
|
|
* @returns {void}
|
|
*/
|
|
const mangleExportsInfo = (exportsInfo, canBeArray) => {
|
|
if (!canMangle(exportsInfo, canBeArray)) return;
|
|
const usedNames = new Set();
|
|
const mangleableExports = [];
|
|
// Don't rename 1-2 char exports or exports that can't be mangled
|
|
for (const exportInfo of exportsInfo.ownedExports) {
|
|
const name = exportInfo.name;
|
|
if (typeof exportInfo.usedName !== "string") {
|
|
if (
|
|
exportInfo.canMangle !== true ||
|
|
(name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) ||
|
|
(name.length === 2 && /^[a-zA-Z_$][a-zA-Z0-9_$]|^[1-9][0-9]/.test(name))
|
|
) {
|
|
exportInfo.usedName = name;
|
|
usedNames.add(name);
|
|
} else {
|
|
mangleableExports.push(exportInfo);
|
|
}
|
|
}
|
|
if (
|
|
exportInfo.exportsInfoOwned &&
|
|
exportInfo.used === UsageState.OnlyPropertiesUsed
|
|
) {
|
|
mangleExportsInfo(exportInfo.exportsInfo, true);
|
|
}
|
|
}
|
|
assignDeterministicIds(
|
|
mangleableExports,
|
|
e => e.name,
|
|
comparator,
|
|
(e, id) => {
|
|
const name = numberToIdentifier(id);
|
|
const size = usedNames.size;
|
|
usedNames.add(name);
|
|
if (size === usedNames.size) return false;
|
|
e.usedName = name;
|
|
return true;
|
|
},
|
|
[26, 52],
|
|
52,
|
|
usedNames.size
|
|
);
|
|
};
|
|
|
|
class MangleExportsPlugin {
|
|
/**
|
|
* @param {Compiler} compiler webpack compiler
|
|
* @returns {void}
|
|
*/
|
|
apply(compiler) {
|
|
compiler.hooks.compilation.tap("MangleExportsPlugin", compilation => {
|
|
const moduleGraph = compilation.moduleGraph;
|
|
compilation.hooks.optimizeCodeGeneration.tap(
|
|
"MangleExportsPlugin",
|
|
modules => {
|
|
for (const module of modules) {
|
|
const exportsInfo = moduleGraph.getExportsInfo(module);
|
|
mangleExportsInfo(exportsInfo, false);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = MangleExportsPlugin;
|