From 53bd5c333e15a6c140c55382652cd663c9c6997a Mon Sep 17 00:00:00 2001 From: hrmny Date: Fri, 29 Sep 2023 16:51:21 +0200 Subject: [PATCH 01/11] pass defineEnv to rust directly --- .../crates/napi/src/next_api/project.rs | 93 ++++++++- .../next-swc/crates/napi/src/turbopack.rs | 30 ++- .../next-swc/crates/next-api/src/project.rs | 138 ++++++++++++-- .../crates/next-build/src/build_options.rs | 9 + .../next-swc/crates/next-build/src/main.rs | 1 + .../crates/next-build/src/next_build.rs | 20 +- .../crates/next-core/src/app_structure.rs | 24 +-- .../next-core/src/next_app/bloom_filter.rs | 180 ------------------ .../crates/next-core/src/next_app/mod.rs | 1 - .../next-core/src/next_client/context.rs | 123 +++--------- .../crates/next-core/src/next_edge/context.rs | 51 +++-- .../next-core/src/next_server/context.rs | 51 +++-- packages/next/src/build/index.ts | 19 ++ packages/next/src/build/swc/index.ts | 94 ++++++++- .../webpack/plugins/define-env-plugin.ts | 2 +- .../next/src/server/dev/hot-reloader-types.ts | 3 +- .../src/server/lib/router-utils/setup-dev.ts | 39 ++++ 17 files changed, 494 insertions(+), 384 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/src/next_app/bloom_filter.rs diff --git a/packages/next-swc/crates/napi/src/next_api/project.rs b/packages/next-swc/crates/napi/src/next_api/project.rs index 29e42e3786470..a8376b88f4078 100644 --- a/packages/next-swc/crates/napi/src/next_api/project.rs +++ b/packages/next-swc/crates/napi/src/next_api/project.rs @@ -7,7 +7,7 @@ use napi::{ JsFunction, Status, }; use next_api::{ - project::{Middleware, ProjectContainer, ProjectOptions}, + project::{DefineEnv, Middleware, PartialProjectOptions, ProjectContainer, ProjectOptions}, route::{Endpoint, Route}, }; use next_core::tracing_presets::{ @@ -44,6 +44,7 @@ use super::{ use crate::register; #[napi(object)] +#[derive(Clone, Debug)] pub struct NapiEnvVar { pub name: String, pub value: String, @@ -74,10 +75,56 @@ pub struct NapiProjectOptions { /// A map of environment variables to use when compiling code. pub env: Vec, + /// A map of environment variables which should get injected at compile + /// time. + pub define_env: NapiDefineEnv, + /// The address of the dev server. pub server_addr: String, } +/// [NapiProjectOptions] with all fields optional. +#[napi(object)] +pub struct NapiPartialProjectOptions { + /// A root path from which all files must be nested under. Trying to access + /// a file outside this root will fail. Think of this as a chroot. + pub root_path: Option, + + /// A path inside the root_path which contains the app/pages directories. + pub project_path: Option, + + /// next.config's distDir. Project initialization occurs eariler than + /// deserializing next.config, so passing it as separate option. + pub dist_dir: Option>, + + /// Whether to watch he filesystem for file changes. + pub watch: Option, + + /// The contents of next.config.js, serialized to JSON. + pub next_config: Option, + + /// The contents of ts/config read by load-jsconfig, serialized to JSON. + pub js_config: Option, + + /// A map of environment variables to use when compiling code. + pub env: Option>, + + /// A map of environment variables which should get injected at compile + /// time. + pub define_env: Option, + + /// The address of the dev server. + pub server_addr: Option, +} + +#[napi(object)] +#[derive(Clone, Debug)] +pub struct NapiDefineEnv { + pub client: Vec, + pub edge: Vec, + pub nodejs: Vec, +} + #[napi(object)] pub struct NapiTurboEngineOptions { /// An upper bound of memory that turbopack will attempt to stay under. @@ -95,13 +142,53 @@ impl From for ProjectOptions { env: val .env .into_iter() - .map(|NapiEnvVar { name, value }| (name, value)) + .map(|var| (var.name, var.value)) .collect(), + define_env: val.define_env.into(), + server_addr: val.server_addr, + } + } +} + +impl From for PartialProjectOptions { + fn from(val: NapiPartialProjectOptions) -> Self { + PartialProjectOptions { + root_path: val.root_path, + project_path: val.project_path, + watch: val.watch, + next_config: val.next_config, + js_config: val.js_config, + env: val + .env + .map(|env| env.into_iter().map(|var| (var.name, var.value)).collect()), + define_env: val.define_env.map(|env| env.into()), server_addr: val.server_addr, } } } +impl From for DefineEnv { + fn from(val: NapiDefineEnv) -> Self { + DefineEnv { + client: val + .client + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + edge: val + .edge + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + nodejs: val + .nodejs + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + } + } +} + pub struct ProjectInstance { turbo_tasks: Arc>, container: Vc, @@ -190,7 +277,7 @@ pub async fn project_new( #[napi(ts_return_type = "{ __napiType: \"Project\" }")] pub async fn project_update( #[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External, - options: NapiProjectOptions, + options: NapiPartialProjectOptions, ) -> napi::Result<()> { let turbo_tasks = project.turbo_tasks.clone(); let options = options.into(); diff --git a/packages/next-swc/crates/napi/src/turbopack.rs b/packages/next-swc/crates/napi/src/turbopack.rs index f6477ccb37d64..0222a332dd2ae 100644 --- a/packages/next-swc/crates/napi/src/turbopack.rs +++ b/packages/next-swc/crates/napi/src/turbopack.rs @@ -6,11 +6,13 @@ use std::{ use anyhow::Context; use napi::bindgen_prelude::*; use next_build::{ - build as turbo_next_build, build_options::BuildContext, BuildOptions as NextBuildOptions, + build as turbo_next_build, + build_options::{BuildContext, DefineEnv}, + BuildOptions as NextBuildOptions, }; use next_core::next_config::{Rewrite, Rewrites, RouteHas}; -use crate::util::MapErr; +use crate::{next_api::project::NapiDefineEnv, util::MapErr}; #[napi(object, object_to_js = false)] #[derive(Debug)] @@ -38,6 +40,7 @@ pub struct NextBuildContext { // TODO(alexkirsz) These are used to generate route types. // pub original_rewrites: Option, // pub original_redirects: Option>, + pub define_env: NapiDefineEnv, } impl TryFrom for NextBuildOptions { @@ -62,10 +65,33 @@ impl TryFrom for NextBuildOptions { .context("NextBuildContext must provide rewrites")? .into(), }), + define_env: value.define_env.into(), }) } } +impl From for DefineEnv { + fn from(val: NapiDefineEnv) -> Self { + DefineEnv { + client: val + .client + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + edge: val + .edge + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + nodejs: val + .nodejs + .into_iter() + .map(|var| (var.name, var.value)) + .collect(), + } + } +} + /// Keep in sync with [`next_core::next_config::Rewrites`] #[napi(object, object_to_js = false)] #[derive(Debug)] diff --git a/packages/next-swc/crates/next-api/src/project.rs b/packages/next-swc/crates/next-api/src/project.rs index 6672be7525862..9c2c761b8a1c9 100644 --- a/packages/next-swc/crates/next-api/src/project.rs +++ b/packages/next-swc/crates/next-api/src/project.rs @@ -83,6 +83,10 @@ pub struct ProjectOptions { /// A map of environment variables to use when compiling code. pub env: Vec<(String, String)>, + /// A map of environment variables which should get injected at compile + /// time. + pub define_env: DefineEnv, + /// Whether to watch the filesystem for file changes. pub watch: bool, @@ -90,6 +94,44 @@ pub struct ProjectOptions { pub server_addr: String, } +#[derive(Debug, Serialize, Deserialize, Clone, TaskInput, PartialEq, Eq, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct PartialProjectOptions { + /// A root path from which all files must be nested under. Trying to access + /// a file outside this root will fail. Think of this as a chroot. + pub root_path: Option, + + /// A path inside the root_path which contains the app/pages directories. + pub project_path: Option, + + /// The contents of next.config.js, serialized to JSON. + pub next_config: Option, + + /// The contents of ts/config read by load-jsconfig, serialized to JSON. + pub js_config: Option, + + /// A map of environment variables to use when compiling code. + pub env: Option>, + + /// A map of environment variables which should get injected at compile + /// time. + pub define_env: Option, + + /// Whether to watch the filesystem for file changes. + pub watch: Option, + + /// The address of the dev server. + pub server_addr: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, TaskInput, PartialEq, Eq, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct DefineEnv { + pub client: Vec<(String, String)>, + pub edge: Vec<(String, String)>, + pub nodejs: Vec<(String, String)>, +} + #[derive(Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, ValueDebugFormat)] pub struct Middleware { pub endpoint: Vc>, @@ -113,18 +155,52 @@ impl ProjectContainer { } #[turbo_tasks::function] - pub async fn update(self: Vc, options: ProjectOptions) -> Result> { - self.await?.options_state.set(options); - Ok(Default::default()) + pub fn update(&self, options: PartialProjectOptions) -> Vc<()> { + let mut new_options = self.options_state.get().clone(); + + if let Some(root_path) = options.root_path { + new_options.root_path = root_path; + } + if let Some(project_path) = options.project_path { + new_options.project_path = project_path; + } + if let Some(next_config) = options.next_config { + new_options.next_config = next_config; + } + if let Some(js_config) = options.js_config { + new_options.js_config = js_config; + } + if let Some(env) = options.env { + new_options.env = env; + } + if let Some(define_env) = options.define_env { + new_options.define_env = define_env; + } + if let Some(watch) = options.watch { + new_options.watch = watch; + } + if let Some(server_addr) = options.server_addr { + new_options.server_addr = server_addr; + } + + self.options_state.set(new_options); + + Default::default() } #[turbo_tasks::function] pub async fn project(self: Vc) -> Result> { let this = self.await?; - let (env, next_config, js_config, root_path, project_path, watch, server_addr) = { + let (env, define_env, next_config, js_config, root_path, project_path, watch, server_addr) = { let options = this.options_state.get(); let env: Vc = Vc::cell(options.env.iter().cloned().collect()); + let define_env: Vc = ProjectDefineEnv { + client: Vc::cell(options.define_env.client.iter().cloned().collect()), + edge: Vc::cell(options.define_env.edge.iter().cloned().collect()), + nodejs: Vc::cell(options.define_env.nodejs.iter().cloned().collect()), + } + .cell(); 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 root_path = options.root_path.clone(); @@ -133,6 +209,7 @@ impl ProjectContainer { let server_addr = options.server_addr.parse()?; ( env, + define_env, next_config, js_config, root_path, @@ -157,6 +234,7 @@ impl ProjectContainer { js_config, dist_dir, env: Vc::upcast(env), + define_env, browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \ versions, last 1 Edge versions" .to_string(), @@ -207,6 +285,10 @@ pub struct Project { /// A map of environment variables to use when compiling code. env: Vc>, + /// A map of environment variables which should get injected at compile + /// time. + define_env: Vc, + browserslist_query: String, mode: NextMode, @@ -214,6 +296,31 @@ pub struct Project { versioned_content_map: Vc, } +#[turbo_tasks::value] +pub struct ProjectDefineEnv { + client: Vc, + edge: Vc, + nodejs: Vc, +} + +#[turbo_tasks::value_impl] +impl ProjectDefineEnv { + #[turbo_tasks::function] + pub fn client(&self) -> Vc { + self.client + } + + #[turbo_tasks::function] + pub fn edge(&self) -> Vc { + self.edge + } + + #[turbo_tasks::function] + pub fn nodejs(&self) -> Vc { + self.nodejs + } +} + #[turbo_tasks::value_impl] impl Project { #[turbo_tasks::function] @@ -353,15 +460,11 @@ impl Project { } #[turbo_tasks::function] - pub(super) async fn client_compile_time_info(self: Vc) -> Result> { - let this = self.await?; - + pub(super) async fn client_compile_time_info(&self) -> Result> { Ok(get_client_compile_time_info( - this.mode, - this.browserslist_query.clone(), - self.dist_root_string(), - this.next_config, - find_app_dir(self.project_path()), + self.mode, + self.browserslist_query.clone(), + self.define_env.client(), )) } @@ -372,16 +475,19 @@ impl Project { this.mode, self.env(), self.server_addr(), + this.define_env.nodejs(), )) } #[turbo_tasks::function] - pub(super) fn edge_compile_time_info(self: Vc) -> Vc { - get_edge_compile_time_info( + pub(super) async fn edge_compile_time_info(self: Vc) -> Result> { + let this = self.await?; + Ok(get_edge_compile_time_info( + this.mode, self.project_path(), self.server_addr(), - self.dist_root_string(), - ) + this.define_env.nodejs(), + )) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-build/src/build_options.rs b/packages/next-swc/crates/next-build/src/build_options.rs index 850cd3989c4fd..7053aed8d299a 100644 --- a/packages/next-swc/crates/next-build/src/build_options.rs +++ b/packages/next-swc/crates/next-build/src/build_options.rs @@ -30,6 +30,8 @@ pub struct BuildOptions { /// The Next.js build context. pub build_context: Option, + + pub define_env: DefineEnv, } #[derive(Clone, Debug)] @@ -40,3 +42,10 @@ pub struct BuildContext { /// Next.js config rewrites. pub rewrites: Rewrites, } + +#[derive(Debug, Clone)] +pub struct DefineEnv { + pub client: Vec<(String, String)>, + pub edge: Vec<(String, String)>, + pub nodejs: Vec<(String, String)>, +} diff --git a/packages/next-swc/crates/next-build/src/main.rs b/packages/next-swc/crates/next-build/src/main.rs index 58ef81d86a554..84986c4ae7d48 100644 --- a/packages/next-swc/crates/next-build/src/main.rs +++ b/packages/next-swc/crates/next-build/src/main.rs @@ -104,6 +104,7 @@ async fn main_inner() -> Result<()> { full_stats: args.full_stats, build_context: None, dist_dir: args.dist_dir, + define_env: unimplemented!("this is passed directly from next.js to rust"), }) .await } diff --git a/packages/next-swc/crates/next-build/src/next_build.rs b/packages/next-swc/crates/next-build/src/next_build.rs index 27713ab28f2e0..1e048ccd5bd5e 100644 --- a/packages/next-swc/crates/next-build/src/next_build.rs +++ b/packages/next-swc/crates/next-build/src/next_build.rs @@ -7,7 +7,6 @@ use std::{ use anyhow::{Context, Result}; use dunce::canonicalize; use next_core::{ - app_structure::find_app_dir_if_enabled, mode::NextMode, next_app::get_app_client_references_chunks, next_client::{get_client_chunking_context, get_client_compile_time_info}, @@ -26,7 +25,7 @@ use next_core::{ use serde::Serialize; use turbo_tasks::{ graph::{AdjacencyMap, GraphTraversal}, - Completion, Completions, TransientInstance, TryJoinIterExt, ValueToString, Vc, + Completion, Completions, TransientInstance, TryJoinIterExt, Vc, }; use turbopack_binding::{ turbo::tasks_fs::{rebase, DiskFileSystem, FileContent, FileSystem, FileSystemPath}, @@ -133,15 +132,14 @@ pub(crate) async fn next_build(options: TransientInstance) -> Resu let next_config = load_next_config(execution_context.with_layer("next_config".to_string())); let mode = NextMode::Build; - let app_dir = find_app_dir_if_enabled(project_root); - let client_compile_time_info = get_client_compile_time_info( - mode, - browserslist_query, - node_root.to_string(), - next_config, - app_dir, - ); - let server_compile_time_info = get_server_compile_time_info(mode, env, ServerAddr::empty()); + + let client_define_env = Vc::cell(options.define_env.client.iter().cloned().collect()); + let client_compile_time_info = + get_client_compile_time_info(mode, browserslist_query, client_define_env); + + let server_define_env = Vc::cell(options.define_env.nodejs.iter().cloned().collect()); + let server_compile_time_info = + get_server_compile_time_info(mode, env, ServerAddr::empty(), server_define_env); // TODO(alexkirsz) Pages should build their own routes, outside of a FS. let next_router_fs = Vc::upcast::>(VirtualFileSystem::new()); diff --git a/packages/next-swc/crates/next-core/src/app_structure.rs b/packages/next-swc/crates/next-core/src/app_structure.rs index 326edcdad30f4..17e46688224b6 100644 --- a/packages/next-swc/crates/next-core/src/app_structure.rs +++ b/packages/next-swc/crates/next-core/src/app_structure.rs @@ -8,8 +8,8 @@ use indexmap::{ }; use serde::{Deserialize, Serialize}; use turbo_tasks::{ - debug::ValueDebugFormat, trace::TraceRawVcs, Completion, Completions, TaskInput, ValueDefault, - ValueToString, Vc, + debug::ValueDebugFormat, trace::TraceRawVcs, Completion, Completions, TaskInput, ValueToString, + Vc, }; use turbopack_binding::{ turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPath}, @@ -475,26 +475,6 @@ pub enum Entrypoint { #[turbo_tasks::value(transparent)] pub struct Entrypoints(IndexMap); -#[turbo_tasks::value_impl] -impl Entrypoints { - #[turbo_tasks::function] - pub fn paths(&self) -> Vc { - Vc::cell(self.0.keys().cloned().collect()) - } -} - -#[turbo_tasks::value(transparent)] -#[derive(Default)] -pub struct EntrypointPaths(Vec); - -#[turbo_tasks::value_impl] -impl ValueDefault for EntrypointPaths { - #[turbo_tasks::function] - fn value_default() -> Vc { - Self::default().cell() - } -} - fn is_parallel_route(name: &str) -> bool { name.starts_with('@') } diff --git a/packages/next-swc/crates/next-core/src/next_app/bloom_filter.rs b/packages/next-swc/crates/next-core/src/next_app/bloom_filter.rs deleted file mode 100644 index 286f82949f02f..0000000000000 --- a/packages/next-swc/crates/next-core/src/next_app/bloom_filter.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::{collections::HashSet, f64::consts::LN_2}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - next_app::{AppPage, AppPath, PageSegment, PathSegment}, - next_config::Redirect, -}; - -pub struct ClientRouterFilter { - pub static_filter: BloomFilter, - pub dynamic_filter: BloomFilter, -} - -pub fn create_client_router_filter( - paths: &[AppPath], - redirects: &[Redirect], - allowed_error_rate: Option, -) -> ClientRouterFilter { - let mut static_paths = HashSet::new(); - let mut dynamic_paths = HashSet::new(); - - for path in paths { - if path.is_dynamic() { - let mut sub_path = AppPath::default(); - - for segment in path.iter() { - if !matches!(segment, PathSegment::Static(_)) { - break; - } - - sub_path.0.push(segment.clone()); - } - - if !sub_path.is_empty() { - dynamic_paths.insert(sub_path.to_string()); - } - } else { - static_paths.insert(path.to_string()); - } - } - - for redirect in redirects { - let app_page = AppPage::parse(&redirect.source).unwrap_or_default(); - - if app_page - .iter() - .all(|token| matches!(token, PageSegment::Static(_))) - { - static_paths.insert(app_page.to_string()); - } - } - - let static_filter = BloomFilter::from(static_paths.iter(), allowed_error_rate.unwrap_or(0.01)); - let dynamic_filter = - BloomFilter::from(dynamic_paths.iter(), allowed_error_rate.unwrap_or(0.01)); - - ClientRouterFilter { - static_filter, - dynamic_filter, - } -} - -// minimal implementation MurmurHash2 hash function -fn murmurhash2(s: &str) -> u32 { - const M: u32 = 0x5bd1e995; - - let mut h: u32 = 0; - for &b in s.as_bytes() { - h = (h ^ b as u32).wrapping_mul(M); - h ^= h >> 13; - h = h.wrapping_mul(M); - } - - h -} - -#[cfg(test)] -mod test { - use crate::next_app::{ - bloom_filter::{create_client_router_filter, murmurhash2, BloomFilter}, - AppPath, PathSegment, - }; - - // testing that we get the same output as the javascript implementation. - #[test] - fn test_murmurhash2() { - assert_eq!(murmurhash2("/"), 4097004964); - assert_eq!(murmurhash2("/test"), 3006934538); - assert_eq!(murmurhash2("/test/route/123/long/as/heck"), 3187325762); - assert_eq!( - murmurhash2("/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - 2001750934 - ); - } - - // testing that we get the same output as the javascript implementation. - #[test] - fn test_create_client_router_filter() { - let app_paths = &[ - AppPath(vec![]), - AppPath(vec![PathSegment::Static("favicon.ico".to_string())]), - AppPath(vec![PathSegment::Static("_not-found".to_string())]), - AppPath(vec![PathSegment::Static("app".to_string())]), - ]; - - assert_eq!( - create_client_router_filter(app_paths, &[], None).static_filter, - BloomFilter { - num_items: 4, - error_rate: 0.01, - num_bits: 39, - num_hashes: 7, - bit_array: vec![ - 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1 - ] - } - ) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct BloomFilter { - num_items: usize, - error_rate: f64, - num_bits: usize, - num_hashes: usize, - bit_array: Vec, -} - -impl BloomFilter { - pub fn new(num_items: usize, error_rate: f64) -> Self { - let num_bits = (-(num_items as f64 * error_rate.ln()) / LN_2.powi(2)).ceil() as usize; - let num_hashes = ((num_bits as f64 / num_items as f64) * LN_2).ceil() as usize; - let bit_array = vec![0; num_bits]; - - BloomFilter { - num_items, - error_rate, - num_bits, - num_hashes, - bit_array, - } - } - - pub fn from<'a>(items: impl IntoIterator, error_rate: f64) -> Self { - let items = items.into_iter().collect::>(); - - let mut filter = Self::new(items.len(), error_rate); - for item in items { - filter.add(item) - } - filter - } - - pub fn add(&mut self, item: &str) { - let hash_values = self.get_hash_values(item); - hash_values.iter().for_each(|&hash| { - self.bit_array[hash] = 1; - }); - } - - pub fn contains(&self, item: &str) -> bool { - let hash_values = self.get_hash_values(item); - hash_values.iter().all(|&hash| self.bit_array[hash] == 1) - } - - fn get_hash_values(&self, item: &str) -> Vec { - let mut hash_values = Vec::new(); - - for i in 1..self.num_hashes + 1 { - let hash = murmurhash2(&format!("{item}{i}")) as usize % self.num_bits; - hash_values.push(hash); - } - - hash_values - } -} diff --git a/packages/next-swc/crates/next-core/src/next_app/mod.rs b/packages/next-swc/crates/next-core/src/next_app/mod.rs index d0f5910f4c282..58ffdcfb4ba18 100644 --- a/packages/next-swc/crates/next-core/src/next_app/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_app/mod.rs @@ -3,7 +3,6 @@ pub mod app_client_shared_chunks; pub mod app_entry; pub mod app_page_entry; pub mod app_route_entry; -pub mod bloom_filter; pub mod metadata; use std::{ diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 6ac20e0580221..f36bda773e70f 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -1,15 +1,20 @@ use core::result::Result::Ok; use anyhow::Result; +use indexmap::IndexMap; use turbo_tasks::{Value, Vc}; use turbo_tasks_fs::FileSystem; use turbopack_binding::{ - turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath}, + turbo::{ + tasks_env::{EnvMap, ProcessEnv}, + tasks_fs::FileSystemPath, + }, turbopack::{ core::{ compile_time_defines, compile_time_info::{ - CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences, + CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, FreeVarReference, + FreeVarReferences, }, environment::{BrowserEnvironment, Environment, ExecutionEnvironment}, free_var_references, @@ -34,12 +39,10 @@ use turbopack_binding::{ use super::transforms::get_next_client_transforms_rules; use crate::{ - app_structure::{get_entrypoints, EntrypointPaths, OptionAppDir}, babel::maybe_add_babel_loader, embed_js::next_js_fs, env::env_for_js, mode::NextMode, - next_app::{bloom_filter::create_client_router_filter, AppPath}, next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping}, next_client::runtime_entry::{RuntimeEntries, RuntimeEntry}, next_config::NextConfig, @@ -67,82 +70,40 @@ use crate::{ util::foreign_code_context_condition, }; -fn defines( - mode: NextMode, - dist_root_path: &str, - next_config: &NextConfig, - app_paths: &[AppPath], -) -> Result { - let filter = create_client_router_filter( - app_paths, - if next_config - .experimental - .client_router_filter_redirects - .unwrap_or_default() - { - next_config - .original_redirects - .as_deref() - .unwrap_or_default() - } else { - &[] - }, - next_config.experimental.client_router_filter_allowed_rate, - ); - - // TODO: macro may need to allow dynamically expand from some iterable values - // TODO(WEB-937): there are more defines needed, see - // packages/next/src/build/webpack/plugins/define-env-plugin.ts - Ok(compile_time_defines!( - process.browser = true, +fn defines(mode: NextMode, define_env: &IndexMap) -> CompileTimeDefines { + // Need the empty NEXT_RUNTIME here for compile time evaluation. + let mut defines = compile_time_defines!( process.turbopack = true, - process.env.TURBOPACK = true, + process.env.NEXT_RUNTIME = "", process.env.NODE_ENV = mode.node_env(), - process.env.NEXT_RUNTIME = "".to_string(), - process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED = next_config - .experimental - .client_router_filter - .unwrap_or_default(), - process.env.__NEXT_CLIENT_ROUTER_S_FILTER = serde_json::to_value(&filter.static_filter)?, - process.env.__NEXT_CLIENT_ROUTER_D_FILTER = serde_json::to_value(&filter.dynamic_filter)?, - process.env.__NEXT_DIST_DIR = dist_root_path.to_string(), - process.env.__NEXT_HAS_REWRITES = true, - )) + process.env.TURBOPACK = true, + ); + + for (k, v) in define_env { + defines + .0 + .entry(k.split('.').map(|s| s.to_string()).collect()) + .or_insert_with(|| CompileTimeDefineValue::JSON(v.clone())); + } + + defines } #[turbo_tasks::function] async fn next_client_defines( mode: NextMode, - dist_root_path: Vc, - next_config: Vc, - app_paths: Vc, + define_env: Vc, ) -> Result> { - let dist_root_path = &*dist_root_path.await?; - Ok(defines( - mode, - dist_root_path.as_str(), - &*next_config.await?, - &app_paths.await?, - )? - .cell()) + Ok(defines(mode, &*define_env.await?).cell()) } #[turbo_tasks::function] async fn next_client_free_vars( mode: NextMode, - dist_root_path: Vc, - next_config: Vc, - app_paths: Vc, + define_env: Vc, ) -> Result> { - let dist_root_path = &*dist_root_path.await?; Ok(free_var_references!( - ..defines( - mode, - dist_root_path.as_str(), - &*next_config.await?, - &app_paths.await? - )? - .into_iter(), + ..defines(mode, &*define_env.await?).into_iter(), Buffer = FreeVarReference::EcmaScriptModule { request: "node:buffer".to_string(), lookup_path: None, @@ -157,28 +118,12 @@ async fn next_client_free_vars( .cell()) } -#[turbo_tasks::function] -async fn get_app_paths( - app_dir: Vc, - next_config: Vc, -) -> Result> { - Ok(if let Some(app_dir) = *app_dir.await? { - get_entrypoints(app_dir, next_config.page_extensions()).paths() - } else { - Default::default() - }) -} - #[turbo_tasks::function] pub fn get_client_compile_time_info( mode: NextMode, browserslist_query: String, - dist_root_path: Vc, - next_config: Vc, - app_dir: Vc, + define_env: Vc, ) -> Vc { - let app_paths = get_app_paths(app_dir, next_config); - CompileTimeInfo::builder(Environment::new(Value::new(ExecutionEnvironment::Browser( BrowserEnvironment { dom: true, @@ -188,18 +133,8 @@ pub fn get_client_compile_time_info( } .into(), )))) - .defines(next_client_defines( - mode, - dist_root_path, - next_config, - app_paths, - )) - .free_var_references(next_client_free_vars( - mode, - dist_root_path, - next_config, - app_paths, - )) + .defines(next_client_defines(mode, define_env)) + .free_var_references(next_client_free_vars(mode, define_env)) .cell() } diff --git a/packages/next-swc/crates/next-core/src/next_edge/context.rs b/packages/next-swc/crates/next-core/src/next_edge/context.rs index 161948773231b..95042352da22c 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/context.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/context.rs @@ -1,12 +1,14 @@ use anyhow::Result; +use indexmap::IndexMap; use turbo_tasks::{Value, Vc}; use turbopack_binding::{ - turbo::tasks_fs::FileSystemPath, + turbo::{tasks_env::EnvMap, tasks_fs::FileSystemPath}, turbopack::{ core::{ compile_time_defines, compile_time_info::{ - CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences, + CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, FreeVarReference, + FreeVarReferences, }, environment::{EdgeWorkerEnvironment, Environment, ExecutionEnvironment, ServerAddr}, free_var_references, @@ -31,46 +33,40 @@ use crate::{ util::foreign_code_context_condition, }; -fn defines(dist_root_path: Option<&str>) -> CompileTimeDefines { - // [TODO] macro may need to allow dynamically expand from some iterable values +fn defines(mode: NextMode, define_env: &IndexMap) -> CompileTimeDefines { let mut defines = compile_time_defines!( process.turbopack = true, - process.env.NODE_ENV = "development", - process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED = false, process.env.NEXT_RUNTIME = "edge", + process.env.NODE_ENV = mode.node_env(), + process.env.TURBOPACK = true, ); - if let Some(dist_root_path) = dist_root_path { - defines.0.insert( - vec![ - "process".to_string(), - "env".to_string(), - "__NEXT_DIST_DIR".to_string(), - ], - dist_root_path.to_string().into(), - ); + for (k, v) in define_env { + defines + .0 + .entry(k.split('.').map(|s| s.to_string()).collect()) + .or_insert_with(|| CompileTimeDefineValue::JSON(v.clone())); } - // TODO(WEB-937) there are more defines needed, see - // packages/next/src/build/webpack-config.ts - defines } #[turbo_tasks::function] -async fn next_edge_defines(dist_root_path: Vc) -> Result> { - let dist_root_path = &*dist_root_path.await?; - Ok(defines(Some(dist_root_path.as_str())).cell()) +async fn next_edge_defines( + mode: NextMode, + define_env: Vc, +) -> Result> { + Ok(defines(mode, &*define_env.await?).cell()) } #[turbo_tasks::function] async fn next_edge_free_vars( + mode: NextMode, project_path: Vc, - dist_root_path: Vc, + define_env: Vc, ) -> Result> { - let dist_root_path = &*dist_root_path.await?; Ok(free_var_references!( - ..defines(Some(dist_root_path.as_str())).into_iter(), + ..defines(mode, &*define_env.await?).into_iter(), Buffer = FreeVarReference::EcmaScriptModule { request: "next/dist/compiled/buffer".to_string(), lookup_path: Some(project_path), @@ -87,15 +83,16 @@ async fn next_edge_free_vars( #[turbo_tasks::function] pub fn get_edge_compile_time_info( + mode: NextMode, project_path: Vc, server_addr: Vc, - dist_root_path: Vc, + define_env: Vc, ) -> Vc { CompileTimeInfo::builder(Environment::new(Value::new( ExecutionEnvironment::EdgeWorker(EdgeWorkerEnvironment { server_addr }.into()), ))) - .defines(next_edge_defines(dist_root_path)) - .free_var_references(next_edge_free_vars(project_path, dist_root_path)) + .defines(next_edge_defines(mode, define_env)) + .free_var_references(next_edge_free_vars(mode, project_path, define_env)) .cell() } diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index 0a4b2c4aaeecc..ba08f19d0cc04 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -1,13 +1,19 @@ use anyhow::Result; +use indexmap::IndexMap; use turbo_tasks::{Value, Vc}; use turbo_tasks_fs::FileSystem; use turbopack_binding::{ - turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath}, + turbo::{ + tasks_env::{EnvMap, ProcessEnv}, + tasks_fs::FileSystemPath, + }, turbopack::{ build::{BuildChunkingContext, MinifyType}, core::{ compile_time_defines, - compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReferences}, + compile_time_info::{ + CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, FreeVarReferences, + }, environment::{Environment, ExecutionEnvironment, NodeJsEnvironment, ServerAddr}, free_var_references, resolve::{parse::Request, pattern::Pattern}, @@ -174,26 +180,38 @@ pub async fn get_server_resolve_options_context( .cell()) } -fn defines(mode: NextMode) -> CompileTimeDefines { - compile_time_defines!( +fn defines(mode: NextMode, define_env: &IndexMap) -> CompileTimeDefines { + let mut defines = compile_time_defines!( process.turbopack = true, - process.env.NODE_ENV = mode.node_env(), - process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED = false, process.env.NEXT_RUNTIME = "nodejs", - process.env.__NEXT_EXPERIMENTAL_REACT = false, - ) - // TODO(WEB-937) there are more defines needed, see - // packages/next/src/build/webpack-config.ts + process.env.NODE_ENV = mode.node_env(), + process.env.TURBOPACK = true, + ); + + for (k, v) in define_env { + defines + .0 + .entry(k.split('.').map(|s| s.to_string()).collect()) + .or_insert_with(|| CompileTimeDefineValue::JSON(v.clone())); + } + + defines } #[turbo_tasks::function] -fn next_server_defines(mode: NextMode) -> Vc { - defines(mode).cell() +async fn next_server_defines( + mode: NextMode, + define_env: Vc, +) -> Result> { + Ok(defines(mode, &*define_env.await?).cell()) } #[turbo_tasks::function] -async fn next_server_free_vars(mode: NextMode) -> Result> { - Ok(free_var_references!(..defines(mode).into_iter()).cell()) +async fn next_server_free_vars( + mode: NextMode, + define_env: Vc, +) -> Result> { + Ok(free_var_references!(..defines(mode, &*define_env.await?).into_iter()).cell()) } #[turbo_tasks::function] @@ -201,12 +219,13 @@ pub fn get_server_compile_time_info( mode: NextMode, process_env: Vc>, server_addr: Vc, + define_env: Vc, ) -> Vc { CompileTimeInfo::builder(Environment::new(Value::new( ExecutionEnvironment::NodeJsLambda(NodeJsEnvironment::current(process_env, server_addr)), ))) - .defines(next_server_defines(mode)) - .free_var_references(next_server_free_vars(mode)) + .defines(next_server_defines(mode, define_env)) + .free_var_references(next_server_free_vars(mode, define_env)) .cell() } diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 3a25959f00a25..210a5034ff642 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -122,6 +122,7 @@ import { teardownCrashReporter, loadBindings, teardownHeapProfiler, + createDefineEnv, } from './swc' import { getNamedRouteRegex } from '../shared/lib/router/utils/route-regex' import { flatReaddir } from '../lib/flat-readdir' @@ -1005,10 +1006,28 @@ export default async function build( : packagePath ? path.dirname(packagePath) : undefined) + + const hasRewrites = + rewrites.beforeFiles.length > 0 || + rewrites.afterFiles.length > 0 || + rewrites.fallback.length > 0 + await binding.turbo.nextBuild({ ...NextBuildContext, root, distDir: config.distDir, + defineEnv: createDefineEnv({ + allowedRevalidateHeaderKeys: + config.experimental.allowedRevalidateHeaderKeys, + clientRouterFilters: NextBuildContext.clientRouterFilters, + config, + dev: false, + distDir, + fetchCacheKeyPrefix: config.experimental.fetchCacheKeyPrefix, + hasRewrites, + middlewareMatchers: undefined, + previewModeId: undefined, + }), }) const [duration] = process.hrtime(turboNextBuildStart) diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index b9cb4c7b2ad34..e5df379581b33 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -10,6 +10,10 @@ import { patchIncorrectLockfile } from '../../lib/patch-incorrect-lockfile' import { downloadWasmSwc, downloadNativeNextSwc } from '../../lib/download-swc' import { NextConfigComplete, TurboRule } from '../../server/config-shared' import { isDeepStrictEqual } from 'util' +import { + DefineEnvPluginOptions, + getDefineEnv, +} from '../webpack/plugins/define-env-plugin' const nextVersion = process.env.__NEXT_VERSION as string @@ -365,7 +369,7 @@ function logLoadFailure(attempts: any, triedWasm = false) { }) } -interface ProjectOptions { +export interface ProjectOptions { /** * A root path from which all files must be nested under. Trying to access * a file outside this root will fail. Think of this as a chroot. @@ -398,6 +402,12 @@ interface ProjectOptions { */ env: Record + defineEnv: { + client: Record + edge: Record + nodejs: Record + } + /** * Whether to watch the filesystem for file changes. */ @@ -409,7 +419,57 @@ interface ProjectOptions { serverAddr: string } -interface TurboEngineOptions { +export interface DefineEnv { + client: Record + edge: Record + nodejs: Record +} + +export function createDefineEnv({ + allowedRevalidateHeaderKeys, + clientRouterFilters, + config, + dev, + distDir, + fetchCacheKeyPrefix, + hasRewrites, + middlewareMatchers, + previewModeId, +}: Omit< + DefineEnvPluginOptions, + 'isClient' | 'isNodeOrEdgeCompilation' | 'isEdgeServer' | 'isNodeServer' +>): DefineEnv { + let defineEnv: Record< + 'client' | 'edge' | 'nodejs', + Record + > = { + client: {}, + edge: {}, + nodejs: {}, + } + + for (const variant of Object.keys(defineEnv) as (keyof typeof defineEnv)[]) { + defineEnv[variant] = getDefineEnv({ + allowedRevalidateHeaderKeys, + clientRouterFilters, + config, + dev, + distDir, + fetchCacheKeyPrefix, + hasRewrites, + isClient: variant === 'client', + isEdgeServer: variant === 'edge', + isNodeOrEdgeCompilation: variant === 'nodejs' || variant === 'edge', + isNodeServer: variant === 'nodejs', + middlewareMatchers, + previewModeId, + }) + } + + return defineEnv +} + +export interface TurboEngineOptions { /** * An upper bound of memory that turbopack will attempt to stay under. */ @@ -481,7 +541,7 @@ export interface ServerClientChange { } export interface Project { - update(options: ProjectOptions): Promise + update(options: Partial): Promise entrypointsSubscribe(): AsyncIterableIterator> hmrEvents(identifier: string): AsyncIterableIterator> hmrIdentifiersSubscribe(): AsyncIterableIterator< @@ -687,15 +747,29 @@ function bindingToApi(binding: any, _wasm: boolean) { }) } - async function rustifyProjectOptions(options: ProjectOptions): Promise { - return { - ...options, - nextConfig: await serializeNextConfig(options.nextConfig), - jsConfig: JSON.stringify(options.jsConfig ?? {}), - env: Object.entries(options.env).map(([name, value]) => ({ + function rustifyEnv(env: Record) { + return Object.entries(env) + .filter(([_, value]) => value != null) + .map(([name, value]) => ({ name, value, - })), + })) + } + + async function rustifyProjectOptions( + options: Partial + ): Promise { + return { + ...options, + nextConfig: + options.nextConfig && (await serializeNextConfig(options.nextConfig)), + jsConfig: options.jsConfig && JSON.stringify(options.jsConfig ?? {}), + env: options.env && rustifyEnv(options.env), + defineEnv: options.defineEnv && { + client: rustifyEnv(options.defineEnv.client), + edge: rustifyEnv(options.defineEnv.edge), + nodejs: rustifyEnv(options.defineEnv.nodejs), + }, } } diff --git a/packages/next/src/build/webpack/plugins/define-env-plugin.ts b/packages/next/src/build/webpack/plugins/define-env-plugin.ts index f498d1019d320..1ca36dcf4613c 100644 --- a/packages/next/src/build/webpack/plugins/define-env-plugin.ts +++ b/packages/next/src/build/webpack/plugins/define-env-plugin.ts @@ -6,7 +6,7 @@ import getBaseWebpackConfig, { errorIfEnvConflicted, } from '../../webpack-config' -interface DefineEnvPluginOptions { +export interface DefineEnvPluginOptions { allowedRevalidateHeaderKeys: string[] | undefined clientRouterFilters: Parameters< typeof getBaseWebpackConfig diff --git a/packages/next/src/server/dev/hot-reloader-types.ts b/packages/next/src/server/dev/hot-reloader-types.ts index fb4f3f03e2470..191e4570697d0 100644 --- a/packages/next/src/server/dev/hot-reloader-types.ts +++ b/packages/next/src/server/dev/hot-reloader-types.ts @@ -4,7 +4,7 @@ import type { Duplex } from 'stream' import type { webpack } from 'next/dist/compiled/webpack/webpack' import type getBaseWebpackConfig from '../../build/webpack-config' import type { RouteMatch } from '../future/route-matches/route-match' -import type { Update as TurbopackUpdate } from '../../build/swc' +import type { Project, Update as TurbopackUpdate } from '../../build/swc' import type { VersionInfo } from './parse-version-info' export const enum HMR_ACTIONS_SENT_TO_BROWSER { @@ -107,6 +107,7 @@ export type HMR_ACTION_TYPES = | ServerErrorAction export interface NextJsHotReloaderInterface { + turbopackProject?: Project activeWebpackConfigs?: Array>> serverStats: webpack.Stats | null edgeServerStats: webpack.Stats | null diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev.ts index a96c809ce21b5..595177bc16cf1 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev.ts @@ -7,6 +7,7 @@ import { ServerClientChange, ServerClientChangeType, Issue, + createDefineEnv, } from '../../../build/swc' import type { Socket } from 'net' import ws from 'next/dist/compiled/ws' @@ -209,6 +210,11 @@ async function startWatcher(opts: SetupOpts) { }) } + const hasRewrites = + opts.fsChecker.rewrites.afterFiles.length > 0 || + opts.fsChecker.rewrites.beforeFiles.length > 0 || + opts.fsChecker.rewrites.fallback.length > 0 + const project = await bindings.turbo.createProject({ projectPath: dir, rootPath: opts.nextConfig.experimental.outputFileTracingRoot || dir, @@ -216,6 +222,17 @@ async function startWatcher(opts: SetupOpts) { jsConfig, watch: true, env: process.env as Record, + defineEnv: createDefineEnv({ + allowedRevalidateHeaderKeys: undefined, + clientRouterFilters: undefined, + config: nextConfig, + dev: false, + distDir, + fetchCacheKeyPrefix: undefined, + hasRewrites, + middlewareMatchers: undefined, + previewModeId: undefined, + }), serverAddr: `127.0.0.1:${opts.port}`, }) const iter = project.entrypointsSubscribe() @@ -966,6 +983,7 @@ async function startWatcher(opts: SetupOpts) { await writeFontManifest() const turbopackHotReloader: NextJsHotReloaderInterface = { + turbopackProject: project, activeWebpackConfigs: undefined, serverStats: null, edgeServerStats: null, @@ -1733,6 +1751,27 @@ async function startWatcher(opts: SetupOpts) { } } + if (hotReloader.turbopackProject) { + const hasRewrites = + opts.fsChecker.rewrites.afterFiles.length > 0 || + opts.fsChecker.rewrites.beforeFiles.length > 0 || + opts.fsChecker.rewrites.fallback.length > 0 + + await hotReloader.turbopackProject.update({ + defineEnv: createDefineEnv({ + allowedRevalidateHeaderKeys: undefined, + clientRouterFilters, + config: nextConfig, + dev: false, + distDir, + fetchCacheKeyPrefix: undefined, + hasRewrites, + middlewareMatchers: undefined, + previewModeId: undefined, + }), + }) + } + hotReloader.activeWebpackConfigs?.forEach((config, idx) => { const isClient = idx === 0 const isNodeServer = idx === 1 From 876a0261e9bc36da4c5e7be268b1715e04d8206d Mon Sep 17 00:00:00 2001 From: hrmny Date: Fri, 29 Sep 2023 17:09:30 +0200 Subject: [PATCH 02/11] remove `next-build` binary --- Cargo.lock | 1 - .../next-swc/crates/next-build/Cargo.toml | 10 +- .../next-swc/crates/next-build/src/main.rs | 110 ------------------ 3 files changed, 1 insertion(+), 120 deletions(-) delete mode 100644 packages/next-swc/crates/next-build/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index a02bfb9037404..8cfe024974653 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3378,7 +3378,6 @@ dependencies = [ "anyhow", "async-recursion", "base64 0.21.4", - "clap 4.4.2", "console-subscriber", "dunce", "indexmap 1.9.3", diff --git a/packages/next-swc/crates/next-build/Cargo.toml b/packages/next-swc/crates/next-build/Cargo.toml index 042b1eb1943cb..146b2eb3412c6 100644 --- a/packages/next-swc/crates/next-build/Cargo.toml +++ b/packages/next-swc/crates/next-build/Cargo.toml @@ -6,12 +6,6 @@ license = "MPL-2.0" edition = "2021" autobenches = false -[[bin]] -name = "next-build" -path = "src/main.rs" -bench = false -required-features = ["cli"] - [lib] bench = false @@ -21,8 +15,7 @@ bench = false # `cargo xxx` without explicitly specifying features, not that we want to # promote this as default backend. Actual configuration is done when building next-swc, # and also turbopack standalone when we have it. -default = ["cli", "custom_allocator", "native-tls"] -cli = ["clap"] +default = ["custom_allocator", "native-tls"] tokio_console = [ "dep:console-subscriber", "tokio/tracing", @@ -40,7 +33,6 @@ profile = [] [dependencies] anyhow = { workspace = true } async-recursion = { workspace = true } -clap = { workspace = true, features = ["derive", "env"], optional = true } console-subscriber = { workspace = true, optional = true } dunce = { workspace = true } next-core = { workspace = true } diff --git a/packages/next-swc/crates/next-build/src/main.rs b/packages/next-swc/crates/next-build/src/main.rs deleted file mode 100644 index 84986c4ae7d48..0000000000000 --- a/packages/next-swc/crates/next-build/src/main.rs +++ /dev/null @@ -1,110 +0,0 @@ -#![feature(arbitrary_self_types)] -#![feature(async_fn_in_trait)] - -use std::path::PathBuf; - -use anyhow::Result; -use clap::Parser; -use next_build::BuildOptions; -use turbopack_binding::turbopack::cli_utils::issue::IssueSeverityCliOption; - -#[global_allocator] -static ALLOC: turbopack_binding::turbo::malloc::TurboMalloc = - turbopack_binding::turbo::malloc::TurboMalloc; - -#[derive(Debug, Parser)] -#[clap(author, version, about, long_about = None)] -pub struct BuildCliArgs { - /// The directory of the Next.js application. - /// If no directory is provided, the current directory will be used. - #[clap(value_parser)] - pub dir: Option, - - /// The root directory of the project. Nothing outside of this directory can - /// be accessed. e. g. the monorepo root. - /// If no directory is provided, `dir` will be used. - #[clap(long, value_parser)] - pub root: Option, - - #[clap(long, value_parser)] - pub dist_dir: Option, - - /// Display version of the binary. Noop if used in library mode. - #[clap(long)] - pub display_version: bool, - - /// Filter by issue severity. - #[clap(short, long)] - pub log_level: Option, - - /// Show all log messages without limit. - #[clap(long)] - pub show_all: bool, - - /// Expand the log details. - #[clap(long)] - pub log_detail: bool, - - /// Whether to enable full task stats recording in Turbo Engine. - #[clap(long)] - pub full_stats: bool, - - /// Enable experimental garbage collection with the provided memory limit in - /// MB. - #[clap(long)] - pub memory_limit: Option, -} - -fn main() { - use turbopack_binding::turbo::malloc::TurboMalloc; - - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .on_thread_stop(|| { - TurboMalloc::thread_stop(); - }) - .build() - .unwrap() - .block_on(main_inner()) - .unwrap() -} - -async fn main_inner() -> Result<()> { - let args = BuildCliArgs::parse(); - - if args.display_version { - // Note: enabling git causes trouble with aarch64 linux builds with libz-sys - println!( - "Build Timestamp\t\t{:#?}", - option_env!("VERGEN_BUILD_TIMESTAMP").unwrap_or_else(|| "N/A") - ); - println!( - "Build Version\t\t{:#?}", - option_env!("VERGEN_BUILD_SEMVER").unwrap_or_else(|| "N/A") - ); - println!( - "Cargo Target Triple\t{:#?}", - option_env!("VERGEN_CARGO_TARGET_TRIPLE").unwrap_or_else(|| "N/A") - ); - println!( - "Cargo Profile\t\t{:#?}", - option_env!("VERGEN_CARGO_PROFILE").unwrap_or_else(|| "N/A") - ); - - return Ok(()); - } - - next_build::build(BuildOptions { - dir: args.dir, - root: args.root, - memory_limit: args.memory_limit, - log_level: args.log_level.map(|l| l.0), - show_all: args.show_all, - log_detail: args.log_detail, - full_stats: args.full_stats, - build_context: None, - dist_dir: args.dist_dir, - define_env: unimplemented!("this is passed directly from next.js to rust"), - }) - .await -} From e4cd752fa5347d3ca8ca26a9d7fec64a6499de80 Mon Sep 17 00:00:00 2001 From: hrmny Date: Fri, 29 Sep 2023 17:33:50 +0200 Subject: [PATCH 03/11] fix test --- test/development/basic/next-rs-api.test.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/development/basic/next-rs-api.test.ts b/test/development/basic/next-rs-api.test.ts index c8b0e604152b1..7d1fdb34adfbb 100644 --- a/test/development/basic/next-rs-api.test.ts +++ b/test/development/basic/next-rs-api.test.ts @@ -2,6 +2,7 @@ import { NextInstance, createNext } from 'e2e-utils' import { trace } from 'next/src/trace' import { PHASE_DEVELOPMENT_SERVER } from 'next/constants' import { + createDefineEnv, Diagnostics, Entrypoints, Issue, @@ -173,6 +174,22 @@ describe('next.rs api', () => { : next.testDir, watch: true, serverAddr: `127.0.0.1:3000`, + defineEnv: createDefineEnv({ + allowedRevalidateHeaderKeys: undefined, + clientRouterFilters: undefined, + config: nextConfig, + dev: true, + distDir: path.join( + process.env.NEXT_SKIP_ISOLATE + ? path.resolve(__dirname, '../../..') + : next.testDir, + '.next' + ), + fetchCacheKeyPrefix: undefined, + hasRewrites: false, + middlewareMatchers: undefined, + previewModeId: undefined, + }), }) projectUpdateSubscription = project.updateInfoSubscribe() }) From 64d0fbc21934bf60f1fad4a58bea1f4f62fb2ed2 Mon Sep 17 00:00:00 2001 From: hrmny Date: Fri, 29 Sep 2023 17:41:05 +0200 Subject: [PATCH 04/11] fix types a bit --- packages/next/src/build/load-jsconfig.ts | 2 +- packages/next/src/build/swc/index.ts | 2 +- packages/next/src/server/lib/router-utils/setup-dev.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next/src/build/load-jsconfig.ts b/packages/next/src/build/load-jsconfig.ts index c865463f977a5..e86824c84d30c 100644 --- a/packages/next/src/build/load-jsconfig.ts +++ b/packages/next/src/build/load-jsconfig.ts @@ -58,7 +58,7 @@ export default async function loadJsConfig( ) let implicitBaseurl - let jsConfig + let jsConfig: { compilerOptions: Record } | undefined // jsconfig is a subset of tsconfig if (useTypeScript) { if ( diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index e5df379581b33..9540d991beb93 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -763,7 +763,7 @@ function bindingToApi(binding: any, _wasm: boolean) { ...options, nextConfig: options.nextConfig && (await serializeNextConfig(options.nextConfig)), - jsConfig: options.jsConfig && JSON.stringify(options.jsConfig ?? {}), + jsConfig: options.jsConfig && JSON.stringify(options.jsConfig), env: options.env && rustifyEnv(options.env), defineEnv: options.defineEnv && { client: rustifyEnv(options.defineEnv.client), diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev.ts index 595177bc16cf1..e47ff4a0e19d3 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev.ts @@ -219,7 +219,7 @@ async function startWatcher(opts: SetupOpts) { projectPath: dir, rootPath: opts.nextConfig.experimental.outputFileTracingRoot || dir, nextConfig: opts.nextConfig, - jsConfig, + jsConfig: jsConfig ?? { compilerOptions: {} }, watch: true, env: process.env as Record, defineEnv: createDefineEnv({ From 65aed0d98383b134e976c0a1631f3359feccc072 Mon Sep 17 00:00:00 2001 From: hrmny Date: Mon, 2 Oct 2023 17:15:44 +0200 Subject: [PATCH 05/11] rustify define env when creating --- packages/next/src/build/swc/index.ts | 81 +++++++++++++--------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 9540d991beb93..6accfadab603c 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -402,11 +402,7 @@ export interface ProjectOptions { */ env: Record - defineEnv: { - client: Record - edge: Record - nodejs: Record - } + defineEnv: DefineEnv /** * Whether to watch the filesystem for file changes. @@ -419,10 +415,12 @@ export interface ProjectOptions { serverAddr: string } +type RustifiedEnv = { name: string; value: string }[] + export interface DefineEnv { - client: Record - edge: Record - nodejs: Record + client: RustifiedEnv + edge: RustifiedEnv + nodejs: RustifiedEnv } export function createDefineEnv({ @@ -439,31 +437,30 @@ export function createDefineEnv({ DefineEnvPluginOptions, 'isClient' | 'isNodeOrEdgeCompilation' | 'isEdgeServer' | 'isNodeServer' >): DefineEnv { - let defineEnv: Record< - 'client' | 'edge' | 'nodejs', - Record - > = { - client: {}, - edge: {}, - nodejs: {}, + let defineEnv: DefineEnv = { + client: [], + edge: [], + nodejs: [], } for (const variant of Object.keys(defineEnv) as (keyof typeof defineEnv)[]) { - defineEnv[variant] = getDefineEnv({ - allowedRevalidateHeaderKeys, - clientRouterFilters, - config, - dev, - distDir, - fetchCacheKeyPrefix, - hasRewrites, - isClient: variant === 'client', - isEdgeServer: variant === 'edge', - isNodeOrEdgeCompilation: variant === 'nodejs' || variant === 'edge', - isNodeServer: variant === 'nodejs', - middlewareMatchers, - previewModeId, - }) + defineEnv[variant] = rustifyEnv( + getDefineEnv({ + allowedRevalidateHeaderKeys, + clientRouterFilters, + config, + dev, + distDir, + fetchCacheKeyPrefix, + hasRewrites, + isClient: variant === 'client', + isEdgeServer: variant === 'edge', + isNodeOrEdgeCompilation: variant === 'nodejs' || variant === 'edge', + isNodeServer: variant === 'nodejs', + middlewareMatchers, + previewModeId, + }) + ) } return defineEnv @@ -623,6 +620,15 @@ export type WrittenEndpoint = config: EndpointConfig } +function rustifyEnv(env: Record): RustifiedEnv { + return Object.entries(env) + .filter(([_, value]) => value != null) + .map(([name, value]) => ({ + name, + value, + })) +} + // TODO(sokra) Support wasm option. function bindingToApi(binding: any, _wasm: boolean) { type NativeFunction = ( @@ -747,15 +753,6 @@ function bindingToApi(binding: any, _wasm: boolean) { }) } - function rustifyEnv(env: Record) { - return Object.entries(env) - .filter(([_, value]) => value != null) - .map(([name, value]) => ({ - name, - value, - })) - } - async function rustifyProjectOptions( options: Partial ): Promise { @@ -765,11 +762,7 @@ function bindingToApi(binding: any, _wasm: boolean) { options.nextConfig && (await serializeNextConfig(options.nextConfig)), jsConfig: options.jsConfig && JSON.stringify(options.jsConfig), env: options.env && rustifyEnv(options.env), - defineEnv: options.defineEnv && { - client: rustifyEnv(options.defineEnv.client), - edge: rustifyEnv(options.defineEnv.edge), - nodejs: rustifyEnv(options.defineEnv.nodejs), - }, + defineEnv: options.defineEnv, } } From ee9e0bff04d2ca1a99e6139d6288830629bdf2e9 Mon Sep 17 00:00:00 2001 From: hrmny Date: Mon, 2 Oct 2023 18:53:05 +0200 Subject: [PATCH 06/11] remove old env injection --- packages/next-swc/crates/next-api/src/app.rs | 6 - .../crates/next-api/src/middleware.rs | 3 - .../next-swc/crates/next-api/src/pages.rs | 7 - .../next-build/src/next_app/app_entries.rs | 11 +- .../crates/next-build/src/next_build.rs | 2 - .../next-build/src/next_pages/page_entries.rs | 7 +- packages/next-swc/crates/next-core/src/env.rs | 358 ------------------ packages/next-swc/crates/next-core/src/lib.rs | 1 - .../next-core/src/next_client/context.rs | 21 +- .../next-core/src/next_server/context.rs | 11 +- 10 files changed, 6 insertions(+), 421 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/src/env.rs diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index 3736b5bba9d49..67c86707803ee 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -295,13 +295,8 @@ impl AppProject { async fn runtime_entries(self: Vc) -> Result> { let this = self.await?; Ok(get_server_runtime_entries( - self.project().project_path(), - // TODO(alexkirsz) Should we pass env here or EnvMap::empty, as is done in - // app_source? - self.project().env(), Value::new(self.rsc_ty()), this.mode, - self.project().next_config(), )) } @@ -330,7 +325,6 @@ impl AppProject { let this = self.await?; Ok(get_client_runtime_entries( self.project().project_path(), - self.client_env(), Value::new(self.client_ty()), this.mode, self.project().next_config(), diff --git a/packages/next-swc/crates/next-api/src/middleware.rs b/packages/next-swc/crates/next-api/src/middleware.rs index ff99ef73c44d7..b86185ccb80ec 100644 --- a/packages/next-swc/crates/next-api/src/middleware.rs +++ b/packages/next-swc/crates/next-api/src/middleware.rs @@ -68,11 +68,8 @@ impl MiddlewareEndpoint { ); let mut evaluatable_assets = get_server_runtime_entries( - self.project.project_path(), - self.project.env(), Value::new(ServerContextType::Middleware), NextMode::Development, - self.project.next_config(), ) .resolve_entries(self.context) .await? diff --git a/packages/next-swc/crates/next-api/src/pages.rs b/packages/next-swc/crates/next-api/src/pages.rs index 3e99b4c259300..b4e5ec17bc77e 100644 --- a/packages/next-swc/crates/next-api/src/pages.rs +++ b/packages/next-swc/crates/next-api/src/pages.rs @@ -406,7 +406,6 @@ impl PagesProject { let this = self.await?; let client_runtime_entries = get_client_runtime_entries( self.project().project_path(), - self.project().env(), Value::new(ClientContextType::Pages { pages_dir: self.pages_dir(), }), @@ -421,13 +420,10 @@ impl PagesProject { async fn runtime_entries(self: Vc) -> Result> { let this = self.await?; Ok(get_server_runtime_entries( - self.project().project_path(), - self.project().env(), Value::new(ServerContextType::Pages { pages_dir: self.pages_dir(), }), this.mode, - self.project().next_config(), )) } @@ -435,13 +431,10 @@ impl PagesProject { async fn data_runtime_entries(self: Vc) -> Result> { let this = self.await?; Ok(get_server_runtime_entries( - self.project().project_path(), - self.project().env(), Value::new(ServerContextType::PagesData { pages_dir: self.pages_dir(), }), this.mode, - self.project().next_config(), )) } diff --git a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs index b9d3f38217436..55e5766e54481 100644 --- a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs +++ b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs @@ -23,10 +23,7 @@ use next_core::{ }; use turbo_tasks::{TryJoinIterExt, Value, Vc}; use turbopack_binding::{ - turbo::{ - tasks_env::{CustomProcessEnv, ProcessEnv}, - tasks_fs::FileSystemPath, - }, + turbo::tasks_fs::FileSystemPath, turbopack::{ build::BuildChunkingContext, core::{ @@ -56,7 +53,6 @@ pub struct AppEntries { pub async fn get_app_entries( project_root: Vc, execution_context: Vc, - env: Vc>, client_compile_time_info: Vc, server_compile_time_info: Vc, next_config: Vc, @@ -85,9 +81,7 @@ pub async fn get_app_entries( // TODO(alexkirsz) Should we pass env here or EnvMap::empty, as is done in // app_source? - let runtime_entries = get_server_runtime_entries(project_root, env, rsc_ty, mode, next_config); - - let env = Vc::upcast(CustomProcessEnv::new(env, next_config.env())); + let runtime_entries = get_server_runtime_entries(rsc_ty, mode); let ssr_ty: Value = Value::new(ServerContextType::AppSSR { app_dir }); @@ -228,7 +222,6 @@ pub async fn get_app_entries( let client_runtime_entries = get_client_runtime_entries( project_root, - env, client_ty, mode, next_config, diff --git a/packages/next-swc/crates/next-build/src/next_build.rs b/packages/next-swc/crates/next-build/src/next_build.rs index 1e048ccd5bd5e..d377917c29a3f 100644 --- a/packages/next-swc/crates/next-build/src/next_build.rs +++ b/packages/next-swc/crates/next-build/src/next_build.rs @@ -148,7 +148,6 @@ pub(crate) async fn next_build(options: TransientInstance) -> Resu next_router_root, project_root, execution_context, - env, client_compile_time_info, server_compile_time_info, next_config, @@ -157,7 +156,6 @@ pub(crate) async fn next_build(options: TransientInstance) -> Resu let app_entries = get_app_entries( project_root, execution_context, - env, client_compile_time_info, server_compile_time_info, next_config, diff --git a/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs b/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs index 6124e4d0206d2..bbbe6c9ae3fc6 100644 --- a/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs +++ b/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs @@ -23,7 +23,7 @@ use next_core::{ }; use turbo_tasks::Vc; use turbopack_binding::{ - turbo::{tasks::Value, tasks_env::ProcessEnv, tasks_fs::FileSystemPath}, + turbo::{tasks::Value, tasks_fs::FileSystemPath}, turbopack::{ build::BuildChunkingContext, core::{ @@ -57,7 +57,6 @@ pub async fn get_page_entries( next_router_root: Vc, project_root: Vc, execution_context: Vc, - env: Vc>, client_compile_time_info: Vc, server_compile_time_info: Vc, next_config: Vc, @@ -120,7 +119,6 @@ pub async fn get_page_entries( let client_runtime_entries = get_client_runtime_entries( project_root, - env, client_ty, mode, next_config, @@ -150,8 +148,7 @@ pub async fn get_page_entries( ssr_resolve_options_context, )); - let ssr_runtime_entries = - get_server_runtime_entries(project_root, env, ssr_ty, mode, next_config); + let ssr_runtime_entries = get_server_runtime_entries(ssr_ty, mode); let ssr_runtime_entries = ssr_runtime_entries.resolve_entries(ssr_module_context); let entries = get_page_entries_for_root_directory( diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs deleted file mode 100644 index e020e8773ff1e..0000000000000 --- a/packages/next-swc/crates/next-core/src/env.rs +++ /dev/null @@ -1,358 +0,0 @@ -use anyhow::Result; -use indexmap::indexmap; -use turbo_tasks::Vc; -use turbopack_binding::{ - turbo::tasks_env::{CustomProcessEnv, EnvMap, FilterProcessEnv, ProcessEnv}, - turbopack::env::EmbeddableProcessEnv, -}; - -use crate::next_config::NextConfig; - -/// Creates a Vc> safe to use in JS, by stringifying and -/// encoding as regular JS strings. Setting `client` to true will additionally -/// filter the env to just the keys that are acceptable for the client to -/// access. -/// -/// For now, it also injects overridden values as if they were real JS code, eg -/// an Object and not a String. -#[turbo_tasks::function] -pub async fn env_for_js( - env: Vc>, - client: bool, - next_config: Vc, -) -> Result>> { - let test_mode = env.read("__NEXT_TEST_MODE".to_string()).await?; - let test_mode = test_mode.as_deref().unwrap_or(""); - - let env = if client { - Vc::upcast(FilterProcessEnv::new( - env, - vec![ - "NEXT_PUBLIC_".to_string(), - "NODE_ENV".to_string(), - "PORT".to_string(), - ], - )) - } else { - // Server doesn't need to have env vars injected since it will have them in the - // real process.env. - Vc::upcast(EnvMap::empty()) - }; - - let env = Vc::upcast(EmbeddableProcessEnv::new(Vc::upcast( - CustomProcessEnv::new(env, next_config.env()), - ))); - - let image_config = next_config.image_config().await?; - let mut map = indexmap! { - // We need to overload the __NEXT_IMAGE_OPTS to override the default remotePatterns field. - // This allows us to support loading from remote hostnames until we properly support reading - // the next.config.js file. - "__NEXT_IMAGE_OPTS".to_string() => serde_json::to_string(&image_config)?, - }; - - let next_config = next_config.await?; - - if next_config.react_strict_mode.unwrap_or(false) { - map.insert("__NEXT_STRICT_MODE".to_string(), "true".to_string()); - } - - if next_config.react_strict_mode.unwrap_or(true) { - map.insert("__NEXT_STRICT_MODE_APP".to_string(), "true".to_string()); - } - - map.insert( - "__NEXT_STRICT_NEXT_HEAD".to_string(), - if next_config.experimental.strict_next_head.unwrap_or(false) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_TRAILING_SLASH".to_string(), - if next_config.trailing_slash.unwrap_or(false) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_ROUTER_BASEPATH".to_string(), - // Don't stringify undefined - if let Some(base_path) = next_config.base_path.as_ref() { - serde_json::to_string(base_path)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_ASSET_PREFIX".to_string(), - // Don't stringify undefined - if let Some(asset_prefix) = next_config.asset_prefix.as_ref() { - serde_json::to_string(asset_prefix)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_MANUAL_TRAILING_SLASH".to_string(), - if next_config.skip_trailing_slash_redirect.unwrap_or(false) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_NO_MIDDLEWARE_URL_NORMALIZE".to_string(), - if next_config.skip_middleware_url_normalize.unwrap_or(false) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_EXTERNAL_MIDDLEWARE_REWRITE_RESOLVE".to_string(), - if next_config - .experimental - .external_middleware_rewrites_resolve - .unwrap_or(false) - { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_SCROLL_RESTORATION".to_string(), - if next_config.experimental.scroll_restoration.unwrap_or(false) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_I18N_SUPPORT".to_string(), - if next_config.i18n.is_none() { - "false".to_string() - } else { - "true".to_string() - }, - ); - - map.insert( - "__NEXT_I18N_DOMAINS".to_string(), - // Don't stringify undefined - match next_config.i18n.as_ref() { - Some(i18n) => match i18n.domains.as_ref() { - Some(domains) => serde_json::to_string(domains)?, - None => "undefined".to_string(), - }, - None => "undefined".to_string(), - }, - ); - - map.insert( - "NEXT_MINIMAL".to_string(), - // Don't stringify undefined - "\"\"".to_string(), - ); - - map.insert( - "__NEXT_ACTIONS_DEPLOYMENT_ID".to_string(), - if next_config - .experimental - .use_deployment_id_server_actions - .unwrap_or(false) - { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "NEXT_DEPLOYMENT_ID".to_string(), - // Don't stringify undefined - if let Some(deployment_id) = next_config.experimental.deployment_id.as_ref() { - serde_json::to_string(deployment_id)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_MANUAL_CLIENT_BASE_PATH".to_string(), - if next_config - .experimental - .manual_client_base_path - .unwrap_or(false) - { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_OPTIMISTIC_CLIENT_CACHE".to_string(), - if next_config - .experimental - .optimistic_client_cache - .unwrap_or(false) - { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_MIDDLEWARE_PREFETCH".to_string(), - // Don't stringify undefined - if let Some(middleware_prefetch) = next_config.experimental.middleware_prefetch.as_ref() { - serde_json::to_string(middleware_prefetch)? - } else { - "undefined".to_string() - }, - ); - - // TODO: Implement crossOrigin in Turbopack script injection - map.insert( - "__NEXT_CROSS_ORIGIN".to_string(), - // Don't stringify undefined - if let Some(cross_origin) = next_config.cross_origin.as_ref() { - serde_json::to_string(cross_origin)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_BUILD_INDICATOR".to_string(), - // Don't stringify undefined - match next_config.dev_indicators.as_ref() { - Some(dev_indicators) => match dev_indicators.build_activity.as_ref() { - Some(build_activity) => serde_json::to_string(build_activity)?, - None => "false".to_string(), - }, - None => "false".to_string(), - }, - ); - - map.insert( - "__NEXT_BUILD_INDICATOR_POSITION".to_string(), - // Don't stringify undefined - match next_config.dev_indicators.as_ref() { - Some(dev_indicators) => match dev_indicators.build_activity_position.as_ref() { - Some(build_activity_position) => serde_json::to_string(build_activity_position)?, - None => "undefined".to_string(), - }, - None => "undefined".to_string(), - }, - ); - - map.insert( - "__NEXT_OPTIMIZE_FONTS".to_string(), - if next_config.optimize_fonts.unwrap_or(true) { - "true".to_string() - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_OPTIMIZE_CSS".to_string(), - // Don't stringify undefined - if let Some(optimize_css) = next_config.experimental.optimize_css.as_ref() { - serde_json::to_string(optimize_css)? - } else { - "false".to_string() - }, - ); - - map.insert( - "__NEXT_SCRIPT_WORKERS".to_string(), - // TODO: This should be true in production mode - // if next_config - // .experimental - // .next_script_workers - // .unwrap_or(false) - // { - // "false".to_string() - // } else { - // "false".to_string() - // }, - "false".to_string(), - ); - - map.insert( - "__NEXT_CONFIG_OUTPUT".to_string(), - // Don't stringify undefined - if let Some(output) = next_config.output.as_ref() { - serde_json::to_string(output)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_ANALYTICS_ID".to_string(), - // Don't stringify undefined - if let Some(analytics_id) = next_config.analytics_id.as_ref() { - serde_json::to_string(analytics_id)? - } else { - "undefined".to_string() - }, - ); - - map.insert( - "__NEXT_HAS_WEB_VITALS_ATTRIBUTION".to_string(), - if next_config.experimental.web_vitals_attribution.is_none() { - "false".to_string() - } else { - "true".to_string() - }, - ); - - map.insert( - "__NEXT_WEB_VITALS_ATTRIBUTION".to_string(), - // Don't stringify undefined - if let Some(web_vitals_attribution) = - next_config.experimental.web_vitals_attribution.as_ref() - { - serde_json::to_string(web_vitals_attribution)? - } else { - "undefined".to_string() - }, - ); - - // TODO: Implement - // map.insert( - // "__NEXT_FETCH_CACHE_KEY_PREFIX".to_string(), - // ); - - // TODO: Implement - // map.insert( - // "__NEXT_HAS_REWRITES".to_string(), - // ); - - // TODO: Implement for node server only? - // map.insert( - // "__NEXT_EXPERIMENTAL_REACT".to_string(), - // ); - - if !test_mode.is_empty() { - map.insert("__NEXT_TEST_MODE".to_string(), "true".to_string()); - } - - Ok(Vc::upcast(CustomProcessEnv::new(env, Vc::cell(map)))) -} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index c583cbe066fcb..32b4ee101b05e 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -13,7 +13,6 @@ mod babel; mod bootstrap; mod embed_js; mod emit; -mod env; mod loader_tree; pub mod middleware; pub mod mode; diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index f36bda773e70f..fe3b43aaf1564 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -5,10 +5,7 @@ use indexmap::IndexMap; use turbo_tasks::{Value, Vc}; use turbo_tasks_fs::FileSystem; use turbopack_binding::{ - turbo::{ - tasks_env::{EnvMap, ProcessEnv}, - tasks_fs::FileSystemPath, - }, + turbo::{tasks_env::EnvMap, tasks_fs::FileSystemPath}, turbopack::{ core::{ compile_time_defines, @@ -23,7 +20,6 @@ use turbopack_binding::{ dev::{react_refresh::assert_can_resolve_react_refresh, DevChunkingContext}, ecmascript::chunk::EcmascriptChunkingContext, ecmascript_plugin::transform::directives::server::ServerDirectiveTransformer, - env::ProcessEnvAsset, node::execution_context::ExecutionContext, turbopack::{ condition::ContextCondition, @@ -41,7 +37,6 @@ use super::transforms::get_next_client_transforms_rules; use crate::{ babel::maybe_add_babel_loader, embed_js::next_js_fs, - env::env_for_js, mode::NextMode, next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping}, next_client::runtime_entry::{RuntimeEntries, RuntimeEntry}, @@ -336,7 +331,6 @@ pub fn get_client_assets_path(client_root: Vc) -> Vc, - env: Vc>, ty: Value, mode: NextMode, next_config: Vc, @@ -344,19 +338,6 @@ pub async fn get_client_runtime_entries( ) -> Result> { let mut runtime_entries = vec![]; - if matches!( - *ty, - ClientContextType::App { .. } | ClientContextType::Pages { .. }, - ) { - runtime_entries.push( - RuntimeEntry::Source(Vc::upcast(ProcessEnvAsset::new( - project_root, - env_for_js(env, true, next_config), - ))) - .cell(), - ); - } - match mode { NextMode::Development => { let resolve_options_context = get_client_resolve_options_context( diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index ba08f19d0cc04..a67ecdb111d2e 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -22,7 +22,6 @@ use turbopack_binding::{ ecmascript_plugin::transform::directives::{ client::ClientDirectiveTransformer, server::ServerDirectiveTransformer, }, - env::ProcessEnvAsset, node::execution_context::ExecutionContext, turbopack::{ condition::ContextCondition, @@ -44,7 +43,6 @@ use super::{ use crate::{ babel::maybe_add_babel_loader, embed_js::next_js_fs, - env::env_for_js, mode::NextMode, next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping}, next_client::{RuntimeEntries, RuntimeEntry}, @@ -582,17 +580,10 @@ pub fn get_build_module_options_context() -> Vc { #[turbo_tasks::function] pub fn get_server_runtime_entries( - project_root: Vc, - env: Vc>, ty: Value, mode: NextMode, - next_config: Vc, ) -> Vc { - let mut runtime_entries = vec![RuntimeEntry::Source(Vc::upcast(ProcessEnvAsset::new( - project_root, - env_for_js(env, false, next_config), - ))) - .cell()]; + let mut runtime_entries = vec![]; if matches!(mode, NextMode::Build) { if let ServerContextType::AppRSC { .. } = ty.into_value() { From a6d46da15976881b92dec71b3be10acc21c0ba09 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 3 Oct 2023 14:48:33 +0200 Subject: [PATCH 07/11] Fix dev variable --- packages/next/src/server/lib/router-utils/setup-dev.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev.ts index e47ff4a0e19d3..90181b0ab4443 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev.ts @@ -226,7 +226,7 @@ async function startWatcher(opts: SetupOpts) { allowedRevalidateHeaderKeys: undefined, clientRouterFilters: undefined, config: nextConfig, - dev: false, + dev: true, distDir, fetchCacheKeyPrefix: undefined, hasRewrites, @@ -1762,7 +1762,7 @@ async function startWatcher(opts: SetupOpts) { allowedRevalidateHeaderKeys: undefined, clientRouterFilters, config: nextConfig, - dev: false, + dev: true, distDir, fetchCacheKeyPrefix: undefined, hasRewrites, From 559acac035f5ab458ecea4bd94c9dec76a77c4a7 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 3 Oct 2023 17:27:16 +0200 Subject: [PATCH 08/11] Move flakey test --- test/turbopack-tests-manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 2941ae9479a69..e8b85847c2267 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -6987,8 +6987,6 @@ "Basic CSS Modules Ordering Development Mode should have correct color on index page (on hover)", "Basic CSS Modules Ordering Development Mode should have correct color on index page (on load)", "Basic CSS Modules Ordering Development Mode should have correct color on index page (on nav)", - "CSS Modules Composes Ordering Development Mode should have correct color on index page (on hover)", - "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering) during hot reloads", "Ordering with Global CSS and Modules (dev) should not execute scripts in any order" @@ -7012,6 +7010,8 @@ "should handle unresolved files gracefully production mode should have correct file references in CSS output" ], "flakey": [ + "CSS Modules Composes Ordering Development Mode should have correct color on index page (on hover)", + "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "CSS Modules Composes Ordering Development Mode should have correct color on index page (on nav from index)", "CSS Modules Composes Ordering Development Mode should have correct color on index page (on nav from other)" ], From f1f8bb1e39863cdd5ab374eca9340be3fdabf2fc Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 3 Oct 2023 12:17:35 -0700 Subject: [PATCH 09/11] ts fix --- packages/next/src/build/webpack-config.ts | 11 -------- .../webpack/plugins/define-env-plugin.ts | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index a6273cfa42c82..692183e05b74e 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -142,17 +142,6 @@ function isModuleCSS(module: { type: string }) { ) } -export function errorIfEnvConflicted(config: NextConfigComplete, key: string) { - const isPrivateKey = /^(?:NODE_.+)|^(?:__.+)$/i.test(key) - const hasNextRuntimeKey = key === 'NEXT_RUNTIME' - - if (isPrivateKey || hasNextRuntimeKey) { - throw new Error( - `The key "${key}" under "env" in ${config.configFileName} is not allowed. https://nextjs.org/docs/messages/env-key-not-allowed` - ) - } -} - function getReactProfilingInProduction() { return { 'react-dom$': 'react-dom/profiling', diff --git a/packages/next/src/build/webpack/plugins/define-env-plugin.ts b/packages/next/src/build/webpack/plugins/define-env-plugin.ts index 1ca36dcf4613c..9d414489b6bc9 100644 --- a/packages/next/src/build/webpack/plugins/define-env-plugin.ts +++ b/packages/next/src/build/webpack/plugins/define-env-plugin.ts @@ -2,15 +2,29 @@ import type { NextConfigComplete } from '../../../server/config-shared' import type { MiddlewareMatcher } from '../../analysis/get-page-static-info' import { webpack } from 'next/dist/compiled/webpack/webpack' import { needsExperimentalReact } from '../../../lib/needs-experimental-react' -import getBaseWebpackConfig, { - errorIfEnvConflicted, -} from '../../webpack-config' +// import type getBaseWebpackConfig from '../../webpack-config' + +function errorIfEnvConflicted(config: NextConfigComplete, key: string) { + const isPrivateKey = /^(?:NODE_.+)|^(?:__.+)$/i.test(key) + const hasNextRuntimeKey = key === 'NEXT_RUNTIME' + + if (isPrivateKey || hasNextRuntimeKey) { + throw new Error( + `The key "${key}" under "env" in ${config.configFileName} is not allowed. https://nextjs.org/docs/messages/env-key-not-allowed` + ) + } +} export interface DefineEnvPluginOptions { allowedRevalidateHeaderKeys: string[] | undefined - clientRouterFilters: Parameters< - typeof getBaseWebpackConfig - >[1]['clientRouterFilters'] + clientRouterFilters?: { + staticFilter: ReturnType< + import('../../../shared/lib/bloom-filter').BloomFilter['export'] + > + dynamicFilter: ReturnType< + import('../../../shared/lib/bloom-filter').BloomFilter['export'] + > + } config: NextConfigComplete dev: boolean distDir: string From e2c7d6b12fdb6217d46e6399ac2922e10ceecdd4 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 3 Oct 2023 12:18:32 -0700 Subject: [PATCH 10/11] rm import --- packages/next/src/build/webpack/plugins/define-env-plugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next/src/build/webpack/plugins/define-env-plugin.ts b/packages/next/src/build/webpack/plugins/define-env-plugin.ts index 9d414489b6bc9..b579f8f605919 100644 --- a/packages/next/src/build/webpack/plugins/define-env-plugin.ts +++ b/packages/next/src/build/webpack/plugins/define-env-plugin.ts @@ -2,7 +2,6 @@ import type { NextConfigComplete } from '../../../server/config-shared' import type { MiddlewareMatcher } from '../../analysis/get-page-static-info' import { webpack } from 'next/dist/compiled/webpack/webpack' import { needsExperimentalReact } from '../../../lib/needs-experimental-react' -// import type getBaseWebpackConfig from '../../webpack-config' function errorIfEnvConflicted(config: NextConfigComplete, key: string) { const isPrivateKey = /^(?:NODE_.+)|^(?:__.+)$/i.test(key) From e964e8ff7cb4dbd2641920729ea9c09649bf6573 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 3 Oct 2023 12:23:47 -0700 Subject: [PATCH 11/11] add DefinePlugin to compiled.d.ts --- packages/next/types/compiled.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next/types/compiled.d.ts b/packages/next/types/compiled.d.ts index 86a12e6f47802..e53f2a5d2657e 100644 --- a/packages/next/types/compiled.d.ts +++ b/packages/next/types/compiled.d.ts @@ -27,6 +27,7 @@ declare module 'next/dist/compiled/webpack/webpack' { export type EntryObject = any export type Chunk = any export type ChunkGroup = any + export type DefinePlugin = any // eslint-disable-next-line @typescript-eslint/no-shadow namespace sources { export type RawSource = any