Skip to content

Commit

Permalink
Evaluate always returns a stream
Browse files Browse the repository at this point in the history
  • Loading branch information
jridgewell committed Mar 22, 2023
1 parent 6164e7f commit 02c42fd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 73 deletions.
24 changes: 12 additions & 12 deletions packages/next-swc/Cargo.lock

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

17 changes: 8 additions & 9 deletions packages/next-swc/crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use turbo_tasks::{
trace::TraceRawVcs,
CompletionVc, Value,
};
use turbo_tasks_bytes::stream::SingleValue;
use turbo_tasks_env::EnvMapVc;
use turbo_tasks_fs::{json::parse_json_with_source_context, FileSystemPathVc};
use turbopack::evaluate_context::node_evaluate_asset_context;
Expand All @@ -28,7 +29,7 @@ use turbopack_ecmascript::{
EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc,
};
use turbopack_node::{
evaluate::{evaluate, JavaScriptEvaluation},
evaluate::evaluate,
execution_context::{ExecutionContext, ExecutionContextVc},
transforms::webpack::{WebpackLoaderConfigItems, WebpackLoaderConfigItemsVc},
};
Expand Down Expand Up @@ -601,15 +602,13 @@ pub async fn load_next_config_internal(
/* debug */ false,
)
.await?;
match &*config_value {
JavaScriptEvaluation::Single(Ok(val)) => {
let next_config: NextConfig = parse_json_with_source_context(val.to_str()?)?;
let next_config = next_config.cell();

Ok(next_config)
}
_ => Ok(NextConfig::default().cell()),
}
let SingleValue::Single(Ok(val)) = config_value.into_single().await else {
return Ok(NextConfig::default().cell());
};
let next_config: NextConfig = parse_json_with_source_context(val.to_str()?)?;

Ok(next_config.cell())
}

#[turbo_tasks::function]
Expand Down
100 changes: 48 additions & 52 deletions packages/next-swc/crates/next-core/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use turbopack_ecmascript::{
EcmascriptModuleAssetVc, InnerAssetsVc, OptionEcmascriptModuleAssetVc,
};
use turbopack_node::{
evaluate::{evaluate, JavaScriptEvaluation},
evaluate::evaluate,
execution_context::{ExecutionContext, ExecutionContextVc},
StructuredError,
};
Expand Down Expand Up @@ -377,59 +377,55 @@ async fn route_internal(
)
.await?;

match &*result {
JavaScriptEvaluation::Single(Ok(val)) => {
// If we received a single message from the router, then it must be a
// rewrite/none/error. Middleware always comes in 2+ chunk streams.
let result: RouterIncomingMessage = parse_json_with_source_context(val.to_str()?)?;
Ok(match result {
RouterIncomingMessage::Rewrite { data } => RouterResult::Rewrite(data),
RouterIncomingMessage::None => RouterResult::None,
_ => RouterResult::Error,
}
.cell())
}
JavaScriptEvaluation::Stream(stream) => {
let mut read = stream.read();

let middleware = match read.next().await {
Some(Ok(first)) => {
// The first chunk is the Middleware's headers/status. Everything after that is
// body contents.
let headers: RouterIncomingMessage =
parse_json_with_source_context(first.to_str()?)?;

// The double encoding here is annoying. It'd be a lot nicer if we could embed
// a buffer directly into the IPC message without having to wrap it in an
// object.
let body = read.map(|data| {
let chunk: RouterIncomingMessage = match data?
.to_str()
.context("error decoding string")
.and_then(parse_json_with_source_context)
{
Ok(c) => c,
Err(e) => return Err(e.to_string()),
};
match chunk {
RouterIncomingMessage::MiddlewareBody { data } => Ok(Bytes::from(data)),
m => Err(format!("unexpected message type: {:#?}", m)),
}
});

match headers {
RouterIncomingMessage::MiddlewareHeaders { data } => MiddlewareResponse {
status_code: data.status_code,
headers: data.headers,
body: Stream::from(body),
},
_ => return Ok(RouterResult::Error.cell()),
}
let mut read = result.read();

let Some(Ok(first)) = read.next().await else {
return Ok(RouterResult::Error.cell());
};
let first: RouterIncomingMessage = parse_json_with_source_context(first.to_str()?)?;

let (res, read) = match first {
RouterIncomingMessage::Rewrite { data } => (RouterResult::Rewrite(data), Some(read)),

RouterIncomingMessage::MiddlewareHeaders { data } => {
// The double encoding here is annoying. It'd be a lot nicer if we could embed
// a buffer directly into the IPC message without having to wrap it in an
// object.
let body = read.map(|data| {
let chunk: RouterIncomingMessage = match data?
.to_str()
.context("error decoding string")
.and_then(parse_json_with_source_context)
{
Ok(c) => c,
Err(e) => return Err(e.to_string()),
};
match chunk {
RouterIncomingMessage::MiddlewareBody { data } => Ok(Bytes::from(data)),
m => Err(format!("unexpected message type: {:#?}", m)),
}
_ => return Ok(RouterResult::Error.cell()),
});
let middleware = MiddlewareResponse {
status_code: data.status_code,
headers: data.headers,
body: Stream::from(body),
};
Ok(RouterResult::Middleware(middleware).cell())

(RouterResult::Middleware(middleware), None)
}

RouterIncomingMessage::None => (RouterResult::None, Some(read)),
_ => (RouterResult::Error, Some(read)),
};

// Middleware will naturally drain the full stream, but the rest only take a
// single item. In order to free the NodeJsOperation, we must pull another
// value out of the stream.
if let Some(mut read) = read {
if let Some(v) = read.next().await {
bail!("unexpected message type: {:#?}", v);
}
_ => Ok(RouterResult::Error.cell()),
}

Ok(res.cell())
}

0 comments on commit 02c42fd

Please sign in to comment.