Skip to content

Introduce experimental Request Interceptors #70961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 34 commits into
base: canary
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5b5883c
Add initial support for loading interceptors
unstubbable Sep 5, 2024
3d4d234
Pass `NextRequest` to interceptors
unstubbable Sep 5, 2024
4c764e8
Run full interceptor chain during client-side navigation
unstubbable Sep 5, 2024
1427887
Settle on sequential interceptor execution for now
unstubbable Sep 6, 2024
622711e
Pass request into `createInterceptor`
unstubbable Sep 6, 2024
fa2e056
Catch interceptor errors in loading boundaries
unstubbable Sep 6, 2024
4c7fd24
Test errors in interceptors
unstubbable Sep 6, 2024
88b6cbd
Interceptors should bail out of static generation
unstubbable Sep 6, 2024
55b3ed1
Test interceptors with PPR
unstubbable Sep 6, 2024
734cb8f
Verify default export of interceptor modules
unstubbable Sep 6, 2024
2a8d674
Test `React.cache` in interceptors
unstubbable Sep 9, 2024
3a539c5
Add Turbopack support for interceptors
unstubbable Sep 11, 2024
c8bac10
Call interceptors before server actions
unstubbable Sep 17, 2024
7b50093
Do not use `timers/promises`; not available in edge runtime
unstubbable Sep 17, 2024
26dc26a
Fix broken edge runtime
unstubbable Sep 17, 2024
b95ba12
Rename `interceptors` to `enableInterceptors` in `next-app-loader`
unstubbable Sep 18, 2024
eb213e5
Inject interceptors into app route module
unstubbable Sep 18, 2024
91e33f8
Call interceptors before route handlers (Webpack only)
unstubbable Sep 18, 2024
4614cb0
Add Turbopack support for route handler interceptors
unstubbable Sep 19, 2024
f3a0c9a
Add test for interceptors feature flag turned off
unstubbable Sep 20, 2024
c8d938a
Strip internal search params from `RequestStore#nextRequest`
unstubbable Sep 20, 2024
adb6cb9
Test `after` in interceptors
unstubbable Sep 23, 2024
03f0d25
Add test for redirecting interceptor
unstubbable Sep 24, 2024
7a57bea
Skip depoyment test
unstubbable Oct 5, 2024
e1c5f14
Modernize dynamic tracking, postpone, static bailout
unstubbable Oct 5, 2024
41f5575
Add interceptors test case to dynamic-io tests
unstubbable Oct 7, 2024
d56a3c3
Add interceptors fixture to dynamic-io error tests
unstubbable Oct 7, 2024
4522100
Fix `relative_path` computation
unstubbable Oct 8, 2024
bc345aa
Update hydration diff snapshots
unstubbable Oct 8, 2024
68f1498
Fix broken module path encoding
unstubbable Oct 8, 2024
0f3577c
Allow request body to be read in each interceptor
unstubbable Oct 9, 2024
63e8675
Skip deployment for dynamic IO interceptors error test
unstubbable Oct 9, 2024
d154bd5
Skip deployments for all interceptor tests
unstubbable Oct 9, 2024
9f99e02
Add auth interceptor layouting example
unstubbable Oct 9, 2024
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
15 changes: 11 additions & 4 deletions crates/next-api/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ impl AppProject {

#[turbo_tasks::function]
fn app_entrypoints(&self) -> Vc<AppEntrypoints> {
get_entrypoints(self.app_dir, self.project.next_config().page_extensions())
get_entrypoints(self.app_dir, self.project.next_config())
}

#[turbo_tasks::function]
Expand Down Expand Up @@ -655,13 +655,15 @@ pub fn app_entry_point_to_route(
page,
path,
root_layouts,
interceptors,
} => Route::AppRoute {
original_name: page.to_string(),
endpoint: Vc::upcast(
AppEndpoint {
ty: AppEndpointType::Route {
path: *path,
root_layouts: *root_layouts,
interceptors: *interceptors,
},
app_project,
page,
Expand Down Expand Up @@ -709,6 +711,7 @@ enum AppEndpointType {
Route {
path: Vc<FileSystemPath>,
root_layouts: Vc<FileSystemPathVec>,
interceptors: Vc<FileSystemPathVec>,
},
Metadata {
metadata: MetadataItem,
Expand Down Expand Up @@ -741,6 +744,7 @@ impl AppEndpoint {
&self,
path: Vc<FileSystemPath>,
root_layouts: Vc<FileSystemPathVec>,
interceptors: Vc<FileSystemPathVec>,
next_config: Vc<NextConfig>,
) -> Result<Vc<AppEntry>> {
let root_layouts = root_layouts.await?;
Expand All @@ -766,6 +770,7 @@ impl AppEndpoint {
self.app_project.project().project_path(),
config,
next_config,
interceptors,
))
}

Expand Down Expand Up @@ -793,9 +798,11 @@ impl AppEndpoint {
let next_config = self.await?.app_project.project().next_config();
let app_entry = match this.ty {
AppEndpointType::Page { loader_tree, .. } => self.app_page_entry(loader_tree),
AppEndpointType::Route { path, root_layouts } => {
self.app_route_entry(path, root_layouts, next_config)
}
AppEndpointType::Route {
path,
root_layouts,
interceptors,
} => self.app_route_entry(path, root_layouts, interceptors, next_config),
AppEndpointType::Metadata { metadata } => {
self.app_metadata_entry(metadata, next_config)
}
Expand Down
22 changes: 18 additions & 4 deletions crates/next-core/src/app_page_loader_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,15 @@ impl AppPageLoaderTreeBuilder {
fn new(
module_asset_context: Vc<ModuleAssetContext>,
server_component_transition: Vc<Box<dyn Transition>>,
project_root: Vc<FileSystemPath>,
base_path: Option<RcStr>,
) -> Self {
AppPageLoaderTreeBuilder {
base: BaseLoaderTreeBuilder::new(module_asset_context, server_component_transition),
base: BaseLoaderTreeBuilder::new(
module_asset_context,
server_component_transition,
project_root,
),
loader_tree_code: String::new(),
pages: Vec::new(),
base_path,
Expand Down Expand Up @@ -319,6 +324,7 @@ impl AppPageLoaderTreeBuilder {
not_found,
metadata,
route: _,
interceptor,
} = &modules;

// Ensure global metadata being written only once at the root level
Expand All @@ -345,6 +351,8 @@ impl AppPageLoaderTreeBuilder {
.await?;
self.write_modules_entry(AppDirModuleType::DefaultPage, *default)
.await?;
self.write_modules_entry(AppDirModuleType::Interceptor, *interceptor)
.await?;

let modules_code = replace(&mut self.loader_tree_code, temp_loader_tree_code);

Expand Down Expand Up @@ -398,11 +406,17 @@ impl AppPageLoaderTreeModule {
loader_tree: Vc<AppPageLoaderTree>,
module_asset_context: Vc<ModuleAssetContext>,
server_component_transition: Vc<Box<dyn Transition>>,
project_root: Vc<FileSystemPath>,
base_path: Option<RcStr>,
) -> Result<Self> {
AppPageLoaderTreeBuilder::new(module_asset_context, server_component_transition, base_path)
.build(loader_tree)
.await
AppPageLoaderTreeBuilder::new(
module_asset_context,
server_component_transition,
project_root,
base_path,
)
.build(loader_tree)
.await
}
}

Expand Down
87 changes: 87 additions & 0 deletions crates/next-core/src/app_route_loader_tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::fmt::Write;

use anyhow::Result;
use indexmap::IndexMap;
use turbo_tasks::{RcStr, Vc};
use turbo_tasks_fs::FileSystemPath;
use turbopack::{transition::Transition, ModuleAssetContext};
use turbopack_core::module::Module;

use crate::{
app_structure::FileSystemPathVec,
base_loader_tree::{AppDirModuleType, BaseLoaderTreeBuilder},
};

pub struct AppRouteLoaderTreeBuilder {
base: BaseLoaderTreeBuilder,
interceptors_code: String,
}

impl AppRouteLoaderTreeBuilder {
fn new(
module_asset_context: Vc<ModuleAssetContext>,
server_component_transition: Vc<Box<dyn Transition>>,
project_root: Vc<FileSystemPath>,
) -> Self {
AppRouteLoaderTreeBuilder {
base: BaseLoaderTreeBuilder::new(
module_asset_context,
server_component_transition,
project_root,
),
interceptors_code: String::new(),
}
}

async fn write_interceptors(&mut self, interceptors: Vc<FileSystemPathVec>) -> Result<()> {
writeln!(self.interceptors_code, "[")?;

for interceptor in interceptors.await?.iter() {
let tuple_code = self
.base
.create_module_tuple_code(AppDirModuleType::Interceptor, **interceptor)
.await?;

writeln!(self.interceptors_code, "{},", tuple_code)?;
}

write!(self.interceptors_code, "]")?;
Ok(())
}

async fn build(
mut self,
interceptors: Vc<FileSystemPathVec>,
) -> Result<AppRouteLoaderTreeModule> {
self.write_interceptors(interceptors).await?;

Ok(AppRouteLoaderTreeModule {
imports: self.base.imports,
interceptors_code: self.interceptors_code.into(),
inner_assets: self.base.inner_assets,
})
}
}

pub struct AppRouteLoaderTreeModule {
pub imports: Vec<RcStr>,
pub interceptors_code: RcStr,
pub inner_assets: IndexMap<RcStr, Vc<Box<dyn Module>>>,
}

impl AppRouteLoaderTreeModule {
pub async fn build(
interceptors: Vc<FileSystemPathVec>,
module_asset_context: Vc<ModuleAssetContext>,
server_component_transition: Vc<Box<dyn Transition>>,
project_root: Vc<FileSystemPath>,
) -> Result<Self> {
AppRouteLoaderTreeBuilder::new(
module_asset_context,
server_component_transition,
project_root,
)
.build(interceptors)
.await
}
}
Loading
Loading