Skip to content

Commit d453d86

Browse files
authored
fix: inline value with properties access (#11508)
1 parent 82051df commit d453d86

File tree

13 files changed

+99
-61
lines changed

13 files changed

+99
-61
lines changed

crates/rspack_core/src/exports/exports_info_getter.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use super::{
99
ExportInfoData, ExportProvided, ExportsInfo, ProvidedExports, UsageState, UsedName, UsedNameItem,
1010
};
1111
use crate::{
12-
ExportsInfoData, MaybeDynamicTargetExportInfo, ModuleGraph, RuntimeSpec, UsageKey, UsedExports,
12+
ExportsInfoData, InlinedUsedName, MaybeDynamicTargetExportInfo, ModuleGraph, RuntimeSpec,
13+
UsageKey, UsedExports,
1314
};
1415

1516
#[derive(Debug, Clone)]
@@ -707,23 +708,14 @@ impl ExportsInfoGetter {
707708
}
708709
return Some(UsedName::Normal(vec![]));
709710
}
710-
if names.len() == 1 {
711-
let name = &names[0];
712-
let info = info.get_read_only_export_info(name);
713-
let used_name = info.get_used_name(Some(name), runtime);
714-
return used_name.map(|name| match name {
715-
UsedNameItem::Str(name) => UsedName::Normal(vec![name]),
716-
UsedNameItem::Inlined(inlined) => UsedName::Inlined(inlined),
717-
});
718-
}
719711
let export_info = info.get_read_only_export_info(&names[0]);
720712
let first = export_info.get_used_name(Some(&names[0]), runtime)?;
721713
let mut arr = match first {
722-
UsedNameItem::Inlined(inlined) => return Some(UsedName::Inlined(inlined)),
723-
UsedNameItem::Str(first) => vec![first],
714+
UsedNameItem::Str(first) => UsedName::Normal(vec![first]),
715+
UsedNameItem::Inlined(inlined) => UsedName::Inlined(InlinedUsedName::new(inlined)),
724716
};
725717
if names.len() == 1 {
726-
return Some(UsedName::Normal(arr));
718+
return Some(arr);
727719
}
728720
if let Some(exports_info) = &export_info.exports_info()
729721
&& export_info.get_used(runtime) == UsageState::OnlyPropertiesUsed
@@ -736,14 +728,14 @@ impl ExportsInfoGetter {
736728
&names[1..],
737729
)?;
738730
let nested = match nested {
739-
UsedName::Inlined(inlined) => return Some(UsedName::Inlined(inlined)),
731+
UsedName::Inlined(_) => return Some(nested),
740732
UsedName::Normal(names) => names,
741733
};
742-
arr.extend(nested);
743-
return Some(UsedName::Normal(arr));
734+
arr.append(nested);
735+
return Some(arr);
744736
}
745-
arr.extend(names.iter().skip(1).cloned());
746-
Some(UsedName::Normal(arr))
737+
arr.append(names.iter().skip(1).cloned());
738+
Some(arr)
747739
}
748740
}
749741
}

crates/rspack_core/src/exports/utils.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rspack_cacheable::{
88
use rspack_util::{atom::Atom, json_stringify, ryu_js};
99
use rustc_hash::FxHashSet as HashSet;
1010

11-
use crate::DependencyId;
11+
use crate::{DependencyId, property_access};
1212

1313
pub static NEXT_EXPORTS_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
1414
pub static NEXT_EXPORT_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
@@ -83,8 +83,8 @@ impl EvaluatedInlinableValue {
8383
Self::String(v)
8484
}
8585

86-
pub fn render(&self) -> Cow<'_, str> {
87-
match self {
86+
pub fn render(&self) -> String {
87+
let s: Cow<str> = match self {
8888
Self::Null => "null".into(),
8989
Self::Undefined => "undefined".into(),
9090
Self::Boolean(v) => if *v { "true" } else { "false" }.into(),
@@ -93,7 +93,8 @@ impl EvaluatedInlinableValue {
9393
buf.format(*v).to_string().into()
9494
}
9595
Self::String(v) => json_stringify(v.as_str()).into(),
96-
}
96+
};
97+
format!("({s})")
9798
}
9899
}
99100

@@ -117,21 +118,42 @@ pub enum UsedNameItem {
117118
Inlined(EvaluatedInlinableValue),
118119
}
119120

121+
#[derive(Debug, Clone)]
122+
pub struct InlinedUsedName {
123+
value: EvaluatedInlinableValue,
124+
suffix: Vec<Atom>,
125+
}
126+
127+
impl InlinedUsedName {
128+
pub fn new(value: EvaluatedInlinableValue) -> Self {
129+
Self {
130+
value,
131+
suffix: Vec::new(),
132+
}
133+
}
134+
135+
pub fn render(&self) -> String {
136+
let mut inlined = self.value.render();
137+
inlined.push_str(&property_access(&self.suffix, 0));
138+
inlined
139+
}
140+
}
141+
120142
#[derive(Debug, Clone)]
121143
pub enum UsedName {
122144
Normal(Vec<Atom>),
123-
Inlined(EvaluatedInlinableValue),
145+
Inlined(InlinedUsedName),
124146
}
125147

126148
impl UsedName {
127149
pub fn is_inlined(&self) -> bool {
128-
matches!(self, UsedName::Inlined(_))
150+
matches!(self, UsedName::Inlined { .. })
129151
}
130152

131-
pub fn inlined(&self) -> Option<&EvaluatedInlinableValue> {
153+
pub fn append(&mut self, item: impl IntoIterator<Item = Atom>) {
132154
match self {
133-
UsedName::Inlined(inlined) => Some(inlined),
134-
_ => None,
155+
UsedName::Normal(vec) => vec.extend(item),
156+
UsedName::Inlined(inlined) => inlined.suffix.extend(item),
135157
}
136158
}
137159
}

crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_self_reference_dependency.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl DependencyTemplate for CommonJsSelfReferenceDependencyTemplate {
195195
UsedName::Normal(used) => format!("{}{}", base, property_access(used, 0)),
196196
// Export a inlinable const from cjs is not possible for now, so self reference a inlinable
197197
// const is also not possible for now, but we compat it here
198-
UsedName::Inlined(inlined) => inlined.render().into_owned(),
198+
UsedName::Inlined(inlined) => inlined.render(),
199199
},
200200
None,
201201
)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ impl ESMExportImportedSpecifierDependency {
852852
ValueKey::Name => name,
853853
ValueKey::UsedName(used) => match used {
854854
UsedName::Normal(used) => format!("{}{}", name, property_access(used, 0)),
855-
UsedName::Inlined(inlined) => inlined.render().into_owned(),
855+
UsedName::Inlined(inlined) => inlined.render(),
856856
},
857857
}
858858
}

crates/rspack_plugin_library/src/module_library_plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ async fn render_startup(
113113
match used_name {
114114
UsedNameItem::Str(used_name) =>
115115
format!("__webpack_exports__{}", property_access(vec![used_name], 0)),
116-
UsedNameItem::Inlined(inlined) => inlined.render().into_owned(),
116+
UsedNameItem::Inlined(inlined) => inlined.render(),
117117
}
118118
)));
119119
}

packages/rspack-test-tools/tests/configCases/inline-const/basic/index.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ it("should inline constants", () => {
1818
expect(constants.REMOVE_m).toBe(13);
1919
// END:A
2020
const block = generated.match(/\/\/ START:A([\s\S]*)\/\/ END:A/)[1];
21-
expect(block.includes(`(/* inlined export .REMOVE_n */ null).toBe(null)`)).toBe(true);
22-
expect(block.includes(`(/* inlined export .REMOVE_u */ undefined).toBe(undefined)`)).toBe(true);
23-
expect(block.includes(`(/* inlined export .REMOVE_b */ true).toBe(true)`)).toBe(true);
24-
expect(block.includes(`(/* inlined export .REMOVE_i */ 123456).toBe(123456)`)).toBe(true);
25-
expect(block.includes(`(/* inlined export .REMOVE_f */ 123.45).toBe(123.45)`)).toBe(true);
26-
expect(block.includes(`(/* inlined export .REMOVE_s */ "remove").toBe("remove")`)).toBe(true);
27-
expect(block.includes(`(/* inlined export .REMOVE_m */ 13).toBe(13)`)).toBe(true);
21+
expect(block.includes(`(/* inlined export .REMOVE_n */ (null)).toBe(null)`)).toBe(true);
22+
expect(block.includes(`(/* inlined export .REMOVE_u */ (undefined)).toBe(undefined)`)).toBe(true);
23+
expect(block.includes(`(/* inlined export .REMOVE_b */ (true)).toBe(true)`)).toBe(true);
24+
expect(block.includes(`(/* inlined export .REMOVE_i */ (123456)).toBe(123456)`)).toBe(true);
25+
expect(block.includes(`(/* inlined export .REMOVE_f */ (123.45)).toBe(123.45)`)).toBe(true);
26+
expect(block.includes(`(/* inlined export .REMOVE_s */ ("remove")).toBe("remove")`)).toBe(true);
27+
expect(block.includes(`(/* inlined export .REMOVE_m */ (13)).toBe(13)`)).toBe(true);
2828
})
2929

3030
it("should inline constants with re-export", () => {
@@ -37,12 +37,12 @@ it("should inline constants with re-export", () => {
3737
expect(reexported.REMOVE_s).toBe("remove");
3838
// END:B
3939
const block = generated.match(/\/\/ START:B([\s\S]*)\/\/ END:B/)[1];
40-
expect(block.includes(`(/* inlined export .REMOVE_n */ null).toBe(null)`)).toBe(true);
41-
expect(block.includes(`(/* inlined export .REMOVE_u */ undefined).toBe(undefined)`)).toBe(true);
42-
expect(block.includes(`(/* inlined export .REMOVE_b */ true).toBe(true)`)).toBe(true);
43-
expect(block.includes(`(/* inlined export .REMOVE_i */ 123456).toBe(123456)`)).toBe(true);
44-
expect(block.includes(`(/* inlined export .REMOVE_f */ 123.45).toBe(123.45)`)).toBe(true);
45-
expect(block.includes(`(/* inlined export .REMOVE_s */ "remove").toBe("remove")`)).toBe(true);
40+
expect(block.includes(`(/* inlined export .REMOVE_n */ (null)).toBe(null)`)).toBe(true);
41+
expect(block.includes(`(/* inlined export .REMOVE_u */ (undefined)).toBe(undefined)`)).toBe(true);
42+
expect(block.includes(`(/* inlined export .REMOVE_b */ (true)).toBe(true)`)).toBe(true);
43+
expect(block.includes(`(/* inlined export .REMOVE_i */ (123456)).toBe(123456)`)).toBe(true);
44+
expect(block.includes(`(/* inlined export .REMOVE_f */ (123.45)).toBe(123.45)`)).toBe(true);
45+
expect(block.includes(`(/* inlined export .REMOVE_s */ ("remove")).toBe("remove")`)).toBe(true);
4646
})
4747

4848
it("should not inline constants with destructing", () => {
@@ -66,9 +66,9 @@ it("should allow inline constants if the rest exports is not used with destructi
6666
expect(destructing.REMOVE_s).toBe("remove");
6767
// END:D
6868
const block = generated.match(/\/\/ START:D([\s\S]*)\/\/ END:D/)[1];
69-
expect(block.includes(`(/* inlined export .REMOVE_i */ 123456).toBe(123456)`)).toBe(true);
70-
expect(block.includes(`(/* inlined export .REMOVE_f */ 123.45).toBe(123.45)`)).toBe(true);
71-
expect(block.includes(`(/* inlined export .REMOVE_s */ "remove").toBe("remove")`)).toBe(true);
69+
expect(block.includes(`(/* inlined export .REMOVE_i */ (123456)).toBe(123456)`)).toBe(true);
70+
expect(block.includes(`(/* inlined export .REMOVE_f */ (123.45)).toBe(123.45)`)).toBe(true);
71+
expect(block.includes(`(/* inlined export .REMOVE_s */ ("remove")).toBe("remove")`)).toBe(true);
7272
})
7373

7474
it("should respect side effects when inline constants", () => {
@@ -77,7 +77,7 @@ it("should respect side effects when inline constants", () => {
7777
expect(globalThis.__sideEffects).toBe("constants.side-effects.js");
7878
// END:E
7979
const block = generated.match(/\/\/ START:E([\s\S]*)\/\/ END:E/)[1];
80-
expect(block.includes(`(/* inlined export .REMOVE_CONST */ true).toBe(true)`)).toBe(true);
80+
expect(block.includes(`(/* inlined export .REMOVE_CONST */ (true)).toBe(true)`)).toBe(true);
8181
})
8282

8383
it("should not inline and link to re-export module when have side effects", () => {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as constants from "../basic/constants";
2+
3+
const generated = /** @type {string} */ (__non_webpack_require__("fs").readFileSync(__filename, "utf-8"));
4+
5+
it("should generate correct code for inline value with properties access", () => {
6+
// START:A
7+
expect(constants.REMOVE_s.toUpperCase()).toBe("REMOVE");
8+
expect(constants.REMOVE_b.valueOf().toString()).toBe("true");
9+
expect(constants.REMOVE_i["toFixed"](1)).toBe("123456.0");
10+
// END:A
11+
const block = generated.match(/\/\/ START:A([\s\S]*)\/\/ END:A/)[1];
12+
expect(block.includes(`/* inlined export .REMOVE_s.toUpperCase */ ("remove").toUpperCase()`)).toBe(true);
13+
expect(block.includes(`/* inlined export .REMOVE_b.valueOf */ (true).valueOf().toString()`)).toBe(true);
14+
expect(block.includes(`/* inlined export .REMOVE_i.toFixed */ (123456).toFixed(1)`)).toBe(true);
15+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** @type {import("@rspack/core").Configuration} */
2+
module.exports = {
3+
optimization: {
4+
moduleIds: "named"
5+
},
6+
experiments: {
7+
inlineConst: true
8+
}
9+
};

packages/rspack-test-tools/tests/configCases/inline-enum/basic/index.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ it("should inline enums", () => {
1313
expect(enums.E.B).toBe(1);
1414
// END:A
1515
const block = generated.match(/\/\/ START:A([\s\S]*)\/\/ END:A/)[1];
16-
expect(block.includes(`(/* inlined export .E.A */ 0).toBe(0)`)).toBe(true);
17-
expect(block.includes(`(/* inlined export .E.B */ 1).toBe(1)`)).toBe(true);
16+
expect(block.includes(`(/* inlined export .E.A */ (0)).toBe(0)`)).toBe(true);
17+
expect(block.includes(`(/* inlined export .E.B */ (1)).toBe(1)`)).toBe(true);
1818
})
1919

2020
it("should inline enums with re-export", () => {
@@ -23,8 +23,8 @@ it("should inline enums with re-export", () => {
2323
expect(reexported.E.B).toBe(1);
2424
// END:B
2525
const block = generated.match(/\/\/ START:B([\s\S]*)\/\/ END:B/)[1];
26-
expect(block.includes(`(/* inlined export .E.A */ 0).toBe(0)`)).toBe(true);
27-
expect(block.includes(`(/* inlined export .E.B */ 1).toBe(1)`)).toBe(true);
26+
expect(block.includes(`(/* inlined export .E.A */ (0)).toBe(0)`)).toBe(true);
27+
expect(block.includes(`(/* inlined export .E.B */ (1)).toBe(1)`)).toBe(true);
2828
})
2929

3030
it("should not inline enums with destructing", () => {
@@ -45,8 +45,8 @@ it("should allow inline enums if the rest exports is not used with destructing",
4545
expect(destructing.E.D).toBe(3);
4646
// END:D
4747
const block = generated.match(/\/\/ START:D([\s\S]*)\/\/ END:D/)[1];
48-
expect(block.includes(`(/* inlined export .E.C */ 2).toBe(2)`)).toBe(true);
49-
expect(block.includes(`(/* inlined export .E.D */ 3).toBe(3)`)).toBe(true);
48+
expect(block.includes(`(/* inlined export .E.C */ (2)).toBe(2)`)).toBe(true);
49+
expect(block.includes(`(/* inlined export .E.D */ (3)).toBe(3)`)).toBe(true);
5050
})
5151

5252
it("should respect side effects when inline enums", () => {
@@ -55,7 +55,7 @@ it("should respect side effects when inline enums", () => {
5555
expect(globalThis.__sideEffects).toBe("enum.side-effects.ts");
5656
// END:E
5757
const block = generated.match(/\/\/ START:E([\s\S]*)\/\/ END:E/)[1];
58-
expect(block.includes(`(/* inlined export .E.A */ 0).toBe(0)`)).toBe(true);
58+
expect(block.includes(`(/* inlined export .E.A */ (0)).toBe(0)`)).toBe(true);
5959
})
6060

6161
it("should respect side effects when inline enums with re-exports", () => {

packages/rspack-test-tools/tests/configCases/inline-enum/const-enum-only/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ it("should inline for const enum for const-only mode", () => {
1818
expect(E2.B).toBe(1);
1919
// END:B
2020
const block = generated.match(/\/\/ START:B([\s\S]*)\/\/ END:B/)[1];
21-
expect(block.includes(`(/* inlined export .E2.A */ 0).toBe(0)`)).toBe(true);
22-
expect(block.includes(`(/* inlined export .E2.B */ 1).toBe(1)`)).toBe(true);
21+
expect(block.includes(`(/* inlined export .E2.A */ (0)).toBe(0)`)).toBe(true);
22+
expect(block.includes(`(/* inlined export .E2.B */ (1)).toBe(1)`)).toBe(true);
2323
})

0 commit comments

Comments
 (0)