Skip to content

Commit

Permalink
chore: pass defineEnv from next.js to rust directly (#56216)
Browse files Browse the repository at this point in the history
### What?

Deduplicates our env var injection between the JS and rust side

Closes WEB-937

---------

Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
Co-authored-by: Zack Tanner <zacktanner@gmail.com>
  • Loading branch information
3 people committed Oct 3, 2023
1 parent f77f222 commit 515784c
Show file tree
Hide file tree
Showing 31 changed files with 530 additions and 941 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 90 additions & 3 deletions packages/next-swc/crates/napi/src/next_api/project.rs
Expand Up @@ -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::{
Expand Down Expand Up @@ -44,6 +44,7 @@ use super::{
use crate::register;

#[napi(object)]
#[derive(Clone, Debug)]
pub struct NapiEnvVar {
pub name: String,
pub value: String,
Expand Down Expand Up @@ -74,10 +75,56 @@ pub struct NapiProjectOptions {
/// A map of environment variables to use when compiling code.
pub env: Vec<NapiEnvVar>,

/// 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<String>,

/// A path inside the root_path which contains the app/pages directories.
pub project_path: Option<String>,

/// next.config's distDir. Project initialization occurs eariler than
/// deserializing next.config, so passing it as separate option.
pub dist_dir: Option<Option<String>>,

/// Whether to watch he filesystem for file changes.
pub watch: Option<bool>,

/// The contents of next.config.js, serialized to JSON.
pub next_config: Option<String>,

/// The contents of ts/config read by load-jsconfig, serialized to JSON.
pub js_config: Option<String>,

/// A map of environment variables to use when compiling code.
pub env: Option<Vec<NapiEnvVar>>,

/// A map of environment variables which should get injected at compile
/// time.
pub define_env: Option<NapiDefineEnv>,

/// The address of the dev server.
pub server_addr: Option<String>,
}

#[napi(object)]
#[derive(Clone, Debug)]
pub struct NapiDefineEnv {
pub client: Vec<NapiEnvVar>,
pub edge: Vec<NapiEnvVar>,
pub nodejs: Vec<NapiEnvVar>,
}

#[napi(object)]
pub struct NapiTurboEngineOptions {
/// An upper bound of memory that turbopack will attempt to stay under.
Expand All @@ -95,13 +142,53 @@ impl From<NapiProjectOptions> 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<NapiPartialProjectOptions> 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<NapiDefineEnv> 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<TurboTasks<MemoryBackend>>,
container: Vc<ProjectContainer>,
Expand Down Expand Up @@ -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<ProjectInstance>,
options: NapiProjectOptions,
options: NapiPartialProjectOptions,
) -> napi::Result<()> {
let turbo_tasks = project.turbo_tasks.clone();
let options = options.into();
Expand Down
30 changes: 28 additions & 2 deletions packages/next-swc/crates/napi/src/turbopack.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -38,6 +40,7 @@ pub struct NextBuildContext {
// TODO(alexkirsz) These are used to generate route types.
// pub original_rewrites: Option<Rewrites>,
// pub original_redirects: Option<Vec<Redirect>>,
pub define_env: NapiDefineEnv,
}

impl TryFrom<NextBuildContext> for NextBuildOptions {
Expand All @@ -62,10 +65,33 @@ impl TryFrom<NextBuildContext> for NextBuildOptions {
.context("NextBuildContext must provide rewrites")?
.into(),
}),
define_env: value.define_env.into(),
})
}
}

impl From<NapiDefineEnv> 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)]
Expand Down
6 changes: 0 additions & 6 deletions packages/next-swc/crates/next-api/src/app.rs
Expand Up @@ -295,13 +295,8 @@ impl AppProject {
async fn runtime_entries(self: Vc<Self>) -> Result<Vc<RuntimeEntries>> {
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(),
))
}

Expand Down Expand Up @@ -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(),
Expand Down
3 changes: 0 additions & 3 deletions packages/next-swc/crates/next-api/src/middleware.rs
Expand Up @@ -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?
Expand Down
7 changes: 0 additions & 7 deletions packages/next-swc/crates/next-api/src/pages.rs
Expand Up @@ -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(),
}),
Expand All @@ -421,27 +420,21 @@ impl PagesProject {
async fn runtime_entries(self: Vc<Self>) -> Result<Vc<RuntimeEntries>> {
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(),
))
}

#[turbo_tasks::function]
async fn data_runtime_entries(self: Vc<Self>) -> Result<Vc<RuntimeEntries>> {
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(),
))
}

Expand Down

0 comments on commit 515784c

Please sign in to comment.