Skip to content

Commit

Permalink
Add support for 'use cache' in route handlers using the Edge runtime
Browse files Browse the repository at this point in the history
Same as #70897, but for the Edge runtime. The changes are based on what
we're already doing for app pages using the Edge runtime.
  • Loading branch information
unstubbable committed Oct 14, 2024
1 parent 9b9dbe4 commit 59f329f
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 12 deletions.
7 changes: 4 additions & 3 deletions crates/next-core/src/next_app/app_route_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub async fn get_app_route_entry(
Vc::upcast(module_asset_context),
project_root,
rsc_entry,
pathname.clone(),
page,
);
}

Expand All @@ -131,7 +131,7 @@ async fn wrap_edge_route(
asset_context: Vc<Box<dyn AssetContext>>,
project_root: Vc<FileSystemPath>,
entry: Vc<Box<dyn Module>>,
pathname: RcStr,
page: AppPage,
) -> Result<Vc<Box<dyn Module>>> {
const INNER: &str = "INNER_ROUTE_ENTRY";

Expand All @@ -140,6 +140,7 @@ async fn wrap_edge_route(
project_root,
indexmap! {
"VAR_USERLAND" => INNER.into(),
"VAR_PAGE" => page.to_string().into(),
},
indexmap! {},
indexmap! {},
Expand All @@ -161,6 +162,6 @@ async fn wrap_edge_route(
asset_context,
project_root,
wrapped,
pathname,
AppPath::from(page).to_string().into(),
))
}
18 changes: 18 additions & 0 deletions packages/next/src/build/templates/edge-app-route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import { createServerModuleMap } from '../../server/app-render/action-utils'
import { setReferenceManifestsSingleton } from '../../server/app-render/encryption-utils'
import { EdgeRouteModuleWrapper } from '../../server/web/edge-route-module-wrapper'

// Import the userland code.
import * as module from 'VAR_USERLAND'

const maybeJSONParse = (str?: string) => (str ? JSON.parse(str) : undefined)

const rscManifest = self.__RSC_MANIFEST?.['VAR_PAGE']
const rscServerManifest = maybeJSONParse(self.__RSC_SERVER_MANIFEST)

if (rscManifest && rscServerManifest) {
setReferenceManifestsSingleton({
clientReferenceManifest: rscManifest,
serverActionsManifest: rscServerManifest,
serverModuleMap: createServerModuleMap({
serverActionsManifest: rscServerManifest,
pageName: 'VAR_PAGE',
}),
})
}

export const ComponentMod = module

export default EdgeRouteModuleWrapper.wrap(module.routeModule)
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const EdgeAppRouteLoader: webpack.LoaderDefinitionFunction<EdgeAppRouteLoaderQue
const buildInfo = getModuleBuildInfo(this._module)

buildInfo.nextEdgeSSR = {
isServerComponent: false,
isServerComponent: true, // Needed for 'use cache'.
page: page,
isAppDir: true,
}
Expand All @@ -55,6 +55,7 @@ const EdgeAppRouteLoader: webpack.LoaderDefinitionFunction<EdgeAppRouteLoaderQue

return await loadEntrypoint('edge-app-route', {
VAR_USERLAND: modulePath,
VAR_PAGE: page,
})
}

Expand Down
6 changes: 5 additions & 1 deletion packages/next/src/build/webpack/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,18 @@ export function forEachEntryModule(

if (
!request.startsWith('next-edge-ssr-loader?') &&
!request.startsWith('next-edge-app-route-loader?') &&
!request.startsWith('next-app-loader?')
)
continue

let entryModule: NormalModule =
compilation.moduleGraph.getResolvedModule(entryDependency)

if (request.startsWith('next-edge-ssr-loader?')) {
if (
request.startsWith('next-edge-ssr-loader?') ||
request.startsWith('next-edge-app-route-loader?')
) {
entryModule.dependencies.forEach((dependency) => {
const modRequest: string | undefined = (dependency as any).request
if (modRequest?.includes('next-app-loader')) {
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/app-dir/app-static/app-static.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -775,9 +775,11 @@ describe('app-dir static/dynamic handling', () => {
"api/large-data/route.js",
"api/large-data/route_client-reference-manifest.js",
"api/revalidate-path-edge/route.js",
"api/revalidate-path-edge/route_client-reference-manifest.js",
"api/revalidate-path-node/route.js",
"api/revalidate-path-node/route_client-reference-manifest.js",
"api/revalidate-tag-edge/route.js",
"api/revalidate-tag-edge/route_client-reference-manifest.js",
"api/revalidate-tag-node/route.js",
"api/revalidate-tag-node/route_client-reference-manifest.js",
"articles/[slug]/page.js",
Expand Down Expand Up @@ -935,6 +937,7 @@ describe('app-dir static/dynamic handling', () => {
"response-url/page.js",
"response-url/page_client-reference-manifest.js",
"route-handler-edge/revalidate-360/route.js",
"route-handler-edge/revalidate-360/route_client-reference-manifest.js",
"route-handler/no-store-force-static/route.js",
"route-handler/no-store-force-static/route_client-reference-manifest.js",
"route-handler/no-store/route.js",
Expand Down Expand Up @@ -968,6 +971,7 @@ describe('app-dir static/dynamic handling', () => {
"stale-cache-serving-edge/app-page/page.js",
"stale-cache-serving-edge/app-page/page_client-reference-manifest.js",
"stale-cache-serving-edge/route-handler/route.js",
"stale-cache-serving-edge/route-handler/route_client-reference-manifest.js",
"stale-cache-serving/app-page/page.js",
"stale-cache-serving/app-page/page_client-reference-manifest.js",
"stale-cache-serving/route-handler/route.js",
Expand Down
3 changes: 0 additions & 3 deletions test/e2e/app-dir/dynamic-io/dynamic-io.routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,6 @@ describe('dynamic-io', () => {
expect(message2).toEqual(json.message2)
}

// TODO: Edge is missing Server Manifest for routes.
/*
str = await next.render('/routes/-edge/use_cache-cached', {})
json = JSON.parse(str)

Expand All @@ -259,7 +257,6 @@ describe('dynamic-io', () => {
expect(json.value).toEqual('at runtime')
expect(message1).toEqual(json.message1)
expect(message2).toEqual(json.message2)
*/
}
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const runtime = 'edge'

export { GET } from '../node/route'
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ async function getCachedRandom() {

export async function GET() {
const rand1 = await getCachedRandom()
// TODO: Remove this extra micro task when bug in use cache wrapper is fixed.
await Promise.resolve()
const rand2 = await getCachedRandom()

const response = JSON.stringify({ rand1, rand2 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ describe('use-cache-route-handler-only', () => {

const itSkipTurbopack = isTurbopack ? it.skip : it

itSkipTurbopack('should cache results in route handlers', async () => {
const response = await next.fetch('/')
itSkipTurbopack('should cache results in node route handlers', async () => {
const response = await next.fetch('/node')
const { rand1, rand2 } = await response.json()

expect(rand1).toEqual(rand2)
})

itSkipTurbopack('should cache results in edge route handlers', async () => {
const response = await next.fetch('/edge')
const { rand1, rand2 } = await response.json()

expect(rand1).toEqual(rand2)
Expand Down

0 comments on commit 59f329f

Please sign in to comment.