Skip to content

Commit 16ab2d4

Browse files
authored
test: Improve testing system for tree shaker (vercel/turborepo#4663)
### Description We need a testing system that supports enabling only _some_ of exports. This PR implements it by using `config.json`. Fix WEB-917. ### Testing Instructions Look at output.mdx
1 parent 039dce4 commit 16ab2d4

File tree

4 files changed

+810
-39
lines changed

4 files changed

+810
-39
lines changed

crates/turbopack-ecmascript/src/tree_shake/tests.rs

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use std::{
88
use anyhow::Error;
99
use indexmap::IndexSet;
1010
use rustc_hash::FxHasher;
11+
use serde::Deserialize;
1112
use swc_core::{
12-
common::SourceMap,
13+
common::{util::take::Take, SourceMap},
1314
ecma::{
1415
ast::{EsVersion, Id, Module},
1516
atoms::JsWord,
@@ -24,15 +25,29 @@ use super::{
2425
DepGraph, Dependency, InternedGraph, ItemId, ItemIdGroupKind, Mode, SplitModuleResult,
2526
},
2627
merge::Merger,
27-
Analyzer,
28+
Analyzer, Key,
2829
};
2930

3031
#[fixture("tests/tree-shaker/analyzer/**/input.js")]
3132
fn test_fixture(input: PathBuf) {
3233
run(input);
3334
}
3435

36+
#[derive(Deserialize)]
37+
struct TestConfig {
38+
/// Enabled exports. This is `Vec<Vec<String>>` because we test multiple
39+
/// exports at once.
40+
#[serde(default)]
41+
exports: Vec<Vec<String>>,
42+
}
43+
3544
fn run(input: PathBuf) {
45+
let config = input.with_file_name("config.json");
46+
let config = std::fs::read_to_string(&config).unwrap_or_else(|_| "{}".into());
47+
let config = serde_json::from_str::<TestConfig>(&config).unwrap_or_else(|e| {
48+
panic!("failed to parse config.json: {}", config);
49+
});
50+
3651
testing::run_test(false, |cm, _handler| {
3752
let fm = cm.load_file(&input).unwrap();
3853

@@ -151,46 +166,73 @@ fn run(input: PathBuf) {
151166

152167
let uri_of_module: JsWord = "entry.js".into();
153168

154-
{
155-
let mut g = analyzer.g.clone();
156-
g.handle_weak(Mode::Development);
157-
let SplitModuleResult { modules, .. } = g.split_module(&uri_of_module, analyzer.items);
158-
159-
writeln!(s, "# Modules (dev)").unwrap();
160-
for (i, module) in modules.iter().enumerate() {
161-
writeln!(s, "## Part {}", i).unwrap();
162-
writeln!(s, "```js\n{}\n```", print(&cm, &[module])).unwrap();
163-
}
164-
165-
let mut merger = Merger::new(SingleModuleLoader {
166-
modules: &modules,
167-
entry_module_uri: &uri_of_module,
168-
});
169-
let module = merger.merge_recursively(modules[0].clone()).unwrap();
170-
171-
writeln!(s, "## Merged (module eval)").unwrap();
172-
writeln!(s, "```js\n{}\n```", print(&cm, &[&module])).unwrap();
173-
}
174-
175-
{
176-
let mut g = analyzer.g.clone();
177-
g.handle_weak(Mode::Production);
178-
let SplitModuleResult { modules, .. } = g.split_module(&uri_of_module, analyzer.items);
169+
let mut describe =
170+
|is_debug: bool, title: &str, entries: Vec<ItemIdGroupKind>, skip_parts: bool| {
171+
let mut g = analyzer.g.clone();
172+
g.handle_weak(if is_debug {
173+
Mode::Development
174+
} else {
175+
Mode::Production
176+
});
177+
let SplitModuleResult {
178+
modules,
179+
entrypoints,
180+
..
181+
} = g.split_module(&uri_of_module, analyzer.items);
182+
183+
if !skip_parts {
184+
writeln!(s, "# Modules ({})", if is_debug { "dev" } else { "prod" }).unwrap();
185+
for (i, module) in modules.iter().enumerate() {
186+
writeln!(s, "## Part {}", i).unwrap();
187+
writeln!(s, "```js\n{}\n```", print(&cm, &[module])).unwrap();
188+
}
189+
}
179190

180-
writeln!(s, "# Modules (prod)").unwrap();
181-
for (i, module) in modules.iter().enumerate() {
182-
writeln!(s, "## Part {}", i).unwrap();
183-
writeln!(s, "```js\n{}\n```", print(&cm, &[module])).unwrap();
184-
}
191+
let mut merger = Merger::new(SingleModuleLoader {
192+
modules: &modules,
193+
entry_module_uri: &uri_of_module,
194+
});
195+
let mut entry = Module::dummy();
196+
197+
for e in &entries {
198+
let key = match e {
199+
ItemIdGroupKind::ModuleEvaluation => Key::ModuleEvaluation,
200+
ItemIdGroupKind::Export(e) => Key::Export(e.0.to_string()),
201+
_ => continue,
202+
};
203+
204+
let index = entrypoints[&key];
205+
entry.body.extend(modules[index as usize].body.clone());
206+
}
185207

186-
let mut merger = Merger::new(SingleModuleLoader {
187-
modules: &modules,
188-
entry_module_uri: &uri_of_module,
189-
});
190-
let module = merger.merge_recursively(modules[0].clone()).unwrap();
208+
let module = merger.merge_recursively(entry).unwrap();
191209

192-
writeln!(s, "## Merged (module eval)").unwrap();
193-
writeln!(s, "```js\n{}\n```", print(&cm, &[&module])).unwrap();
210+
writeln!(s, "## Merged ({})", title).unwrap();
211+
writeln!(s, "```js\n{}\n```", print(&cm, &[&module])).unwrap();
212+
};
213+
describe(
214+
true,
215+
"module eval",
216+
vec![ItemIdGroupKind::ModuleEvaluation],
217+
false,
218+
);
219+
describe(
220+
false,
221+
"module eval",
222+
vec![ItemIdGroupKind::ModuleEvaluation],
223+
false,
224+
);
225+
226+
for exports in config.exports {
227+
describe(
228+
false,
229+
&exports.join(","),
230+
exports
231+
.into_iter()
232+
.map(|e| ItemIdGroupKind::Export((e.into(), Default::default())))
233+
.collect(),
234+
true,
235+
);
194236
}
195237

196238
NormalizedOutput::from(s)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"exports":[
3+
["external1"],
4+
["external1", "external2"]
5+
]
6+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { upper } from "module";
2+
export let foobar = "foo";
3+
export const foo = foobar;
4+
const bar = "bar";
5+
foobar += bar;
6+
let foobarCopy = foobar;
7+
foobar += "foo";
8+
console.log(foobarCopy);
9+
foobarCopy += "Unused";
10+
function internal() {
11+
return upper(foobar);
12+
}
13+
export function external1() {
14+
return internal() + foobar;
15+
}
16+
export function external2() {
17+
foobar += ".";
18+
}

0 commit comments

Comments
 (0)