Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 742a2c7

Browse files
authored
next/root-params (#80255)
Implements accessing root params (params segments that occur above root layouts) via compiler-generated getters from the `next/root-params` module: ```tsx // app/[lang]/layout.tsx // (there is no app/layout.tsx, this is the root layout) import { lang } from "next/root-params"; // ^^^^ coresponds to the [lang] segment above this module export default async function RootLayout({ children }) { return ( <html lang={await lang()}> <body>{children}</body> </html> ); } ``` - This API is only usable within server components (support for using it in route handlers will be added in the future). It can be called anywhere in the component tree, not just in a page or a layout. - It **cannot be used in server actions**, because they're not tied to a route. - It will replace `unstable_rootParams`, which will be removed soon. Note that we can also have multiple root layouts with distinct params, like this: ``` app/product/[productId]/layout.tsx app/brand/[brandId]/layout.tsx ``` In this case we'll generate getters for both `productId` and `brandId`. They can be called anywhere, but they'll return `undefined` if used in a subtree where a param isn't available. Note that this PR does not yet generate type declarations for the generated getters, essentially leaving them typed as `any`. This will be handled in a follow up. ## Implementation notes ### Turbopack We collect the root param names when analyzing the folder structure in `app_structure.rs`. The set is then passed down (as a Vc) all the way to `next_import_map.rs`, where we insert an alias to a virtual `next/root-params.js` module. We use a `ImportMapping::Dynamic` to generate its code lazily in a separate turbo task (which is the only place that actually reads the root params). This avoids invalidating the whole `ResolveOptionsContext` if the root params change. ### Webpack We alias `next/root-params` to `next-root-params-loader`, which scans the directory structure manually (i haven't found a good way to re-use existing methods for doing this) and returns the generated module. Each directory we traverse before finding a root layout is marked as a `contextDependency`, which should invalidate the loader's result if new files are added to any of them or if they get renamed, because it might mean that the set of root params changed.
1 parent 29ae22b commit 742a2c7

File tree

63 files changed

+1863
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1863
-20
lines changed

crates/next-api/src/app.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use next_core::{
33
all_assets_from_entries,
44
app_segment_config::NextSegmentConfig,
55
app_structure::{
6-
AppPageLoaderTree, Entrypoint as AppEntrypoint, Entrypoints as AppEntrypoints,
7-
FileSystemPathVec, MetadataItem, get_entrypoints,
6+
AppPageLoaderTree, CollectedRootParams, Entrypoint as AppEntrypoint,
7+
Entrypoints as AppEntrypoints, FileSystemPathVec, MetadataItem, collect_root_params,
8+
get_entrypoints,
89
},
910
get_edge_resolve_options_context, get_next_package,
1011
next_app::{
@@ -203,6 +204,11 @@ impl AppProject {
203204
)
204205
}
205206

207+
#[turbo_tasks::function]
208+
async fn collected_root_params(self: Vc<Self>) -> Result<Vc<CollectedRootParams>> {
209+
Ok(collect_root_params(self.app_entrypoints()))
210+
}
211+
206212
#[turbo_tasks::function]
207213
async fn client_module_options_context(self: Vc<Self>) -> Result<Vc<ModuleOptionsContext>> {
208214
Ok(get_client_module_options_context(
@@ -297,6 +303,7 @@ impl AppProject {
297303
self.project().next_mode(),
298304
self.project().next_config(),
299305
self.project().execution_context(),
306+
Some(self.collected_root_params()),
300307
))
301308
}
302309

@@ -308,6 +315,7 @@ impl AppProject {
308315
self.project().next_mode(),
309316
self.project().next_config(),
310317
self.project().execution_context(),
318+
Some(self.collected_root_params()),
311319
))
312320
}
313321

@@ -319,6 +327,7 @@ impl AppProject {
319327
self.project().next_mode(),
320328
self.project().next_config(),
321329
self.project().execution_context(),
330+
Some(self.collected_root_params()),
322331
))
323332
}
324333

@@ -332,6 +341,7 @@ impl AppProject {
332341
self.project().next_mode(),
333342
self.project().next_config(),
334343
self.project().execution_context(),
344+
Some(self.collected_root_params()),
335345
))
336346
}
337347

@@ -629,6 +639,7 @@ impl AppProject {
629639
self.project().next_mode(),
630640
self.project().next_config(),
631641
self.project().execution_context(),
642+
None, // root params are not available in client modules
632643
))
633644
}
634645

@@ -640,6 +651,7 @@ impl AppProject {
640651
self.project().next_mode(),
641652
self.project().next_config(),
642653
self.project().execution_context(),
654+
None, // root params are not available in client modules
643655
))
644656
}
645657

@@ -978,7 +990,9 @@ pub fn app_entry_point_to_route(
978990
entrypoint: AppEntrypoint,
979991
) -> Vc<Route> {
980992
match entrypoint {
981-
AppEntrypoint::AppPage { pages, loader_tree } => Route::AppPage(
993+
AppEntrypoint::AppPage {
994+
pages, loader_tree, ..
995+
} => Route::AppPage(
982996
pages
983997
.into_iter()
984998
.map(|page| AppPageRoute {
@@ -1012,6 +1026,7 @@ pub fn app_entry_point_to_route(
10121026
page,
10131027
path,
10141028
root_layouts,
1029+
..
10151030
} => Route::AppRoute {
10161031
original_name: page.to_string().into(),
10171032
endpoint: ResolvedVc::upcast(
@@ -1023,7 +1038,7 @@ pub fn app_entry_point_to_route(
10231038
.resolved_cell(),
10241039
),
10251040
},
1026-
AppEntrypoint::AppMetadata { page, metadata } => Route::AppRoute {
1041+
AppEntrypoint::AppMetadata { page, metadata, .. } => Route::AppRoute {
10271042
original_name: page.to_string().into(),
10281043
endpoint: ResolvedVc::upcast(
10291044
AppEndpoint {

crates/next-api/src/pages.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ impl PagesProject {
548548
self.project().next_mode(),
549549
self.project().next_config(),
550550
self.project().execution_context(),
551+
None, // root params are not available in pages dir
551552
))
552553
}
553554

@@ -564,6 +565,7 @@ impl PagesProject {
564565
self.project().next_mode(),
565566
self.project().next_config(),
566567
self.project().execution_context(),
568+
None, // root params are not available in pages dir
567569
))
568570
}
569571

crates/next-api/src/project.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ impl Project {
13391339
self.next_mode(),
13401340
self.next_config(),
13411341
self.execution_context(),
1342+
None, // root params can't be used in middleware
13421343
),
13431344
Layer::new_with_user_friendly_name(
13441345
rcstr!("middleware-edge"),
@@ -1399,6 +1400,7 @@ impl Project {
13991400
self.next_mode(),
14001401
self.next_config(),
14011402
self.execution_context(),
1403+
None, // root params can't be used in middleware
14021404
),
14031405
Layer::new_with_user_friendly_name(rcstr!("middleware"), rcstr!("Middleware")),
14041406
)))
@@ -1516,6 +1518,7 @@ impl Project {
15161518
self.next_mode(),
15171519
self.next_config(),
15181520
self.execution_context(),
1521+
None, // root params can't be used in instrumentation
15191522
),
15201523
Layer::new_with_user_friendly_name(
15211524
rcstr!("instrumentation"),
@@ -1577,6 +1580,7 @@ impl Project {
15771580
self.next_mode(),
15781581
self.next_config(),
15791582
self.execution_context(),
1583+
None, // root params can't be used in instrumentation
15801584
),
15811585
Layer::new_with_user_friendly_name(
15821586
rcstr!("instrumentation-edge"),

0 commit comments

Comments
 (0)