Skip to content

Commit

Permalink
Merge 98f74f2 into 97baee4
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Dec 18, 2022
2 parents 97baee4 + 98f74f2 commit a7249a7
Show file tree
Hide file tree
Showing 31 changed files with 861 additions and 431 deletions.
1 change: 1 addition & 0 deletions crates/next-core/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"css.escape": "^1.5.1",
"next": "^13.0.6",
"platform": "1.3.6",
"postcss": "^8.4.20",
"react-dom": "^18.2.0",
"react": "^18.2.0",
"source-map": "0.8.0-beta.0",
Expand Down
4 changes: 2 additions & 2 deletions crates/next-core/js/src/entry/config/next.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const loadConfig = require("next/dist/server/config").default;
const { PHASE_DEVELOPMENT_SERVER } = require("next/dist/shared/lib/constants");

module.exports = (async () => {
module.exports = async () => {
const nextConfig = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd());
nextConfig.rewrites = await nextConfig.rewrites?.();
nextConfig.redirects = await nextConfig.redirects?.();
return nextConfig;
})();
};
27 changes: 27 additions & 0 deletions crates/next-core/js/src/entry/config/postcss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const {
lazyPostCSS,
} = require("next/dist/build/webpack/config/blocks/css/index");
const { getSupportedBrowsers } = require("next/dist/build/utils");

module.exports = async (cssContent, from, to) => {
const rootDir = process.cwd();
const supportedBrowsers = getSupportedBrowsers(rootDir, true, {
experimental: {
legacyBrowsers: false,
},
});
/**@type {{ postcssWithPlugins: import('postcss').Processor }} */
const { postcssWithPlugins } = await lazyPostCSS(
rootDir,
supportedBrowsers,
true
);
const { css, map } = await postcssWithPlugins.process(cssContent, {
from,
to,
map: {
inline: true,
},
});
return { css, map };
};
3 changes: 2 additions & 1 deletion crates/next-core/src/app_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use turbopack_ecmascript::{
};
use turbopack_env::ProcessEnvAssetVc;
use turbopack_node::{
create_node_rendered_source,
node_entry::{NodeRenderingEntry, NodeRenderingEntryVc},
NodeEntry, NodeEntryVc,
};
Expand Down Expand Up @@ -64,6 +63,7 @@ use crate::{
get_server_environment, get_server_module_options_context,
get_server_resolve_options_context, ServerContextType,
},
render_from_node::rendered_source::create_node_rendered_source,
util::{pathname_for_path, regular_expression_for_path},
};

Expand Down Expand Up @@ -383,6 +383,7 @@ async fn create_app_source_for_directory(
sources.push(create_node_rendered_source(
specificity,
server_root,
project_root,
pathname,
path_regex,
AppRenderer {
Expand Down
1 change: 1 addition & 0 deletions crates/next-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod next_import_map;
pub mod next_server;
mod page_loader;
pub mod react_refresh;
mod render_from_node;
mod runtime;
mod server_rendered_source;
mod util;
Expand Down
5 changes: 3 additions & 2 deletions crates/next-core/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use turbopack_core::asset::AssetContentVc;
use turbopack_dev_server::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
};
use turbopack_node::{
node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc,

use crate::render_from_node::{
node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc,
};

/// A content source which creates the next.js `_devPagesManifest.json` and
Expand Down
21 changes: 3 additions & 18 deletions crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ use turbo_tasks::{
Value,
};
use turbo_tasks_fs::{FileSystemEntryType, FileSystemPathVc};
use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc};
use turbopack_core::{
asset::Asset,
environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment},
reference_type::{EntryReferenceSubType, ReferenceType},
source_asset::SourceAssetVc,
};
Expand All @@ -21,10 +19,7 @@ use turbopack_ecmascript::{
};
use turbopack_node::evaluate::{evaluate, JavaScriptValue};

use crate::{
embed_js::next_asset,
next_server::{get_build_module_options_context, get_build_resolve_options_context},
};
use crate::{embed_js::next_asset, render_from_node::create_node_evaluate_asset_context};

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -205,18 +200,7 @@ pub async fn load_next_config(
project_path: FileSystemPathVc,
intermediate_output_path: FileSystemPathVc,
) -> Result<NextConfigVc> {
let context = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(Default::default()),
EnvironmentVc::new(
Value::new(ExecutionEnvironment::NodeJsBuildTime(
NodeJsEnvironment::default().cell(),
)),
Value::new(EnvironmentIntention::Build),
),
get_build_module_options_context(),
get_build_resolve_options_context(project_path),
)
.as_asset_context();
let context = create_node_evaluate_asset_context(project_path);
let next_config_mjs_path = project_path.join("next.config.mjs").realpath();
let next_config_js_path = project_path.join("next.config.js").realpath();
let config_asset = if matches!(
Expand Down Expand Up @@ -259,6 +243,7 @@ pub async fn load_next_config(
context,
intermediate_output_path,
runtime_entries,
vec![],
)
.await?;
match &*config_value {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use turbopack_core::issue::{Issue, IssueVc};

#[turbo_tasks::value(shared)]
#[derive(Copy, Clone)]
pub(super) struct RenderingIssue {
pub struct RenderingIssue {
pub context: FileSystemPathVc,
pub message: StringVc,
pub status: Option<i32>,
Expand Down
64 changes: 64 additions & 0 deletions crates/next-core/src/render_from_node/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::collections::BTreeMap;

use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use turbopack_dev_server::source::{query::Query, HeaderValue};
use turbopack_node::{ResponseHeaders, StructuredError};

pub mod issue;
pub mod node_api_source;
pub mod render_proxy;
pub mod render_static;
pub mod rendered_source;

pub use render_static::create_node_evaluate_asset_context;

#[turbo_tasks::value(shared)]
pub struct RenderData {
params: IndexMap<String, String>,
method: String,
url: String,
query: Query,
headers: BTreeMap<String, HeaderValue>,
path: String,
}

#[derive(Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
enum RenderStaticOutgoingMessage<'a> {
Headers { data: &'a RenderData },
}

#[derive(Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
enum RenderProxyOutgoingMessage<'a> {
Headers { data: &'a RenderData },
BodyChunk { data: &'a [u8] },
BodyEnd,
}

#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
enum RenderProxyIncomingMessage {
Headers { data: ResponseHeaders },
Body { data: Vec<u8> },
Error(StructuredError),
}

#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
enum RenderStaticIncomingMessage {
Result { result: RenderResult },
Error(StructuredError),
}

#[derive(Deserialize)]
#[serde(untagged)]
pub enum RenderResult {
Simple(String),
Advanced {
body: String,
#[serde(rename = "contentType")]
content_type: Option<String>,
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use turbopack_dev_server::source::{
ContentSourceVc,
};
use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc;
use turbopack_node::{get_intermediate_asset, path_regex::PathRegexVc, NodeEntryVc};

use super::{get_intermediate_asset, render_proxy, NodeEntryVc, RenderData};
use crate::path_regex::PathRegexVc;
use super::{render_proxy::render_proxy, RenderData};

/// Creates a [NodeApiContentSource].
#[turbo_tasks::function]
Expand Down Expand Up @@ -179,9 +179,9 @@ impl Introspectable for NodeApiContentSource {
set.insert((
StringVc::cell("intermediate asset".to_string()),
IntrospectableAssetVc::new(get_intermediate_asset(
entry.module,
self.runtime_entries,
entry.chunking_context,
entry
.module
.as_evaluated_chunk(entry.chunking_context, Some(self.runtime_entries)),
entry.intermediate_output_path,
)),
));
Expand Down
146 changes: 146 additions & 0 deletions crates/next-core/src/render_from_node/render_proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use anyhow::{bail, Result};
use turbo_tasks::primitives::StringVc;
use turbo_tasks_fs::FileSystemPathVc;
use turbopack_core::{asset::AssetVc, chunk::ChunkingContextVc};
use turbopack_dev_server::source::{BodyVc, ProxyResult, ProxyResultVc};
use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc};
use turbopack_node::{get_intermediate_asset, get_renderer_pool, trace_stack, NodeJsOperation};

use super::{
issue::RenderingIssue, RenderDataVc, RenderProxyIncomingMessage, RenderProxyOutgoingMessage,
ResponseHeaders,
};

/// Renders a module as static HTML in a node.js process.
#[turbo_tasks::function]
pub async fn render_proxy(
path: FileSystemPathVc,
module: EcmascriptModuleAssetVc,
runtime_entries: EcmascriptChunkPlaceablesVc,
chunking_context: ChunkingContextVc,
intermediate_output_path: FileSystemPathVc,
data: RenderDataVc,
body: BodyVc,
) -> Result<ProxyResultVc> {
let intermediate_asset = get_intermediate_asset(
module.as_evaluated_chunk(chunking_context, Some(runtime_entries)),
intermediate_output_path,
);
let renderer_pool = get_renderer_pool(intermediate_asset, intermediate_output_path);
let pool = renderer_pool.await?;
let mut operation = match pool.operation().await {
Ok(operation) => operation,
Err(err) => {
return proxy_error(path, err, None).await;
}
};

match run_proxy_operation(
&mut operation,
data,
body,
intermediate_asset,
intermediate_output_path,
)
.await
{
Ok(proxy_result) => Ok(proxy_result.cell()),
Err(err) => Ok(proxy_error(path, err, Some(operation)).await?),
}
}

async fn run_proxy_operation(
operation: &mut NodeJsOperation,
data: RenderDataVc,
body: BodyVc,
intermediate_asset: AssetVc,
intermediate_output_path: FileSystemPathVc,
) -> Result<ProxyResult> {
let data = data.await?;
// First, send the render data.
operation
.send(RenderProxyOutgoingMessage::Headers { data: &data })
.await?;

let body = body.await?;
// Then, send the binary body in chunks.
for chunk in body.chunks() {
operation
.send(RenderProxyOutgoingMessage::BodyChunk {
data: chunk.as_bytes(),
})
.await?;
}

operation.send(RenderProxyOutgoingMessage::BodyEnd).await?;

let (status, headers) = match operation.recv().await? {
RenderProxyIncomingMessage::Headers {
data: ResponseHeaders { status, headers },
} => (status, headers),
RenderProxyIncomingMessage::Error(error) => {
bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?)
}
_ => {
bail!("unexpected response from the Node.js process while reading response headers")
}
};

let body = match operation.recv().await? {
RenderProxyIncomingMessage::Body { data: body } => body,
RenderProxyIncomingMessage::Error(error) => {
bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?)
}
_ => {
bail!("unexpected response from the Node.js process while reading response body")
}
};

Ok(ProxyResult {
status,
headers,
body: body.into(),
})
}

async fn proxy_error(
path: FileSystemPathVc,
error: anyhow::Error,
operation: Option<NodeJsOperation>,
) -> Result<ProxyResultVc> {
let message = format!("{error:?}");

let status = match operation {
Some(operation) => Some(operation.wait_or_kill().await?),
None => None,
};

let mut details = vec![];
if let Some(status) = status {
details.push(format!("status: {status}"));
}

let body = format!(
"An error occurred while proxying a request to Node.js:\n{message}\n{}",
details.join("\n")
);

RenderingIssue {
context: path,
message: StringVc::cell(message),
status: status.and_then(|status| status.code()),
}
.cell()
.as_issue()
.emit();

Ok(ProxyResult {
status: 500,
headers: vec![
"content-type".to_string(),
"text/html; charset=utf-8".to_string(),
],
body: body.into(),
}
.cell())
}

0 comments on commit a7249a7

Please sign in to comment.