Skip to content
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

Transform client reference in middleware layer #66294

Merged
merged 12 commits into from
May 30, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@ impl AfterResolvePlugin for NextNodeSharedRuntimeResolvePlugin {
"next/dist/server/future/route-modules/{}/vendored/contexts/{}.js",
match self.context {
ServerContextType::Pages { .. } => "pages",
ServerContextType::AppRoute { .. } => "app-route",
ServerContextType::AppRoute { .. } | ServerContextType::Instrumentation { .. } =>
"app-route",
ServerContextType::AppSSR { .. } | ServerContextType::AppRSC { .. } => "app-page",
_ => "unknown",
},
Expand Down
15 changes: 11 additions & 4 deletions packages/next/src/build/create-compiler-aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,16 @@ export function createAppRouterApiAliases(isServerOnlyLayer: boolean) {
return aliasMap
}

export function createRSCRendererAliases(bundledReactChannel: string) {
return {
// react-server-dom-webpack alias
'react-server-dom-webpack/client$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client`,
'react-server-dom-webpack/client.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client.edge`,
'react-server-dom-webpack/server.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.edge`,
'react-server-dom-webpack/server.node$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.node`,
}
}

export function createRSCAliases(
bundledReactChannel: string,
{
Expand Down Expand Up @@ -262,10 +272,7 @@ export function createRSCAliases(
'react-dom/server.edge$': `next/dist/compiled/react-dom${bundledReactChannel}/server.edge`,
'react-dom/server.browser$': `next/dist/compiled/react-dom${bundledReactChannel}/server.browser`,
// react-server-dom-webpack alias
'react-server-dom-webpack/client$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client`,
'react-server-dom-webpack/client.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client.edge`,
'react-server-dom-webpack/server.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.edge`,
'react-server-dom-webpack/server.node$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.node`,
...createRSCRendererAliases(bundledReactChannel),
}

if (!isEdgeServer) {
Expand Down
7 changes: 7 additions & 0 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ import {
createRSCAliases,
createNextApiEsmAliases,
createAppRouterApiAliases,
createRSCRendererAliases,
} from './create-compiler-aliases'
import { hasCustomExportOutput } from '../export/utils'
import { CssChunkingPlugin } from './webpack/plugins/css-chunking-plugin'
Expand Down Expand Up @@ -529,6 +530,7 @@ export default async function getBaseWebpackConfig(
: []

const instrumentLayerLoaders = [
'next-flight-loader',
// When using Babel, we will have to add the SWC loader
// as an additional pass to handle RSC correctly.
// This will cause some performance overhead but
Expand All @@ -538,6 +540,7 @@ export default async function getBaseWebpackConfig(
].filter(Boolean)

const middlewareLayerLoaders = [
'next-flight-loader',
// When using Babel, we will have to use SWC to do the optimization
// for middleware to tree shake the unused default optimized imports like "next/server".
// This will cause some performance overhead but
Expand Down Expand Up @@ -1470,6 +1473,8 @@ export default async function getBaseWebpackConfig(
use: middlewareLayerLoaders,
resolve: {
conditionNames: reactServerCondition,
// Always use default channels when use installed react
alias: createRSCRendererAliases(''),
},
},
{
Expand All @@ -1478,6 +1483,8 @@ export default async function getBaseWebpackConfig(
use: instrumentLayerLoaders,
resolve: {
conditionNames: reactServerCondition,
// Always use default channels when use installed react
alias: createRSCRendererAliases(''),
},
},
...(hasAppDir
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/module-layer/instrumentation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
// TODO: support react client transform in turbopack
// import { textValue } from './lib/mixed-lib/shared-module'

export async function register() {
if (Object(React).useState) {
throw new Error('instrumentation is not working correctly in server layer')
}
console.log('instrumentation:register')
}
4 changes: 4 additions & 0 deletions test/e2e/module-layer/lib/mixed-lib/shared-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Link from 'next/link'

export const textValue = 'text-value'
export const TestLink = Link
4 changes: 3 additions & 1 deletion test/e2e/module-layer/middleware.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'server-only'
import * as React from 'react'
import { NextResponse } from 'next/server'
import { textValue } from './lib/mixed-lib/shared-module'
huozhi marked this conversation as resolved.
Show resolved Hide resolved
// import './lib/mixed-lib'

export function middleware(request) {
Expand All @@ -10,9 +11,10 @@ export function middleware(request) {
throw new Error('React.useState should not be defined in server layer')
}

if (request.nextUrl.pathname === '/react-version') {
if (request.nextUrl.pathname === '/middleware') {
return Response.json({
React: Object.keys(ReactObject),
textValue,
})
}

Expand Down
8 changes: 7 additions & 1 deletion test/e2e/module-layer/module-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,15 @@ describe('module layer', () => {
}

it('should render installed react-server condition for middleware', async () => {
const json = await next.fetch('/react-version').then((res) => res.json())
const json = await next.fetch('/middleware').then((res) => res.json())
expect(json.React).toContain('version') // basic react-server export
expect(json.React).not.toContain('useEffect') // no client api export
expect(json.textValue).toBe('text-value')
})

it('should call instrumentation hook without errors', async () => {
const output = next.cliOutput
expect(output).toContain('instrumentation:register')
})

// This is for backward compatibility, don't change react usage in existing pages/api
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/module-layer/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
experimental: {
instrumentationHook: true,
},
}
Loading