Merge pull request #11999 from webpack/bugfix/11990

fixes unused export bug
This commit is contained in:
Tobias Koppers 2020-11-16 16:52:23 +01:00 committed by GitHub
commit 5f686b6d6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 107 additions and 5 deletions

View File

@ -1211,25 +1211,27 @@ class ExportInfo {
* @param {ModuleGraph} moduleGraph the module graph
* @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
* @param {Set<ExportInfo> | undefined} alreadyVisited set of already visited export info to avoid circular references
* @returns {{ module: Module, export: string[] | undefined } | CIRCULAR | undefined} the target
* @returns {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined } | CIRCULAR | undefined} the target
*/
_getTarget(moduleGraph, resolveTargetFilter, alreadyVisited) {
/**
* @param {{ connection: ModuleGraphConnection, export: string[] | undefined } | null} inputTarget unresolved target
* @param {Set<ExportInfo>} alreadyVisited set of already visited export info to avoid circular references
* @returns {{ module: Module, export: string[] | undefined } | CIRCULAR | null} resolved target
* @returns {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined } | CIRCULAR | null} resolved target
*/
const resolveTarget = (inputTarget, alreadyVisited) => {
if (!inputTarget) return null;
if (!inputTarget.export) {
return {
module: inputTarget.connection.module,
connection: inputTarget.connection,
export: undefined
};
}
/** @type {{ module: Module, export: string[] | undefined }} */
/** @type {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined }} */
let target = {
module: inputTarget.connection.module,
connection: inputTarget.connection,
export: inputTarget.export
};
if (!resolveTargetFilter(target)) return target;
@ -1252,6 +1254,7 @@ class ExportInfo {
} else {
target = {
module: newTarget.module,
connection: newTarget.connection,
export: newTarget.export
? newTarget.export.concat(target.export.slice(1))
: target.export.slice(1)
@ -1290,6 +1293,24 @@ class ExportInfo {
return target;
}
/**
* Move the target forward as long resolveTargetFilter is fulfilled
* @param {ModuleGraph} moduleGraph the module graph
* @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
* @returns {{ module: Module, export: string[] | undefined } | undefined} the target
*/
moveTarget(moduleGraph, resolveTargetFilter) {
const target = this._getTarget(moduleGraph, resolveTargetFilter, undefined);
if (target === CIRCULAR) return undefined;
if (!target) return undefined;
this._target.clear();
this._target.set(undefined, {
connection: target.connection,
export: target.export
});
return target;
}
createNestedExportsInfo() {
if (this.exportsInfoOwned) return this.exportsInfo;
this.exportsInfoOwned = true;

View File

@ -232,16 +232,31 @@ class SideEffectsFlagPlugin {
module
)) {
const dep = connection.dependency;
let isReexport;
if (
dep instanceof HarmonyExportImportedSpecifierDependency ||
(isReexport =
dep instanceof HarmonyExportImportedSpecifierDependency) ||
(dep instanceof HarmonyImportSpecifierDependency &&
!dep.namespaceObjectAsContext)
) {
// TODO improve for export *
if (isReexport && dep.name) {
const exportInfo = moduleGraph.getExportInfo(
connection.originModule,
dep.name
);
exportInfo.moveTarget(
moduleGraph,
({ module }) =>
module.getSideEffectsConnectionState(moduleGraph) ===
false
);
}
// TODO improve for nested imports
const ids = dep.getIds(moduleGraph);
if (ids.length > 0) {
const exportInfo = exportsInfo.getExportInfo(ids[0]);
const target = exportInfo.getTarget(
const target = exportInfo.moveTarget(
moduleGraph,
({ module }) =>
module.getSideEffectsConnectionState(moduleGraph) ===

View File

@ -0,0 +1,2 @@
import { value3 } from "./reexport";
expect(value3).toBe(42);

View File

@ -0,0 +1,2 @@
import { value2 } from "./module";
expect(value2).toBe(42);

View File

@ -0,0 +1,9 @@
import { value, value3 } from "./reexport";
it("should generate working code", () => {
expect(value).toBe(42);
expect(value3).toBe(42);
});
it("should run the chunk1", () => import("./chunk1"));
it("should run the chunk2", () => import("./chunk2"));

View File

@ -0,0 +1 @@
export default 42;

View File

@ -0,0 +1,2 @@
export const value = 42;
export const value2 = 42;

View File

@ -0,0 +1,5 @@
{
"sideEffects": [
"./reexport.js"
]
}

View File

@ -0,0 +1 @@
export default 42;

View File

@ -0,0 +1,4 @@
export * from "./reexport2";
import { value4 } from "./reexport2";
import v from "./reexport-concat";
export const value3 = v + value4 - value4;

View File

@ -0,0 +1,3 @@
export * from "./module";
export const value4 = 42;
module.id;

View File

@ -0,0 +1,2 @@
import { value3 } from "./reexport";
expect(value3).toBe(42);

View File

@ -0,0 +1,2 @@
import { value2 } from "./module";
expect(value2).toBe(42);

View File

@ -0,0 +1,9 @@
import { value, value3 } from "./reexport";
it("should generate working code", () => {
expect(value).toBe(42);
expect(value3).toBe(42);
});
it("should run the chunk1", () => import("./chunk1"));
it("should run the chunk2", () => import("./chunk2"));

View File

@ -0,0 +1 @@
export default 42;

View File

@ -0,0 +1,2 @@
export const value = 42;
export const value2 = 42;

View File

@ -0,0 +1,5 @@
{
"sideEffects": [
"./reexport.js"
]
}

View File

@ -0,0 +1 @@
export default 42;

View File

@ -0,0 +1,4 @@
export { value } from "./reexport2";
import { value4 } from "./reexport2";
import v from "./reexport-concat";
export const value3 = v + value4 - value4;

View File

@ -0,0 +1,3 @@
export { value } from "./module";
export const value4 = 42;
module.id;

8
types.d.ts vendored
View File

@ -3030,6 +3030,14 @@ declare abstract class ExportInfo {
export: string[];
}) => boolean
): { module: Module; export: string[] };
/**
* Move the target forward as long resolveTargetFilter is fulfilled
*/
moveTarget(
moduleGraph: ModuleGraph,
resolveTargetFilter: (arg0: { module: Module; export: string[] }) => boolean
): { module: Module; export: string[] };
createNestedExportsInfo(): ExportsInfo;
getNestedExportsInfo(): ExportsInfo;
updateHash(hash?: any, runtime?: any): void;