mirror of https://github.com/webpack/webpack.git
feat: static analyze destructuring assignment dynamic import variable for tree shaking (#19925)
This commit is contained in:
parent
ae52500e95
commit
73cecf5e78
|
@ -8,7 +8,10 @@
|
|||
const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
|
||||
const CommentCompilationWarning = require("../CommentCompilationWarning");
|
||||
const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
|
||||
const { getImportAttributes } = require("../javascript/JavascriptParser");
|
||||
const {
|
||||
VariableInfo,
|
||||
getImportAttributes
|
||||
} = require("../javascript/JavascriptParser");
|
||||
const ContextDependencyHelpers = require("./ContextDependencyHelpers");
|
||||
const ImportContextDependency = require("./ImportContextDependency");
|
||||
const ImportDependency = require("./ImportDependency");
|
||||
|
@ -184,6 +187,15 @@ class ImportParserPlugin {
|
|||
PLUGIN_NAME,
|
||||
(expr) => {
|
||||
if (expr.type === "ImportExpression") return true;
|
||||
const nameInfo = parser.getNameForExpression(expr);
|
||||
if (
|
||||
nameInfo &&
|
||||
nameInfo.rootInfo instanceof VariableInfo &&
|
||||
nameInfo.rootInfo.name &&
|
||||
parser.getTagData(nameInfo.rootInfo.name, dynamicImportTag)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
parser.hooks.preDeclarator.tap(PLUGIN_NAME, (decl) => {
|
||||
|
@ -196,9 +208,19 @@ class ImportParserPlugin {
|
|||
tagDynamicImportReferenced(parser, decl.init.argument, decl.id.name);
|
||||
}
|
||||
});
|
||||
parser.hooks.expression.for(dynamicImportTag).tap(PLUGIN_NAME, () => {
|
||||
parser.hooks.expression.for(dynamicImportTag).tap(PLUGIN_NAME, (expr) => {
|
||||
const settings = /** @type {ImportSettings} */ (parser.currentTagData);
|
||||
const referencedPropertiesInDestructuring =
|
||||
parser.destructuringAssignmentPropertiesFor(expr);
|
||||
if (referencedPropertiesInDestructuring) {
|
||||
for (const ids of exportsFromEnumerable(
|
||||
[...referencedPropertiesInDestructuring].map(({ id }) => id)
|
||||
)) {
|
||||
settings.references.push(ids);
|
||||
}
|
||||
} else {
|
||||
settings.references.push([]);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
parser.hooks.expressionMemberChain
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
export const a = 1;
|
||||
export default 3;
|
||||
export const usedExports = __webpack_exports_info__.usedExports;
|
|
@ -1,2 +0,0 @@
|
|||
exports.a = 1;
|
||||
exports.b = 2;
|
|
@ -1 +0,0 @@
|
|||
["a"]
|
|
@ -1 +0,0 @@
|
|||
{"a": 1}
|
|
@ -1 +0,0 @@
|
|||
"a"
|
|
@ -1,2 +0,0 @@
|
|||
exports.a = 1;
|
||||
exports.b = 2;
|
|
@ -1 +0,0 @@
|
|||
["a"]
|
|
@ -1 +0,0 @@
|
|||
{"a": 1}
|
|
@ -1 +0,0 @@
|
|||
"a"
|
|
@ -1,36 +0,0 @@
|
|||
it("should load only used exports", async (done) => {
|
||||
const { default: def, usedExports } = await import("./dir1/a");
|
||||
expect(def).toBe(3);
|
||||
expect(usedExports).toEqual(["default", "usedExports"]);
|
||||
done();
|
||||
});
|
||||
|
||||
it("should get warning on using 'webpackExports' with destructuring assignment", async (done) => {
|
||||
const { default: def } = await import(/* webpackExports: ["a"] */"./dir1/a?2");
|
||||
expect(def).toBe(3);
|
||||
done();
|
||||
});
|
||||
|
||||
it("should not tree-shake default export for exportsType=default module", async () => {
|
||||
const { default: object } = await import("./dir2/json/object.json");
|
||||
const { default: array } = await import("./dir2/json/array.json");
|
||||
const { default: primitive } = await import("./dir2/json/primitive.json");
|
||||
expect(object).toEqual({ a: 1 });
|
||||
expect(array).toEqual(["a"]);
|
||||
expect(primitive).toBe("a");
|
||||
const { default: a } = await import("./dir2/a");
|
||||
expect(a).toEqual({ a: 1, b: 2 });
|
||||
});
|
||||
|
||||
it("should not tree-shake default export for exportsType=default context module", async () => {
|
||||
const dir = "json";
|
||||
const { default: object } = await import(`./dir3/${dir}/object.json`);
|
||||
const { default: array } = await import(`./dir3/${dir}/array.json`);
|
||||
const { default: primitive } = await import(`./dir3/${dir}/primitive.json`);
|
||||
expect(object).toEqual({ a: 1 });
|
||||
expect(array).toEqual(["a"]);
|
||||
expect(primitive).toBe("a");
|
||||
const file = "a";
|
||||
const { default: a } = await import(`./dir3/${file}`);
|
||||
expect(a).toEqual({ a: 1, b: 2 });
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
it("should load only used exports", async (done) => {
|
||||
const { default: def, usedExports } = await import("../statical-dynamic-import/dir1/a");
|
||||
expect(def).toBe(3);
|
||||
expect(usedExports).toEqual(["default", "usedExports"]);
|
||||
done();
|
||||
});
|
||||
|
||||
it("should get warning on using 'webpackExports' with destructuring assignment", async (done) => {
|
||||
const { default: def } = await import(/* webpackExports: ["a"] */"../statical-dynamic-import/dir1/a?2");
|
||||
expect(def).toBe(3);
|
||||
done();
|
||||
});
|
||||
|
||||
it("should not tree-shake default export for exportsType=default module", async () => {
|
||||
const { default: object } = await import("../statical-dynamic-import/dir2/json/object.json");
|
||||
const { default: array } = await import("../statical-dynamic-import/dir2/json/array.json");
|
||||
const { default: primitive } = await import("../statical-dynamic-import/dir2/json/primitive.json");
|
||||
expect(object).toEqual({ a: 1 });
|
||||
expect(array).toEqual(["a"]);
|
||||
expect(primitive).toBe("a");
|
||||
const { default: a } = await import("../statical-dynamic-import/dir2/a");
|
||||
expect(a).toEqual({ a: 1, b: 2 });
|
||||
});
|
||||
|
||||
it("should not tree-shake default export for exportsType=default context module", async () => {
|
||||
const dir = "json";
|
||||
const { default: object } = await import(`../statical-dynamic-import/dir3/${dir}/object.json`);
|
||||
const { default: array } = await import(`../statical-dynamic-import/dir3/${dir}/array.json`);
|
||||
const { default: primitive } = await import(`../statical-dynamic-import/dir3/${dir}/primitive.json`);
|
||||
expect(object).toEqual({ a: 1 });
|
||||
expect(array).toEqual(["a"]);
|
||||
expect(primitive).toBe("a");
|
||||
const file = "a";
|
||||
const { default: a } = await import(`../statical-dynamic-import/dir3/${file}`);
|
||||
expect(a).toEqual({ a: 1, b: 2 });
|
||||
});
|
||||
|
||||
it("should static analyze dynamic import variable destructuring assignment", async () => {
|
||||
const m = await import("../statical-dynamic-import/dir1/a?3");
|
||||
const { default: def, usedExports } = m;
|
||||
expect(def).toBe(3);
|
||||
expect(usedExports).toEqual(["default", "usedExports"]);
|
||||
});
|
|
@ -53,12 +53,20 @@ it("should walk with correct order", async () => {
|
|||
});
|
||||
|
||||
it("should analyze arguments in call member chain", async () => {
|
||||
import("../statical-dynamic-import/dir4/lib?2").then(({ b }) => {
|
||||
await import("../statical-dynamic-import/dir4/lib?2").then(({ b }) => {
|
||||
b.f((async () => {
|
||||
import("../statical-dynamic-import/dir4/a?2").then(({ a, usedExports }) => {
|
||||
await import("../statical-dynamic-import/dir4/a?2").then(({ a, usedExports }) => {
|
||||
expect(a).toBe(1);
|
||||
expect(usedExports).toEqual(["a", "usedExports"]);
|
||||
});
|
||||
})());
|
||||
});
|
||||
});
|
||||
|
||||
it("should static analyze dynamic import variable destructuring assignment", async () => {
|
||||
await import("../statical-dynamic-import/dir1/a?3").then(m => {
|
||||
const { default: def, usedExports } = m;
|
||||
expect(def).toBe(3);
|
||||
expect(usedExports).toEqual(["default", "usedExports"]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -73,9 +73,9 @@ it("should walk with correct order", async () => {
|
|||
});
|
||||
|
||||
it("should analyze arguments in call member chain", async () => {
|
||||
import("../statical-dynamic-import/dir4/lib?2").then(m => {
|
||||
await import("../statical-dynamic-import/dir4/lib?2").then(m => {
|
||||
m.b.f((async () => {
|
||||
import("../statical-dynamic-import/dir4/a?2").then(m2 => {
|
||||
await import("../statical-dynamic-import/dir4/a?2").then(m2 => {
|
||||
expect(m2.a).toBe(1);
|
||||
expect(m2.usedExports).toEqual(["a", "usedExports"]);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue