Merge pull request #14291 from webpack/feature/eval-bailouzt

avoid bailout of unused eval
This commit is contained in:
Tobias Koppers 2021-09-24 10:13:05 +02:00 committed by GitHub
commit aa83e463c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 185 additions and 5 deletions

View File

@ -28,7 +28,12 @@ class JavascriptMetaInfoPlugin {
parser.hooks.call.for("eval").tap("JavascriptMetaInfoPlugin", () => {
parser.state.module.buildInfo.moduleConcatenationBailout = "eval()";
parser.state.module.buildInfo.usingEval = true;
InnerGraph.bailout(parser.state);
const currentSymbol = InnerGraph.getTopLevelSymbol(parser.state);
if (currentSymbol) {
InnerGraph.addUsage(parser.state, null, currentSymbol);
} else {
InnerGraph.bailout(parser.state);
}
});
parser.hooks.finish.tap("JavascriptMetaInfoPlugin", () => {
let topLevelDeclarations =

View File

@ -394,6 +394,9 @@ module.exports = mergeExports(fn, {
"DEP_WEBPACK_AGGRESSIVE_SPLITTING_PLUGIN"
)();
},
get InnerGraph() {
return require("./optimize/InnerGraph");
},
get LimitChunkCountPlugin() {
return require("./optimize/LimitChunkCountPlugin");
},
@ -535,6 +538,9 @@ module.exports = mergeExports(fn, {
get comparators() {
return require("./util/comparators");
},
get runtime() {
return require("./util/runtime");
},
get serialization() {
return require("./util/serialization");
},

View File

@ -16,7 +16,7 @@ const { UsageState } = require("../ExportsInfo");
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
/** @typedef {Map<TopLevelSymbol, Set<string | TopLevelSymbol> | true>} InnerGraph */
/** @typedef {Map<TopLevelSymbol | null, Set<string | TopLevelSymbol> | true>} InnerGraph */
/** @typedef {function(boolean | Set<string> | undefined): void} UsageCallback */
/**
@ -75,7 +75,7 @@ exports.isEnabled = parserState => {
/**
* @param {ParserState} state parser state
* @param {TopLevelSymbol} symbol the symbol
* @param {TopLevelSymbol | null} symbol the symbol, or null for all symbols
* @param {string | TopLevelSymbol | true} usage usage data
* @returns {void}
*/
@ -172,6 +172,26 @@ exports.inferDependencyUsage = state => {
}
if (isTerminal) {
nonTerminal.delete(key);
// For the global key, merge with all other keys
if (key === null) {
const globalValue = innerGraph.get(null);
if (globalValue) {
for (const [key, value] of innerGraph) {
if (key !== null && value !== true) {
if (globalValue === true) {
innerGraph.set(key, true);
} else {
const newSet = new Set(value);
for (const item of globalValue) {
newSet.add(item);
}
innerGraph.set(key, newSet);
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,15 @@
import { a, b, c } from "./test";
export function x() {
a();
}
export function y() {
b();
eval("x()");
}
export function z() {
c();
y();
}

View File

@ -0,0 +1,27 @@
const createTestCases = require("../_helpers/createTestCases");
module.exports = createTestCases({
nothing: {
usedExports: [],
expect: {
"./test": []
}
},
nonEval: {
usedExports: ["x"],
expect: {
"./test": ["a"]
}
},
directEval: {
usedExports: ["y"],
expect: {
"./test": ["a", "b", "c"]
}
},
indirectEval: {
usedExports: ["z"],
expect: {
"./test": ["a", "b", "c"]
}
}
});

111
types.d.ts vendored
View File

@ -9783,6 +9783,7 @@ declare class RuntimeChunkPlugin {
*/
apply(compiler: Compiler): void;
}
type RuntimeCondition = undefined | string | boolean | SortableSet<string>;
declare class RuntimeModule extends Module {
constructor(name: string, stage?: number);
name: string;
@ -9829,7 +9830,8 @@ declare interface RuntimeRequirementsContext {
codeGenerationResults: CodeGenerationResults;
}
type RuntimeSpec = undefined | string | SortableSet<string>;
declare abstract class RuntimeSpecMap<T> {
declare class RuntimeSpecMap<T> {
constructor(clone?: RuntimeSpecMap<T>);
get(runtime: RuntimeSpec): T;
has(runtime: RuntimeSpec): boolean;
set(runtime?: any, value?: any): void;
@ -9840,7 +9842,8 @@ declare abstract class RuntimeSpecMap<T> {
values(): IterableIterator<T>;
readonly size?: number;
}
declare abstract class RuntimeSpecSet {
declare class RuntimeSpecSet {
constructor(iterable?: any);
add(runtime?: any): void;
has(runtime?: any): boolean;
[Symbol.iterator](): IterableIterator<RuntimeSpec>;
@ -11299,6 +11302,10 @@ declare interface TimestampAndHash {
timestamp?: number;
hash: string;
}
declare class TopLevelSymbol {
constructor(name: string);
name: string;
}
/**
* Use a Trusted Types policy to create urls for chunks.
@ -12155,6 +12162,52 @@ declare namespace exports {
};
}
export namespace optimize {
export namespace InnerGraph {
export let bailout: (parserState: ParserState) => void;
export let enable: (parserState: ParserState) => void;
export let isEnabled: (parserState: ParserState) => boolean;
export let addUsage: (
state: ParserState,
symbol: null | TopLevelSymbol,
usage: string | true | TopLevelSymbol
) => void;
export let addVariableUsage: (
parser: JavascriptParser,
name: string,
usage: string | true | TopLevelSymbol
) => void;
export let inferDependencyUsage: (state: ParserState) => void;
export let onUsage: (
state: ParserState,
onUsageCallback: (arg0?: boolean | Set<string>) => void
) => void;
export let setTopLevelSymbol: (
state: ParserState,
symbol: TopLevelSymbol
) => void;
export let getTopLevelSymbol: (
state: ParserState
) => void | TopLevelSymbol;
export let tagTopLevelSymbol: (
parser: JavascriptParser,
name: string
) => TopLevelSymbol;
export let isDependencyUsedByExports: (
dependency: Dependency,
usedByExports: boolean | Set<string>,
moduleGraph: ModuleGraph,
runtime: RuntimeSpec
) => boolean;
export let getDependencyUsedByExportsCondition: (
dependency: Dependency,
usedByExports: boolean | Set<string>,
moduleGraph: ModuleGraph
) =>
| null
| false
| ((arg0: ModuleGraphConnection, arg1: RuntimeSpec) => ConnectionState);
export { TopLevelSymbol, topLevelSymbolTag };
}
export {
AggressiveMergingPlugin,
AggressiveSplittingPlugin,
@ -12280,6 +12333,59 @@ declare namespace exports {
b: DependencyLocation
) => 0 | 1 | -1;
}
export namespace runtime {
export let getEntryRuntime: (
compilation: Compilation,
name: string,
options?: EntryOptions
) => RuntimeSpec;
export let forEachRuntime: (
runtime: RuntimeSpec,
fn: (arg0: string) => void,
deterministicOrder?: boolean
) => void;
export let getRuntimeKey: (runtime: RuntimeSpec) => string;
export let keyToRuntime: (key: string) => RuntimeSpec;
export let runtimeToString: (runtime: RuntimeSpec) => string;
export let runtimeConditionToString: (
runtimeCondition: RuntimeCondition
) => string;
export let runtimeEqual: (a: RuntimeSpec, b: RuntimeSpec) => boolean;
export let compareRuntime: (a: RuntimeSpec, b: RuntimeSpec) => 0 | 1 | -1;
export let mergeRuntime: (a: RuntimeSpec, b: RuntimeSpec) => RuntimeSpec;
export let mergeRuntimeCondition: (
a: RuntimeCondition,
b: RuntimeCondition,
runtime: RuntimeSpec
) => RuntimeCondition;
export let mergeRuntimeConditionNonFalse: (
a: undefined | string | true | SortableSet<string>,
b: undefined | string | true | SortableSet<string>,
runtime: RuntimeSpec
) => undefined | string | true | SortableSet<string>;
export let mergeRuntimeOwned: (
a: RuntimeSpec,
b: RuntimeSpec
) => RuntimeSpec;
export let intersectRuntime: (
a: RuntimeSpec,
b: RuntimeSpec
) => RuntimeSpec;
export let subtractRuntime: (
a: RuntimeSpec,
b: RuntimeSpec
) => RuntimeSpec;
export let subtractRuntimeCondition: (
a: RuntimeCondition,
b: RuntimeCondition,
runtime: RuntimeSpec
) => RuntimeCondition;
export let filterRuntime: (
runtime: RuntimeSpec,
filter: (arg0: RuntimeSpec) => boolean
) => undefined | string | boolean | SortableSet<string>;
export { RuntimeSpecMap, RuntimeSpecSet };
}
export namespace serialization {
export const register: (
Constructor: Constructor,
@ -12425,5 +12531,6 @@ declare namespace exports {
LoaderContext
};
}
declare const topLevelSymbolTag: unique symbol;
export = exports;