Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions WIP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
➜ yokohama git:(mischnic/turbopack-static-info) ✗ pnpm next build test/e2e/app-dir/app-middleware-proxy/

> Build error occurred
> Error: Static info mismatch for /Users/niklas/conductor/workspaces/next.js/yokohama/test/e2e/app-dir/app-middleware-proxy/proxy.js: {
> "baseline": {

"middleware": {
"matchers": [
{
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/headers(\\.json)?[\\/#\\?]?$",
"originalSource": "/headers"
}
]
},
"type": "pages"

},
"turbopack": {
"middleware": {
"matchers": [
{
"regexp": "^(?:\\/(\_next\\/data\\/[^/]{1,}))?\\/headers(\\\\.json)?[\\/#\\?]?$",
"originalSource": "/headers"
}
]
},
"type": "pages"
}
}
at ignore-listed frames
 ELIFECYCLE  Command failed with exit code 1.

➜ yokohama git:(mischnic/turbopack-static-info) ✗ pnpm next build test/e2e/app-dir/app-alias
✓ Compiled successfully in 4.2s
✓ Finished TypeScript in 1265ms

> Build error occurred
> Error: Static info mismatch for /Users/niklas/conductor/workspaces/next.js/yokohama/test/e2e/app-dir/app-alias/src/app/typing/[slug]/page.tsx: {
> "baseline": {

"generateStaticParams": true,
"type": "app"

},
"turbopack": {
"type": "app"
}
}
at ignore-listed frames
13 changes: 12 additions & 1 deletion crates/next-api/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ use crate::{
},
server_actions::{build_server_actions_loader, create_server_actions_manifest},
sri_manifest::get_sri_manifest_asset,
static_info_manifest::StaticInfoManifestAsset,
webpack_stats::generate_webpack_stats,
};

Expand Down Expand Up @@ -2022,7 +2023,17 @@ impl Endpoint for AppEndpoint {
let node_root = project.node_root().owned().await?;
let client_relative_root = project.client_relative_path().owned().await?;

let output_assets = output.output_assets();
let output_assets =
output
.output_assets()
.concat_asset(Vc::upcast(StaticInfoManifestAsset::new_app(
node_root.join(&format!(
"server/app{}/static-info.json",
&self.app_endpoint_entry().await?.original_name
))?,
*self.app_endpoint_entry().await?.config,
)));

let output_assets = if let Some(sri) =
&*project.next_config().experimental_sri().await?
&& let Some(algorithm) = sri.algorithm.clone()
Expand Down
1 change: 1 addition & 0 deletions crates/next-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ pub mod route;
pub mod routes_hashes_manifest;
mod server_actions;
mod sri_manifest;
mod static_info_manifest;
mod versioned_content_map;
mod webpack_stats;
80 changes: 23 additions & 57 deletions crates/next-api/src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use next_core::{
next_edge::entry::wrap_edge_entry,
next_manifests::{EdgeFunctionDefinition, MiddlewaresManifestV2, ProxyMatcher, Regions},
segment_config::NextSegmentConfig,
util::{MiddlewareMatcherKind, NextRuntime},
util::NextRuntime,
};
use tracing::Instrument;
use turbo_rcstr::{RcStr, rcstr};
Expand Down Expand Up @@ -35,6 +35,7 @@ use crate::{
},
project::Project,
route::{Endpoint, EndpointOutput, EndpointOutputPaths, ModuleGraphs},
static_info_manifest::StaticInfoManifestAsset,
};

#[turbo_tasks::value]
Expand Down Expand Up @@ -163,62 +164,25 @@ impl MiddlewareEndpoint {
.unwrap_or(false);
let base_path = next_config.base_path().await?;

let matchers = if let Some(matchers) = config.middleware_matcher.as_ref() {
matchers
.iter()
.map(|matcher| {
let mut matcher = match matcher {
MiddlewareMatcherKind::Str(matcher) => ProxyMatcher {
original_source: matcher.as_str().into(),
..Default::default()
},
MiddlewareMatcherKind::Matcher(matcher) => matcher.clone(),
};

// Mirrors implementation in get-page-static-info.ts getMiddlewareMatchers
let mut source = matcher.original_source.to_string();
let is_root = source == "/";
let has_locale = matcher.locale;

if has_i18n_locales && has_locale {
if is_root {
source.clear();
}
source.insert_str(0, "/:nextInternalLocale((?!_next/)[^/.]{1,})");
}

if is_root {
source.push('(');
if has_i18n {
source.push_str("|\\\\.json|");
}
source.push_str("/?index|/?index\\\\.json)?")
} else {
source.push_str("{(\\\\.json)}?")
};

source.insert_str(0, "/:nextData(_next/data/[^/]{1,})?");

if let Some(base_path) = base_path.as_ref() {
source.insert_str(0, base_path);
}

// TODO: The implementation of getMiddlewareMatchers outputs a regex here
// using path-to-regexp. Currently there is no
// equivalent of that so it post-processes
// this value to the relevant regex in manifest-loader.ts
matcher.regexp = Some(RcStr::from(source));

matcher
})
.collect()
} else {
vec![ProxyMatcher {
regexp: Some(rcstr!("^/.*$")),
original_source: rcstr!("/:path*"),
..Default::default()
}]
};
let matchers = config
.get_proxy_matchers(has_i18n, has_i18n_locales, base_path.as_deref())
.unwrap_or_else(|| {
vec![ProxyMatcher {
regexp: Some(rcstr!("^/.*$")),
original_source: rcstr!("/:path*"),
..Default::default()
}]
});

let static_info_manifest = StaticInfoManifestAsset::new_middleware(
this.project
.node_root()
.await?
.join("server/middleware/static-info.json")?,
*this.config,
)
.to_resolved()
.await?;

if matches!(this.runtime, NextRuntime::NodeJs) {
let chunk = self.node_chunk().to_resolved().await?;
Expand Down Expand Up @@ -249,6 +213,7 @@ impl MiddlewareEndpoint {
.to_resolved()
.await?;
output_assets.push(ResolvedVc::upcast(middleware_manifest_v2));
output_assets.push(ResolvedVc::upcast(static_info_manifest));

Ok(Vc::cell(output_assets))
} else {
Expand Down Expand Up @@ -310,6 +275,7 @@ impl MiddlewareEndpoint {
.to_resolved()
.await?;
output_assets.push(ResolvedVc::upcast(middleware_manifest_v2));
output_assets.push(ResolvedVc::upcast(static_info_manifest));

Ok(Vc::cell(output_assets))
}
Expand Down
12 changes: 11 additions & 1 deletion crates/next-api/src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ use crate::{
project::Project,
route::{Endpoint, EndpointOutput, EndpointOutputPaths, ModuleGraphs, Route, Routes},
sri_manifest::get_sri_manifest_asset,
static_info_manifest::StaticInfoManifestAsset,
webpack_stats::generate_webpack_stats,
};

Expand Down Expand Up @@ -1607,7 +1608,16 @@ impl Endpoint for PageEndpoint {
let node_root = project.node_root().owned().await?;
let client_relative_root = project.client_relative_path().owned().await?;

let output_assets = output.output_assets();
let output_assets = output.output_assets().concat_asset(Vc::upcast(
StaticInfoManifestAsset::new_pages(
node_root.join(&format!(
"server/pages{}/static-info.json",
get_asset_prefix_from_pathname(&this.pathname),
))?,
parse_segment_config_from_source(self.source(), ParseSegmentMode::Base),
),
));

let output_assets = if let Some(sri) =
&*project.next_config().experimental_sri().await?
&& let Some(algorithm) = sri.algorithm.clone()
Expand Down
134 changes: 134 additions & 0 deletions crates/next-api/src/static_info_manifest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use anyhow::Result;
use next_core::{
next_manifests::ProxyMatcher, segment_config::NextSegmentConfig, util::NextRuntime,
};
use serde::Serialize;
use turbo_rcstr::{RcStr, rcstr};
use turbo_tasks::{ResolvedVc, Vc};
use turbo_tasks_fs::{File, FileContent, FileSystemPath};
use turbopack_core::{
asset::{Asset, AssetContent},
output::{OutputAsset, OutputAssetsReference},
};

#[turbo_tasks::value]
pub struct StaticInfoManifestAsset {
output_path: FileSystemPath,
config: ResolvedVc<NextSegmentConfig>,
ty: RcStr,
}

#[turbo_tasks::value_impl]
impl StaticInfoManifestAsset {
#[turbo_tasks::function]
pub fn new_app(output_path: FileSystemPath, config: ResolvedVc<NextSegmentConfig>) -> Vc<Self> {
StaticInfoManifestAsset {
output_path,
config,
ty: rcstr!("app"),
}
.cell()
}

#[turbo_tasks::function]
pub fn new_pages(
output_path: FileSystemPath,
config: ResolvedVc<NextSegmentConfig>,
) -> Vc<Self> {
StaticInfoManifestAsset {
output_path,
config,
ty: rcstr!("pages"),
}
.cell()
}

#[turbo_tasks::function]
pub fn new_middleware(
output_path: FileSystemPath,
config: ResolvedVc<NextSegmentConfig>,
) -> Vc<Self> {
StaticInfoManifestAsset {
output_path,
config,
// This is what the JS implementation does
ty: rcstr!("pages"),
}
.cell()
}
}

#[turbo_tasks::value_impl]
impl OutputAssetsReference for StaticInfoManifestAsset {}

#[turbo_tasks::value_impl]
impl OutputAsset for StaticInfoManifestAsset {
#[turbo_tasks::function]
async fn path(&self) -> Vc<FileSystemPath> {
self.output_path.clone().cell()
}
}

#[turbo_tasks::value_impl]
impl Asset for StaticInfoManifestAsset {
#[turbo_tasks::function]
async fn content(&self) -> Result<Vc<AssetContent>> {
let config = self.config.await?;

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct ManifestMiddleware {
#[serde(skip_serializing_if = "Option::is_none")]
pub matchers: Option<Vec<ProxyMatcher>>,
}
impl ManifestMiddleware {
fn is_empty(&self) -> bool {
self.matchers.is_none()
}
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Manifest<'a> {
#[serde(rename = "type")]
ty: &'a str,
#[serde(skip_serializing_if = "ManifestMiddleware::is_empty")]
middleware: ManifestMiddleware,
#[serde(skip_serializing_if = "std::ops::Not::not")]
generate_static_params: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
generate_sitemaps: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
generate_image_metadata: bool,
#[serde(skip_serializing_if = "Option::is_none")]
runtime: Option<NextRuntime>,
#[serde(skip_serializing_if = "Option::is_none")]
preferred_region: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
max_duration: Option<u32>,
}

let preferred_region = config.preferred_region.as_ref().and_then(|v| match &v[..] {
[] => None,
[region] => Some(region.to_string()),
regions => Some(regions.join(",")),
});
let json = serde_json::to_string(&Manifest {
ty: self.ty.as_str(),
middleware: ManifestMiddleware {
// TODO
matchers: config.get_proxy_matchers(false, false, None),
},
runtime: config.runtime,
generate_image_metadata: config.generate_image_metadata,
generate_static_params: config.generate_static_params.is_some(),
generate_sitemaps: config.generate_sitemaps,
preferred_region,
max_duration: config.max_duration,
})?;

Ok(AssetContent::file(
FileContent::Content(File::from(json)).cell(),
))
}
}
11 changes: 11 additions & 0 deletions crates/next-core/src/next_app/app_page_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub async fn get_app_page_entry(
let server_component_transition =
ResolvedVc::upcast(NextServerComponentTransition::new().to_resolved().await?);

let x = loader_tree;

let base_path = next_config.base_path().owned().await?;
let loader_tree = AppPageLoaderTreeModule::build(
loader_tree,
Expand Down Expand Up @@ -107,6 +109,15 @@ pub async fn get_app_page_entry(
)
.module();

println!(
"get_app_page_entry: {:?} {:?} {:?} {:?} {:?}",
pathname,
original_name,
x.await?.page,
x.await?.modules.page,
rsc_entry.ident_string().await?,
);

if is_edge {
rsc_entry = wrap_edge_page(
*ResolvedVc::upcast(module_asset_context),
Expand Down
Loading
Loading