Skip to content

Commit 37eb69e

Browse files
authored
initial work for compile-time evaluation (vercel/turborepo#3495)
Allows to skip unreachable code based on compile-time constant conditions e. g. ``` if (!process.turbopack) { require("will-not-be-processed"); } ``` * add if() and process.turbopack fixes WEB-491 * Removes unreachable code fixes WEB-498 * evaluate some logical operations `&&`, `||`, `??`, `!` * fix arguments handling fixes WEB-529 * nested effects for function called with closures * handle closures when array methods are used fixes WEB-538 * evaluates `process.turbopack` fixes WEB-496
1 parent a3ec520 commit 37eb69e

File tree

125 files changed

+104726
-65655
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+104726
-65655
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
it("importing a not existing file should throw", () => {
2+
// This is a check to make sure that the following tests would fail if they require("fail")
3+
expect(() => {
4+
require("./not-existing-file");
5+
}).toThrow();
6+
});
7+
8+
function maybeReturn(x) {
9+
if (x) {
10+
return true;
11+
}
12+
}
13+
14+
function func() {
15+
if (false) {
16+
require("fail");
17+
import("fail");
18+
}
19+
if (true) {
20+
require("./ok");
21+
}
22+
if (true) {
23+
require("./ok");
24+
} else {
25+
require("fail");
26+
import("fail");
27+
}
28+
if (false) {
29+
require("fail");
30+
import("fail");
31+
} else {
32+
require("./ok");
33+
}
34+
}
35+
36+
it("should not follow conditional references", () => {
37+
func();
38+
39+
expect(func.toString()).not.toContain("import(");
40+
});
41+
42+
it("should allow replacements in IIFEs", () => {
43+
(function func() {
44+
if (false) {
45+
require("fail");
46+
import("fail");
47+
}
48+
})();
49+
});
50+
51+
it("should support functions that only sometimes return", () => {
52+
let ok = false;
53+
if (maybeReturn(true)) {
54+
ok = true;
55+
}
56+
expect(ok).toBe(true);
57+
});
58+
59+
it("should evaluate process.turbopack", () => {
60+
let ok = false;
61+
if (process.turbopack) {
62+
ok = true;
63+
} else {
64+
require("fail");
65+
import("fail");
66+
}
67+
expect(ok).toBe(true);
68+
});
69+
70+
it("should evaluate !process.turbopack", () => {
71+
if (!process.turbopack) {
72+
require("fail");
73+
import("fail");
74+
}
75+
});
76+
77+
// it("should evaluate NODE_ENV", () => {
78+
// if (process.env.NODE_ENV !== "development") {
79+
// require("fail");
80+
// import("fail");
81+
// }
82+
// });

crates/next-dev-tests/tests/integration/turbopack/basic/comptime/input/ok.js

Whitespace-only changes.

crates/turbopack-core/src/reference_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::fmt::Display;
22

3-
// These enums list well known types, which we use internally. Plugins might add
3+
// These enums list well-known types, which we use internally. Plugins might add
44
// custom types too.
55

66
// TODO when plugins are supported, replace u8 with a trait that defines the

crates/turbopack-create-test-app/src/test_app_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl TestAppBuilder {
141141
};
142142

143143
#[cfg(windows)]
144-
let relative_effect = relative_effect.replace("\\", "/");
144+
let relative_effect = relative_effect.replace('\\', "/");
145145

146146
formatdoc! {r#"
147147
{SETUP_IMPORTS}

crates/turbopack-dev-server/src/http.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub async fn process_request_with_content_source(
7676

7777
let header_map = response.headers_mut().expect("headers must be defined");
7878

79-
for (header_name, header_value) in &*headers {
79+
for (header_name, header_value) in headers {
8080
header_map.append(
8181
HeaderName::try_from(header_name.clone())?,
8282
hyper::header::HeaderValue::try_from(header_value.as_str())?,

crates/turbopack-dev-server/src/source/resolve.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ pub async fn resolve_source_request(
5656
ContentSourceResult::NeedData(needed) => {
5757
current_source = needed.source.resolve().await?;
5858
current_asset_path = needed.path.clone();
59-
data = request_to_data(&mut request_overwrites, &needed.vary).await?;
59+
data = request_to_data(&request_overwrites, &needed.vary).await?;
6060
}
6161
ContentSourceResult::Result { get_content, .. } => {
6262
let content_vary = get_content.vary().await?;
63-
let content_data = request_to_data(&mut request_overwrites, &content_vary).await?;
63+
let content_data = request_to_data(&request_overwrites, &content_vary).await?;
6464
let content = get_content.get(Value::new(content_data));
6565
match &*content.await? {
6666
ContentSourceContent::Rewrite(rewrite) => {

crates/turbopack-ecmascript/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ lazy_static = "1.4.0"
2020
next-font = { path = "../next-font" }
2121
next-transform-dynamic = { path = "../next-transform-dynamic" }
2222
next-transform-strip-page-exports = { path = "../next-transform-strip-page-exports" }
23+
num-bigint = "0.4"
24+
num-traits = "0.2.15"
2325
once_cell = "1.13.0"
26+
parking_lot = "0.12.1"
2427
pin-project-lite = "0.2.9"
2528
regex = "1.5.4"
2629
serde = "1.0.136"
@@ -58,9 +61,6 @@ swc_core = { workspace = true, features = [
5861
"base",
5962
] }
6063

61-
[dependencies.num-bigint]
62-
version = "0.4"
63-
6464
[dev-dependencies]
6565
criterion = { version = "0.3.5", features = ["async_tokio"] }
6666
rstest = "0.12.0"

crates/turbopack-ecmascript/benches/analyzer.rs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
use std::{
2-
fs,
3-
path::PathBuf,
4-
sync::{Arc, Mutex},
5-
time::Duration,
6-
};
1+
use std::{fs, path::PathBuf, sync::Arc, time::Duration};
72

83
use criterion::{Bencher, BenchmarkId, Criterion};
94
use swc_core::{
@@ -23,8 +18,8 @@ use turbopack_core::{
2318
};
2419
use turbopack_ecmascript::analyzer::{
2520
graph::{create_graph, EvalContext, VarGraph},
26-
linker::{link, LinkCache},
27-
test_utils::visitor,
21+
linker::link,
22+
test_utils::{early_visitor, visitor},
2823
};
2924

3025
pub fn benchmark(c: &mut Criterion) {
@@ -95,28 +90,24 @@ fn bench_link(b: &mut Bencher, input: &BenchInput) {
9590
.unwrap();
9691

9792
b.to_async(rt).iter(|| async {
98-
let cache = Mutex::new(LinkCache::new());
9993
for val in input.var_graph.values.values() {
10094
VcStorage::with(async {
95+
let env = EnvironmentVc::new(
96+
Value::new(ExecutionEnvironment::NodeJsLambda(
97+
NodeJsEnvironment {
98+
compile_target: CompileTargetVc::unknown(),
99+
..Default::default()
100+
}
101+
.into(),
102+
)),
103+
Value::new(EnvironmentIntention::ServerRendering),
104+
);
101105
link(
102106
&input.var_graph,
103107
val.clone(),
104-
&(|val| {
105-
Box::pin(visitor(
106-
val,
107-
EnvironmentVc::new(
108-
Value::new(ExecutionEnvironment::NodeJsLambda(
109-
NodeJsEnvironment {
110-
compile_target: CompileTargetVc::unknown(),
111-
..Default::default()
112-
}
113-
.into(),
114-
)),
115-
Value::new(EnvironmentIntention::ServerRendering),
116-
),
117-
))
118-
}),
119-
&cache,
108+
&early_visitor,
109+
&(|val| visitor(val, env)),
110+
Default::default(),
120111
)
121112
.await
122113
})

0 commit comments

Comments
 (0)