Skip to content

Commit 406e14f

Browse files
authored
feat: static analyze destructuring assignment dynamic import variable for tree shaking (#11731)
1 parent 43cbda7 commit 406e14f

File tree

25 files changed

+181
-134
lines changed

25 files changed

+181
-134
lines changed

crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rspack_core::{
66
TemplateContext, TemplateReplaceSource,
77
};
88
use rspack_error::Diagnostic;
9+
use swc_core::atoms::Atom;
910

1011
use super::{
1112
context_dependency_template_as_require_call, create_resource_identifier_for_context_dependency,
@@ -15,7 +16,7 @@ use super::{
1516
#[derive(Debug, Clone)]
1617
pub struct ImportContextDependency {
1718
id: DependencyId,
18-
pub options: ContextOptions,
19+
options: ContextOptions,
1920
range: DependencyRange,
2021
value_range: DependencyRange,
2122
resource_identifier: String,
@@ -43,6 +44,10 @@ impl ImportContextDependency {
4344
factorize_info: Default::default(),
4445
}
4546
}
47+
48+
pub fn set_referenced_exports(&mut self, referenced_exports: Vec<Vec<Atom>>) {
49+
self.options.referenced_exports = Some(referenced_exports);
50+
}
4651
}
4752

4853
#[cacheable_dyn]

crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ pub fn create_import_dependency_referenced_exports(
6363
pub struct ImportDependency {
6464
id: DependencyId,
6565
#[cacheable(with=AsPreset)]
66-
pub request: Atom,
66+
request: Atom,
6767
pub range: DependencyRange,
6868
#[cacheable(with=AsOption<AsVec<AsVec<AsPreset>>>)]
69-
pub referenced_exports: Option<Vec<Vec<Atom>>>,
70-
pub attributes: Option<ImportAttributes>,
69+
referenced_exports: Option<Vec<Vec<Atom>>>,
70+
attributes: Option<ImportAttributes>,
7171
pub comments: Vec<(bool, String)>,
72-
pub resource_identifier: String,
73-
pub factorize_info: FactorizeInfo,
74-
pub optional: bool,
72+
resource_identifier: String,
73+
factorize_info: FactorizeInfo,
74+
optional: bool,
7575
}
7676

7777
impl ImportDependency {
@@ -97,6 +97,10 @@ impl ImportDependency {
9797
comments,
9898
}
9999
}
100+
101+
pub fn set_referenced_exports(&mut self, referenced_exports: Vec<Vec<Atom>>) {
102+
self.referenced_exports = Some(referenced_exports);
103+
}
100104
}
101105

102106
#[cacheable_dyn]

crates/rspack_plugin_javascript/src/dependency/esm/import_eager_dependency.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub struct ImportEagerDependency {
2323
request: Atom,
2424
range: DependencyRange,
2525
#[cacheable(with=AsOption<AsVec<AsVec<AsPreset>>>)]
26-
pub referenced_exports: Option<Vec<Vec<Atom>>>,
26+
referenced_exports: Option<Vec<Vec<Atom>>>,
2727
attributes: Option<ImportAttributes>,
2828
resource_identifier: String,
2929
factorize_info: FactorizeInfo,
@@ -48,6 +48,10 @@ impl ImportEagerDependency {
4848
factorize_info: Default::default(),
4949
}
5050
}
51+
52+
pub fn set_referenced_exports(&mut self, referenced_exports: Vec<Vec<Atom>>) {
53+
self.referenced_exports = Some(referenced_exports);
54+
}
5155
}
5256

5357
#[cacheable_dyn]

crates/rspack_plugin_javascript/src/parser_plugin/define_plugin/utils.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ pub fn gen_const_dep(
4444
}
4545
}
4646

47-
pub fn code_to_string(
48-
code: &Value,
47+
pub fn code_to_string<'a>(
48+
code: &'a Value,
4949
asi_safe: Option<bool>,
50-
obj_keys: Option<FxHashSet<DestructuringAssignmentProperty>>,
51-
) -> Cow<'_, str> {
50+
obj_keys: Option<&FxHashSet<DestructuringAssignmentProperty>>,
51+
) -> Cow<'a, str> {
5252
fn wrap_ansi(code: Cow<str>, is_arr: bool, asi_safe: Option<bool>) -> Cow<str> {
5353
match asi_safe {
5454
Some(true) if is_arr => code,
@@ -75,10 +75,7 @@ pub fn code_to_string(
7575
let elements = obj
7676
.iter()
7777
.filter_map(|(key, value)| {
78-
if obj_keys
79-
.as_ref()
80-
.is_none_or(|keys| keys.iter().any(|prop| prop.id.as_str() == key))
81-
{
78+
if obj_keys.is_none_or(|keys| keys.iter().any(|prop| prop.id.as_str() == key)) {
8279
Some(format!(
8380
"{}:{}",
8481
json!(key),

crates/rspack_plugin_javascript/src/parser_plugin/define_plugin/walk_data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ impl WalkData {
368368
let code = code_to_string(
369369
&record.object,
370370
Some(!parser.is_asi_position(span.lo)),
371-
parser.destructuring_assignment_properties_for(&span),
371+
parser.destructuring_assignment_properties.get(&span),
372372
);
373373
parser.add_presentational_dependency(Box::new(gen_const_dep(
374374
parser, code, for_name, start, end,

crates/rspack_plugin_javascript/src/parser_plugin/esm_import_dependency_parser_plugin.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ impl JavascriptParserPlugin for ESMImportDependencyParserPlugin {
178178
.definitions_db
179179
.expect_get_tag_info(parser.current_tag_info?);
180180
let settings = ESMSpecifierData::downcast(tag_info.data.clone()?);
181-
let referenced_properties_in_destructuring =
182-
parser.destructuring_assignment_properties_for(&ident.span());
181+
let referenced_properties_in_destructuring = parser
182+
.destructuring_assignment_properties
183+
.get(&ident.span())
184+
.cloned();
183185
let dep = ESMImportSpecifierDependency::new(
184186
settings.source,
185187
settings.name,
@@ -309,8 +311,10 @@ impl JavascriptParserPlugin for ESMImportDependencyParserPlugin {
309311
};
310312
let mut ids = settings.ids;
311313
ids.extend(non_optional_members.iter().cloned());
312-
let referenced_properties_in_destructuring =
313-
parser.destructuring_assignment_properties_for(&member_expr.span());
314+
let referenced_properties_in_destructuring = parser
315+
.destructuring_assignment_properties
316+
.get(&member_expr.span())
317+
.cloned();
314318
let dep = ESMImportSpecifierDependency::new(
315319
settings.source,
316320
settings.name,

crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl JavascriptParserPlugin for ImportMetaPlugin {
167167
) -> Option<bool> {
168168
if root_name == expr_name::IMPORT_META {
169169
if let Some(referenced_properties_in_destructuring) =
170-
parser.destructuring_assignment_properties_for(&span)
170+
parser.destructuring_assignment_properties.get(&span)
171171
{
172172
let mut content = vec![];
173173
for prop in referenced_properties_in_destructuring {

crates/rspack_plugin_javascript/src/parser_plugin/import_parser_plugin.rs

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ use crate::{
2222
dependency::{ImportContextDependency, ImportDependency, ImportEagerDependency},
2323
utils::object_properties::{get_attributes, get_value_by_obj_prop},
2424
visitors::{
25-
ContextModuleScanResult, JavascriptParser, Statement, TagInfoData, TopLevelScope,
26-
VariableDeclaration, context_reg_exp, create_context_dependency, create_traceable_error,
27-
get_non_optional_part, parse_order_string,
25+
AllowedMemberTypes, ContextModuleScanResult, ExportedVariableInfo, JavascriptParser,
26+
MemberExpressionInfo, Statement, TagInfoData, TopLevelScope, VariableDeclaration,
27+
context_reg_exp, create_context_dependency, create_traceable_error, get_non_optional_part,
28+
parse_order_string,
2829
},
2930
webpack_comment::try_extract_webpack_magic_comment,
3031
};
@@ -55,30 +56,26 @@ impl ImportsReferencesState {
5556
self.inner.insert(import, ImportReferences::default());
5657
}
5758

58-
pub fn add_import_reference(&mut self, import: Span, reference: Vec<Atom>) {
59-
let references = self
60-
.inner
61-
.get_mut(&import)
62-
.expect("should add_import before");
63-
references.references.push(reference);
59+
fn get_import(&self, import: &Span) -> Option<&ImportReferences> {
60+
self.inner.get(import)
61+
}
62+
63+
fn get_import_mut(&mut self, import: &Span) -> Option<&mut ImportReferences> {
64+
self.inner.get_mut(import)
65+
}
66+
67+
fn get_import_mut_expect(&mut self, import: &Span) -> &mut ImportReferences {
68+
self.get_import_mut(import).expect("should get import")
6469
}
6570

66-
fn take_import_references(
71+
fn take_all_import_references(
6772
&mut self,
6873
) -> impl Iterator<Item = (ImportDependencyLocator, Vec<Vec<Atom>>)> + use<> {
6974
let inner = std::mem::take(&mut self.inner);
7075
inner
7176
.into_values()
7277
.filter_map(|value| value.dep_locator.map(|locator| (locator, value.references)))
7378
}
74-
75-
fn get_import(&self, import: &Span) -> Option<&ImportReferences> {
76-
self.inner.get(import)
77-
}
78-
79-
fn get_import_mut(&mut self, import: &Span) -> Option<&mut ImportReferences> {
80-
self.inner.get_mut(import)
81-
}
8279
}
8380

8481
#[derive(Debug, Default)]
@@ -87,6 +84,12 @@ struct ImportReferences {
8784
references: Vec<Vec<Atom>>,
8885
}
8986

87+
impl ImportReferences {
88+
pub fn add_reference(&mut self, reference: Vec<Atom>) {
89+
self.references.push(reference);
90+
}
91+
}
92+
9093
#[derive(Debug, PartialEq, Eq, Hash)]
9194
struct ImportDependencyLocator {
9295
block_idx: Option<usize>,
@@ -104,14 +107,24 @@ pub struct ImportParserPlugin;
104107
impl JavascriptParserPlugin for ImportParserPlugin {
105108
fn can_collect_destructuring_assignment_properties(
106109
&self,
107-
_parser: &mut JavascriptParser,
110+
parser: &mut JavascriptParser,
108111
expr: &Expr,
109112
) -> Option<bool> {
110113
if let Some(call) = expr.as_call()
111114
&& call.callee.is_import()
112115
{
113116
return Some(true);
114117
}
118+
if let MemberExpressionInfo::Expression(info) =
119+
parser.get_member_expression_info_from_expr(expr, AllowedMemberTypes::Expression)?
120+
&& let ExportedVariableInfo::VariableInfo(id) = &info.root_info
121+
&& let Some(name) = &parser.definitions_db.expect_get_variable(*id).name
122+
&& parser
123+
.get_tag_data(&name.clone(), DYNAMIC_IMPORT_TAG)
124+
.is_some()
125+
{
126+
return Some(true);
127+
}
115128
None
116129
}
117130

@@ -135,7 +148,7 @@ impl JavascriptParserPlugin for ImportParserPlugin {
135148
fn identifier(
136149
&self,
137150
parser: &mut JavascriptParser,
138-
_ident: &Ident,
151+
ident: &Ident,
139152
for_name: &str,
140153
) -> Option<bool> {
141154
if for_name != DYNAMIC_IMPORT_TAG {
@@ -145,9 +158,22 @@ impl JavascriptParserPlugin for ImportParserPlugin {
145158
.definitions_db
146159
.expect_get_tag_info(parser.current_tag_info?);
147160
let data = ImportTagData::downcast(tag_info.data.clone()?);
148-
parser
149-
.dynamic_import_references
150-
.add_import_reference(data.import_span, vec![]);
161+
if let Some(keys) = parser
162+
.destructuring_assignment_properties
163+
.get(&ident.span())
164+
{
165+
for key in keys {
166+
parser
167+
.dynamic_import_references
168+
.get_import_mut_expect(&data.import_span)
169+
.add_reference(vec![key.id.clone()]);
170+
}
171+
} else {
172+
parser
173+
.dynamic_import_references
174+
.get_import_mut_expect(&data.import_span)
175+
.add_reference(vec![]);
176+
}
151177
Some(true)
152178
}
153179

@@ -170,7 +196,8 @@ impl JavascriptParserPlugin for ImportParserPlugin {
170196
let ids = get_non_optional_part(members, members_optionals);
171197
parser
172198
.dynamic_import_references
173-
.add_import_reference(data.import_span, ids.to_vec());
199+
.get_import_mut_expect(&data.import_span)
200+
.add_reference(ids.to_vec());
174201
Some(true)
175202
}
176203

@@ -198,7 +225,8 @@ impl JavascriptParserPlugin for ImportParserPlugin {
198225
}
199226
parser
200227
.dynamic_import_references
201-
.add_import_reference(data.import_span, ids.to_vec());
228+
.get_import_mut_expect(&data.import_span)
229+
.add_reference(ids.to_vec());
202230
parser.walk_expr_or_spread(&expr.args);
203231
Some(true)
204232
}
@@ -263,8 +291,10 @@ impl JavascriptParserPlugin for ImportParserPlugin {
263291
.collect::<Vec<_>>()
264292
});
265293

266-
let referenced_in_destructuring =
267-
parser.destructuring_assignment_properties_for(&import_call_span);
294+
let referenced_in_destructuring = parser
295+
.destructuring_assignment_properties
296+
.get(&import_call_span)
297+
.cloned();
268298
let referenced_in_member = parser
269299
.dynamic_import_references
270300
.get_import(&import_call_span);
@@ -421,7 +451,10 @@ impl JavascriptParserPlugin for ImportParserPlugin {
421451
}
422452

423453
fn finish(&self, parser: &mut JavascriptParser) -> Option<bool> {
424-
for (locator, references) in parser.dynamic_import_references.take_import_references() {
454+
for (locator, references) in parser
455+
.dynamic_import_references
456+
.take_all_import_references()
457+
{
425458
let dep = if let Some(block_idx) = locator.block_idx
426459
&& let Some(block) = parser.get_block_mut(block_idx)
427460
{
@@ -437,19 +470,19 @@ impl JavascriptParserPlugin for ImportParserPlugin {
437470
let dep = dep
438471
.downcast_mut::<ImportDependency>()
439472
.expect("Failed to downcast to ImportDependency");
440-
dep.referenced_exports = Some(references);
473+
dep.set_referenced_exports(references);
441474
}
442475
DependencyType::DynamicImportEager => {
443476
let dep = dep
444477
.downcast_mut::<ImportEagerDependency>()
445478
.expect("Failed to downcast to ImportEagerDependency");
446-
dep.referenced_exports = Some(references);
479+
dep.set_referenced_exports(references);
447480
}
448481
DependencyType::ImportContext => {
449482
let dep = dep
450483
.downcast_mut::<ImportContextDependency>()
451484
.expect("Failed to downcast to ImportContextDependency");
452-
dep.options.referenced_exports = Some(references);
485+
dep.set_referenced_exports(references);
453486
}
454487
_ => unreachable!(),
455488
};
@@ -530,10 +563,11 @@ fn walk_import_then_fulfilled_callback(
530563
parser
531564
.dynamic_import_references
532565
.add_import(import_call.span());
566+
let import_references = parser
567+
.dynamic_import_references
568+
.get_import_mut_expect(&import_call.span());
533569
for key in keys {
534-
parser
535-
.dynamic_import_references
536-
.add_import_reference(import_call.span(), vec![key.id.clone()]);
570+
import_references.add_reference(vec![key.id.clone()]);
537571
}
538572
}
539573
} else {

0 commit comments

Comments
 (0)