feat(turbopack): embed build time info, emits next features telemetry event (#53028)
### What? closes WEB-1301. To collect some information inside of rust binary, embed it as build-time constant. It supersedes existing target triple embedding as well.
This commit is contained in:
parent
f1bd1eda8e
commit
974accc2c7
15 changed files with 285 additions and 21 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
@ -2640,6 +2640,12 @@ version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
|
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_debug"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "isahc"
|
name = "isahc"
|
||||||
version = "1.7.2"
|
version = "1.7.2"
|
||||||
|
@ -3378,6 +3384,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"shadow-rs",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -3548,6 +3555,7 @@ dependencies = [
|
||||||
"sentry",
|
"sentry",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"shadow-rs",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-chrome",
|
"tracing-chrome",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
|
@ -3743,6 +3751,15 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -5189,6 +5206,18 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shadow-rs"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "970538704756fd0bb4ec8cb89f80674afb661e7c0fe716f9ba5be57717742300"
|
||||||
|
dependencies = [
|
||||||
|
"const_format",
|
||||||
|
"is_debug",
|
||||||
|
"time 0.3.20",
|
||||||
|
"tzdb",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -6870,6 +6899,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
"time-macros 0.2.8",
|
"time-macros 0.2.8",
|
||||||
|
@ -7983,6 +8014,25 @@ version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tz-rs"
|
||||||
|
version = "0.6.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4"
|
||||||
|
dependencies = [
|
||||||
|
"const_fn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdb"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec758958f2fb5069cd7fae385be95cc8eceb8cdfd270c7d14de6034f0108d99e"
|
||||||
|
dependencies = [
|
||||||
|
"iana-time-zone",
|
||||||
|
"tz-rs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-trie"
|
name = "ucd-trie"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
|
@ -121,6 +121,7 @@ serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0.93"
|
serde_json = "1.0.93"
|
||||||
serde_qs = "0.11.0"
|
serde_qs = "0.11.0"
|
||||||
serde_yaml = "0.9.17"
|
serde_yaml = "0.9.17"
|
||||||
|
shadow-rs = { version = "0.23.0", default-features = false, features = ["tzdb"] }
|
||||||
syn = "1.0.107"
|
syn = "1.0.107"
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
thiserror = "1.0.38"
|
thiserror = "1.0.38"
|
||||||
|
|
|
@ -50,6 +50,7 @@ turbo-tasks = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
shadow-rs = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-futures = "0.2.5"
|
tracing-futures = "0.2.5"
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
|
@ -84,6 +85,8 @@ sentry = { version = "0.27.0", default-features = false, features = [
|
||||||
napi-build = "2"
|
napi-build = "2"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
# It is not a mistake this dependency is specified in dep / build-dep both.
|
||||||
|
shadow-rs = { workspace = true }
|
||||||
turbopack-binding = { workspace = true, features = [
|
turbopack-binding = { workspace = true, features = [
|
||||||
"__turbo_tasks_build"
|
"__turbo_tasks_build"
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -10,22 +10,15 @@ use turbopack_binding::turbo::tasks_build::generate_register;
|
||||||
extern crate napi_build;
|
extern crate napi_build;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Emit current platform's target-triple into a text file to create static const
|
// Generates, stores build-time information as static values.
|
||||||
// in util.rs
|
// There are some places relying on correct values for this (i.e telemetry),
|
||||||
let out_dir = env::var("OUT_DIR").expect("Outdir should exist");
|
// So failing build if this fails.
|
||||||
let dest_path = Path::new(&out_dir).join("triple.txt");
|
shadow_rs::new().expect("Should able to generate build time information");
|
||||||
let mut f =
|
|
||||||
BufWriter::new(File::create(dest_path).expect("Failed to create target triple text"));
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
env::var("TARGET").expect("Target should be specified")
|
|
||||||
)
|
|
||||||
.expect("Failed to write target triple text");
|
|
||||||
|
|
||||||
// Emit current package.json's version field into a text file to create static
|
// Emit current package.json's version field into a text file to create static
|
||||||
// const in util.rs This is being used to set correct release version for
|
// const in util.rs This is being used to set correct release version for
|
||||||
// the sentry's crash reporter.
|
// the sentry's crash reporter.
|
||||||
|
let out_dir = env::var("OUT_DIR").expect("Outdir should exist");
|
||||||
let pkg_file =
|
let pkg_file =
|
||||||
File::open(Path::new("../../package.json")).expect("Should able to open package.json");
|
File::open(Path::new("../../package.json")).expect("Should able to open package.json");
|
||||||
let json: serde_json::Value = serde_json::from_reader(pkg_file).unwrap();
|
let json: serde_json::Value = serde_json::from_reader(pkg_file).unwrap();
|
||||||
|
|
|
@ -58,6 +58,9 @@ pub mod turbopack;
|
||||||
pub mod turbotrace;
|
pub mod turbotrace;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
// Declare build-time information variables generated in build.rs
|
||||||
|
shadow_rs::shadow!(build);
|
||||||
|
|
||||||
// don't use turbo malloc (`mimalloc`) on linux-musl-aarch64 because of the
|
// don't use turbo malloc (`mimalloc`) on linux-musl-aarch64 because of the
|
||||||
// compile error
|
// compile error
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
|
|
|
@ -41,6 +41,9 @@ pub struct NapiProjectOptions {
|
||||||
/// The contents of next.config.js, serialized to JSON.
|
/// The contents of next.config.js, serialized to JSON.
|
||||||
pub next_config: String,
|
pub next_config: String,
|
||||||
|
|
||||||
|
/// The contents of ts/config read by load-jsconfig, serialized to JSON.
|
||||||
|
pub js_config: String,
|
||||||
|
|
||||||
/// A map of environment variables to use when compiling code.
|
/// A map of environment variables to use when compiling code.
|
||||||
pub env: Vec<NapiEnvVar>,
|
pub env: Vec<NapiEnvVar>,
|
||||||
}
|
}
|
||||||
|
@ -58,6 +61,7 @@ impl From<NapiProjectOptions> for ProjectOptions {
|
||||||
project_path: val.project_path,
|
project_path: val.project_path,
|
||||||
watch: val.watch,
|
watch: val.watch,
|
||||||
next_config: val.next_config,
|
next_config: val.next_config,
|
||||||
|
js_config: val.js_config,
|
||||||
env: val
|
env: val
|
||||||
.env
|
.env
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -41,13 +41,12 @@ use sentry::ClientOptions;
|
||||||
use tracing_chrome::{ChromeLayerBuilder, FlushGuard};
|
use tracing_chrome::{ChromeLayerBuilder, FlushGuard};
|
||||||
use tracing_subscriber::{filter, prelude::*, util::SubscriberInitExt, Layer};
|
use tracing_subscriber::{filter, prelude::*, util::SubscriberInitExt, Layer};
|
||||||
|
|
||||||
static TARGET_TRIPLE: &str = include_str!(concat!(env!("OUT_DIR"), "/triple.txt"));
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
static PACKAGE_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/package.txt"));
|
static PACKAGE_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/package.txt"));
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn get_target_triple() -> String {
|
pub fn get_target_triple() -> String {
|
||||||
TARGET_TRIPLE.to_owned()
|
crate::build::BUILD_TARGET.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
|
pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
|
||||||
|
|
|
@ -23,6 +23,7 @@ next-core = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
shadow-rs = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
turbopack-binding = { workspace = true, features = [
|
turbopack-binding = { workspace = true, features = [
|
||||||
"__turbo_tasks_memory",
|
"__turbo_tasks_memory",
|
||||||
|
@ -42,6 +43,8 @@ tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
# It is not a mistake this dependency is specified in dep / build-dep both.
|
||||||
|
shadow-rs = { workspace = true }
|
||||||
turbopack-binding = { workspace = true, features = [
|
turbopack-binding = { workspace = true, features = [
|
||||||
"__turbo_tasks_build"
|
"__turbo_tasks_build"
|
||||||
]}
|
]}
|
|
@ -1,5 +1,10 @@
|
||||||
use turbopack_binding::turbo::tasks_build::generate_register;
|
use turbopack_binding::turbo::tasks_build::generate_register;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// Generates, stores build-time information as static values.
|
||||||
|
// There are some places relying on correct values for this (i.e telemetry),
|
||||||
|
// So failing build if this fails.
|
||||||
|
shadow_rs::new().expect("Should able to generate build time information");
|
||||||
|
|
||||||
generate_register();
|
generate_register();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ mod pages;
|
||||||
pub mod project;
|
pub mod project;
|
||||||
pub mod route;
|
pub mod route;
|
||||||
|
|
||||||
|
// Declare build-time information variables generated in build.rs
|
||||||
|
shadow_rs::shadow!(build);
|
||||||
|
|
||||||
pub fn register() {
|
pub fn register() {
|
||||||
next_core::register();
|
next_core::register();
|
||||||
turbopack_binding::turbopack::build::register();
|
turbopack_binding::turbopack::build::register();
|
||||||
|
|
|
@ -7,8 +7,9 @@ use next_core::{
|
||||||
get_edge_chunking_context, get_edge_compile_time_info,
|
get_edge_chunking_context, get_edge_compile_time_info,
|
||||||
mode::NextMode,
|
mode::NextMode,
|
||||||
next_client::{get_client_chunking_context, get_client_compile_time_info},
|
next_client::{get_client_chunking_context, get_client_compile_time_info},
|
||||||
next_config::NextConfig,
|
next_config::{JsConfig, NextConfig},
|
||||||
next_server::{get_server_chunking_context, get_server_compile_time_info},
|
next_server::{get_server_chunking_context, get_server_compile_time_info},
|
||||||
|
next_telemetry::NextFeatureTelemetry,
|
||||||
util::NextSourceConfig,
|
util::NextSourceConfig,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -23,8 +24,8 @@ use turbopack_binding::{
|
||||||
turbopack::{
|
turbopack::{
|
||||||
build::BuildChunkingContext,
|
build::BuildChunkingContext,
|
||||||
core::{
|
core::{
|
||||||
chunk::ChunkingContext, compile_time_info::CompileTimeInfo, environment::ServerAddr,
|
chunk::ChunkingContext, compile_time_info::CompileTimeInfo, diagnostics::DiagnosticExt,
|
||||||
PROJECT_FILESYSTEM_NAME,
|
environment::ServerAddr, PROJECT_FILESYSTEM_NAME,
|
||||||
},
|
},
|
||||||
dev::DevChunkingContext,
|
dev::DevChunkingContext,
|
||||||
ecmascript::chunk::EcmascriptChunkingContext,
|
ecmascript::chunk::EcmascriptChunkingContext,
|
||||||
|
@ -35,6 +36,7 @@ use turbopack_binding::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{AppProject, OptionAppProject},
|
app::{AppProject, OptionAppProject},
|
||||||
|
build,
|
||||||
entrypoints::Entrypoints,
|
entrypoints::Entrypoints,
|
||||||
pages::PagesProject,
|
pages::PagesProject,
|
||||||
route::{Endpoint, Route},
|
route::{Endpoint, Route},
|
||||||
|
@ -53,6 +55,9 @@ pub struct ProjectOptions {
|
||||||
/// The contents of next.config.js, serialized to JSON.
|
/// The contents of next.config.js, serialized to JSON.
|
||||||
pub next_config: String,
|
pub next_config: String,
|
||||||
|
|
||||||
|
/// The contents of ts/config read by load-jsconfig, serialized to JSON.
|
||||||
|
pub js_config: String,
|
||||||
|
|
||||||
/// A map of environment variables to use when compiling code.
|
/// A map of environment variables to use when compiling code.
|
||||||
pub env: Vec<(String, String)>,
|
pub env: Vec<(String, String)>,
|
||||||
|
|
||||||
|
@ -92,12 +97,14 @@ impl ProjectContainer {
|
||||||
let this = self.await?;
|
let this = self.await?;
|
||||||
let options = this.state.get();
|
let options = this.state.get();
|
||||||
let next_config = NextConfig::from_string(Vc::cell(options.next_config.clone()));
|
let next_config = NextConfig::from_string(Vc::cell(options.next_config.clone()));
|
||||||
|
let js_config = JsConfig::from_string(Vc::cell(options.js_config.clone()));
|
||||||
let env: Vc<EnvMap> = Vc::cell(options.env.iter().cloned().collect());
|
let env: Vc<EnvMap> = Vc::cell(options.env.iter().cloned().collect());
|
||||||
Ok(Project {
|
Ok(Project {
|
||||||
root_path: options.root_path.clone(),
|
root_path: options.root_path.clone(),
|
||||||
project_path: options.project_path.clone(),
|
project_path: options.project_path.clone(),
|
||||||
watch: options.watch,
|
watch: options.watch,
|
||||||
next_config,
|
next_config,
|
||||||
|
js_config,
|
||||||
env: Vc::upcast(env),
|
env: Vc::upcast(env),
|
||||||
browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \
|
browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \
|
||||||
versions, last 1 Edge versions"
|
versions, last 1 Edge versions"
|
||||||
|
@ -128,6 +135,9 @@ pub struct Project {
|
||||||
/// Next config.
|
/// Next config.
|
||||||
next_config: Vc<NextConfig>,
|
next_config: Vc<NextConfig>,
|
||||||
|
|
||||||
|
/// Js/Tsconfig read by load-jsconfig
|
||||||
|
js_config: Vc<JsConfig>,
|
||||||
|
|
||||||
/// A map of environment variables to use when compiling code.
|
/// A map of environment variables to use when compiling code.
|
||||||
env: Vc<Box<dyn ProcessEnv>>,
|
env: Vc<Box<dyn ProcessEnv>>,
|
||||||
|
|
||||||
|
@ -225,6 +235,11 @@ impl Project {
|
||||||
Ok(self.await?.next_config)
|
Ok(self.await?.next_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn js_config(self: Vc<Self>) -> Result<Vc<JsConfig>> {
|
||||||
|
Ok(self.await?.js_config)
|
||||||
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub(super) fn execution_context(self: Vc<Self>) -> Vc<ExecutionContext> {
|
pub(super) fn execution_context(self: Vc<Self>) -> Vc<ExecutionContext> {
|
||||||
let node_root = self.node_root();
|
let node_root = self.node_root();
|
||||||
|
@ -305,6 +320,84 @@ impl Project {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a telemetry event corresponding to webpack configuration telemetry
|
||||||
|
/// (https://github.com/vercel/next.js/blob/9da305fe320b89ee2f8c3cfb7ecbf48856368913/packages/next/src/build/webpack-config.ts#L2516)
|
||||||
|
/// to detect which feature is enabled.
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn collect_project_feature_telemetry(self: Vc<Self>) -> Result<Vc<()>> {
|
||||||
|
let emit_event = |feature_name: &str, enabled: bool| {
|
||||||
|
NextFeatureTelemetry::new(feature_name.to_string(), enabled)
|
||||||
|
.cell()
|
||||||
|
.emit();
|
||||||
|
};
|
||||||
|
|
||||||
|
// First, emit an event for the binary target triple.
|
||||||
|
// This is different to webpack-config; when this is being called,
|
||||||
|
// it is always using SWC so we don't check swc here.
|
||||||
|
emit_event(build::BUILD_TARGET, true);
|
||||||
|
|
||||||
|
// Go over jsconfig and report enabled features.
|
||||||
|
let compiler_options = self.js_config().compiler_options().await?;
|
||||||
|
let compiler_options = compiler_options.as_object();
|
||||||
|
let experimental_decorators_enabled = compiler_options
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|compiler_options| compiler_options.get("experimentalDecorators"))
|
||||||
|
.is_some();
|
||||||
|
let jsx_import_source_enabled = compiler_options
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|compiler_options| compiler_options.get("jsxImportSource"))
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
emit_event("swcExperimentalDecorators", experimental_decorators_enabled);
|
||||||
|
emit_event("swcImportSource", jsx_import_source_enabled);
|
||||||
|
|
||||||
|
// Go over config and report enabled features.
|
||||||
|
// [TODO]: useSwcLoader is not being reported as it is not directly corresponds (it checks babel config existence)
|
||||||
|
// need to confirm what we'll do with turbopack.
|
||||||
|
let config = self.next_config();
|
||||||
|
|
||||||
|
emit_event("swcMinify", *config.swc_minify().await?);
|
||||||
|
emit_event(
|
||||||
|
"skipMiddlewareUrlNormalize",
|
||||||
|
*config.skip_middleware_url_normalize().await?,
|
||||||
|
);
|
||||||
|
|
||||||
|
emit_event(
|
||||||
|
"skipTrailingSlashRedirect",
|
||||||
|
*config.skip_trailing_slash_redirect().await?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let config = &config.await?;
|
||||||
|
|
||||||
|
emit_event("modularizeImports", config.modularize_imports.is_some());
|
||||||
|
emit_event("transpilePackages", config.transpile_packages.is_some());
|
||||||
|
emit_event("turbotrace", config.experimental.turbotrace.is_some());
|
||||||
|
|
||||||
|
// compiler options
|
||||||
|
let compiler_options = config.compiler.as_ref();
|
||||||
|
let swc_relay_enabled = compiler_options.and_then(|c| c.relay.as_ref()).is_some();
|
||||||
|
let styled_components_enabled = compiler_options
|
||||||
|
.map(|c| c.styled_components.is_some())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let react_remove_properties_enabled = compiler_options
|
||||||
|
.and_then(|c| c.react_remove_properties)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let remove_console_enabled = compiler_options
|
||||||
|
.map(|c| c.remove_console.is_some())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let emotion_enabled = compiler_options
|
||||||
|
.map(|c| c.emotion.is_some())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
emit_event("swcRelay", swc_relay_enabled);
|
||||||
|
emit_event("swcStyledComponents", styled_components_enabled);
|
||||||
|
emit_event("swcReactRemoveProperties", react_remove_properties_enabled);
|
||||||
|
emit_event("swcRemoveConsole", remove_console_enabled);
|
||||||
|
emit_event("swcEmotion", emotion_enabled);
|
||||||
|
|
||||||
|
Ok(unit())
|
||||||
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub(super) fn ssr_chunking_context(self: Vc<Self>) -> Vc<BuildChunkingContext> {
|
pub(super) fn ssr_chunking_context(self: Vc<Self>) -> Vc<BuildChunkingContext> {
|
||||||
self.server_chunking_context().with_layer("ssr".to_string())
|
self.server_chunking_context().with_layer("ssr".to_string())
|
||||||
|
@ -349,6 +442,8 @@ impl Project {
|
||||||
/// provided page_extensions).
|
/// provided page_extensions).
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub async fn entrypoints(self: Vc<Self>) -> Result<Vc<Entrypoints>> {
|
pub async fn entrypoints(self: Vc<Self>) -> Result<Vc<Entrypoints>> {
|
||||||
|
self.collect_project_feature_telemetry().await?;
|
||||||
|
|
||||||
let mut routes = IndexMap::new();
|
let mut routes = IndexMap::new();
|
||||||
let app_project = self.app_project();
|
let app_project = self.app_project();
|
||||||
let pages_project = self.pages_project();
|
let pages_project = self.pages_project();
|
||||||
|
|
|
@ -117,12 +117,14 @@ pub struct NextConfig {
|
||||||
public_runtime_config: IndexMap<String, serde_json::Value>,
|
public_runtime_config: IndexMap<String, serde_json::Value>,
|
||||||
server_runtime_config: IndexMap<String, serde_json::Value>,
|
server_runtime_config: IndexMap<String, serde_json::Value>,
|
||||||
static_page_generation_timeout: f64,
|
static_page_generation_timeout: f64,
|
||||||
swc_minify: bool,
|
swc_minify: Option<bool>,
|
||||||
target: Option<String>,
|
target: Option<String>,
|
||||||
trailing_slash: bool,
|
trailing_slash: bool,
|
||||||
typescript: TypeScriptConfig,
|
typescript: TypeScriptConfig,
|
||||||
use_file_system_public_routes: bool,
|
use_file_system_public_routes: bool,
|
||||||
webpack: Option<serde_json::Value>,
|
webpack: Option<serde_json::Value>,
|
||||||
|
skip_middleware_url_normalize: Option<bool>,
|
||||||
|
skip_trailing_slash_redirect: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TraceRawVcs)]
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TraceRawVcs)]
|
||||||
|
@ -446,15 +448,13 @@ pub struct ExperimentalConfig {
|
||||||
runtime: Option<serde_json::Value>,
|
runtime: Option<serde_json::Value>,
|
||||||
scroll_restoration: Option<bool>,
|
scroll_restoration: Option<bool>,
|
||||||
shared_pool: Option<bool>,
|
shared_pool: Option<bool>,
|
||||||
skip_middleware_url_normalize: Option<bool>,
|
|
||||||
skip_trailing_slash_redirect: Option<bool>,
|
|
||||||
sri: Option<serde_json::Value>,
|
sri: Option<serde_json::Value>,
|
||||||
swc_file_reading: Option<bool>,
|
swc_file_reading: Option<bool>,
|
||||||
swc_minify: Option<bool>,
|
swc_minify: Option<bool>,
|
||||||
swc_minify_debug_options: Option<serde_json::Value>,
|
swc_minify_debug_options: Option<serde_json::Value>,
|
||||||
swc_trace_profiling: Option<bool>,
|
swc_trace_profiling: Option<bool>,
|
||||||
transpile_packages: Option<Vec<String>>,
|
transpile_packages: Option<Vec<String>>,
|
||||||
turbotrace: Option<serde_json::Value>,
|
pub turbotrace: Option<serde_json::Value>,
|
||||||
url_imports: Option<serde_json::Value>,
|
url_imports: Option<serde_json::Value>,
|
||||||
web_vitals_attribution: Option<serde_json::Value>,
|
web_vitals_attribution: Option<serde_json::Value>,
|
||||||
worker_threads: Option<bool>,
|
worker_threads: Option<bool>,
|
||||||
|
@ -653,6 +653,25 @@ impl NextConfig {
|
||||||
self.await?.sass_options.clone().unwrap_or_default(),
|
self.await?.sass_options.clone().unwrap_or_default(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn swc_minify(self: Vc<Self>) -> Result<Vc<bool>> {
|
||||||
|
Ok(Vc::cell(self.await?.swc_minify.unwrap_or(false)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn skip_middleware_url_normalize(self: Vc<Self>) -> Result<Vc<bool>> {
|
||||||
|
Ok(Vc::cell(
|
||||||
|
self.await?.skip_middleware_url_normalize.unwrap_or(false),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn skip_trailing_slash_redirect(self: Vc<Self>) -> Result<Vc<bool>> {
|
||||||
|
Ok(Vc::cell(
|
||||||
|
self.await?.skip_trailing_slash_redirect.unwrap_or(false),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_configs() -> Vc<Vec<String>> {
|
fn next_configs() -> Vc<Vec<String>> {
|
||||||
|
@ -799,6 +818,34 @@ pub async fn has_next_config(context: Vc<FileSystemPath>) -> Result<Vc<bool>> {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A subset of ts/jsconfig that next.js implicitly
|
||||||
|
/// interops with.
|
||||||
|
#[turbo_tasks::value(serialization = "custom", eq = "manual")]
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct JsConfig {
|
||||||
|
compiler_options: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl JsConfig {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn from_string(string: Vc<String>) -> Result<Vc<Self>> {
|
||||||
|
let string = string.await?;
|
||||||
|
let config: JsConfig = serde_json::from_str(&string)
|
||||||
|
.with_context(|| format!("failed to parse next.config.js: {}", string))?;
|
||||||
|
|
||||||
|
Ok(config.cell())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn compiler_options(self: Vc<Self>) -> Result<Vc<serde_json::Value>> {
|
||||||
|
Ok(Vc::cell(
|
||||||
|
self.await?.compiler_options.clone().unwrap_or_default(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[turbo_tasks::value]
|
#[turbo_tasks::value]
|
||||||
struct OutdatedConfigIssue {
|
struct OutdatedConfigIssue {
|
||||||
path: Vc<FileSystemPath>,
|
path: Vc<FileSystemPath>,
|
||||||
|
|
|
@ -5,6 +5,48 @@ use turbopack_binding::{
|
||||||
turbopack::core::diagnostics::{Diagnostic, DiagnosticPayload},
|
turbopack::core::diagnostics::{Diagnostic, DiagnosticPayload},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A struct represent telemetry event if certain feature of next.js
|
||||||
|
/// is enabled, such as next.config.swcMinify.
|
||||||
|
/// This is an equivalent representation of the following code:
|
||||||
|
/// https://github.com/vercel/next.js/blob/9da305fe320b89ee2f8c3cfb7ecbf48856368913/packages/next/src/build/webpack-config.ts#L2516
|
||||||
|
#[turbo_tasks::value(shared)]
|
||||||
|
pub struct NextFeatureTelemetry {
|
||||||
|
pub event_name: String,
|
||||||
|
pub feature_name: String,
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NextFeatureTelemetry {
|
||||||
|
pub fn new(feature_name: String, enabled: bool) -> Self {
|
||||||
|
NextFeatureTelemetry {
|
||||||
|
event_name: "EVENT_BUILD_FEATURE_USAGE".to_string(),
|
||||||
|
feature_name,
|
||||||
|
enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Diagnostic for NextFeatureTelemetry {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn category(&self) -> Vc<String> {
|
||||||
|
Vc::cell("NextFeatureTelemetry_category_tbd".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn name(&self) -> Vc<String> {
|
||||||
|
Vc::cell(self.event_name.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn payload(&self) -> Vc<DiagnosticPayload> {
|
||||||
|
Vc::cell(HashMap::from([(
|
||||||
|
self.feature_name.clone(),
|
||||||
|
self.enabled.to_string(),
|
||||||
|
)]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A struct represent telemetry event for the feature usage,
|
/// A struct represent telemetry event for the feature usage,
|
||||||
/// referred as `importing` a certain module. (i.e importing @next/image)
|
/// referred as `importing` a certain module. (i.e importing @next/image)
|
||||||
#[turbo_tasks::value(shared)]
|
#[turbo_tasks::value(shared)]
|
||||||
|
|
|
@ -340,6 +340,17 @@ interface ProjectOptions {
|
||||||
*/
|
*/
|
||||||
nextConfig: NextConfigComplete
|
nextConfig: NextConfigComplete
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jsconfig, or tsconfig contents.
|
||||||
|
*
|
||||||
|
* Next.js implicitly requires to read it to support few options
|
||||||
|
* https://nextjs.org/docs/architecture/nextjs-compiler#legacy-decorators
|
||||||
|
* https://nextjs.org/docs/architecture/nextjs-compiler#importsource
|
||||||
|
*/
|
||||||
|
jsConfig: {
|
||||||
|
compilerOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of environment variables to use when compiling code.
|
* A map of environment variables to use when compiling code.
|
||||||
*/
|
*/
|
||||||
|
@ -561,6 +572,7 @@ function bindingToApi(binding: any, _wasm: boolean) {
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
nextConfig: await serializeNextConfig(options.nextConfig),
|
nextConfig: await serializeNextConfig(options.nextConfig),
|
||||||
|
jsConfig: JSON.stringify(options.jsConfig ?? {}),
|
||||||
env: Object.entries(options.env).map(([name, value]) => ({
|
env: Object.entries(options.env).map(([name, value]) => ({
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -226,6 +226,9 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
if (experimentalTurbo) {
|
if (experimentalTurbo) {
|
||||||
const { loadBindings } =
|
const { loadBindings } =
|
||||||
require('../build/swc') as typeof import('../build/swc')
|
require('../build/swc') as typeof import('../build/swc')
|
||||||
|
const { default: loadJsConfig } =
|
||||||
|
require('../build/load-jsconfig') as typeof import('../build/load-jsconfig')
|
||||||
|
const { jsConfig } = await loadJsConfig(dir, config)
|
||||||
|
|
||||||
resetEnv()
|
resetEnv()
|
||||||
let bindings = await loadBindings()
|
let bindings = await loadBindings()
|
||||||
|
@ -236,6 +239,7 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
projectPath: dir,
|
projectPath: dir,
|
||||||
rootPath: args['--root'] ?? findRootDir(dir) ?? dir,
|
rootPath: args['--root'] ?? findRootDir(dir) ?? dir,
|
||||||
nextConfig: config,
|
nextConfig: config,
|
||||||
|
jsConfig,
|
||||||
env: {
|
env: {
|
||||||
NEXT_PUBLIC_ENV_VAR: 'world',
|
NEXT_PUBLIC_ENV_VAR: 'world',
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue