mirror of https://github.com/webpack/webpack.git
fix edge case in scope analysis
fix double declaration problem in variable declarations remove TrackingSet rename StackedSetMap to StackedMap and remove add method add more scope analysis test
This commit is contained in:
parent
acc7c3e1ea
commit
ec518945f1
|
|
@ -9,19 +9,21 @@ const { Parser } = require("acorn");
|
|||
const { SyncBailHook, HookMap } = require("tapable");
|
||||
const vm = require("vm");
|
||||
const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
||||
const StackedSetMap = require("./util/StackedSetMap");
|
||||
const StackedMap = require("./util/StackedMap");
|
||||
|
||||
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
||||
|
||||
const parser = Parser.extend(require("./parsing/importAwaitAcornPlugin"));
|
||||
|
||||
/**
|
||||
* @typedef {Object} VariableInfo
|
||||
* @property {string | true} freeName
|
||||
* @property {TagInfo} tagInfo
|
||||
*/
|
||||
class VariableInfo {
|
||||
constructor(declaredScope, freeName, tagInfo) {
|
||||
this.declaredScope = declaredScope;
|
||||
this.freeName = freeName;
|
||||
this.tagInfo = tagInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/** @typedef {string | true | VariableInfo} ExportedVariableInfo */
|
||||
/** @typedef {string | ScopeInfo | VariableInfo} ExportedVariableInfo */
|
||||
|
||||
/**
|
||||
* @typedef {Object} TagInfo
|
||||
|
|
@ -32,7 +34,7 @@ const parser = Parser.extend(require("./parsing/importAwaitAcornPlugin"));
|
|||
|
||||
/**
|
||||
* @typedef {Object} ScopeInfo
|
||||
* @property {StackedSetMap<string, VariableInfo | true>} definitions
|
||||
* @property {StackedMap<string, VariableInfo | ScopeInfo>} definitions
|
||||
* @property {boolean | "arrow"} topLevelScope
|
||||
* @property {boolean} inShorthand
|
||||
* @property {boolean} isStrict
|
||||
|
|
@ -2132,16 +2134,16 @@ class JavascriptParser {
|
|||
* @returns {any} resut of hook
|
||||
*/
|
||||
callHooksForInfoWithFallback(hookMap, info, fallback, defined, ...args) {
|
||||
if (info === true) {
|
||||
if (defined !== undefined) {
|
||||
return defined();
|
||||
}
|
||||
return;
|
||||
}
|
||||
let name;
|
||||
if (typeof info === "string") {
|
||||
name = info;
|
||||
} else {
|
||||
if (!(info instanceof VariableInfo)) {
|
||||
if (defined !== undefined) {
|
||||
return defined();
|
||||
}
|
||||
return;
|
||||
}
|
||||
let tagInfo = info.tagInfo;
|
||||
while (tagInfo !== undefined) {
|
||||
const hook = hookMap.get(tagInfo.tag);
|
||||
|
|
@ -2474,7 +2476,7 @@ class JavascriptParser {
|
|||
inTry: false,
|
||||
inShorthand: false,
|
||||
isStrict: false,
|
||||
definitions: new StackedSetMap()
|
||||
definitions: new StackedMap()
|
||||
};
|
||||
const state = (this.state = initialState || {});
|
||||
this.comments = comments;
|
||||
|
|
@ -2529,7 +2531,7 @@ class JavascriptParser {
|
|||
|
||||
getTagData(name, tag) {
|
||||
const info = this.scope.definitions.get(name);
|
||||
if (typeof info === "object") {
|
||||
if (info instanceof VariableInfo) {
|
||||
let tagInfo = info.tagInfo;
|
||||
while (tagInfo !== undefined) {
|
||||
if (tagInfo.tag === tag) return tagInfo.data;
|
||||
|
|
@ -2543,38 +2545,33 @@ class JavascriptParser {
|
|||
/** @type {VariableInfo} */
|
||||
let newInfo;
|
||||
if (oldInfo === undefined) {
|
||||
newInfo = {
|
||||
freeName: name,
|
||||
tagInfo: {
|
||||
tag,
|
||||
data,
|
||||
next: undefined
|
||||
}
|
||||
};
|
||||
} else if (oldInfo === true) {
|
||||
newInfo = {
|
||||
freeName: true,
|
||||
tagInfo: {
|
||||
tag,
|
||||
data,
|
||||
next: undefined
|
||||
}
|
||||
};
|
||||
newInfo = new VariableInfo(this.scope, name, {
|
||||
tag,
|
||||
data,
|
||||
next: undefined
|
||||
});
|
||||
} else if (oldInfo instanceof VariableInfo) {
|
||||
newInfo = new VariableInfo(oldInfo.declaredScope, oldInfo.freeName, {
|
||||
tag,
|
||||
data,
|
||||
next: oldInfo.tagInfo
|
||||
});
|
||||
} else {
|
||||
newInfo = {
|
||||
freeName: oldInfo.freeName,
|
||||
tagInfo: {
|
||||
tag,
|
||||
data,
|
||||
next: oldInfo.tagInfo
|
||||
}
|
||||
};
|
||||
newInfo = new VariableInfo(oldInfo, true, {
|
||||
tag,
|
||||
data,
|
||||
next: undefined
|
||||
});
|
||||
}
|
||||
this.scope.definitions.set(name, newInfo);
|
||||
}
|
||||
|
||||
defineVariable(name) {
|
||||
this.scope.definitions.set(name, true);
|
||||
const oldInfo = this.scope.definitions.get(name);
|
||||
// Don't redefine variable in same scope to keep existing tags
|
||||
if (oldInfo instanceof VariableInfo && oldInfo.declaredScope === this.scope)
|
||||
return;
|
||||
this.scope.definitions.set(name, this.scope);
|
||||
}
|
||||
|
||||
undefineVariable(name) {
|
||||
|
|
@ -2589,8 +2586,6 @@ class JavascriptParser {
|
|||
const value = this.scope.definitions.get(name);
|
||||
if (value === undefined) {
|
||||
return name;
|
||||
} else if (value === true) {
|
||||
return true;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
|
@ -2606,10 +2601,10 @@ class JavascriptParser {
|
|||
if (variableInfo === name) {
|
||||
this.scope.definitions.delete(name);
|
||||
} else {
|
||||
this.scope.definitions.set(name, {
|
||||
freeName: variableInfo,
|
||||
tagInfo: undefined
|
||||
});
|
||||
this.scope.definitions.set(
|
||||
name,
|
||||
new VariableInfo(this.scope, variableInfo, undefined)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.scope.definitions.set(name, variableInfo);
|
||||
|
|
@ -2664,14 +2659,14 @@ class JavascriptParser {
|
|||
return undefined;
|
||||
}
|
||||
const rootInfo = this.getVariableInfo(rootName);
|
||||
/** @type {string | true} */
|
||||
/** @type {string | ScopeInfo} */
|
||||
let resolvedRoot;
|
||||
if (typeof rootInfo === "object") {
|
||||
if (rootInfo instanceof VariableInfo) {
|
||||
resolvedRoot = rootInfo.freeName;
|
||||
} else {
|
||||
resolvedRoot = rootInfo;
|
||||
}
|
||||
if (resolvedRoot === true) {
|
||||
if (typeof resolvedRoot !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
let name = resolvedRoot;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,20 @@ const topLevelSymbolTag = Symbol("top level symbol");
|
|||
|
||||
/** @typedef {Map<TopLevelSymbol | Dependency, Set<string | TopLevelSymbol> | true>} InnerGraph */
|
||||
|
||||
const isPure = expr => {
|
||||
switch (expr.type) {
|
||||
case "Identifier":
|
||||
return true;
|
||||
case "Literal":
|
||||
return true;
|
||||
case "ConditionalExpression":
|
||||
return (
|
||||
isPure(expr.test) && isPure(expr.consequent) && isPure(expr.alternate)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
class TopLevelSymbol {
|
||||
/**
|
||||
* @param {string} name name of the function
|
||||
|
|
@ -65,7 +79,7 @@ class InnerGraphPlugin {
|
|||
parser.state.harmonyAllExportDependentDependencies = new Set();
|
||||
});
|
||||
|
||||
parser.hooks.finish.tap("HarmonyImportDependencyParserPlugin", () => {
|
||||
parser.hooks.finish.tap("InnerGraphPlugin", () => {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
if (!innerGraph) return;
|
||||
|
|
@ -158,14 +172,26 @@ class InnerGraphPlugin {
|
|||
) {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
parser.defineVariable("*default*");
|
||||
const fn = new TopLevelSymbol("*default*", innerGraph);
|
||||
parser.tagVariable("*default*", topLevelSymbolTag, fn);
|
||||
const name = "*default*";
|
||||
parser.defineVariable(name);
|
||||
const fn = new TopLevelSymbol(name, innerGraph);
|
||||
parser.tagVariable(name, topLevelSymbolTag, fn);
|
||||
statementWithTopLevelSymbol.set(statement, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const tagVar = name => {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
parser.defineVariable(name);
|
||||
const existingTag = parser.getTagData(name, topLevelSymbolTag);
|
||||
const fn = existingTag || new TopLevelSymbol(name, innerGraph);
|
||||
if (!existingTag) {
|
||||
parser.tagVariable(name, topLevelSymbolTag, fn);
|
||||
}
|
||||
return fn;
|
||||
};
|
||||
/** @type {WeakMap<{}, TopLevelSymbol>} */
|
||||
const declWithTopLevelSymbol = new WeakMap();
|
||||
parser.hooks.preDeclarator.tap(
|
||||
|
|
@ -181,30 +207,26 @@ class InnerGraphPlugin {
|
|||
decl.init.type === "ArrowFunctionExpression" ||
|
||||
decl.init.type === "ClassExpression"
|
||||
) {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
parser.defineVariable(decl.id.name);
|
||||
const fn = new TopLevelSymbol(decl.id.name, innerGraph);
|
||||
parser.tagVariable(decl.id.name, topLevelSymbolTag, fn);
|
||||
const name = decl.id.name;
|
||||
const fn = tagVar(name);
|
||||
declWithTopLevelSymbol.set(decl, fn);
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
decl.init.range[0] - decl.id.range[1] > 9 &&
|
||||
parser
|
||||
.getComments([decl.id.range[1], decl.init.range[0]])
|
||||
.some(
|
||||
comment =>
|
||||
comment.type === "Block" &&
|
||||
/^\s*(#|@)__PURE__\s*$/.test(comment.value)
|
||||
)
|
||||
(decl.init.range[0] - decl.id.range[1] > 9 &&
|
||||
parser
|
||||
.getComments([decl.id.range[1], decl.init.range[0]])
|
||||
.some(
|
||||
comment =>
|
||||
comment.type === "Block" &&
|
||||
/^\s*(#|@)__PURE__\s*$/.test(comment.value)
|
||||
)) ||
|
||||
isPure(decl.init)
|
||||
) {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const name = decl.id.name;
|
||||
parser.defineVariable(name);
|
||||
const fn = new TopLevelSymbol(name, innerGraph);
|
||||
parser.tagVariable(name, topLevelSymbolTag, fn);
|
||||
const fn = tagVar(name);
|
||||
declWithTopLevelSymbol.set(decl, fn);
|
||||
const dep = new PureExpressionDependency(decl.init.range);
|
||||
dep.loc = decl.loc;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibi
|
|||
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
||||
const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency");
|
||||
const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency");
|
||||
const StackedSetMap = require("../util/StackedSetMap");
|
||||
const StackedMap = require("../util/StackedMap");
|
||||
const ConcatenatedModule = require("./ConcatenatedModule");
|
||||
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
|
@ -487,21 +487,21 @@ class ConcatConfiguration {
|
|||
constructor(rootModule, cloneFrom) {
|
||||
this.rootModule = rootModule;
|
||||
if (cloneFrom) {
|
||||
/** @type {StackedSetMap} */
|
||||
/** @type {StackedMap<Module, true>} */
|
||||
this.modules = cloneFrom.modules.createChild();
|
||||
/** @type {StackedSetMap} */
|
||||
/** @type {StackedMap<Module, Module>} */
|
||||
this.warnings = cloneFrom.warnings.createChild();
|
||||
} else {
|
||||
/** @type {StackedSetMap} */
|
||||
this.modules = new StackedSetMap();
|
||||
this.modules.add(rootModule);
|
||||
/** @type {StackedSetMap} */
|
||||
this.warnings = new StackedSetMap();
|
||||
/** @type {StackedMap<Module, true>} */
|
||||
this.modules = new StackedMap();
|
||||
this.modules.set(rootModule, true);
|
||||
/** @type {StackedMap<Module, Module>} */
|
||||
this.warnings = new StackedMap();
|
||||
}
|
||||
}
|
||||
|
||||
add(module) {
|
||||
this.modules.add(module);
|
||||
this.modules.set(module, true);
|
||||
}
|
||||
|
||||
has(module) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const TOMBSTONE = Symbol("tombstone");
|
||||
const UNDEFINED_MARKER = Symbol("undefined");
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {T | undefined} Cell<T>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {T | typeof TOMBSTONE | typeof UNDEFINED_MARKER} InternalCell<T>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template K
|
||||
* @template V
|
||||
* @param {[K, InternalCell<V>]} pair the internal cell
|
||||
* @returns {[K, Cell<V>]} its “safe” representation
|
||||
*/
|
||||
const extractPair = pair => {
|
||||
const key = pair[0];
|
||||
const val = pair[1];
|
||||
if (val === UNDEFINED_MARKER || val === TOMBSTONE) {
|
||||
return [key, undefined];
|
||||
} else {
|
||||
return /** @type {[K, Cell<V>]} */ (pair);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @template K
|
||||
* @template V
|
||||
*/
|
||||
class StackedMap {
|
||||
/**
|
||||
* @param {Map<K, InternalCell<V>>[]=} parentStack an optional parent
|
||||
*/
|
||||
constructor(parentStack) {
|
||||
/** @type {Map<K, InternalCell<V>>} */
|
||||
this.map = new Map();
|
||||
/** @type {Map<K, InternalCell<V>>[]} */
|
||||
this.stack = parentStack === undefined ? [] : parentStack.slice();
|
||||
this.stack.push(this.map);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the key of the element to add
|
||||
* @param {V} value the value of the element to add
|
||||
* @returns {void}
|
||||
*/
|
||||
set(item, value) {
|
||||
this.map.set(item, value === undefined ? UNDEFINED_MARKER : value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the item to delete
|
||||
* @returns {void}
|
||||
*/
|
||||
delete(item) {
|
||||
if (this.stack.length > 1) {
|
||||
this.map.set(item, TOMBSTONE);
|
||||
} else {
|
||||
this.map.delete(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the item to test
|
||||
* @returns {boolean} true if the item exists in this set
|
||||
*/
|
||||
has(item) {
|
||||
const topValue = this.map.get(item);
|
||||
if (topValue !== undefined) {
|
||||
return topValue !== TOMBSTONE;
|
||||
}
|
||||
if (this.stack.length > 1) {
|
||||
for (let i = this.stack.length - 2; i >= 0; i--) {
|
||||
const value = this.stack[i].get(item);
|
||||
if (value !== undefined) {
|
||||
this.map.set(item, value);
|
||||
return value !== TOMBSTONE;
|
||||
}
|
||||
}
|
||||
this.map.set(item, TOMBSTONE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the key of the element to return
|
||||
* @returns {Cell<V>} the value of the element
|
||||
*/
|
||||
get(item) {
|
||||
const topValue = this.map.get(item);
|
||||
if (topValue !== undefined) {
|
||||
return topValue === TOMBSTONE || topValue === UNDEFINED_MARKER
|
||||
? undefined
|
||||
: topValue;
|
||||
}
|
||||
if (this.stack.length > 1) {
|
||||
for (let i = this.stack.length - 2; i >= 0; i--) {
|
||||
const value = this.stack[i].get(item);
|
||||
if (value !== undefined) {
|
||||
this.map.set(item, value);
|
||||
return value === TOMBSTONE || value === UNDEFINED_MARKER
|
||||
? undefined
|
||||
: value;
|
||||
}
|
||||
}
|
||||
this.map.set(item, TOMBSTONE);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
_compress() {
|
||||
if (this.stack.length === 1) return;
|
||||
this.map = new Map();
|
||||
for (const data of this.stack) {
|
||||
for (const pair of data) {
|
||||
if (pair[1] === TOMBSTONE) {
|
||||
this.map.delete(pair[0]);
|
||||
} else {
|
||||
this.map.set(pair[0], pair[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.stack = [this.map];
|
||||
}
|
||||
|
||||
asArray() {
|
||||
this._compress();
|
||||
return Array.from(this.map.keys());
|
||||
}
|
||||
|
||||
asSet() {
|
||||
this._compress();
|
||||
return new Set(this.map.keys());
|
||||
}
|
||||
|
||||
asPairArray() {
|
||||
this._compress();
|
||||
return Array.from(this.map.entries(), extractPair);
|
||||
}
|
||||
|
||||
asMap() {
|
||||
return new Map(this.asPairArray());
|
||||
}
|
||||
|
||||
get size() {
|
||||
this._compress();
|
||||
return this.map.size;
|
||||
}
|
||||
|
||||
createChild() {
|
||||
return new StackedMap(this.stack);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StackedMap;
|
||||
|
|
@ -10,12 +10,12 @@ const UNDEFINED_MARKER = Symbol("undefined");
|
|||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {T | true | undefined} Cell<T>
|
||||
* @typedef {T | undefined} Cell<T>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {T | true | typeof TOMBSTONE | typeof UNDEFINED_MARKER} InternalCell<T>
|
||||
* @typedef {T | typeof TOMBSTONE | typeof UNDEFINED_MARKER} InternalCell<T>
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +38,7 @@ const extractPair = pair => {
|
|||
* @template K
|
||||
* @template V
|
||||
*/
|
||||
class StackedSetMap {
|
||||
class StackedMap {
|
||||
/**
|
||||
* @param {Map<K, InternalCell<V>>[]=} parentStack an optional parent
|
||||
*/
|
||||
|
|
@ -50,14 +50,6 @@ class StackedSetMap {
|
|||
this.stack.push(this.map);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the item to add
|
||||
* @returns {void}
|
||||
*/
|
||||
add(item) {
|
||||
this.map.set(item, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} item the key of the element to add
|
||||
* @param {V} value the value of the element to add
|
||||
|
|
@ -167,8 +159,8 @@ class StackedSetMap {
|
|||
}
|
||||
|
||||
createChild() {
|
||||
return new StackedSetMap(this.stack);
|
||||
return new StackedMap(this.stack);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StackedSetMap;
|
||||
module.exports = StackedMap;
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template U
|
||||
* @typedef {import("./StackedSetMap")<T,U>} StackedSetMap<T,U>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template U
|
||||
*/
|
||||
class TrackingSet {
|
||||
/**
|
||||
* @param {StackedSetMap<T,U>} set the set to track
|
||||
*/
|
||||
constructor(set) {
|
||||
/** @type {StackedSetMap<T,U>} */
|
||||
this.set = set;
|
||||
/** @type {Set<T>} */
|
||||
this.set2 = new Set();
|
||||
this.stack = set.stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item the item to add
|
||||
* @returns {void}
|
||||
*/
|
||||
add(item) {
|
||||
this.set2.add(item);
|
||||
this.set.add(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item the item to delete
|
||||
* @returns {void}
|
||||
*/
|
||||
delete(item) {
|
||||
this.set2.delete(item);
|
||||
this.set.delete(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item the item to test
|
||||
* @returns {boolean} true if the item exists in this set
|
||||
*/
|
||||
has(item) {
|
||||
return this.set.has(item);
|
||||
}
|
||||
|
||||
createChild() {
|
||||
return this.set.createChild();
|
||||
}
|
||||
|
||||
getAddedItems() {
|
||||
return this.set2;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TrackingSet;
|
||||
|
|
@ -635,26 +635,26 @@ Entrypoint entry-1 = vendor-1.js entry-1.js
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for commons-plugin-issue-4980 1`] = `
|
||||
"Hash: 4de9d58c5e07bace3a862cc016e810ab8d72814f
|
||||
"Hash: e8a1307ea3c8604531519325cea6a11512fc55f7
|
||||
Child
|
||||
Hash: 4de9d58c5e07bace3a86
|
||||
Hash: e8a1307ea3c860453151
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
app.20e7d920f7a5dd7ba86a.js 6.72 KiB {143} [emitted] app
|
||||
vendor.44602d2bdfb280718742.js 606 bytes {736} [emitted] vendor
|
||||
Entrypoint app = vendor.44602d2bdfb280718742.js app.20e7d920f7a5dd7ba86a.js
|
||||
vendor.3ca106870164d059e3b7.js 606 bytes {736} [emitted] vendor
|
||||
Entrypoint app = vendor.3ca106870164d059e3b7.js app.20e7d920f7a5dd7ba86a.js
|
||||
[117] ./entry-1.js + 2 modules 190 bytes {143} [built]
|
||||
[381] ./constants.js 87 bytes {736} [built]
|
||||
+ 4 hidden modules
|
||||
Child
|
||||
Hash: 2cc016e810ab8d72814f
|
||||
Hash: 9325cea6a11512fc55f7
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
app.9ff34c93a677586ea3e1.js 6.74 KiB {143} [emitted] app
|
||||
vendor.44602d2bdfb280718742.js 606 bytes {736} [emitted] vendor
|
||||
Entrypoint app = vendor.44602d2bdfb280718742.js app.9ff34c93a677586ea3e1.js
|
||||
vendor.3ca106870164d059e3b7.js 606 bytes {736} [emitted] vendor
|
||||
Entrypoint app = vendor.3ca106870164d059e3b7.js app.9ff34c93a677586ea3e1.js
|
||||
[381] ./constants.js 87 bytes {736} [built]
|
||||
[655] ./entry-2.js + 2 modules 197 bytes {143} [built]
|
||||
+ 4 hidden modules"
|
||||
|
|
@ -1103,7 +1103,7 @@ chunk {trees} trees.js (trees) 71 bytes [rendered]
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for import-context-filter 1`] = `
|
||||
"Hash: ad66943c56c470a291e2
|
||||
"Hash: 10cc1554ce1aa0fa0104
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
|
|
@ -1525,11 +1525,11 @@ If you don't want to include a polyfill, you can use an empty module like this:
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for module-reasons 1`] = `
|
||||
"Hash: d467214b226e6b223582
|
||||
"Hash: 7c9265c9403a708454f8
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
main.js 2.8 KiB {179} [emitted] main
|
||||
Asset Size Chunks Chunk Names
|
||||
main.js 2.89 KiB {179} [emitted] main
|
||||
Entrypoint main = main.js
|
||||
[237] ./index.js + 2 modules 102 bytes {179} [built]
|
||||
entry ./index main
|
||||
|
|
@ -2467,7 +2467,7 @@ Entrypoint e2 = runtime.js e2.js"
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for scope-hoisting-bailouts 1`] = `
|
||||
"Hash: 8d50ea5a3930d4e325f5
|
||||
"Hash: f517daabbf7f98de61bd
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Entrypoint index = index.js
|
||||
|
|
@ -2593,7 +2593,7 @@ Entrypoint main = main.js
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for side-effects-simple-unused 1`] = `
|
||||
"Hash: 0dd96a6d2b50b602067c
|
||||
"Hash: d07e55dc2ba899045482
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
|
|
@ -3625,11 +3625,11 @@ chunk {794} default/async-a.js (async-a) 134 bytes <{179}> [rendered]
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for tree-shaking 1`] = `
|
||||
"Hash: d1c58bcd9027a12fc6a5
|
||||
"Hash: 394ab56fdb998a8398e6
|
||||
Time: Xms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
Asset Size Chunks Chunk Names
|
||||
bundle.js 7.78 KiB {179} [emitted] main
|
||||
bundle.js 7.86 KiB {179} [emitted] main
|
||||
Entrypoint main = bundle.js
|
||||
[10] ./index.js 315 bytes {179} [built]
|
||||
[no exports]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
import { A, B, C1, C2, D1, D2, E1, E2, E3, F, G } from "./test";
|
||||
|
||||
export { a, b, c, d, e };
|
||||
|
||||
if (Math.random() > 0.5) {
|
||||
var a = () => A;
|
||||
let b = () => B;
|
||||
}
|
||||
|
||||
let b;
|
||||
|
||||
var c = () => C1;
|
||||
couldCallExportC();
|
||||
var c = () => C2;
|
||||
couldCallExportC();
|
||||
|
||||
while (Math.random() > 0.5) {
|
||||
let d = () => D1;
|
||||
}
|
||||
|
||||
while (Math.random() > 0.5) {
|
||||
var d = () => D2;
|
||||
}
|
||||
|
||||
while (Math.random() > 0.5) {
|
||||
let d = () => D1;
|
||||
}
|
||||
|
||||
if(false) {
|
||||
E1();
|
||||
}
|
||||
|
||||
export var e = true ? E2 : E3;
|
||||
|
||||
export { f, g }
|
||||
|
||||
if(true) {
|
||||
let inner = () => F;
|
||||
|
||||
var f = () => inner();
|
||||
}
|
||||
|
||||
if(true) {
|
||||
const inner = () => G;
|
||||
|
||||
var g = () => inner();
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
const createTestCases = require("../_helpers/createTestCases");
|
||||
module.exports = createTestCases({
|
||||
nothing: {
|
||||
usedExports: [],
|
||||
expect: {
|
||||
"./test": []
|
||||
}
|
||||
},
|
||||
a: {
|
||||
usedExports: ["a"],
|
||||
expect: {
|
||||
"./test": ["A"]
|
||||
}
|
||||
},
|
||||
b: {
|
||||
usedExports: ["b"],
|
||||
expect: {
|
||||
"./test": []
|
||||
}
|
||||
},
|
||||
c: {
|
||||
usedExports: ["c"],
|
||||
expect: {
|
||||
"./test": ["C1", "C2"]
|
||||
}
|
||||
},
|
||||
d: {
|
||||
usedExports: ["d"],
|
||||
expect: {
|
||||
"./test": ["D2"]
|
||||
}
|
||||
},
|
||||
e: {
|
||||
usedExports: ["e"],
|
||||
expect: {
|
||||
"./test": ["E2"]
|
||||
}
|
||||
},
|
||||
f: {
|
||||
usedExports: ["f"],
|
||||
expect: {
|
||||
"./test": ["F"]
|
||||
}
|
||||
},
|
||||
g: {
|
||||
usedExports: ["g"],
|
||||
expect: {
|
||||
"./test": ["G"]
|
||||
}
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue