From d330f7b02c2151cf2d6e76c5ae6852d96fd43763 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Thu, 7 Sep 2023 13:53:07 -0700 Subject: [PATCH 1/5] fix: ensure mpa navigation render side effects are only fired once (#55032) This is to fix an issue where these redirect side effects can be fired multiple times when the router reducer state changes. This block is still run when the router state updates, which can lead to superfluous attempts to redirect to a page. With these changes, we keep track of the page that is being redirected to. If a re-render occurs while that request is in flight, we don't trigger the side effects. [Slack x-ref](https://vercel.slack.com/archives/C04DUD7EB1B/p1694049914264839) --- .../next/src/client/components/app-router.tsx | 33 +++++++++------- .../reducers/navigate-reducer.test.tsx | 23 ++++++----- .../reducers/refresh-reducer.test.tsx | 12 ++++-- .../reducers/server-patch-reducer.test.tsx | 12 ++++-- .../router-reducer/router-reducer-types.ts | 6 ++- .../navigation/app/mpa-nav-test/page.js | 38 +++++++++++++++++++ .../e2e/app-dir/navigation/navigation.test.ts | 31 ++++++++++++++- .../e2e/app-dir/navigation/pages/slow-page.js | 13 +++++++ 8 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 test/e2e/app-dir/navigation/app/mpa-nav-test/page.js create mode 100644 test/e2e/app-dir/navigation/pages/slow-page.js diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index 2c3c541e02b8e..a8de967825e16 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -33,12 +33,12 @@ import { ACTION_RESTORE, ACTION_SERVER_ACTION, ACTION_SERVER_PATCH, + Mutable, PrefetchKind, ReducerActions, RouterChangeByServerResponse, RouterNavigate, ServerActionDispatcher, - ServerActionMutable, } from './router-reducer/router-reducer-types' import { createHrefFromUrl } from './router-reducer/create-href-from-url' import { @@ -73,7 +73,7 @@ export function getServerActionDispatcher() { return globalServerActionDispatcher } -let globalServerActionMutable: ServerActionMutable['globalMutable'] = { +let globalMutable: Mutable['globalMutable'] = { refresh: () => {}, // noop until the router is initialized } @@ -145,7 +145,7 @@ function useServerActionDispatcher(dispatch: React.Dispatch) { dispatch({ ...actionPayload, type: ACTION_SERVER_ACTION, - mutable: { globalMutable: globalServerActionMutable }, + mutable: { globalMutable }, cache: createEmptyCacheNode(), }) }) @@ -174,7 +174,7 @@ function useChangeByServerResponse( previousTree, overrideCanonicalUrl, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, }) }) }, @@ -186,7 +186,7 @@ function useNavigate(dispatch: React.Dispatch): RouterNavigate { return useCallback( (href, navigateType, forceOptimisticNavigation, shouldScroll) => { const url = new URL(addBasePath(href), location.href) - globalServerActionMutable.pendingNavigatePath = href + globalMutable.pendingNavigatePath = href return dispatch({ type: ACTION_NAVIGATE, @@ -197,7 +197,7 @@ function useNavigate(dispatch: React.Dispatch): RouterNavigate { shouldScroll: shouldScroll ?? true, navigateType, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, }) }, [dispatch] @@ -322,7 +322,7 @@ function Router({ dispatch({ type: ACTION_REFRESH, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, origin: window.location.origin, }) }) @@ -338,7 +338,7 @@ function Router({ dispatch({ type: ACTION_FAST_REFRESH, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, origin: window.location.origin, }) }) @@ -357,7 +357,7 @@ function Router({ }, [appRouter]) useEffect(() => { - globalServerActionMutable.refresh = appRouter.refresh + globalMutable.refresh = appRouter.refresh }, [appRouter.refresh]) if (process.env.NODE_ENV !== 'production') { @@ -409,11 +409,16 @@ function Router({ // in . At least I hope so. (It will run twice in dev strict mode, // but that's... fine?) if (pushRef.mpaNavigation) { - const location = window.location - if (pushRef.pendingPush) { - location.assign(canonicalUrl) - } else { - location.replace(canonicalUrl) + // if there's a re-render, we don't want to trigger another redirect if one is already in flight to the same URL + if (globalMutable.pendingMpaPath !== canonicalUrl) { + const location = window.location + if (pushRef.pendingPush) { + location.assign(canonicalUrl) + } else { + location.replace(canonicalUrl) + } + + globalMutable.pendingMpaPath = canonicalUrl } // TODO-APP: Should we listen to navigateerror here to catch failed // navigations somehow? And should we call window.stop() if a SPA navigation diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx index 4ed01fed08c83..fcde9b963e9fd 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx @@ -106,6 +106,10 @@ const getInitialRouterStateTree = (): FlightRouterState => [ true, ] +const globalMutable = { + refresh: () => {}, +} + async function runPromiseThrowChain(fn: any): Promise { try { return await fn() @@ -194,7 +198,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => @@ -438,7 +442,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -633,7 +637,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -792,7 +796,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -948,7 +952,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1147,7 +1151,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1317,7 +1321,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1630,7 +1634,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1841,6 +1845,7 @@ describe('navigateReducer', () => { hashFragment: '#hash', pendingPush: true, shouldScroll: true, + globalMutable, }, } @@ -1983,7 +1988,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx index 9ed54e8994d2e..bbf36b1ec538c 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx @@ -66,6 +66,10 @@ const getInitialRouterStateTree = (): FlightRouterState => [ true, ] +const globalMutable = { + refresh: () => {}, +} + async function runPromiseThrowChain(fn: any): Promise { try { return await fn() @@ -139,7 +143,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -300,7 +304,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -487,7 +491,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -723,7 +727,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } diff --git a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx index 0540c02079cb1..9e7035dc7e819 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx @@ -7,6 +7,10 @@ import type { const buildId = 'development' +const globalMutable = { + refresh: () => {}, +} + jest.mock('../fetch-server-response', () => { const flightData: FlightData = [ [ @@ -184,7 +188,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => @@ -375,7 +379,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => serverPatchReducer(state, action)) @@ -514,7 +518,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const state = createInitialRouterState({ @@ -556,7 +560,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => diff --git a/packages/next/src/client/components/router-reducer/router-reducer-types.ts b/packages/next/src/client/components/router-reducer/router-reducer-types.ts index defbb657c7c42..d9c641c4045b7 100644 --- a/packages/next/src/client/components/router-reducer/router-reducer-types.ts +++ b/packages/next/src/client/components/router-reducer/router-reducer-types.ts @@ -38,11 +38,15 @@ export interface Mutable { prefetchCache?: AppRouterState['prefetchCache'] hashFragment?: string shouldScroll?: boolean + globalMutable: { + pendingNavigatePath?: string + pendingMpaPath?: string + refresh: () => void + } } export interface ServerActionMutable extends Mutable { inFlightServerAction?: Promise | null - globalMutable: { pendingNavigatePath?: string; refresh: () => void } actionResultResolved?: boolean } diff --git a/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js b/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js new file mode 100644 index 0000000000000..9a335e2d0995c --- /dev/null +++ b/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js @@ -0,0 +1,38 @@ +'use client' +import Link from 'next/link' +import { useEffect, useRef } from 'react' + +export default function Page() { + const prefetchRef = useRef() + const slowPageRef = useRef() + + useEffect(() => { + function triggerPrefetch() { + const event = new MouseEvent('mouseover', { + view: window, + bubbles: true, + cancelable: true, + }) + + prefetchRef.current.dispatchEvent(event) + console.log('dispatched') + } + + slowPageRef.current.click() + + setInterval(() => { + triggerPrefetch() + }, 1000) + }, []) + + return ( + <> + + To /slow-page + + + Prefetch link + + + ) +} diff --git a/test/e2e/app-dir/navigation/navigation.test.ts b/test/e2e/app-dir/navigation/navigation.test.ts index 67beabf483fe3..b3e1cf19c4261 100644 --- a/test/e2e/app-dir/navigation/navigation.test.ts +++ b/test/e2e/app-dir/navigation/navigation.test.ts @@ -1,5 +1,5 @@ import { createNextDescribe } from 'e2e-utils' -import { check } from 'next-test-utils' +import { check, waitFor } from 'next-test-utils' import type { Request } from 'playwright-chromium' createNextDescribe( @@ -497,6 +497,33 @@ createNextDescribe( .waitForElementByCss('#link-to-app') expect(await browser.url()).toBe(next.url + '/some') }) + + if (!isNextDev) { + // this test is pretty hard to test in playwright, so most of the heavy lifting is in the page component itself + // it triggers a hover on a link to initiate a prefetch request every second, and so we check that + // it doesn't repeatedly initiate the mpa navigation request + it('should not continously initiate a mpa navigation to the same URL when router state changes', async () => { + let requestCount = 0 + const browser = await next.browser('/mpa-nav-test', { + beforePageLoad(page) { + page.on('request', (request) => { + const url = new URL(request.url()) + // skip rsc prefetches + if (url.pathname === '/slow-page' && !url.search) { + requestCount++ + } + }) + }, + }) + + await browser.waitForElementByCss('#link-to-slow-page') + + // wait a few seconds since prefetches are triggered in 1s intervals in the page component + await waitFor(5000) + + expect(requestCount).toBe(1) + }) + } }) describe('nested navigation', () => { @@ -562,7 +589,7 @@ createNextDescribe( ) }) - it('should emit refresh meta tag (peramnent) for redirect page when streaming', async () => { + it('should emit refresh meta tag (permanent) for redirect page when streaming', async () => { const html = await next.render('/redirect/suspense-2') expect(html).toContain( '' diff --git a/test/e2e/app-dir/navigation/pages/slow-page.js b/test/e2e/app-dir/navigation/pages/slow-page.js new file mode 100644 index 0000000000000..ad37357cb6dcf --- /dev/null +++ b/test/e2e/app-dir/navigation/pages/slow-page.js @@ -0,0 +1,13 @@ +export default function Page() { + return 'Hello from slow page' +} + +export async function getServerSideProps({ resolvedUrl }) { + if (!resolvedUrl.includes('?_rsc')) { + // only stall on the navigation, not prefetch + await new Promise((resolve) => setTimeout(resolve, 100000)) + } + return { + props: {}, + } +} From 7267538e0019e8b0ab49c959272af86e54777a14 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 7 Sep 2023 14:07:53 -0700 Subject: [PATCH 2/5] Revert "perf: add bundled rendering runtimes (#52997)" (#55117) This reverts commit a5b7c77c1ff0096af7609a8bfc1e064d30db4e30. Our E2E tests are failing with this change this reverts to allow investigating async x-ref: https://github.com/vercel/next.js/actions/runs/6112149126/job/16589769954 --- .eslintrc.json | 5 +- bench/basic-app/app/api/app/route.js | 5 - bench/basic-app/app/layout.js | 12 - bench/basic-app/app/page.js | 7 - bench/basic-app/next.config.js | 5 - bench/basic-app/pages/api/index.js | 3 - bench/basic-app/pages/pages/index.js | 7 - .../js/src/entry/app-edge-renderer.tsx | 2 - .../next-core/js/src/entry/app-renderer.tsx | 8 +- .../next-core/js/src/entry/app/hydrate.tsx | 2 +- .../js/src/internal/page-server-handler.tsx | 6 +- .../crates/next-core/src/app_source.rs | 17 +- .../crates/next-core/src/next_edge/context.rs | 7 +- .../src/next_edge/route_transition.rs | 16 +- .../crates/next-core/src/next_import_map.rs | 66 +-- .../next-core/src/next_server/context.rs | 16 +- .../next-core/src/next_shared/resolve.rs | 51 +- ...File(__q____q____q____star__0__-3e4dd8.txt | 17 - ...FileSync(__q____q____q____star_-e11df4.txt | 15 - .../Error during SSR Rendering-8ad1c9.txt | 47 -- .../Error during SSR Rendering-d9114a.txt | 6 + .../next/import/conditions/input/app/test.js | 4 +- ...rror resolving commonjs request-b2593b.txt | 13 + ...rror resolving commonjs request-dd84e7.txt | 13 + ...File(__q____q____q____star__0__-76c34b.txt | 17 - ...FileSync(__q____q____q____star_-f7e52c.txt | 15 - packages/next/config.d.ts | 4 +- packages/next/config.js | 2 +- packages/next/package.json | 2 - packages/next/src/build/index.ts | 32 +- packages/next/src/build/templates/app-page.ts | 2 +- .../next/src/build/templates/app-route.ts | 3 +- .../next/src/build/templates/pages-api.ts | 3 +- packages/next/src/build/templates/pages.ts | 2 +- packages/next/src/build/utils.ts | 18 +- packages/next/src/build/webpack-config.ts | 118 ++--- .../plugins/next-types-plugin/index.ts | 9 +- packages/next/src/client/app-index.tsx | 4 +- packages/next/src/client/compat/router.ts | 2 +- ...ge.external.ts => action-async-storage.ts} | 0 .../next/src/client/components/app-router.tsx | 6 +- .../components/bailout-to-client-rendering.ts | 2 +- .../next/src/client/components/headers.ts | 5 +- .../src/client/components/layout-router.tsx | 4 +- .../next/src/client/components/navigation.ts | 8 +- .../internal/helpers/use-websocket.ts | 2 +- .../client/components/redirect-boundary.tsx | 2 +- .../next/src/client/components/redirect.ts | 2 +- .../render-from-template-context.tsx | 2 +- ...e.external.ts => request-async-storage.ts} | 0 .../router-reducer/apply-flight-data.ts | 5 +- .../create-initial-router-state.test.tsx | 5 +- .../create-initial-router-state.ts | 4 +- .../fill-cache-with-data-property.test.tsx | 5 +- .../fill-cache-with-data-property.ts | 5 +- .../fill-cache-with-new-subtree-data.test.tsx | 5 +- .../fill-cache-with-new-subtree-data.ts | 5 +- ...ll-lazy-items-till-leaf-with-head.test.tsx | 5 +- .../fill-lazy-items-till-leaf-with-head.ts | 5 +- ...te-cache-below-flight-segmentpath.test.tsx | 5 +- ...validate-cache-below-flight-segmentpath.ts | 2 +- .../invalidate-cache-by-router-state.test.tsx | 5 +- .../invalidate-cache-by-router-state.ts | 2 +- .../reducers/find-head-in-cache.test.tsx | 2 +- .../reducers/find-head-in-cache.ts | 2 +- .../reducers/navigate-reducer.test.tsx | 2 +- .../reducers/navigate-reducer.ts | 2 +- .../reducers/prefetch-reducer.test.tsx | 2 +- .../reducers/refresh-reducer.test.tsx | 2 +- .../reducers/refresh-reducer.ts | 2 +- .../reducers/restore-reducer.test.tsx | 2 +- .../reducers/server-action-reducer.ts | 2 +- .../reducers/server-patch-reducer.test.tsx | 2 +- .../router-reducer/router-reducer-types.ts | 2 +- ....ts => static-generation-async-storage.ts} | 0 .../components/static-generation-bailout.ts | 2 +- packages/next/src/client/image-component.tsx | 4 +- packages/next/src/client/index.tsx | 14 +- packages/next/src/client/legacy/image.tsx | 2 +- packages/next/src/client/link.tsx | 4 +- packages/next/src/client/router.ts | 2 +- packages/next/src/client/script.tsx | 2 +- packages/next/src/export/worker.ts | 14 +- packages/next/src/lib/chalk.ts | 2 +- packages/next/src/lib/constants.ts | 5 - packages/next/src/pages/_document.tsx | 7 +- .../src/server/app-render/action-handler.ts | 7 +- .../next/src/server/app-render/app-render.tsx | 17 +- .../next/src/server/app-render/entry-base.ts | 44 +- .../app-render/server-inserted-html.tsx | 2 +- .../request-async-storage-wrapper.ts | 2 +- ...static-generation-async-storage-wrapper.ts | 2 +- packages/next/src/server/base-server.ts | 8 +- .../next/src/server/dev/next-dev-server.ts | 2 +- .../src/server/dev/static-paths-worker.ts | 8 +- .../module-loader/node-module-loader.ts | 5 +- .../route-modules/app-page/module.compiled.ts | 11 - .../future/route-modules/app-page/module.ts | 5 - .../route-modules/app-page/shared-modules.ts | 13 - .../app-route/module.compiled.ts | 11 - .../future/route-modules/app-route/module.ts | 26 +- .../route-modules/app-route/shared-modules.ts | 3 - .../pages-api/module.compiled.ts | 11 - .../future/route-modules/pages-api/module.ts | 10 - .../route-modules/pages/module.compiled.ts | 11 - .../future/route-modules/pages/module.ts | 8 +- .../route-modules/pages/shared-modules.ts | 12 - .../future/route-modules/route-module.ts | 5 - .../src/server/lib/incremental-cache/index.ts | 5 +- packages/next/src/server/lib/patch-fetch.ts | 2 +- .../next/src/server/lib/server-ipc/index.ts | 1 - .../next/src/server/lib/trace/constants.ts | 1 + packages/next/src/server/load-components.ts | 35 +- .../server/load-default-error-components.ts | 78 --- packages/next/src/server/next-server.ts | 339 ++++++------- packages/next/src/server/render-result.ts | 2 +- packages/next/src/server/render.tsx | 22 +- packages/next/src/server/require-hook.ts | 36 +- .../next/src/server/response-cache/index.ts | 5 +- .../next/src/server/response-cache/web.ts | 4 +- packages/next/src/server/web/adapter.ts | 2 +- .../adapters/request-cookies.ts | 2 +- .../web/spec-extension/revalidate-tag.ts | 2 +- .../web/spec-extension/unstable-cache.ts | 2 +- ...ntext.shared-runtime.ts => amp-context.ts} | 0 packages/next/src/shared/lib/amp.ts | 2 +- ...hared-runtime.ts => app-router-context.ts} | 0 packages/next/src/shared/lib/dynamic.tsx | 2 +- ...red-runtime.ts => head-manager-context.ts} | 0 packages/next/src/shared/lib/head.tsx | 4 +- ...red-runtime.ts => hooks-client-context.ts} | 0 ...text.shared-runtime.ts => html-context.ts} | 0 ...red-runtime.ts => image-config-context.ts} | 0 ....shared-runtime.ts => loadable-context.ts} | 0 ...adable.shared-runtime.tsx => loadable.tsx} | 2 +- ...xt.shared-runtime.ts => router-context.ts} | 0 .../src/shared/lib/router/adapters.test.tsx | 2 +- ...apters.shared-runtime.tsx => adapters.tsx} | 7 +- ...ig.shared-runtime.ts => runtime-config.ts} | 0 ...d-runtime.tsx => server-inserted-html.tsx} | 0 packages/next/src/shared/lib/utils.ts | 2 +- packages/next/src/trace/index.ts | 3 +- packages/next/taskfile-webpack.js | 35 -- packages/next/taskfile.js | 183 +++++-- packages/next/webpack.config.js | 145 ------ pnpm-lock.yaml | 3 - scripts/minimal-server.js | 19 +- .../app-action-size-limit-invalid.test.ts | 2 +- .../e2e/getserversideprops/app/pages/index.js | 2 +- test/e2e/opentelemetry/opentelemetry.test.ts | 456 +++++++++--------- test/e2e/prerender-native-module.test.ts | 3 + test/e2e/prerender.test.ts | 5 + .../app/node_modules/comps/index.js | 5 + .../app/node_modules/comps/package.json | 6 + .../externalize-next-server/app/package.json | 6 + .../app/pages/index.js | 12 + .../test/index.test.js | 19 + .../jsconfig-baseurl/test/index.test.js | 6 + .../jsconfig-paths/test/index.test.js | 7 +- 159 files changed, 949 insertions(+), 1504 deletions(-) delete mode 100644 bench/basic-app/app/api/app/route.js delete mode 100644 bench/basic-app/app/layout.js delete mode 100644 bench/basic-app/app/page.js delete mode 100644 bench/basic-app/next.config.js delete mode 100644 bench/basic-app/pages/api/index.js delete mode 100644 bench/basic-app/pages/pages/index.js delete mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt delete mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt delete mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt create mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt create mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt create mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt delete mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt delete mode 100644 packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt rename packages/next/src/client/components/{action-async-storage.external.ts => action-async-storage.ts} (100%) rename packages/next/src/client/components/{request-async-storage.external.ts => request-async-storage.ts} (100%) rename packages/next/src/client/components/{static-generation-async-storage.external.ts => static-generation-async-storage.ts} (100%) delete mode 100644 packages/next/src/server/future/route-modules/app-page/module.compiled.ts delete mode 100644 packages/next/src/server/future/route-modules/app-page/shared-modules.ts delete mode 100644 packages/next/src/server/future/route-modules/app-route/module.compiled.ts delete mode 100644 packages/next/src/server/future/route-modules/app-route/shared-modules.ts delete mode 100644 packages/next/src/server/future/route-modules/pages-api/module.compiled.ts delete mode 100644 packages/next/src/server/future/route-modules/pages/module.compiled.ts delete mode 100644 packages/next/src/server/future/route-modules/pages/shared-modules.ts delete mode 100644 packages/next/src/server/load-default-error-components.ts rename packages/next/src/shared/lib/{amp-context.shared-runtime.ts => amp-context.ts} (100%) rename packages/next/src/shared/lib/{app-router-context.shared-runtime.ts => app-router-context.ts} (100%) rename packages/next/src/shared/lib/{head-manager-context.shared-runtime.ts => head-manager-context.ts} (100%) rename packages/next/src/shared/lib/{hooks-client-context.shared-runtime.ts => hooks-client-context.ts} (100%) rename packages/next/src/shared/lib/{html-context.shared-runtime.ts => html-context.ts} (100%) rename packages/next/src/shared/lib/{image-config-context.shared-runtime.ts => image-config-context.ts} (100%) rename packages/next/src/shared/lib/{loadable-context.shared-runtime.ts => loadable-context.ts} (100%) rename packages/next/src/shared/lib/{loadable.shared-runtime.tsx => loadable.tsx} (99%) rename packages/next/src/shared/lib/{router-context.shared-runtime.ts => router-context.ts} (100%) rename packages/next/src/shared/lib/router/{adapters.shared-runtime.tsx => adapters.tsx} (95%) rename packages/next/src/shared/lib/{runtime-config.shared-runtime.ts => runtime-config.ts} (100%) rename packages/next/src/shared/lib/{server-inserted-html.shared-runtime.tsx => server-inserted-html.tsx} (100%) delete mode 100644 packages/next/taskfile-webpack.js delete mode 100644 packages/next/webpack.config.js create mode 100644 test/integration/externalize-next-server/app/node_modules/comps/index.js create mode 100644 test/integration/externalize-next-server/app/node_modules/comps/package.json create mode 100644 test/integration/externalize-next-server/app/package.json create mode 100644 test/integration/externalize-next-server/app/pages/index.js create mode 100644 test/integration/externalize-next-server/test/index.test.js diff --git a/.eslintrc.json b/.eslintrc.json index feb49b2ecbbff..8c46d8c02736f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -162,10 +162,7 @@ }, { "files": ["packages/**"], - "excludedFiles": [ - "packages/next/taskfile*.js", - "packages/next/webpack.config.js" - ], + "excludedFiles": ["packages/next/taskfile.js"], "rules": { "no-shadow": ["warn", { "builtinGlobals": false }], "import/no-extraneous-dependencies": [ diff --git a/bench/basic-app/app/api/app/route.js b/bench/basic-app/app/api/app/route.js deleted file mode 100644 index 944ba5a8e827f..0000000000000 --- a/bench/basic-app/app/api/app/route.js +++ /dev/null @@ -1,5 +0,0 @@ -export function GET() { - return { name: 'John Doe' } -} - -export const dynamic = 'force-dynamic' diff --git a/bench/basic-app/app/layout.js b/bench/basic-app/app/layout.js deleted file mode 100644 index 8ebf54889577d..0000000000000 --- a/bench/basic-app/app/layout.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react' - -export default function Layout({ children }) { - return ( - - - My App - - {children} - - ) -} diff --git a/bench/basic-app/app/page.js b/bench/basic-app/app/page.js deleted file mode 100644 index 83dc3aa56c9a0..0000000000000 --- a/bench/basic-app/app/page.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' - -export default function Page() { - return

My Page

-} - -export const dynamic = 'force-dynamic' diff --git a/bench/basic-app/next.config.js b/bench/basic-app/next.config.js deleted file mode 100644 index 0957c472383fa..0000000000000 --- a/bench/basic-app/next.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - experimental: { - serverMinification: true, - }, -} diff --git a/bench/basic-app/pages/api/index.js b/bench/basic-app/pages/api/index.js deleted file mode 100644 index 8f603094bd288..0000000000000 --- a/bench/basic-app/pages/api/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function handler(req, res) { - res.status(200).json({ name: 'John Doe' }) -} diff --git a/bench/basic-app/pages/pages/index.js b/bench/basic-app/pages/pages/index.js deleted file mode 100644 index e06229eee0637..0000000000000 --- a/bench/basic-app/pages/pages/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export default () => 'Hello World' - -export function getServerSideProps() { - return { - props: {}, - } -} diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx index 38f27b3c1c7a3..fdec9ffc360fe 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx @@ -2,8 +2,6 @@ // the other imports import startOperationStreamHandler from '../internal/operation-stream' -import 'next/dist/server/node-polyfill-fetch' - import { join } from 'path' import { parse as parseUrl } from 'node:url' diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 25437fec08ef4..951f91570d92d 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -3,15 +3,13 @@ import startOperationStreamHandler from '../internal/operation-stream' import '../polyfill/app-polyfills.ts' -// TODO: when actions are supported, this should be removed/changed -process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = 'next' -import 'next/dist/server/require-hook' import type { IncomingMessage } from 'node:http' import type { RenderData } from 'types/turbopack' import type { RenderOpts } from 'next/dist/server/app-render/types' +import { renderToHTMLOrFlight } from 'next/dist/server/app-render/app-render' import { RSC_VARY_HEADER } from 'next/dist/client/components/app-router-headers' import { headersFromEntries, initProxiedHeaders } from '../internal/headers' import { parse, ParsedUrlQuery } from 'node:querystring' @@ -25,10 +23,6 @@ import { join } from 'node:path' import { nodeFs } from 'next/dist/server/lib/node-fs-methods' import { IncrementalCache } from 'next/dist/server/lib/incremental-cache' -const { - renderToHTMLOrFlight, -} = require('next/dist/compiled/next-server/app-page.runtime.dev') - installRequireAndChunkLoad() const MIME_TEXT_HTML_UTF8 = 'text/html; charset=utf-8' diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx index c4e1bce96aa5e..abdf23d0fd7d3 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -6,7 +6,7 @@ import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-we import { callServer } from 'next/dist/client/app-call-server' import { linkGc } from 'next/dist/client/app-link-gc' -import { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context' import { initializeHMR } from '@vercel/turbopack-next/dev/client' diff --git a/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx b/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx index cecafb35f77a7..6182b2d7d4539 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx +++ b/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx @@ -3,12 +3,11 @@ import { IPC } from '@vercel/turbopack-node/ipc/index' import 'next/dist/server/node-polyfill-fetch.js' -import 'next/dist/server/require-hook' import './shims' import type { IncomingMessage, ServerResponse } from 'node:http' -import type { RenderOpts } from 'next/dist/server/render' +import { renderToHTML, RenderOpts } from 'next/dist/server/render' import { getRedirectStatus } from 'next/dist/lib/redirect-status' import { PERMANENT_REDIRECT_STATUS } from 'next/dist/shared/lib/constants' import { buildStaticPaths } from 'next/dist/build/utils' @@ -22,9 +21,6 @@ import type { RenderData } from 'types/turbopack' import type { ChunkGroup } from 'types/next' import type { NextComponentType } from 'next/types' import { parse } from 'node:querystring' -const { - renderToHTML, -} = require('next/dist/compiled/next-server/pages.runtime.dev') const ipc = IPC as Ipc diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 4265f52139b4b..cf35f3795f884 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, io::Write as _, iter::once}; use anyhow::{bail, Result}; use indexmap::indexmap; -use indoc::formatdoc; +use indoc::indoc; use serde_json::Value as JsonValue; use turbo_tasks::Vc; use turbopack_binding::{ @@ -964,18 +964,13 @@ impl AppRenderer { .emit(); } - let mut result = RopeBuilder::from( - formatdoc!( - " - \"TURBOPACK {{ chunking-type: isolatedParallel; transition: {rsc_transition} }}\"; + let mut result = RopeBuilder::from(indoc! {" + \"TURBOPACK { chunking-type: isolatedParallel; transition: next-edge-server-component }\"; import GlobalErrorMod from \"next/dist/client/components/error-boundary\" - const {{ GlobalError }} = GlobalErrorMod; - \"TURBOPACK {{ chunking-type: isolatedParallel; transition: {rsc_transition} }}\"; + const { GlobalError } = GlobalErrorMod; + \"TURBOPACK { chunking-type: isolatedParallel; transition: next-edge-server-component }\"; import base from \"next/dist/server/app-render/entry-base\"\n - " - ) - .into_bytes(), - ); + "}); for import in loader_tree_module.imports { writeln!(result, "{import}")?; diff --git a/packages/next-swc/crates/next-core/src/next_edge/context.rs b/packages/next-swc/crates/next-core/src/next_edge/context.rs index cfe9eebf19f94..54c7dd3331a63 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/context.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/context.rs @@ -96,9 +96,10 @@ pub async fn get_edge_resolve_options_context( ]; match ty { - ServerContextType::AppRSC { .. } => custom_conditions.push("react-server".to_string()), - ServerContextType::AppRoute { .. } - | ServerContextType::Pages { .. } + ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { + custom_conditions.push("react-server".to_string()) + } + ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } | ServerContextType::AppSSR { .. } | ServerContextType::Middleware { .. } => {} diff --git a/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs b/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs index 05326de255203..de0bd2f2e7bf7 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs @@ -58,26 +58,24 @@ impl Transition for NextEdgeRouteTransition { #[turbo_tasks::function] async fn process_module( - self: Vc, + &self, asset: Vc>, context: Vc, ) -> Result>> { - let new_context = self.process_context(context); - let this = self.await?; let new_asset = route_bootstrap( asset, - Vc::upcast(new_context), - this.base_path, - this.bootstrap_asset, + Vc::upcast(context), + self.base_path, + self.bootstrap_asset, Vc::cell(indexmap! { - "NAME".to_string() => this.entry_name.clone(), + "NAME".to_string() => self.entry_name.clone(), }), ); let asset = ChunkGroupFilesAsset { module: Vc::upcast(new_asset), - client_root: this.output_path, - chunking_context: this.edge_chunking_context, + client_root: self.output_path, + chunking_context: self.edge_chunking_context, runtime_entries: None, }; diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index c530f3bcb9290..e05ac926c139f 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -216,26 +216,25 @@ pub async fn get_next_server_import_map( let ty = ty.into_value(); insert_next_server_special_aliases(&mut import_map, ty, mode, NextRuntime::NodeJs).await?; - let external: Vc = ImportMapping::External(None).cell(); + let external = ImportMapping::External(None).cell(); - import_map.insert_exact_alias("next/dist/server/require-hook", external); match ty { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { + import_map.insert_exact_alias("next", external); + import_map.insert_wildcard_alias("next/", external); import_map.insert_exact_alias("react", external); import_map.insert_wildcard_alias("react/", external); import_map.insert_exact_alias("react-dom", external); import_map.insert_wildcard_alias("react-dom/", external); import_map.insert_exact_alias("styled-jsx", external); import_map.insert_wildcard_alias("styled-jsx/", external); - import_map.insert_wildcard_alias("react-server-dom-webpack/", external); - // TODO: we should not bundle next/dist/build/utils in the pages renderer at all - import_map.insert_wildcard_alias("next/dist/build/utils", external); + import_map.insert_exact_alias("react-server-dom-webpack/", external); } ServerContextType::AppSSR { .. } | ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { match mode { - NextMode::Build => { + NextMode::Development | NextMode::Build => { import_map.insert_wildcard_alias("next/dist/server/", external); import_map.insert_wildcard_alias("next/dist/shared/", external); } @@ -243,7 +242,6 @@ pub async fn get_next_server_import_map( // The sandbox can't be bundled and needs to be external import_map.insert_exact_alias("next/dist/server/web/sandbox", external); } - NextMode::Development => {} } import_map.insert_exact_alias( "next/head", @@ -379,11 +377,6 @@ async fn insert_next_server_special_aliases( NextRuntime::Edge => request_to_import_mapping(context_dir, request), NextRuntime::NodeJs => external_request_to_import_mapping(request), }; - let passthrough_external_if_node = - move |context_dir: Vc, request: &str| match runtime { - NextRuntime::Edge => request_to_import_mapping(context_dir, request), - NextRuntime::NodeJs => ImportMapping::External(None).cell(), - }; match (mode, ty) { (_, ServerContextType::Pages { pages_dir }) => { import_map.insert_exact_alias( @@ -420,7 +413,12 @@ async fn insert_next_server_special_aliases( (_, ServerContextType::PagesData { .. }) => {} // In development, we *always* use the bundled version of React, even in // SSR, since we're bundling Next.js alongside it. - (NextMode::DevServer, ServerContextType::AppSSR { app_dir }) => { + ( + NextMode::DevServer, + ServerContextType::AppSSR { app_dir } + | ServerContextType::AppRSC { app_dir, .. } + | ServerContextType::AppRoute { app_dir }, + ) => { import_map.insert_exact_alias( "@opentelemetry/api", // TODO(WEB-625) this actually need to prefer the local version of @@ -429,40 +427,28 @@ async fn insert_next_server_special_aliases( ); import_map.insert_exact_alias( "react", - passthrough_external_if_node(app_dir, "next/dist/compiled/react"), + request_to_import_mapping(app_dir, "next/dist/compiled/react"), ); import_map.insert_wildcard_alias( "react/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), ); import_map.insert_exact_alias( "react-dom", - passthrough_external_if_node( + request_to_import_mapping( app_dir, "next/dist/compiled/react-dom/server-rendering-stub.js", ), ); import_map.insert_wildcard_alias( "react-dom/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react-dom/*"), - ); - import_map.insert_exact_alias( - "styled-jsx", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx"), - ); - import_map.insert_wildcard_alias( - "styled-jsx/", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); import_map.insert_wildcard_alias( "react-server-dom-webpack/", - passthrough_external_if_node( - app_dir, - "next/dist/compiled/react-server-dom-webpack/*", - ), + request_to_import_mapping(app_dir, "next/dist/compiled/react-server-dom-webpack/*"), ); } - // NOTE(alexkirsz) This logic maps loosely to // `next.js/packages/next/src/build/webpack-config.ts`, where: // @@ -474,7 +460,7 @@ async fn insert_next_server_special_aliases( // * passes through (react|react-dom|react-server-dom-webpack)/(.*) to // next/dist/compiled/$1/$2 ( - NextMode::Build | NextMode::Development | NextMode::DevServer, + NextMode::Build | NextMode::Development, ServerContextType::AppRSC { app_dir, .. } | ServerContextType::AppRoute { app_dir }, ) => { import_map.insert_exact_alias( @@ -483,20 +469,10 @@ async fn insert_next_server_special_aliases( // @opentelemetry/api request_to_import_mapping(app_dir, "next/dist/compiled/@opentelemetry/api"), ); - if matches!(ty, ServerContextType::AppRSC { .. }) { - import_map.insert_exact_alias( - "react", - request_to_import_mapping( - app_dir, - "next/dist/compiled/react/react.shared-subset", - ), - ); - } else { - import_map.insert_exact_alias( - "react", - request_to_import_mapping(app_dir, "next/dist/compiled/react"), - ); - } + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react/react.shared-subset"), + ); import_map.insert_exact_alias( "react-dom", request_to_import_mapping( diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index 1d242498b36df..e7485ff100ade 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -46,10 +46,7 @@ use crate::{ next_import_map::{get_next_server_import_map, mdx_import_source_file}, next_server::resolve::ExternalPredicate, next_shared::{ - resolve::{ - ModuleFeatureReportResolvePlugin, NextExternalResolvePlugin, - UnsupportedModulesResolvePlugin, - }, + resolve::{ModuleFeatureReportResolvePlugin, UnsupportedModulesResolvePlugin}, transforms::{ emotion::get_emotion_transform_plugin, get_relay_transform_plugin, styled_components::get_styled_components_transform_plugin, @@ -111,9 +108,10 @@ pub async fn get_server_resolve_options_context( let mut custom_conditions = vec![mode.node_env().to_string(), "node".to_string()]; match ty { - ServerContextType::AppRSC { .. } => custom_conditions.push("react-server".to_string()), - ServerContextType::AppRoute { .. } - | ServerContextType::Pages { .. } + ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { + custom_conditions.push("react-server".to_string()) + } + ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } | ServerContextType::AppSSR { .. } | ServerContextType::Middleware { .. } => {} @@ -123,15 +121,12 @@ pub async fn get_server_resolve_options_context( ExternalPredicate::AllExcept(next_config.transpile_packages()).cell(), ); - let next_external_plugin = NextExternalResolvePlugin::new(project_path); - let plugins = match ty { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { vec![ Vc::upcast(module_feature_report_resolve_plugin), Vc::upcast(external_cjs_modules_plugin), Vc::upcast(unsupported_modules_resolve_plugin), - Vc::upcast(next_external_plugin), ] } ServerContextType::AppSSR { .. } @@ -142,7 +137,6 @@ pub async fn get_server_resolve_options_context( Vc::upcast(module_feature_report_resolve_plugin), Vc::upcast(server_component_externals_plugin), Vc::upcast(unsupported_modules_resolve_plugin), - Vc::upcast(next_external_plugin), ] } }; diff --git a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs index ea7f044c12cc8..013f87f9fd5b6 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs @@ -13,7 +13,7 @@ use turbopack_binding::{ parse::Request, pattern::Pattern, plugin::{ResolvePlugin, ResolvePluginCondition}, - ResolveResult, ResolveResultItem, ResolveResultOption, + ResolveResultOption, }, }, }; @@ -102,55 +102,6 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin { } } -#[turbo_tasks::value] -pub(crate) struct NextExternalResolvePlugin { - root: Vc, -} - -#[turbo_tasks::value_impl] -impl NextExternalResolvePlugin { - #[turbo_tasks::function] - pub fn new(root: Vc) -> Vc { - NextExternalResolvePlugin { root }.cell() - } -} - -#[turbo_tasks::value_impl] -impl ResolvePlugin for NextExternalResolvePlugin { - #[turbo_tasks::function] - fn after_resolve_condition(&self) -> Vc { - ResolvePluginCondition::new( - self.root.root(), - Glob::new( - "**/next/dist/**/*.{external,shared-runtime,runtime.dev,runtime.prod}.js" - .to_string(), - ), - ) - } - - #[turbo_tasks::function] - async fn after_resolve( - &self, - fs_path: Vc, - _context: Vc, - _request: Vc, - ) -> Result> { - let raw_fs_path = &*fs_path.await?; - let path = raw_fs_path.path.to_string(); - // Find the starting index of 'next/dist' and slice from that point. It should - // always be found since the glob pattern above is specific enough. - let starting_index = path.find("next/dist").unwrap(); - // Replace '/esm/' with '/' to match the CJS version of the file. - let modified_path = &path[starting_index..].replace("/esm/", "/"); - Ok(Vc::cell(Some( - ResolveResult::primary(ResolveResultItem::OriginalReferenceTypeExternal( - modified_path.to_string(), - )) - .into(), - ))) - } -} - /// A resolver plugin tracks the usage of certain import paths, emit /// telemetry events if there is a match. #[turbo_tasks::value] diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt deleted file mode 100644 index a5ad94c85fb0a..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt +++ /dev/null @@ -1,17 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:64:56 lint TP1004 fs.readFile(???*0*) is very dynamic - 60 | } - 61 | async function loadWasm(wasm) { - 62 | const modules = {}; - 63 | await Promise.all(wasm.map(async (binding)=>{ - + v - 64 + const module1 = await WebAssembly.compile(await _fs.promises.readFile(binding.filePath)); - + ^ - 65 | modules[binding.name] = module1; - 66 | })); - 67 | return modules; - 68 | } - - - *0* ???*1*["filePath"] - ⚠️ unknown object - - *1* binding - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt deleted file mode 100644 index c80db085946c2..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt +++ /dev/null @@ -1,15 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:355:28 lint TP1004 fs.readFileSync(???*0*, "utf-8") is very dynamic - 351 | } - 352 | const moduleContext = lazyModuleContext; - 353 | const evaluateInContext = (filepath)=>{ - 354 | if (!moduleContext.paths.has(filepath)) { - + v - 355 + const content = (0, _fs.readFileSync)(filepath, "utf-8"); - + ^ - 356 | try { - 357 | (0, _vm.runInContext)(content, moduleContext.runtime.context, { - 358 | filename: filepath - 359 | }); - - - *0* filepath - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt deleted file mode 100644 index 39e97b4ccc85e..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt +++ /dev/null @@ -1,47 +0,0 @@ -error - [rendering] [root of the server]/invalid Error during SSR Rendering - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` - - Debug info: - - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` - See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host - at defaultLoader (packages/next/dist/shared/lib/image-loader.js:41:27) - 37 | process.env.NEXT_RUNTIME !== "edge") { - 38 | // We use dynamic require because this should only error in development - 39 | const { hasMatch } = require("./match-remote-pattern"); - 40 | if (!hasMatch(config.domains, config.remotePatterns, parsedSrc)) { - | v - 41 + throw new Error("Invalid src prop (" + src + ') on `next/image`, hostname "' + parsedSrc.hostname + '" i...xt.config.js`\n' + "See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host"); - | ^ - 42 | } - 43 | } - 44 | } - 45 | } - - at (packages/next/dist/shared/lib/get-img-props.js:101:36) - 97 | const { widths , kind } = getWidths(config, width, sizes); - 98 | const last = widths.length - 1; - 99 | return { - 100 | sizes: !sizes && kind === "w" ? "100vw" : sizes, - | v - 101 + srcSet: widths.map((w, i)=>loader({ - | ^ - 102 | config, - 103 | src, - 104 | quality, - 105 | width: w - - at generateImgAttrs (packages/next/dist/shared/lib/get-img-props.js:101:24) - 97 | const { widths , kind } = getWidths(config, width, sizes); - 98 | const last = widths.length - 1; - 99 | return { - 100 | sizes: !sizes && kind === "w" ? "100vw" : sizes, - | v - 101 + srcSet: widths.map((w, i)=>loader({ - | ^ - 102 | config, - 103 | src, - 104 | quality, - 105 | width: w - - at getImgProps (packages/next/dist/shared/lib/get-img-props.js:392:27) - at (packages/next/dist/client/image-component.js:275:82) \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt new file mode 100644 index 0000000000000..ce775cb8df7e8 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt @@ -0,0 +1,6 @@ +error - [rendering] [root of the server]/invalid Error during SSR Rendering + Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` + + Debug info: + - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` + See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js index 108b763da879c..e2c2f40a06dd7 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js @@ -120,7 +120,7 @@ function runTests() { expect(json).toMatchObject({ edgeThenNode: 'node', nodeThenEdge: 'node', - reactServer: 'default', + reactServer: 'react-server', }) }) @@ -129,7 +129,7 @@ function runTests() { expect(json).toMatchObject({ edgeThenNode: 'edge', nodeThenEdge: 'edge', - reactServer: 'default', + reactServer: 'react-server', }) }) diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt new file mode 100644 index 0000000000000..72c048d7b6481 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt @@ -0,0 +1,13 @@ +error - [resolve] [project]/packages/next/dist/compiled/nanoid/index.cjs /packages/next/dist/compiled/nanoid/index.cjs:1:45 Error resolving commonjs request + + v---------------v + 1 + (()=>{var e={113:e=>{"use strict";e.exports=require("crypto")},660:(e,r,t)=>{let l=t(113);let{urlAlphabet:a}=t(591);const n=128;let _,u;let fillPool=e=>{if(!_||...ndefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(660);module.exports=t})(); + + ^---------------^ + + unable to resolve module "crypto" + + | It was not possible to find the requested file. + | Parsed request as written in source code: module "crypto" + | Path where resolving has started: [project]/packages/next/dist/compiled/nanoid/index.cjs + | Type of request: commonjs request + | Import map: No import map entry + | \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt new file mode 100644 index 0000000000000..72c048d7b6481 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt @@ -0,0 +1,13 @@ +error - [resolve] [project]/packages/next/dist/compiled/nanoid/index.cjs /packages/next/dist/compiled/nanoid/index.cjs:1:45 Error resolving commonjs request + + v---------------v + 1 + (()=>{var e={113:e=>{"use strict";e.exports=require("crypto")},660:(e,r,t)=>{let l=t(113);let{urlAlphabet:a}=t(591);const n=128;let _,u;let fillPool=e=>{if(!_||...ndefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(660);module.exports=t})(); + + ^---------------^ + + unable to resolve module "crypto" + + | It was not possible to find the requested file. + | Parsed request as written in source code: module "crypto" + | Path where resolving has started: [project]/packages/next/dist/compiled/nanoid/index.cjs + | Type of request: commonjs request + | Import map: No import map entry + | \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt deleted file mode 100644 index a5ad94c85fb0a..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt +++ /dev/null @@ -1,17 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:64:56 lint TP1004 fs.readFile(???*0*) is very dynamic - 60 | } - 61 | async function loadWasm(wasm) { - 62 | const modules = {}; - 63 | await Promise.all(wasm.map(async (binding)=>{ - + v - 64 + const module1 = await WebAssembly.compile(await _fs.promises.readFile(binding.filePath)); - + ^ - 65 | modules[binding.name] = module1; - 66 | })); - 67 | return modules; - 68 | } - - - *0* ???*1*["filePath"] - ⚠️ unknown object - - *1* binding - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt deleted file mode 100644 index c80db085946c2..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt +++ /dev/null @@ -1,15 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:355:28 lint TP1004 fs.readFileSync(???*0*, "utf-8") is very dynamic - 351 | } - 352 | const moduleContext = lazyModuleContext; - 353 | const evaluateInContext = (filepath)=>{ - 354 | if (!moduleContext.paths.has(filepath)) { - + v - 355 + const content = (0, _fs.readFileSync)(filepath, "utf-8"); - + ^ - 356 | try { - 357 | (0, _vm.runInContext)(content, moduleContext.runtime.context, { - 358 | filename: filepath - 359 | }); - - - *0* filepath - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next/config.d.ts b/packages/next/config.d.ts index 2da1ee3c4029c..78fe148a8dc9b 100644 --- a/packages/next/config.d.ts +++ b/packages/next/config.d.ts @@ -1,3 +1,3 @@ -import getConfig from './dist/shared/lib/runtime-config.shared-runtime' -export * from './dist/shared/lib/runtime-config.shared-runtime' +import getConfig from './dist/shared/lib/runtime-config' +export * from './dist/shared/lib/runtime-config' export default getConfig diff --git a/packages/next/config.js b/packages/next/config.js index 6510748638097..2da980d8b0065 100644 --- a/packages/next/config.js +++ b/packages/next/config.js @@ -1 +1 @@ -module.exports = require('./dist/shared/lib/runtime-config.shared-runtime') +module.exports = require('./dist/shared/lib/runtime-config') diff --git a/packages/next/package.json b/packages/next/package.json index 30ee061047fad..28fbd949a8972 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -83,7 +83,6 @@ }, "taskr": { "requires": [ - "./taskfile-webpack.js", "./taskfile-ncc.js", "./taskfile-swc.js", "./taskfile-watch.js" @@ -300,7 +299,6 @@ "tar": "6.1.15", "taskr": "1.1.0", "terser": "5.14.1", - "terser-webpack-plugin": "5.3.9", "text-table": "0.2.0", "timers-browserify": "2.0.12", "tty-browserify": "0.0.1", diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index b0e0870ca1392..8ad7407b4be45 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -143,13 +143,8 @@ import { createClientRouterFilter } from '../lib/create-client-router-filter' import { createValidFileMatcher } from '../server/lib/find-page-file' import { startTypeChecking } from './type-check' import { generateInterceptionRoutesRewrites } from '../lib/generate-interception-routes-rewrites' - import { buildDataRoute } from '../server/lib/router-utils/build-data-route' -import { - baseOverrides, - defaultOverrides, - experimentalOverrides, -} from '../server/require-hook' +import { baseOverrides, experimentalOverrides } from '../server/require-hook' import { initialize } from '../server/lib/incremental-cache-server' import { nodeFs } from '../server/lib/node-fs-methods' @@ -1248,7 +1243,6 @@ export default async function build( forkOptions: { env: { ...process.env, - __NEXT_PRIVATE_RENDER_RUNTIME: type, __NEXT_INCREMENTAL_CACHE_IPC_PORT: ipcPort + '', __NEXT_INCREMENTAL_CACHE_IPC_KEY: ipcValidationKey, __NEXT_PRIVATE_PREBUNDLED_REACT: @@ -2090,25 +2084,6 @@ export default async function build( ...Object.values(experimentalOverrides).map((override) => require.resolve(override) ), - ...(config.experimental.turbotrace - ? [] - : Object.keys(defaultOverrides).map((value) => - require.resolve(value, { - paths: [require.resolve('next/dist/server/require-hook')], - }) - )), - require.resolve( - 'next/dist/compiled/next-server/app-page.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/app-route.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/pages.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/pages-api.runtime.prod' - ), ] // ensure we trace any dependencies needed for custom @@ -2134,7 +2109,10 @@ export default async function build( const minimalServerEntries = [ ...sharedEntriesSet, require.resolve( - 'next/dist/compiled/next-server/server.runtime.prod' + 'next/dist/compiled/minimal-next-server/next-server-cached.js' + ), + require.resolve( + 'next/dist/compiled/minimal-next-server/next-server.js' ), ].filter(Boolean) diff --git a/packages/next/src/build/templates/app-page.ts b/packages/next/src/build/templates/app-page.ts index f0d2ab692e2aa..c75509904c3a8 100644 --- a/packages/next/src/build/templates/app-page.ts +++ b/packages/next/src/build/templates/app-page.ts @@ -1,7 +1,7 @@ import type { LoaderTree } from '../../server/lib/app-dir-module' // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-page/module.compiled' +import * as module from 'next/dist/server/future/route-modules/app-page/module' import { RouteKind } from '../../server/future/route-kind' const AppPageRouteModule = diff --git a/packages/next/src/build/templates/app-route.ts b/packages/next/src/build/templates/app-route.ts index b4b8e5b0fe6cd..50a8b6165a747 100644 --- a/packages/next/src/build/templates/app-route.ts +++ b/packages/next/src/build/templates/app-route.ts @@ -1,8 +1,7 @@ import '../../server/node-polyfill-headers' // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-route/module.compiled' - +import * as module from 'next/dist/server/future/route-modules/app-route/module' import type { AppRouteRouteModuleOptions } from '../../server/future/route-modules/app-route/module' import { RouteKind } from '../../server/future/route-kind' diff --git a/packages/next/src/build/templates/pages-api.ts b/packages/next/src/build/templates/pages-api.ts index eaeec836cb61e..a48822f9ed75a 100644 --- a/packages/next/src/build/templates/pages-api.ts +++ b/packages/next/src/build/templates/pages-api.ts @@ -1,6 +1,5 @@ // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages-api/module.compiled' - +import * as module from 'next/dist/server/future/route-modules/pages-api/module' import { RouteKind } from '../../server/future/route-kind' import { hoist } from './helpers' diff --git a/packages/next/src/build/templates/pages.ts b/packages/next/src/build/templates/pages.ts index b5def5d13c552..3f3527e6650d6 100644 --- a/packages/next/src/build/templates/pages.ts +++ b/packages/next/src/build/templates/pages.ts @@ -1,5 +1,5 @@ // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages/module.compiled' +import * as module from 'next/dist/server/future/route-modules/pages/module' import { RouteKind } from '../../server/future/route-kind' import { hoist } from './helpers' diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index 423beb27f6dca..867429c2ba901 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -14,7 +14,7 @@ import type { EdgeFunctionDefinition, MiddlewareManifest, } from './webpack/plugins/middleware-plugin' -import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage' import '../server/require-hook' import '../server/node-polyfill-fetch' @@ -65,9 +65,7 @@ import { nodeFs } from '../server/lib/node-fs-methods' import * as ciEnvironment from '../telemetry/ci-info' import { normalizeAppPath } from '../shared/lib/router/utils/app-paths' import { denormalizeAppPagePath } from '../shared/lib/page-path/denormalize-app-path' -// import { AppRouteRouteModule } from '../server/future/route-modules/app-route/module' -const { AppRouteRouteModule } = - require('../server/future/route-modules/app-route/module.compiled') as typeof import('../server/future/route-modules/app-route/module') +import { AppRouteRouteModule } from '../server/future/route-modules/app-route/module' export type ROUTER_TYPE = 'pages' | 'app' @@ -1391,9 +1389,7 @@ export async function isPageStatic({ const isPageStaticSpan = trace('is-page-static-utils', parentId) return isPageStaticSpan .traceAsyncFn(async () => { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) setHttpClientAndAgentOptions({ httpAgentOptions, }) @@ -1677,9 +1673,7 @@ export async function hasCustomGetInitialProps( runtimeEnvConfig: any, checkingApp: boolean ): Promise { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, @@ -1702,9 +1696,7 @@ export async function getDefinedNamedExports( distDir: string, runtimeEnvConfig: any ): Promise> { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, pathname: page, diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index d1b7487618fe2..f1f053d05eb9b 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -103,19 +103,6 @@ const reactPackagesRegex = /^(react|react-dom|react-server-dom-webpack)($|\/)/ const asyncStoragesRegex = /next[\\/]dist[\\/](esm[\\/])?client[\\/]components[\\/](static-generation-async-storage|action-async-storage|request-async-storage)/ -const pathSeparators = '[/\\\\]' -const optionalEsmPart = `((${pathSeparators}esm)?${pathSeparators})` -const sharedRuntimeFileEnd = '(\\.shared-runtime(\\.js)?)$' -const externalFileEnd = '(\\.external(\\.js)?)$' -const nextDist = `next${pathSeparators}dist` - -const sharedRuntimePattern = new RegExp( - `${nextDist}${optionalEsmPart}.*${sharedRuntimeFileEnd}` -) -const externalPattern = new RegExp( - `${nextDist}${optionalEsmPart}.*${externalFileEnd}` -) - // exports. const edgeConditionNames = [ 'edge-light', @@ -1024,7 +1011,7 @@ export default async function getBaseWebpackConfig( const customRootAliases: { [key: string]: string[] } = {} if (dev) { - const nextDistPath = 'next/dist/' + (isEdgeServer ? 'esm/' : '') + const nextDist = 'next/dist/' + (isEdgeServer ? 'esm/' : '') customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [ ...(pagesDir ? pageExtensions.reduce((prev, ext) => { @@ -1032,7 +1019,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_app.js`, + `${nextDist}pages/_app.js`, ] customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [ ...(pagesDir @@ -1041,7 +1028,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_error.js`, + `${nextDist}pages/_error.js`, ] customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [ ...(pagesDir @@ -1050,7 +1037,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_document.js`, + `${nextDist}pages/_document.js`, ] } @@ -1324,7 +1311,6 @@ export default async function getBaseWebpackConfig( WEBPACK_LAYERS.serverSideRendering, WEBPACK_LAYERS.appPagesBrowser, WEBPACK_LAYERS.actionBrowser, - WEBPACK_LAYERS.appRouteHandler, ].includes(layer!) if ( @@ -1381,7 +1367,7 @@ export default async function getBaseWebpackConfig( } const notExternalModules = - /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers|router)$)|string-hash|private-next-rsc-action-validate|private-next-rsc-action-client-wrapper|private-next-rsc-action-proxy$)/ + /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-action-validate|private-next-rsc-action-client-wrapper|private-next-rsc-action-proxy$)/ if (notExternalModules.test(request)) { return } @@ -1404,59 +1390,41 @@ export default async function getBaseWebpackConfig( // Also disable esm request when appDir is enabled const isEsmRequested = dependencyType === 'esm' - /** - * @param localRes the full path to the file - * @returns the externalized path - * @description returns an externalized path if the file is a Next.js file and ends with either `.shared-runtime.js` or `.external.js` - * This is used to ensure that files used across the rendering runtime(s) and the user code are one and the same. The logic in this function - * will rewrite the require to the correct bundle location depending on the layer at which the file is being used. - */ const isLocalCallback = (localRes: string) => { - const isSharedRuntime = sharedRuntimePattern.test(localRes) - const isExternal = externalPattern.test(localRes) - - // if the file ends with .external, we need to make it a commonjs require in all cases - // this is used mainly to share the async local storage across the routing, rendering and user layers. - if (isExternal) { - // it's important we return the path that starts with `next/dist/` here instead of the absolute path - // otherwise NFT will get tripped up - return `commonjs ${localRes.replace(/.*?next[/\\]dist/, 'next/dist')}` - } - // if the file ends with .shared-runtime, we need to make it point to the correct bundle depending on the layer - // this is because each shared-runtime files are unique per bundle, so if you use app-router context in pages, - // it'll be a different instance than the one used in the app-router runtime. - if (isSharedRuntime) { - if (dev) { - return `commonjs ${localRes}` - } + // Makes sure dist/shared and dist/server are not bundled + // we need to process shared `router/router`, `head` and `dynamic`, + // so that the DefinePlugin can inject process.env values. - const name = path.parse(localRes).name.replace('.shared-runtime', '') + // Treat next internals as non-external for server layer + if (isWebpackServerLayer(layer)) { + return + } - const camelCaseName = name.replace(/-([a-z])/g, (_, w) => - w.toUpperCase() + const isNextExternal = + /next[/\\]dist[/\\](esm[\\/])?(shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic|app-dynamic|image-external|lazy-dynamic|head[^-]))/.test( + localRes + ) || + // There's no need to bundle the dev overlay + (process.env.NODE_ENV === 'development' && + /next[/\\]dist[/\\](esm[/\\])?client[/\\]components[/\\]react-dev-overlay[/\\]/.test( + localRes + )) + + if (isNextExternal) { + // Generate Next.js external import + const externalRequest = path.posix.join( + 'next', + 'dist', + path + .relative( + // Root of Next.js package: + path.join(__dirname, '..'), + localRes + ) + // Windows path normalization + .replace(/\\/g, '/') ) - - // there's no externals for API routes but if need be, they'll need to be added here and have - // their own layer - const runtime = - layer === 'app-route-handler' - ? 'app-route' - : isAppLayer - ? 'app-page' - : 'pages' - return [ - 'commonjs ' + - path.posix.join( - 'next', - 'dist', - 'compiled', - 'next-server', - `${runtime}.runtime.${dev ? 'dev' : 'prod'}` - ), - 'default', - 'sharedModules', - camelCaseName, - ] + return `commonjs ${externalRequest}` } } @@ -1477,10 +1445,6 @@ export default async function getBaseWebpackConfig( return } - if (/^next\/dist\/compiled\/next-server/.test(request)) { - return `commonjs ${request}` - } - if ( /^next\/dist\/shared\/(?!lib\/router\/router)/.test(request) || /^next\/dist\/compiled\/.*\.c?js$/.test(request) @@ -2067,14 +2031,6 @@ export default async function getBaseWebpackConfig( }, ...(hasAppDir ? [ - { - layer: WEBPACK_LAYERS.appRouteHandler, - test: new RegExp( - `private-next-app-dir\\/.*\\/route\\.(${pageExtensions.join( - '|' - )})$` - ), - }, { // Make sure that AsyncLocalStorage module instance is shared between server and client // layers. @@ -2283,7 +2239,7 @@ export default async function getBaseWebpackConfig( WEBPACK_LAYERS.appPagesBrowser, ], }, - exclude: [codeCondition.exclude], + exclude: [asyncStoragesRegex, codeCondition.exclude], use: [ ...(dev && isClient ? [ diff --git a/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts b/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts index c2b1089df5b3f..2be12daecdbc6 100644 --- a/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts +++ b/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts @@ -442,7 +442,7 @@ declare module 'next/link' { declare module 'next/navigation' { export * from 'next/dist/client/components/navigation.js' - import type { NavigateOptions, AppRouterInstance as OriginalAppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime.js' + import type { NavigateOptions, AppRouterInstance as OriginalAppRouterInstance } from 'next/dist/shared/lib/app-router-context.js' interface AppRouterInstance extends OriginalAppRouterInstance { /** * Navigate to the provided href. @@ -575,11 +575,8 @@ export class NextTypesPlugin { } return } - if ( - mod.layer !== WEBPACK_LAYERS.reactServerComponents && - mod.layer !== WEBPACK_LAYERS.appRouteHandler - ) - return + + if (mod.layer !== WEBPACK_LAYERS.reactServerComponents) return const IS_LAYOUT = /[/\\]layout\.[^./\\]+$/.test(mod.resource) const IS_PAGE = !IS_LAYOUT && /[/\\]page\.[^.]+$/.test(mod.resource) diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 47c0bd13f369e..8f82d244837e6 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -7,8 +7,8 @@ import React, { use } from 'react' // eslint-disable-next-line import/no-extraneous-dependencies import { createFromReadableStream } from 'react-server-dom-webpack/client' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' -import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' +import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context' import onRecoverableError from './on-recoverable-error' import { callServer } from './app-call-server' import { isNextRouterError } from './components/is-next-router-error' diff --git a/packages/next/src/client/compat/router.ts b/packages/next/src/client/compat/router.ts index e9143c4117bd7..58b1b9f02ed05 100644 --- a/packages/next/src/client/compat/router.ts +++ b/packages/next/src/client/compat/router.ts @@ -1,5 +1,5 @@ import { useContext } from 'react' -import { RouterContext } from '../../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../../shared/lib/router-context' import { NextRouter } from '../router' /** diff --git a/packages/next/src/client/components/action-async-storage.external.ts b/packages/next/src/client/components/action-async-storage.ts similarity index 100% rename from packages/next/src/client/components/action-async-storage.external.ts rename to packages/next/src/client/components/action-async-storage.ts diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index a8de967825e16..db181118a674a 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -14,11 +14,11 @@ import { LayoutRouterContext, GlobalLayoutRouterContext, CacheStates, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import type { CacheNode, AppRouterInstance, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import type { FlightRouterState, FlightData, @@ -44,7 +44,7 @@ import { createHrefFromUrl } from './router-reducer/create-href-from-url' import { SearchParamsContext, PathnameContext, -} from '../../shared/lib/hooks-client-context.shared-runtime' +} from '../../shared/lib/hooks-client-context' import { useReducerWithReduxDevtools } from './use-reducer-with-devtools' import { ErrorBoundary } from './error-boundary' import { diff --git a/packages/next/src/client/components/bailout-to-client-rendering.ts b/packages/next/src/client/components/bailout-to-client-rendering.ts index 799398b5f300c..76356e05304a8 100644 --- a/packages/next/src/client/components/bailout-to-client-rendering.ts +++ b/packages/next/src/client/components/bailout-to-client-rendering.ts @@ -1,5 +1,5 @@ import { suspense } from '../../shared/lib/lazy-dynamic/dynamic-no-ssr' -import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' +import { staticGenerationAsyncStorage } from './static-generation-async-storage' export function bailoutToClientRendering(): boolean | never { const staticGenerationStore = staticGenerationAsyncStorage.getStore() diff --git a/packages/next/src/client/components/headers.ts b/packages/next/src/client/components/headers.ts index a0a27a184cbfe..d090264391e7c 100644 --- a/packages/next/src/client/components/headers.ts +++ b/packages/next/src/client/components/headers.ts @@ -4,8 +4,8 @@ import { } from '../../server/web/spec-extension/adapters/request-cookies' import { HeadersAdapter } from '../../server/web/spec-extension/adapters/headers' import { RequestCookies } from '../../server/web/spec-extension/cookies' -import { requestAsyncStorage } from './request-async-storage.external' -import { actionAsyncStorage } from './action-async-storage.external' +import { requestAsyncStorage } from './request-async-storage' +import { actionAsyncStorage } from './action-async-storage' import { staticGenerationBailout } from './static-generation-bailout' import { DraftMode } from './draft-mode' @@ -17,6 +17,7 @@ export function headers() { ) { return HeadersAdapter.seal(new Headers({})) } + const requestStore = requestAsyncStorage.getStore() if (!requestStore) { throw new Error( diff --git a/packages/next/src/client/components/layout-router.tsx b/packages/next/src/client/components/layout-router.tsx index 1f0ffff7e2de8..3e410a93fb0ca 100644 --- a/packages/next/src/client/components/layout-router.tsx +++ b/packages/next/src/client/components/layout-router.tsx @@ -1,6 +1,6 @@ 'use client' -import type { ChildSegmentMap } from '../../shared/lib/app-router-context.shared-runtime' +import type { ChildSegmentMap } from '../../shared/lib/app-router-context' import type { FlightRouterState, FlightSegmentPath, @@ -17,7 +17,7 @@ import { LayoutRouterContext, GlobalLayoutRouterContext, TemplateContext, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import { fetchServerResponse } from './router-reducer/fetch-server-response' import { createInfinitePromise } from './infinite-promise' import { ErrorBoundary } from './error-boundary' diff --git a/packages/next/src/client/components/navigation.ts b/packages/next/src/client/components/navigation.ts index b3d69dcb065e8..bf6a56100080d 100644 --- a/packages/next/src/client/components/navigation.ts +++ b/packages/next/src/client/components/navigation.ts @@ -4,11 +4,11 @@ import { AppRouterContext, GlobalLayoutRouterContext, LayoutRouterContext, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import { SearchParamsContext, PathnameContext, -} from '../../shared/lib/hooks-client-context.shared-runtime' +} from '../../shared/lib/hooks-client-context' import { clientHookInServerComponentError } from './client-hook-in-server-component-error' import { getSegmentValue } from './router-reducer/reducers/get-segment-value' @@ -111,12 +111,12 @@ export function usePathname(): string { export { ServerInsertedHTMLContext, useServerInsertedHTML, -} from '../../shared/lib/server-inserted-html.shared-runtime' +} from '../../shared/lib/server-inserted-html' /** * Get the router methods. For example router.push('/dashboard') */ -export function useRouter(): import('../../shared/lib/app-router-context.shared-runtime').AppRouterInstance { +export function useRouter(): import('../../shared/lib/app-router-context').AppRouterInstance { clientHookInServerComponentError('useRouter') const router = useContext(AppRouterContext) if (router === null) { diff --git a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts index d37fce9851e91..4d92a279c3ed5 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts +++ b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts @@ -1,5 +1,5 @@ import { useCallback, useContext, useEffect, useRef } from 'react' -import { GlobalLayoutRouterContext } from '../../../../../shared/lib/app-router-context.shared-runtime' +import { GlobalLayoutRouterContext } from '../../../../../shared/lib/app-router-context' import { getSocketUrl } from './get-socket-url' export function useWebsocket(assetPrefix: string) { diff --git a/packages/next/src/client/components/redirect-boundary.tsx b/packages/next/src/client/components/redirect-boundary.tsx index 8d407fd6e9d6e..23e5493ae83fb 100644 --- a/packages/next/src/client/components/redirect-boundary.tsx +++ b/packages/next/src/client/components/redirect-boundary.tsx @@ -1,6 +1,6 @@ 'use client' import React, { useEffect } from 'react' -import { AppRouterInstance } from '../../shared/lib/app-router-context.shared-runtime' +import { AppRouterInstance } from '../../shared/lib/app-router-context' import { useRouter } from './navigation' import { RedirectType, diff --git a/packages/next/src/client/components/redirect.ts b/packages/next/src/client/components/redirect.ts index b9a2cfebd883f..10e72bc1ccbef 100644 --- a/packages/next/src/client/components/redirect.ts +++ b/packages/next/src/client/components/redirect.ts @@ -1,4 +1,4 @@ -import { requestAsyncStorage } from './request-async-storage.external' +import { requestAsyncStorage } from './request-async-storage' import type { ResponseCookies } from '../../server/web/spec-extension/cookies' const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT' diff --git a/packages/next/src/client/components/render-from-template-context.tsx b/packages/next/src/client/components/render-from-template-context.tsx index c1755cc5056bf..be486842c4f33 100644 --- a/packages/next/src/client/components/render-from-template-context.tsx +++ b/packages/next/src/client/components/render-from-template-context.tsx @@ -1,7 +1,7 @@ 'use client' import React, { useContext } from 'react' -import { TemplateContext } from '../../shared/lib/app-router-context.shared-runtime' +import { TemplateContext } from '../../shared/lib/app-router-context' export default function RenderFromTemplateContext(): JSX.Element { const children = useContext(TemplateContext) diff --git a/packages/next/src/client/components/request-async-storage.external.ts b/packages/next/src/client/components/request-async-storage.ts similarity index 100% rename from packages/next/src/client/components/request-async-storage.external.ts rename to packages/next/src/client/components/request-async-storage.ts diff --git a/packages/next/src/client/components/router-reducer/apply-flight-data.ts b/packages/next/src/client/components/router-reducer/apply-flight-data.ts index 003d0a5cde9e4..e7a2f11a84f48 100644 --- a/packages/next/src/client/components/router-reducer/apply-flight-data.ts +++ b/packages/next/src/client/components/router-reducer/apply-flight-data.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { FlightDataPath } from '../../../server/app-render/types' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx index 414b553c63249..a6052636ef256 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import type { FlightRouterState } from '../../../server/app-render/types' -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { createInitialRouterState } from './create-initial-router-state' const buildId = 'development' diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts index 94fdabb9b577a..7f7cca2003b0b 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts @@ -1,8 +1,8 @@ import type { ReactNode } from 'react' -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' -import { CacheStates } from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../shared/lib/app-router-context' import { createHrefFromUrl } from './create-href-from-url' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' import { extractPathFromFlightRouterState } from './compute-changed-path' diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx index 648069ea76986..28f8c3412ab3a 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx @@ -1,10 +1,7 @@ import React from 'react' import { fetchServerResponse } from './fetch-server-response' import { fillCacheWithDataProperty } from './fill-cache-with-data-property' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' describe('fillCacheWithDataProperty', () => { it('should add data property', () => { const fetchServerResponseMock: jest.Mock< diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts index 42df61a952af5..81df295dba302 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts @@ -1,8 +1,5 @@ import { FlightSegmentPath } from '../../../server/app-render/types' -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { createRouterCacheKey } from './create-router-cache-key' import { fetchServerResponse } from './fetch-server-response' diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx index ac888a3ede0ff..187f86a478751 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightData } from '../../../server/app-render/types' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts index 7e9a93699fb65..5d48eaee9ef9f 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import type { FlightDataPath } from '../../../server/app-render/types' import { invalidateCacheByRouterState } from './invalidate-cache-by-router-state' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx index 1edbeffd7b3e9..606440a96f9c9 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightData } from '../../../server/app-render/types' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts index f558edfab2f1e..c5ddedd52351e 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx index 8c23c47d42d74..915f09cae0cae 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx @@ -1,10 +1,7 @@ import React from 'react' import type { FlightData } from '../../../server/app-render/types' import { invalidateCacheBelowFlightSegmentPath } from './invalidate-cache-below-flight-segmentpath' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts index d637d850b145a..ac343f8d79679 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightSegmentPath } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx index bdd819b0614d9..65ce9e42c05ee 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { invalidateCacheByRouterState } from './invalidate-cache-by-router-state' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' describe('invalidateCacheByRouterState', () => { diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts index 1ec39ae9e35fd..820e5909bf031 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx index 2d4cdef348b1e..807374c855577 100644 --- a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx @@ -3,7 +3,7 @@ import type { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { findHeadInCache } from './find-head-in-cache' describe('findHeadInCache', () => { diff --git a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts index 08dcefc65f2ce..f4d5e768b9808 100644 --- a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts +++ b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts @@ -1,5 +1,5 @@ import type { FlightRouterState } from '../../../../server/app-render/types' -import type { CacheNode } from '../../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../../shared/lib/app-router-context' import { createRouterCacheKey } from '../create-router-cache-key' export function findHeadInCache( diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx index fcde9b963e9fd..db40adfa3c5b1 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx @@ -79,7 +79,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { NavigateAction, diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts index e47c42b2aa60a..fe8a4a24c4b8b 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts @@ -1,7 +1,7 @@ import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import type { FlightRouterState, FlightSegmentPath, diff --git a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx index bbbee6ff5f2a4..8055123367a94 100644 --- a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx @@ -36,7 +36,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { PrefetchAction, diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx index bbf36b1ec538c..90ce7dc9423a3 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx @@ -46,7 +46,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { RefreshAction, ACTION_REFRESH } from '../router-reducer-types' import { refreshReducer } from './refresh-reducer' diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts index bd6dfc4ef9047..cd87ef3802b00 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts @@ -11,7 +11,7 @@ import { } from '../router-reducer-types' import { handleExternalUrl } from './navigate-reducer' import { handleMutable } from '../handle-mutable' -import { CacheStates } from '../../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../../shared/lib/app-router-context' import { fillLazyItemsTillLeafWithHead } from '../fill-lazy-items-till-leaf-with-head' export function refreshReducer( diff --git a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx index 36c978926517f..b11f39b141ccf 100644 --- a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx @@ -3,7 +3,7 @@ import type { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { RestoreAction, ACTION_RESTORE } from '../router-reducer-types' import { restoreReducer } from './restore-reducer' diff --git a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts index 0c6caaba746ca..3b8fa6acb4013 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts @@ -27,7 +27,7 @@ import { createHrefFromUrl } from '../create-href-from-url' import { handleExternalUrl } from './navigate-reducer' import { applyRouterStatePatchToTree } from '../apply-router-state-patch-to-tree' import { isNavigatingToNewRootLayout } from '../is-navigating-to-new-root-layout' -import { CacheStates } from '../../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../../shared/lib/app-router-context' import { handleMutable } from '../handle-mutable' import { fillLazyItemsTillLeafWithHead } from '../fill-lazy-items-till-leaf-with-head' diff --git a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx index 9e7035dc7e819..db72a92fce743 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx @@ -45,7 +45,7 @@ jest.mock('../fetch-server-response', () => { import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { ServerPatchAction, diff --git a/packages/next/src/client/components/router-reducer/router-reducer-types.ts b/packages/next/src/client/components/router-reducer/router-reducer-types.ts index d9c641c4045b7..284628dbf9098 100644 --- a/packages/next/src/client/components/router-reducer/router-reducer-types.ts +++ b/packages/next/src/client/components/router-reducer/router-reducer-types.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState, FlightData, diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.ts similarity index 100% rename from packages/next/src/client/components/static-generation-async-storage.external.ts rename to packages/next/src/client/components/static-generation-async-storage.ts diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index 4d35150664251..c5072218f035c 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -1,5 +1,5 @@ import { DynamicServerError } from './hooks-server-context' -import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' +import { staticGenerationAsyncStorage } from './static-generation-async-storage' class StaticGenBailoutError extends Error { code = 'NEXT_STATIC_GEN_BAILOUT' diff --git a/packages/next/src/client/image-component.tsx b/packages/next/src/client/image-component.tsx index 321b07ecd0a5f..3f2183c004b10 100644 --- a/packages/next/src/client/image-component.tsx +++ b/packages/next/src/client/image-component.tsx @@ -25,9 +25,9 @@ import type { ImageLoaderProps, } from '../shared/lib/image-config' import { imageConfigDefault } from '../shared/lib/image-config' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import { warnOnce } from '../shared/lib/utils/warn-once' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' // @ts-ignore - This is replaced by webpack alias import defaultLoader from 'next/dist/shared/lib/image-loader' diff --git a/packages/next/src/client/index.tsx b/packages/next/src/client/index.tsx index 0f8a95c93746e..f7c163f020d31 100644 --- a/packages/next/src/client/index.tsx +++ b/packages/next/src/client/index.tsx @@ -10,16 +10,16 @@ import type { import React from 'react' import ReactDOM from 'react-dom/client' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' import mitt, { MittEmitter } from '../shared/lib/mitt' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import { handleSmoothScroll } from '../shared/lib/router/utils/handle-smooth-scroll' import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic' import { urlQueryToSearchParams, assign, } from '../shared/lib/router/utils/querystring' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config' import { getURL, loadGetInitialProps, @@ -34,17 +34,17 @@ import measureWebVitals from './performance-relayer' import { RouteAnnouncer } from './route-announcer' import { createRouter, makePublicRouterInstance } from './router' import { getProperError } from '../lib/is-error' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import { ImageConfigComplete } from '../shared/lib/image-config' import { removeBasePath } from './remove-base-path' import { hasBasePath } from './has-base-path' -import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime' +import { AppRouterContext } from '../shared/lib/app-router-context' import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' -import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' +} from '../shared/lib/router/adapters' +import { SearchParamsContext } from '../shared/lib/hooks-client-context' import onRecoverableError from './on-recoverable-error' import tracer from './tracing/tracer' import reportToSocket from './tracing/report-to-socket' diff --git a/packages/next/src/client/legacy/image.tsx b/packages/next/src/client/legacy/image.tsx index 07ec2e217c200..d1456477bacf6 100644 --- a/packages/next/src/client/legacy/image.tsx +++ b/packages/next/src/client/legacy/image.tsx @@ -16,7 +16,7 @@ import { VALID_LOADERS, } from '../../shared/lib/image-config' import { useIntersection } from '../use-intersection' -import { ImageConfigContext } from '../../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../../shared/lib/image-config-context' import { warnOnce } from '../../shared/lib/utils/warn-once' import { normalizePathTrailingSlash } from '../normalize-trailing-slash' diff --git a/packages/next/src/client/link.tsx b/packages/next/src/client/link.tsx index 7a15dee249e26..94226c8caa5c0 100644 --- a/packages/next/src/client/link.tsx +++ b/packages/next/src/client/link.tsx @@ -12,12 +12,12 @@ import { isLocalURL } from '../shared/lib/router/utils/is-local-url' import { formatUrl } from '../shared/lib/router/utils/format-url' import { isAbsoluteUrl } from '../shared/lib/utils' import { addLocale } from './add-locale' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import { AppRouterContext, AppRouterInstance, PrefetchOptions as AppRouterPrefetchOptions, -} from '../shared/lib/app-router-context.shared-runtime' +} from '../shared/lib/app-router-context' import { useIntersection } from './use-intersection' import { getDomainLocale } from './get-domain-locale' import { addBasePath } from './add-base-path' diff --git a/packages/next/src/client/router.ts b/packages/next/src/client/router.ts index f43126691e5e5..342ecb623df74 100644 --- a/packages/next/src/client/router.ts +++ b/packages/next/src/client/router.ts @@ -2,7 +2,7 @@ import React from 'react' import Router from '../shared/lib/router/router' import type { NextRouter } from '../shared/lib/router/router' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import isError from '../lib/is-error' type SingletonRouterBase = { diff --git a/packages/next/src/client/script.tsx b/packages/next/src/client/script.tsx index f695e691c482d..a4b2c6dcd3184 100644 --- a/packages/next/src/client/script.tsx +++ b/packages/next/src/client/script.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom' import React, { useEffect, useContext, useRef } from 'react' import { ScriptHTMLAttributes } from 'react' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' import { DOMAttributeNames } from './head-manager' import { requestIdleCallback } from './request-idle-callback' diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index b9fb7b9afd60a..31f58755996a4 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -59,7 +59,7 @@ import { RSC, } from '../client/components/app-router-headers' -const envConfig = require('../shared/lib/runtime-config.shared-runtime') +const envConfig = require('../shared/lib/runtime-config') ;(globalThis as any).__NEXT_DATA__ = { nextExport: true, @@ -307,10 +307,8 @@ export default async function exportPage({ await promises.mkdir(baseDir, { recursive: true }) let renderResult: RenderResult | undefined let curRenderOpts: RenderOpts = {} - const renderToHTML = - require('../server/future/route-modules/pages/module.compiled') - .renderToHTML as typeof import('../server/render').renderToHTML - + const { renderToHTML } = + require('../server/render') as typeof import('../server/render') let renderMethod = renderToHTML let inAmpMode = false, hybridAmp = false @@ -481,6 +479,7 @@ export default async function exportPage({ const module = await RouteModuleLoader.load( filename ) + // Call the handler with the request and context from the module. const response = await module.handle(request, context) @@ -536,9 +535,8 @@ export default async function exportPage({ results.fromBuildExportRevalidate = 0 } } else { - const renderToHTMLOrFlight = - require('../server/future/route-modules/app-page/module.compiled') - .renderToHTMLOrFlight as typeof import('../server/app-render/app-render').renderToHTMLOrFlight + const { renderToHTMLOrFlight } = + require('../server/app-render/app-render') as typeof import('../server/app-render/app-render') try { curRenderOpts.params ||= {} diff --git a/packages/next/src/lib/chalk.ts b/packages/next/src/lib/chalk.ts index d0939d9148b97..8e40472953f8f 100644 --- a/packages/next/src/lib/chalk.ts +++ b/packages/next/src/lib/chalk.ts @@ -1,6 +1,6 @@ let chalk: typeof import('next/dist/compiled/chalk') -if (process.env.NEXT_RUNTIME === 'edge' || process.env.NEXT_MINIMAL) { +if (process.env.NEXT_RUNTIME === 'edge') { chalk = require('./web/chalk').default } else { chalk = require('next/dist/compiled/chalk') diff --git a/packages/next/src/lib/constants.ts b/packages/next/src/lib/constants.ts index 46f85311a9f0a..fc94397c6aca7 100644 --- a/packages/next/src/lib/constants.ts +++ b/packages/next/src/lib/constants.ts @@ -132,10 +132,6 @@ const WEBPACK_LAYERS_NAMES = { * The server bundle layer for metadata routes. */ appMetadataRoute: 'app-metadata-route', - /** - * The layer for the server bundle for App Route handlers. - */ - appRouteHandler: 'app-route-handler', } export const WEBPACK_LAYERS = { @@ -145,7 +141,6 @@ export const WEBPACK_LAYERS = { WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.actionBrowser, WEBPACK_LAYERS_NAMES.appMetadataRoute, - WEBPACK_LAYERS_NAMES.appRouteHandler, ], }, } diff --git a/packages/next/src/pages/_document.tsx b/packages/next/src/pages/_document.tsx index f0a29cb15d1fc..a8526011c5d33 100644 --- a/packages/next/src/pages/_document.tsx +++ b/packages/next/src/pages/_document.tsx @@ -17,11 +17,8 @@ import { BuildManifest, getPageFiles } from '../server/get-page-files' import { htmlEscapeJsonString } from '../server/htmlescape' import isError from '../lib/is-error' -import { - HtmlContext, - useHtmlContext, -} from '../shared/lib/html-context.shared-runtime' -import type { HtmlProps } from '../shared/lib/html-context.shared-runtime' +import { HtmlContext, useHtmlContext } from '../shared/lib/html-context' +import type { HtmlProps } from '../shared/lib/html-context' export { DocumentContext, DocumentInitialProps, DocumentProps } diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 9f6059ec48f5a..6b8bc3228a005 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -19,10 +19,10 @@ import { isRedirectError, } from '../../client/components/redirect' import RenderResult from '../render-result' -import { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../../client/components/static-generation-async-storage' import { FlightRenderResult } from './flight-render-result' import { ActionResult } from './types' -import { ActionAsyncStorage } from '../../client/components/action-async-storage.external' +import { ActionAsyncStorage } from '../../client/components/action-async-storage' import { filterReqHeaders, actionsForbiddenHeaders, @@ -31,8 +31,7 @@ import { appendMutableCookies, getModifiedCookieValues, } from '../web/spec-extension/adapters/request-cookies' - -import { RequestStore } from '../../client/components/request-async-storage.external' +import { RequestStore } from '../../client/components/request-async-storage' import { NEXT_CACHE_REVALIDATED_TAGS_HEADER, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER, diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 1dd2eb8f7c639..30749ac66a83d 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -11,9 +11,9 @@ import type { Segment, } from './types' -import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' import type { StaticGenerationBailout } from '../../client/components/static-generation-bailout' -import type { RequestAsyncStorage } from '../../client/components/request-async-storage.external' +import type { RequestAsyncStorage } from '../../client/components/request-async-storage' import React from 'react' import { createServerComponentRenderer } from './create-server-components-renderer' @@ -286,13 +286,10 @@ export async function renderToHTMLOrFlight( * that we need to resolve the final metadata. */ - let requestId: string - - if (process.env.NEXT_RUNTIME === 'edge') { - requestId = crypto.randomUUID() - } else { - requestId = require('next/dist/compiled/nanoid').nanoid() - } + const requestId = + process.env.NEXT_RUNTIME === 'edge' + ? crypto.randomUUID() + : require('next/dist/compiled/nanoid').nanoid() const LayoutRouter = ComponentMod.LayoutRouter as typeof import('../../client/components/layout-router').default @@ -1395,7 +1392,7 @@ export async function renderToHTMLOrFlight( ) const { HeadManagerContext } = - require('../../shared/lib/head-manager-context.shared-runtime') as typeof import('../../shared/lib/head-manager-context.shared-runtime') + require('../../shared/lib/head-manager-context') as typeof import('../../shared/lib/head-manager-context') // On each render, create a new `ServerInsertedHTML` context to capture // injected nodes from user code (`useServerInsertedHTML`). diff --git a/packages/next/src/server/app-render/entry-base.ts b/packages/next/src/server/app-render/entry-base.ts index 0cc53e0214d86..6bc5fd7e7ace1 100644 --- a/packages/next/src/server/app-render/entry-base.ts +++ b/packages/next/src/server/app-render/entry-base.ts @@ -1,26 +1,36 @@ +const { default: AppRouter } = + require('next/dist/client/components/app-router') as typeof import('../../client/components/app-router') +const { default: LayoutRouter } = + require('next/dist/client/components/layout-router') as typeof import('../../client/components/layout-router') +const { default: RenderFromTemplateContext } = + require('next/dist/client/components/render-from-template-context') as typeof import('../../client/components/render-from-template-context') + +const { staticGenerationAsyncStorage } = + require('next/dist/client/components/static-generation-async-storage') as typeof import('../../client/components/static-generation-async-storage') + +const { requestAsyncStorage } = + require('next/dist/client/components/request-async-storage') as typeof import('../../client/components/request-async-storage') +const { actionAsyncStorage } = + require('next/dist/client/components/action-async-storage') as typeof import('../../client/components/action-async-storage') + +const { staticGenerationBailout } = + require('next/dist/client/components/static-generation-bailout') as typeof import('../../client/components/static-generation-bailout') +const { default: StaticGenerationSearchParamsBailoutProvider } = + require('next/dist/client/components/static-generation-searchparams-bailout-provider') as typeof import('../../client/components/static-generation-searchparams-bailout-provider') +const { createSearchParamsBailoutProxy } = + require('next/dist/client/components/searchparams-bailout-proxy') as typeof import('../../client/components/searchparams-bailout-proxy') + +const serverHooks = + require('next/dist/client/components/hooks-server-context') as typeof import('../../client/components/hooks-server-context') + const { renderToReadableStream, decodeReply, decodeAction, // eslint-disable-next-line import/no-extraneous-dependencies } = require('react-server-dom-webpack/server.edge') - -import AppRouter from '../../client/components/app-router' -import LayoutRouter from '../../client/components/layout-router' -import RenderFromTemplateContext from '../../client/components/render-from-template-context' -import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' -import { requestAsyncStorage } from '../../client/components/request-async-storage.external' -import { actionAsyncStorage } from '../../client/components/action-async-storage.external' -import { staticGenerationBailout } from '../../client/components/static-generation-bailout' -import StaticGenerationSearchParamsBailoutProvider from '../../client/components/static-generation-searchparams-bailout-provider' -import { createSearchParamsBailoutProxy } from '../../client/components/searchparams-bailout-proxy' -import * as serverHooks from '../../client/components/hooks-server-context' - -import { - preloadStyle, - preloadFont, - preconnect, -} from '../../server/app-render/rsc/preloads' +const { preloadStyle, preloadFont, preconnect } = + require('next/dist/server/app-render/rsc/preloads') as typeof import('../../server/app-render/rsc/preloads') const { NotFoundBoundary } = require('next/dist/client/components/not-found-boundary') as typeof import('../../client/components/not-found-boundary') diff --git a/packages/next/src/server/app-render/server-inserted-html.tsx b/packages/next/src/server/app-render/server-inserted-html.tsx index 764dc62792077..f044c24feaba3 100644 --- a/packages/next/src/server/app-render/server-inserted-html.tsx +++ b/packages/next/src/server/app-render/server-inserted-html.tsx @@ -2,7 +2,7 @@ // elements into the HTML stream. import React from 'react' -import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html.shared-runtime' +import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html' export function createServerInsertedHTML() { const serverInsertedHTMLCallbacks: (() => React.ReactNode)[] = [] diff --git a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts index 1376ecfb197cd..50795855c53d4 100644 --- a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts @@ -1,7 +1,7 @@ import type { BaseNextRequest, BaseNextResponse } from '../base-http' import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http' import type { AsyncLocalStorage } from 'async_hooks' -import type { RequestStore } from '../../client/components/request-async-storage.external' +import type { RequestStore } from '../../client/components/request-async-storage' import type { RenderOpts } from '../app-render/types' import type { AsyncStorageWrapper } from './async-storage-wrapper' import type { NextRequest } from '../web/spec-extension/request' diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index d5adfc9de38b4..a28ac0e8ecb2a 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -1,5 +1,5 @@ import type { AsyncStorageWrapper } from './async-storage-wrapper' -import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage' import type { AsyncLocalStorage } from 'async_hooks' import type { IncrementalCache } from '../lib/incremental-cache' diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index fab999db35ddc..d826f2bdd4e04 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -55,7 +55,7 @@ import { getCookieParser, checkIsOnDemandRevalidate, } from './api-utils' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config' import { setRevalidateHeaders } from './send-payload/revalidate-headers' import { execOnce } from '../shared/lib/utils' @@ -427,11 +427,7 @@ export default abstract class Server { } = this.nextConfig this.buildId = this.getBuildId() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = - minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE + this.minimalMode = minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE this.hasAppDir = this.getHasAppDir(dev) const serverComponents = this.hasAppDir diff --git a/packages/next/src/server/dev/next-dev-server.ts b/packages/next/src/server/dev/next-dev-server.ts index 839fa1b13c0e4..1eca11b7358cb 100644 --- a/packages/next/src/server/dev/next-dev-server.ts +++ b/packages/next/src/server/dev/next-dev-server.ts @@ -41,7 +41,7 @@ import { UnwrapPromise, withCoalescedInvoke, } from '../../lib/coalesced-function' -import { loadDefaultErrorComponents } from '../load-default-error-components' +import { loadDefaultErrorComponents } from '../load-components' import { DecodeError, MiddlewareNotFoundError } from '../../shared/lib/utils' import * as Log from '../../build/output/log' import isError, { getProperError } from '../../lib/is-error' diff --git a/packages/next/src/server/dev/static-paths-worker.ts b/packages/next/src/server/dev/static-paths-worker.ts index ddd6526e52f23..68932df7a36b0 100644 --- a/packages/next/src/server/dev/static-paths-worker.ts +++ b/packages/next/src/server/dev/static-paths-worker.ts @@ -14,10 +14,8 @@ import { loadComponents } from '../load-components' import { setHttpClientAndAgentOptions } from '../setup-http-agent-env' import { IncrementalCache } from '../lib/incremental-cache' import * as serverHooks from '../../client/components/hooks-server-context' -import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' - -const { AppRouteRouteModule } = - require('../future/route-modules/app-route/module.compiled') as typeof import('../future/route-modules/app-route/module') +import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' +import { AppRouteRouteModule } from '../future/route-modules/app-route/module' type RuntimeConfig = any @@ -58,7 +56,7 @@ export async function loadStaticPaths({ fallback?: boolean | 'blocking' }> { // update work memory runtime-config - require('../../shared/lib/runtime-config.shared-runtime').setConfig(config) + require('../../shared/lib/runtime-config').setConfig(config) setHttpClientAndAgentOptions({ httpAgentOptions, }) diff --git a/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts b/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts index 6f70685df7e75..3283eb00a53f5 100644 --- a/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts +++ b/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts @@ -7,10 +7,7 @@ export class NodeModuleLoader implements ModuleLoader { public async load(id: string): Promise { if (process.env.NEXT_RUNTIME !== 'edge') { // Need to `await` to cover the case that route is marked ESM modules by ESM escalation. - return await (process.env.NEXT_MINIMAL - ? // @ts-ignore - __non_webpack_require__(id) - : require(id)) + return await require(id) } throw new Error('NodeModuleLoader is not supported in edge runtime.') diff --git a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts b/packages/next/src/server/future/route-modules/app-page/module.compiled.ts deleted file mode 100644 index 78601739acbe5..0000000000000 --- a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/app-page/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/app-page/module.ts b/packages/next/src/server/future/route-modules/app-page/module.ts index daa0291a1c8b4..418e37420d7e9 100644 --- a/packages/next/src/server/future/route-modules/app-page/module.ts +++ b/packages/next/src/server/future/route-modules/app-page/module.ts @@ -11,7 +11,6 @@ import { type RouteModuleOptions, type RouteModuleHandleContext, } from '../route-module' -import * as sharedModules from './shared-modules' type AppPageUserlandModule = { /** @@ -35,8 +34,6 @@ export class AppPageRouteModule extends RouteModule< AppPageRouteDefinition, AppPageUserlandModule > { - static readonly sharedModules = sharedModules - public render( req: IncomingMessage, res: ServerResponse, @@ -52,6 +49,4 @@ export class AppPageRouteModule extends RouteModule< } } -export { renderToHTMLOrFlight } - export default AppPageRouteModule diff --git a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts b/packages/next/src/server/future/route-modules/app-page/shared-modules.ts deleted file mode 100644 index e986c1bad3894..0000000000000 --- a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts +++ /dev/null @@ -1,13 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as serverInsertedHtml from '../../../../shared/lib/server-inserted-html.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/app-route/module.compiled.ts b/packages/next/src/server/future/route-modules/app-route/module.compiled.ts deleted file mode 100644 index f5909104bc772..0000000000000 --- a/packages/next/src/server/future/route-modules/app-route/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/app-route/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/app-route.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/app-route-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/app-route.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/app-route/module.ts b/packages/next/src/server/future/route-modules/app-route/module.ts index d1d36d31501e4..bf47738d35fea 100644 --- a/packages/next/src/server/future/route-modules/app-route/module.ts +++ b/packages/next/src/server/future/route-modules/app-route/module.ts @@ -35,14 +35,22 @@ import { appendMutableCookies } from '../../../web/spec-extension/adapters/reque import { RouteKind } from '../../route-kind' import { parsedUrlQueryToParams } from './helpers/parsed-url-query-to-params' -import * as serverHooks from '../../../../client/components/hooks-server-context' -import * as headerHooks from '../../../../client/components/headers' -import { staticGenerationBailout } from '../../../../client/components/static-generation-bailout' - -import { requestAsyncStorage } from '../../../../client/components/request-async-storage.external' -import { staticGenerationAsyncStorage } from '../../../../client/components/static-generation-async-storage.external' -import { actionAsyncStorage } from '../../../../client/components/action-async-storage.external' -import * as sharedModules from './shared-modules' +// These are imported weirdly like this because of the way that the bundling +// works. We need to import the built files from the dist directory, but we +// can't do that directly because we need types from the source files. So we +// import the types from the source files and then import the built files. +const { requestAsyncStorage } = + require('next/dist/client/components/request-async-storage') as typeof import('../../../../client/components/request-async-storage') +const { staticGenerationAsyncStorage } = + require('next/dist/client/components/static-generation-async-storage') as typeof import('../../../../client/components/static-generation-async-storage') +const serverHooks = + require('next/dist/client/components/hooks-server-context') as typeof import('../../../../client/components/hooks-server-context') +const headerHooks = + require('next/dist/client/components/headers') as typeof import('../../../../client/components/headers') +const { staticGenerationBailout } = + require('next/dist/client/components/static-generation-bailout') as typeof import('../../../../client/components/static-generation-bailout') +const { actionAsyncStorage } = + require('next/dist/client/components/action-async-storage') as typeof import('../../../../client/components/action-async-storage') /** * AppRouteRouteHandlerContext is the context that is passed to the route @@ -139,8 +147,6 @@ export class AppRouteRouteModule extends RouteModule< */ public readonly staticGenerationBailout = staticGenerationBailout - public static readonly sharedModules = sharedModules - /** * A reference to the mutation related async storage, such as mutations of * cookies. diff --git a/packages/next/src/server/future/route-modules/app-route/shared-modules.ts b/packages/next/src/server/future/route-modules/app-route/shared-modules.ts deleted file mode 100644 index e6139d5a69404..0000000000000 --- a/packages/next/src/server/future/route-modules/app-route/shared-modules.ts +++ /dev/null @@ -1,3 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -// TODO: remove this. We need it because using notFound from next/navigation imports this file :( -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts b/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts deleted file mode 100644 index ed74c41adb918..0000000000000 --- a/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/pages-api/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/pages-api.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/pages-api-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/pages-api.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/pages-api/module.ts b/packages/next/src/server/future/route-modules/pages-api/module.ts index 976daeeec4a87..88dbda73b464c 100644 --- a/packages/next/src/server/future/route-modules/pages-api/module.ts +++ b/packages/next/src/server/future/route-modules/pages-api/module.ts @@ -100,16 +100,6 @@ export class PagesAPIRouteModule extends RouteModule< PagesAPIRouteDefinition, PagesAPIUserlandModule > { - constructor(options: PagesAPIRouteModuleOptions) { - super(options) - - if (typeof options.userland.default !== 'function') { - throw new Error( - `Page ${options.definition.page} does not export a default function.` - ) - } - } - /** * * @param req the incoming server request diff --git a/packages/next/src/server/future/route-modules/pages/module.compiled.ts b/packages/next/src/server/future/route-modules/pages/module.compiled.ts deleted file mode 100644 index a935b62abdcad..0000000000000 --- a/packages/next/src/server/future/route-modules/pages/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/pages/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/pages.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/pages-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/pages.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/pages/module.ts b/packages/next/src/server/future/route-modules/pages/module.ts index e2730ef668901..dac8ae5546441 100644 --- a/packages/next/src/server/future/route-modules/pages/module.ts +++ b/packages/next/src/server/future/route-modules/pages/module.ts @@ -17,8 +17,7 @@ import { type RouteModuleHandleContext, type RouteModuleOptions, } from '../route-module' -import { renderToHTMLImpl, renderToHTML } from '../../../render' -import * as sharedModules from './shared-modules' +import { renderToHTMLImpl } from '../../../render' /** * The userland module for a page. This is the module that is exported from the @@ -105,8 +104,6 @@ export class PagesRouteModule extends RouteModule< > { private readonly components: PagesComponents - static readonly sharedModules = sharedModules - constructor(options: PagesRouteModuleOptions) { super(options) @@ -132,7 +129,4 @@ export class PagesRouteModule extends RouteModule< } } -// needed for the static build -export { renderToHTML } - export default PagesRouteModule diff --git a/packages/next/src/server/future/route-modules/pages/shared-modules.ts b/packages/next/src/server/future/route-modules/pages/shared-modules.ts deleted file mode 100644 index 55cdfbdeca37c..0000000000000 --- a/packages/next/src/server/future/route-modules/pages/shared-modules.ts +++ /dev/null @@ -1,12 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/route-module.ts b/packages/next/src/server/future/route-modules/route-module.ts index a8e5dd6c5945a..52188ed506dff 100644 --- a/packages/next/src/server/future/route-modules/route-module.ts +++ b/packages/next/src/server/future/route-modules/route-module.ts @@ -44,11 +44,6 @@ export abstract class RouteModule< */ public readonly definition: Readonly - /** - * The shared modules that are exposed and required for the route module. - */ - public static readonly sharedModules: any - constructor({ userland, definition }: RouteModuleOptions) { this.userland = userland this.definition = definition diff --git a/packages/next/src/server/lib/incremental-cache/index.ts b/packages/next/src/server/lib/incremental-cache/index.ts index 3032aa685300b..ae2b11b4dc00f 100644 --- a/packages/next/src/server/lib/incremental-cache/index.ts +++ b/packages/next/src/server/lib/incremental-cache/index.ts @@ -131,10 +131,7 @@ export class IncrementalCache { maxMemoryCacheSize = parseInt(process.env.__NEXT_TEST_MAX_ISR_CACHE, 10) } this.dev = dev - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = minimalMode + this.minimalMode = minimalMode this.requestHeaders = requestHeaders this.requestProtocol = requestProtocol this.allowedRevalidateHeaderKeys = allowedRevalidateHeaderKeys diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 080361704b718..fb4d02c97b251 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -1,4 +1,4 @@ -import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' import type * as ServerHooks from '../../client/components/hooks-server-context' import { AppRenderSpan, NextNodeServerSpan } from './trace/constants' diff --git a/packages/next/src/server/lib/server-ipc/index.ts b/packages/next/src/server/lib/server-ipc/index.ts index 023cbde2d25d8..8e7bd60a8855d 100644 --- a/packages/next/src/server/lib/server-ipc/index.ts +++ b/packages/next/src/server/lib/server-ipc/index.ts @@ -115,7 +115,6 @@ export const createWorker = async ( __NEXT_PRIVATE_STANDALONE_CONFIG: process.env.__NEXT_PRIVATE_STANDALONE_CONFIG, NODE_ENV: process.env.NODE_ENV, - __NEXT_PRIVATE_RENDER_RUNTIME: type, __NEXT_PRIVATE_PREBUNDLED_REACT: type === 'app' ? (useServerActions ? 'experimental' : 'next') : '', ...(process.env.NEXT_CPU_PROF diff --git a/packages/next/src/server/lib/trace/constants.ts b/packages/next/src/server/lib/trace/constants.ts index 1b45358bdf8ed..50eb4528c7dec 100644 --- a/packages/next/src/server/lib/trace/constants.ts +++ b/packages/next/src/server/lib/trace/constants.ts @@ -43,6 +43,7 @@ enum NextNodeServerSpan { generatePublicRoutes = 'NextNodeServer.generatePublicRoutes', generateImageRoutes = 'NextNodeServer.generateImageRoutes.route', sendRenderResult = 'NextNodeServer.sendRenderResult', + sendStatic = 'NextNodeServer.sendStatic', proxyRequest = 'NextNodeServer.proxyRequest', runApi = 'NextNodeServer.runApi', render = 'NextNodeServer.render', diff --git a/packages/next/src/server/load-components.ts b/packages/next/src/server/load-components.ts index 39da802ff39b1..d2b563493ebe6 100644 --- a/packages/next/src/server/load-components.ts +++ b/packages/next/src/server/load-components.ts @@ -55,7 +55,7 @@ export type LoadComponentsReturnType = { /** * Load manifest file with retries, defaults to 3 attempts. */ -export async function loadManifestWithRetries( +async function loadManifestWithRetries( manifestPath: string, attempts = 3 ): Promise { @@ -87,6 +87,34 @@ async function loadJSManifest( } } +async function loadDefaultErrorComponentsImpl( + distDir: string +): Promise { + const Document = interopDefault(require('next/dist/pages/_document')) + const AppMod = require('next/dist/pages/_app') + const App = interopDefault(AppMod) + + // Load the compiled route module for this builtin error. + // TODO: (wyattjoh) replace this with just exporting the route module when the transition is complete + const ComponentMod = + require('./future/route-modules/pages/builtin/_error') as typeof import('./future/route-modules/pages/builtin/_error') + const Component = ComponentMod.routeModule.userland.default + + return { + App, + Document, + Component, + pageConfig: {}, + buildManifest: await loadManifestWithRetries( + join(distDir, `fallback-${BUILD_MANIFEST}`) + ), + reactLoadableManifest: {}, + ComponentMod, + pathname: '/_error', + routeModule: ComponentMod.routeModule, + } +} + async function loadComponentsImpl({ distDir, pathname, @@ -177,3 +205,8 @@ export const loadComponents = getTracer().wrap( LoadComponentsSpan.loadComponents, loadComponentsImpl ) + +export const loadDefaultErrorComponents = getTracer().wrap( + LoadComponentsSpan.loadDefaultErrorComponents, + loadDefaultErrorComponentsImpl +) diff --git a/packages/next/src/server/load-default-error-components.ts b/packages/next/src/server/load-default-error-components.ts deleted file mode 100644 index c390e9180b3d9..0000000000000 --- a/packages/next/src/server/load-default-error-components.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { - AppType, - DocumentType, - NextComponentType, -} from '../shared/lib/utils' -import type { ClientReferenceManifest } from '../build/webpack/plugins/flight-manifest-plugin' -import type { - PageConfig, - GetStaticPaths, - GetServerSideProps, - GetStaticProps, -} from 'next/types' -import type { RouteModule } from './future/route-modules/route-module' - -import { BUILD_MANIFEST } from '../shared/lib/constants' -import { join } from 'path' -import { BuildManifest } from './get-page-files' -import { interopDefault } from '../lib/interop-default' -import { getTracer } from './lib/trace/tracer' -import { LoadComponentsSpan } from './lib/trace/constants' -import { loadManifestWithRetries } from './load-components' -export type ManifestItem = { - id: number | string - files: string[] -} - -export type ReactLoadableManifest = { [moduleId: string]: ManifestItem } - -export type LoadComponentsReturnType = { - Component: NextComponentType - pageConfig: PageConfig - buildManifest: BuildManifest - subresourceIntegrityManifest?: Record - reactLoadableManifest: ReactLoadableManifest - clientReferenceManifest?: ClientReferenceManifest - serverActionsManifest?: any - Document: DocumentType - App: AppType - getStaticProps?: GetStaticProps - getStaticPaths?: GetStaticPaths - getServerSideProps?: GetServerSideProps - ComponentMod: any - routeModule?: RouteModule - isAppPath?: boolean - pathname: string -} - -async function loadDefaultErrorComponentsImpl( - distDir: string -): Promise { - const Document = interopDefault(require('next/dist/pages/_document')) - const AppMod = require('next/dist/pages/_app') - const App = interopDefault(AppMod) - - // Load the compiled route module for this builtin error. - // TODO: (wyattjoh) replace this with just exporting the route module when the transition is complete - const ComponentMod = - require('./future/route-modules/pages/builtin/_error') as typeof import('./future/route-modules/pages/builtin/_error') - const Component = ComponentMod.routeModule.userland.default - - return { - App, - Document, - Component, - pageConfig: {}, - buildManifest: await loadManifestWithRetries( - join(distDir, `fallback-${BUILD_MANIFEST}`) - ), - reactLoadableManifest: {}, - ComponentMod, - pathname: '/_error', - routeModule: ComponentMod.routeModule, - } -} -export const loadDefaultErrorComponents = getTracer().wrap( - LoadComponentsSpan.loadDefaultErrorComponents, - loadDefaultErrorComponentsImpl -) diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 7abf3605541ad..087752225090f 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -15,7 +15,7 @@ import { import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plugin' import type RenderResult from './render-result' import type { FetchEventResult } from './web/types' -import type { PrerenderManifest } from '../build' +import type { PrerenderManifest, RoutesManifest } from '../build' import { BaseNextRequest, BaseNextResponse } from './base-http' import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin' import type { PayloadOptions } from './send-payload' @@ -26,6 +26,7 @@ import { } from '../shared/lib/router/utils/route-matcher' import type { MiddlewareRouteMatch } from '../shared/lib/router/utils/middleware-route-matcher' import type { RouteMatch } from './future/route-matches/route-match' +import { renderToHTML, type RenderOpts } from './render' import fs from 'fs' import { join, resolve, isAbsolute } from 'path' @@ -48,6 +49,7 @@ import { findDir } from '../lib/find-pages-dir' import { UrlWithParsedQuery } from 'url' import { NodeNextRequest, NodeNextResponse } from './base-http/node' import { sendRenderResult } from './send-payload' +import { getExtension, serveStatic } from './serve-static' import { ParsedUrlQuery } from 'querystring' import { ParsedUrl, parseUrl } from '../shared/lib/router/utils/parse-url' import * as Log from '../build/output/log' @@ -94,6 +96,7 @@ import { invokeRequest } from './lib/server-ipc/invoke-request' import { pipeReadable } from './pipe-readable' import { filterReqHeaders, ipcForbiddenHeaders } from './lib/server-ipc/utils' import { createRequestResponseMocks } from './lib/mock-request' +import chalk from 'next/dist/compiled/chalk' import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' import { signalFromNodeResponse } from './web/spec-extension/adapters/next-request' import { RouteModuleLoader } from './future/helpers/module-loader/route-module-loader' @@ -379,6 +382,14 @@ export default class NextNodeServer extends BaseServer { }) } + protected sendStatic( + req: NodeNextRequest, + res: NodeNextResponse, + path: string + ): Promise { + return serveStatic(req.originalRequest, res.originalResponse, path) + } + protected async runApi( req: BaseNextRequest | NodeNextRequest, res: BaseNextResponse | NodeNextResponse, @@ -441,7 +452,7 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, pathname: string, query: NextParsedUrlQuery, - renderOpts: import('./render').RenderOpts + renderOpts: RenderOpts ): Promise { return getTracer().trace(NextNodeServerSpan.renderHTML, async () => this.renderHTMLImpl(req, res, pathname, query, renderOpts) @@ -453,35 +464,17 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, pathname: string, query: NextParsedUrlQuery, - renderOpts: import('./render').RenderOpts + renderOpts: RenderOpts ): Promise { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: renderHTML should not be called in minimal mode' - ) - // the `else` branch is needed for tree-shaking - } else { - // Due to the way we pass data by mutating `renderOpts`, we can't extend the - // object here but only updating its `nextFontManifest` field. - // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952 - renderOpts.nextFontManifest = this.nextFontManifest - - if (this.hasAppDir && renderOpts.isAppPath) { - const { renderToHTMLOrFlight: appRenderToHTMLOrFlight } = - require('./future/route-modules/app-page/module.compiled') as typeof import('./app-render/app-render') - return appRenderToHTMLOrFlight( - req.originalRequest, - res.originalResponse, - pathname, - query, - renderOpts - ) - } - - // TODO: re-enable this once we've refactored to use implicit matches - // throw new Error('Invariant: render should have used routeModule') - - return require('./future/route-modules/pages/module.compiled').renderToHTML( + // Due to the way we pass data by mutating `renderOpts`, we can't extend the + // object here but only updating its `nextFontManifest` field. + // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952 + renderOpts.nextFontManifest = this.nextFontManifest + + if (this.hasAppDir && renderOpts.isAppPath) { + const { renderToHTMLOrFlight: appRenderToHTMLOrFlight } = + require('./app-render/app-render') as typeof import('./app-render/app-render') + return appRenderToHTMLOrFlight( req.originalRequest, res.originalResponse, pathname, @@ -489,6 +482,17 @@ export default class NextNodeServer extends BaseServer { renderOpts ) } + + // TODO: re-enable this once we've refactored to use implicit matches + // throw new Error('Invariant: render should have used routeModule') + + return renderToHTML( + req.originalRequest, + res.originalResponse, + pathname, + query, + renderOpts + ) } protected async imageOptimizer( @@ -496,63 +500,55 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, paramsResult: import('./image-optimizer').ImageParamsResult ): Promise<{ buffer: Buffer; contentType: string; maxAge: number }> { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: imageOptimizer should not be called in minimal mode' - ) - } else { - const { imageOptimizer } = - require('./image-optimizer') as typeof import('./image-optimizer') - - return imageOptimizer( - req.originalRequest, - res.originalResponse, - paramsResult, - this.nextConfig, - this.renderOpts.dev, - async (newReq, newRes, newParsedUrl) => { - if (newReq.url === req.url) { - throw new Error( - `Invariant attempted to optimize _next/image itself` - ) - } + const { imageOptimizer } = + require('./image-optimizer') as typeof import('./image-optimizer') + + return imageOptimizer( + req.originalRequest, + res.originalResponse, + paramsResult, + this.nextConfig, + this.renderOpts.dev, + async (newReq, newRes, newParsedUrl) => { + if (newReq.url === req.url) { + throw new Error(`Invariant attempted to optimize _next/image itself`) + } - if (this.isRenderWorker) { - const invokeRes = await invokeRequest( - `http://${this.fetchHostname || 'localhost'}:${this.port}${ - newReq.url || '' - }`, - { - method: newReq.method || 'GET', - headers: newReq.headers, - signal: signalFromNodeResponse(res.originalResponse), - } - ) - const filteredResHeaders = filterReqHeaders( - toNodeOutgoingHttpHeaders(invokeRes.headers), - ipcForbiddenHeaders - ) - - for (const key of Object.keys(filteredResHeaders)) { - newRes.setHeader(key, filteredResHeaders[key] || '') + if (this.isRenderWorker) { + const invokeRes = await invokeRequest( + `http://${this.fetchHostname || 'localhost'}:${this.port}${ + newReq.url || '' + }`, + { + method: newReq.method || 'GET', + headers: newReq.headers, + signal: signalFromNodeResponse(res.originalResponse), } - newRes.statusCode = invokeRes.status || 200 + ) + const filteredResHeaders = filterReqHeaders( + toNodeOutgoingHttpHeaders(invokeRes.headers), + ipcForbiddenHeaders + ) - if (invokeRes.body) { - await pipeReadable(invokeRes.body, newRes) - } else { - res.send() - } - return + for (const key of Object.keys(filteredResHeaders)) { + newRes.setHeader(key, filteredResHeaders[key] || '') } - return this.getRequestHandler()( - new NodeNextRequest(newReq), - new NodeNextResponse(newRes), - newParsedUrl - ) + newRes.statusCode = invokeRes.status || 200 + + if (invokeRes.body) { + await pipeReadable(invokeRes.body, newRes) + } else { + res.send() + } + return } - ) - } + return this.getRequestHandler()( + new NodeNextRequest(newReq), + new NodeNextResponse(newRes), + newParsedUrl + ) + } + ) } protected getPagePath(pathname: string, locales?: string[]): string { @@ -723,109 +719,99 @@ export default class NextNodeServer extends BaseServer { res: BaseNextResponse, parsedUrl: NextUrlWithParsedQuery ) { - if ( - this.minimalMode || - this.nextConfig.output === 'export' || - process.env.NEXT_MINIMAL - ) { + if (this.minimalMode || this.nextConfig.output === 'export') { res.statusCode = 400 res.body('Bad Request').send() return { finished: true, } - // the `else` branch is needed for tree-shaking - } else { - const { ImageOptimizerCache } = - require('./image-optimizer') as typeof import('./image-optimizer') - - const imageOptimizerCache = new ImageOptimizerCache({ - distDir: this.distDir, - nextConfig: this.nextConfig, - }) + } + const { ImageOptimizerCache } = + require('./image-optimizer') as typeof import('./image-optimizer') - const { getHash, sendResponse, ImageError } = - require('./image-optimizer') as typeof import('./image-optimizer') + const imageOptimizerCache = new ImageOptimizerCache({ + distDir: this.distDir, + nextConfig: this.nextConfig, + }) - if (!this.imageResponseCache) { - throw new Error('invariant image optimizer cache was not initialized') - } - const imagesConfig = this.nextConfig.images + const { getHash, sendResponse, ImageError } = + require('./image-optimizer') as typeof import('./image-optimizer') - if (imagesConfig.loader !== 'default' || imagesConfig.unoptimized) { - await this.render404(req, res) - return { finished: true } - } - const paramsResult = ImageOptimizerCache.validateParams( - (req as NodeNextRequest).originalRequest, - parsedUrl.query, - this.nextConfig, - !!this.renderOpts.dev - ) + if (!this.imageResponseCache) { + throw new Error('invariant image optimizer cache was not initialized') + } + const imagesConfig = this.nextConfig.images - if ('errorMessage' in paramsResult) { - res.statusCode = 400 - res.body(paramsResult.errorMessage).send() - return { finished: true } - } - const cacheKey = ImageOptimizerCache.getCacheKey(paramsResult) + if (imagesConfig.loader !== 'default' || imagesConfig.unoptimized) { + await this.render404(req, res) + return { finished: true } + } + const paramsResult = ImageOptimizerCache.validateParams( + (req as NodeNextRequest).originalRequest, + parsedUrl.query, + this.nextConfig, + !!this.renderOpts.dev + ) - try { - const { getExtension } = - require('./serve-static') as typeof import('./serve-static') - const cacheEntry = await this.imageResponseCache.get( - cacheKey, - async () => { - const { buffer, contentType, maxAge } = await this.imageOptimizer( - req as NodeNextRequest, - res as NodeNextResponse, - paramsResult - ) - const etag = getHash([buffer]) - - return { - value: { - kind: 'IMAGE', - buffer, - etag, - extension: getExtension(contentType) as string, - }, - revalidate: maxAge, - } - }, - { - incrementalCache: imageOptimizerCache, - } - ) + if ('errorMessage' in paramsResult) { + res.statusCode = 400 + res.body(paramsResult.errorMessage).send() + return { finished: true } + } + const cacheKey = ImageOptimizerCache.getCacheKey(paramsResult) - if (cacheEntry?.value?.kind !== 'IMAGE') { - throw new Error( - 'invariant did not get entry from image response cache' + try { + const cacheEntry = await this.imageResponseCache.get( + cacheKey, + async () => { + const { buffer, contentType, maxAge } = await this.imageOptimizer( + req as NodeNextRequest, + res as NodeNextResponse, + paramsResult ) - } - sendResponse( - (req as NodeNextRequest).originalRequest, - (res as NodeNextResponse).originalResponse, - paramsResult.href, - cacheEntry.value.extension, - cacheEntry.value.buffer, - paramsResult.isStatic, - cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', - imagesConfig, - cacheEntry.revalidate || 0, - Boolean(this.renderOpts.dev) - ) - } catch (err) { - if (err instanceof ImageError) { - res.statusCode = err.statusCode - res.body(err.message).send() + const etag = getHash([buffer]) + return { - finished: true, + value: { + kind: 'IMAGE', + buffer, + etag, + extension: getExtension(contentType) as string, + }, + revalidate: maxAge, } + }, + { + incrementalCache: imageOptimizerCache, } - throw err + ) + + if (cacheEntry?.value?.kind !== 'IMAGE') { + throw new Error('invariant did not get entry from image response cache') } - return { finished: true } + sendResponse( + (req as NodeNextRequest).originalRequest, + (res as NodeNextResponse).originalResponse, + paramsResult.href, + cacheEntry.value.extension, + cacheEntry.value.buffer, + paramsResult.isStatic, + cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', + imagesConfig, + cacheEntry.revalidate || 0, + Boolean(this.renderOpts.dev) + ) + } catch (err) { + if (err instanceof ImageError) { + res.statusCode = err.statusCode + res.body(err.message).send() + return { + finished: true, + } + } + throw err } + return { finished: true } } protected async handleCatchallRenderRequest( @@ -1026,7 +1012,6 @@ export default class NextNodeServer extends BaseServer { const enabledVerboseLogging = this.nextConfig.experimental.logging === 'verbose' if (this.renderOpts.dev) { - const chalk = require('next/dist/compiled/chalk') const _req = req as NodeNextRequest | IncomingMessage const _res = res as NodeNextResponse | ServerResponse const origReq = 'originalRequest' in _req ? _req.originalRequest : _req @@ -1447,12 +1432,6 @@ export default class NextNodeServer extends BaseServer { parsed: UrlWithParsedQuery onWarning?: (warning: Error) => void }) { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: runMiddleware should not be called in minimal mode' - ) - } - // Middleware is skipped for on-demand revalidate requests if ( checkIsOnDemandRevalidate(params.request, this.renderOpts.previewProps) @@ -1696,7 +1675,10 @@ export default class NextNodeServer extends BaseServer { protected getRoutesManifest(): NormalizedRouteManifest | undefined { return getTracer().trace(NextNodeServerSpan.getRoutesManifest, () => { - const manifest = loadManifest(join(this.distDir, ROUTES_MANIFEST)) + const manifest: RoutesManifest = require(join( + this.distDir, + ROUTES_MANIFEST + )) let rewrites = manifest.rewrites ?? { beforeFiles: [], @@ -1754,11 +1736,6 @@ export default class NextNodeServer extends BaseServer { match?: RouteMatch onWarning?: (warning: Error) => void }): Promise { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'Middleware is not supported in minimal mode. Please remove the `NEXT_MINIMAL` environment variable.' - ) - } let edgeInfo: ReturnType | undefined const { query, page, match } = params diff --git a/packages/next/src/server/render-result.ts b/packages/next/src/server/render-result.ts index 2a8252e4fd143..b93dfce5fae21 100644 --- a/packages/next/src/server/render-result.ts +++ b/packages/next/src/server/render-result.ts @@ -1,4 +1,4 @@ -import { StaticGenerationStore } from '../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../client/components/static-generation-async-storage' import { pipeReadable, PipeTarget } from './pipe-readable' type ContentTypeOption = string | undefined diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index fe36e793348e2..ac0989082aa9b 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -1,7 +1,7 @@ import type { IncomingMessage, ServerResponse } from 'http' import type { ParsedUrlQuery } from 'querystring' import type { NextRouter } from '../shared/lib/router/router' -import type { HtmlProps } from '../shared/lib/html-context.shared-runtime' +import type { HtmlProps } from '../shared/lib/html-context' import type { DomainLocale } from './config' import type { AppType, @@ -52,12 +52,12 @@ import { } from '../shared/lib/constants' import { isSerializableProps } from '../lib/is-serializable-props' import { isInAmpMode } from '../shared/lib/amp-mode' -import { AmpStateContext } from '../shared/lib/amp-context.shared-runtime' +import { AmpStateContext } from '../shared/lib/amp-context' import { defaultHead } from '../shared/lib/head' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' -import Loadable from '../shared/lib/loadable.shared-runtime' -import { LoadableContext } from '../shared/lib/loadable-context.shared-runtime' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' +import Loadable from '../shared/lib/loadable' +import { LoadableContext } from '../shared/lib/loadable-context' +import { RouterContext } from '../shared/lib/router-context' import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic' import { ComponentsEnhancer, @@ -65,7 +65,7 @@ import { isResSent, loadGetInitialProps, } from '../shared/lib/utils' -import { HtmlContext } from '../shared/lib/html-context.shared-runtime' +import { HtmlContext } from '../shared/lib/html-context' import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path' import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-path' import { getRequestMeta, NextParsedUrlQuery } from './request-meta' @@ -79,16 +79,16 @@ import { renderToInitialStream, continueFromInitialStream, } from './stream-utils/node-web-streams-helper' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import stripAnsi from 'next/dist/compiled/strip-ansi' import { stripInternalQueries } from './internal-utils' import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' -import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime' -import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' +} from '../shared/lib/router/adapters' +import { AppRouterContext } from '../shared/lib/app-router-context' +import { SearchParamsContext } from '../shared/lib/hooks-client-context' import { getTracer } from './lib/trace/tracer' import { RenderSpan } from './lib/trace/constants' import { ReflectAdapter } from './web/spec-extension/adapters/reflect' diff --git a/packages/next/src/server/require-hook.ts b/packages/next/src/server/require-hook.ts index 9b2e1526eec0e..1f53b3b479109 100644 --- a/packages/next/src/server/require-hook.ts +++ b/packages/next/src/server/require-hook.ts @@ -2,13 +2,11 @@ // This is needed for userland plugins to attach to the same webpack instance as Next.js'. // Individually compiled modules are as defined for the compilation in bundles/webpack/packages/*. -import path, { dirname } from 'path' - // This module will only be loaded once per process. +const { dirname } = require('path') const mod = require('module') const resolveFilename = mod._resolveFilename -const originalRequire = mod.prototype.require const hookPropertyMap = new Map() let aliasedPrebundledReact = false @@ -21,9 +19,10 @@ const resolve = process.env.NEXT_MINIMAL const toResolveMap = (map: Record): [string, string][] => Object.entries(map).map(([key, value]) => [key, resolve(value)]) +// these must use require.resolve to be statically analyzable export const defaultOverrides = { - 'styled-jsx': dirname(resolve('styled-jsx/package.json')), - 'styled-jsx/style': resolve('styled-jsx/style'), + 'styled-jsx': dirname(require.resolve('styled-jsx/package.json')), + 'styled-jsx/style': require.resolve('styled-jsx/style'), } export const baseOverrides = { @@ -79,6 +78,7 @@ export function addHookAliases(aliases: [string, string][] = []) { } } +// Add default aliases addHookAliases(toResolveMap(defaultOverrides)) // Override built-in React packages if necessary @@ -117,29 +117,3 @@ mod._resolveFilename = function ( // We use `bind` here to avoid referencing outside variables to create potential memory leaks. }.bind(null, resolveFilename, hookPropertyMap) - -// This is a hack to make sure that if a user requires a Next.js module that wasn't bundled -// that needs to point to the rendering runtime version, it will point to the correct one. -// This can happen on `pages` when a user requires a dependency that uses next/image for example. -// This is only needed in production as in development we fallback to the external version. -if ( - process.env.NODE_ENV !== 'development' && - process.env.__NEXT_PRIVATE_RENDER_RUNTIME && - !process.env.TURBOPACK -) { - const currentRuntime = `${ - process.env.__NEXT_PRIVATE_RENDER_RUNTIME === 'pages' - ? 'next/dist/compiled/next-server/pages.runtime' - : 'next/dist/compiled/next-server/app-page.runtime' - }.prod` - - mod.prototype.require = function (request: string) { - if (request.endsWith('.shared-runtime')) { - const base = path.basename(request, '.shared-runtime') - const camelized = base.replace(/-([a-z])/g, (g) => g[1].toUpperCase()) - const instance = originalRequire.call(this, currentRuntime) - return instance.default.sharedModules[camelized] - } - return originalRequire.call(this, request) - } -} diff --git a/packages/next/src/server/response-cache/index.ts b/packages/next/src/server/response-cache/index.ts index 7bd6710cc4a80..6d135da26e939 100644 --- a/packages/next/src/server/response-cache/index.ts +++ b/packages/next/src/server/response-cache/index.ts @@ -20,10 +20,7 @@ export default class ResponseCache { constructor(minimalMode: boolean) { this.pendingResponses = new Map() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = minimalMode + this.minimalMode = minimalMode } public get( diff --git a/packages/next/src/server/response-cache/web.ts b/packages/next/src/server/response-cache/web.ts index f255fdd5412d4..e37ccca314812 100644 --- a/packages/next/src/server/response-cache/web.ts +++ b/packages/next/src/server/response-cache/web.ts @@ -15,9 +15,7 @@ export default class WebResponseCache { constructor(minimalMode: boolean) { this.pendingResponses = new Map() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - Object.assign(this, { minimalMode }) + this.minimalMode = minimalMode } public get( diff --git a/packages/next/src/server/web/adapter.ts b/packages/next/src/server/web/adapter.ts index 5c6ad3e7ed5ab..1ea32a75956cd 100644 --- a/packages/next/src/server/web/adapter.ts +++ b/packages/next/src/server/web/adapter.ts @@ -18,7 +18,7 @@ import { import { NEXT_QUERY_PARAM_PREFIX } from '../../lib/constants' import { ensureInstrumentationRegistered } from './globals' import { RequestAsyncStorageWrapper } from '../async-storage/request-async-storage-wrapper' -import { requestAsyncStorage } from '../../client/components/request-async-storage.external' +import { requestAsyncStorage } from '../../client/components/request-async-storage' import { PrerenderManifest } from '../../build' class NextRequestHint extends NextRequest { diff --git a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts index d44ea986cad65..df3c369eef877 100644 --- a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts +++ b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts @@ -1,5 +1,5 @@ import type { RequestCookies } from '../cookies' -import { StaticGenerationStore } from '../../../../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../../../../client/components/static-generation-async-storage' import { ResponseCookies } from '../cookies' import { ReflectAdapter } from './reflect' diff --git a/packages/next/src/server/web/spec-extension/revalidate-tag.ts b/packages/next/src/server/web/spec-extension/revalidate-tag.ts index 7c7bff8c2f784..8d7cd68bd3a9a 100644 --- a/packages/next/src/server/web/spec-extension/revalidate-tag.ts +++ b/packages/next/src/server/web/spec-extension/revalidate-tag.ts @@ -1,7 +1,7 @@ import { StaticGenerationAsyncStorage, StaticGenerationStore, -} from '../../../client/components/static-generation-async-storage.external' +} from '../../../client/components/static-generation-async-storage' export function revalidateTag(tag: string) { const staticGenerationAsyncStorage = ( diff --git a/packages/next/src/server/web/spec-extension/unstable-cache.ts b/packages/next/src/server/web/spec-extension/unstable-cache.ts index 1e85b5c290971..aad3ed2baf20a 100644 --- a/packages/next/src/server/web/spec-extension/unstable-cache.ts +++ b/packages/next/src/server/web/spec-extension/unstable-cache.ts @@ -2,7 +2,7 @@ import { StaticGenerationStore, staticGenerationAsyncStorage as _staticGenerationAsyncStorage, StaticGenerationAsyncStorage, -} from '../../../client/components/static-generation-async-storage.external' +} from '../../../client/components/static-generation-async-storage' import { CACHE_ONE_YEAR } from '../../../lib/constants' import { addImplicitTags } from '../../lib/patch-fetch' diff --git a/packages/next/src/shared/lib/amp-context.shared-runtime.ts b/packages/next/src/shared/lib/amp-context.ts similarity index 100% rename from packages/next/src/shared/lib/amp-context.shared-runtime.ts rename to packages/next/src/shared/lib/amp-context.ts diff --git a/packages/next/src/shared/lib/amp.ts b/packages/next/src/shared/lib/amp.ts index 8edd21db9c299..04518b2389357 100644 --- a/packages/next/src/shared/lib/amp.ts +++ b/packages/next/src/shared/lib/amp.ts @@ -1,5 +1,5 @@ import React from 'react' -import { AmpStateContext } from './amp-context.shared-runtime' +import { AmpStateContext } from './amp-context' import { isInAmpMode } from './amp-mode' export function useAmp(): boolean { diff --git a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts b/packages/next/src/shared/lib/app-router-context.ts similarity index 100% rename from packages/next/src/shared/lib/app-router-context.shared-runtime.ts rename to packages/next/src/shared/lib/app-router-context.ts diff --git a/packages/next/src/shared/lib/dynamic.tsx b/packages/next/src/shared/lib/dynamic.tsx index 390410edda29e..cb497fc587d4f 100644 --- a/packages/next/src/shared/lib/dynamic.tsx +++ b/packages/next/src/shared/lib/dynamic.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Loadable from './loadable.shared-runtime' +import Loadable from './loadable' const isServerSide = typeof window === 'undefined' diff --git a/packages/next/src/shared/lib/head-manager-context.shared-runtime.ts b/packages/next/src/shared/lib/head-manager-context.ts similarity index 100% rename from packages/next/src/shared/lib/head-manager-context.shared-runtime.ts rename to packages/next/src/shared/lib/head-manager-context.ts diff --git a/packages/next/src/shared/lib/head.tsx b/packages/next/src/shared/lib/head.tsx index 42f95767bfa4c..3156e259f656f 100644 --- a/packages/next/src/shared/lib/head.tsx +++ b/packages/next/src/shared/lib/head.tsx @@ -2,8 +2,8 @@ import React, { useContext } from 'react' import Effect from './side-effect' -import { AmpStateContext } from './amp-context.shared-runtime' -import { HeadManagerContext } from './head-manager-context.shared-runtime' +import { AmpStateContext } from './amp-context' +import { HeadManagerContext } from './head-manager-context' import { isInAmpMode } from './amp-mode' import { warnOnce } from './utils/warn-once' diff --git a/packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts b/packages/next/src/shared/lib/hooks-client-context.ts similarity index 100% rename from packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts rename to packages/next/src/shared/lib/hooks-client-context.ts diff --git a/packages/next/src/shared/lib/html-context.shared-runtime.ts b/packages/next/src/shared/lib/html-context.ts similarity index 100% rename from packages/next/src/shared/lib/html-context.shared-runtime.ts rename to packages/next/src/shared/lib/html-context.ts diff --git a/packages/next/src/shared/lib/image-config-context.shared-runtime.ts b/packages/next/src/shared/lib/image-config-context.ts similarity index 100% rename from packages/next/src/shared/lib/image-config-context.shared-runtime.ts rename to packages/next/src/shared/lib/image-config-context.ts diff --git a/packages/next/src/shared/lib/loadable-context.shared-runtime.ts b/packages/next/src/shared/lib/loadable-context.ts similarity index 100% rename from packages/next/src/shared/lib/loadable-context.shared-runtime.ts rename to packages/next/src/shared/lib/loadable-context.ts diff --git a/packages/next/src/shared/lib/loadable.shared-runtime.tsx b/packages/next/src/shared/lib/loadable.tsx similarity index 99% rename from packages/next/src/shared/lib/loadable.shared-runtime.tsx rename to packages/next/src/shared/lib/loadable.tsx index 82ba84182701f..1592d98551093 100644 --- a/packages/next/src/shared/lib/loadable.shared-runtime.tsx +++ b/packages/next/src/shared/lib/loadable.tsx @@ -23,7 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE // Modified to be compatible with webpack 4 / Next.js import React from 'react' -import { LoadableContext } from './loadable-context.shared-runtime' +import { LoadableContext } from './loadable-context' function resolve(obj: any) { return obj && obj.default ? obj.default : obj diff --git a/packages/next/src/shared/lib/router-context.shared-runtime.ts b/packages/next/src/shared/lib/router-context.ts similarity index 100% rename from packages/next/src/shared/lib/router-context.shared-runtime.ts rename to packages/next/src/shared/lib/router-context.ts diff --git a/packages/next/src/shared/lib/router/adapters.test.tsx b/packages/next/src/shared/lib/router/adapters.test.tsx index e47ce2174dd35..fa8e48f2fc088 100644 --- a/packages/next/src/shared/lib/router/adapters.test.tsx +++ b/packages/next/src/shared/lib/router/adapters.test.tsx @@ -1,4 +1,4 @@ -import { adaptForAppRouterInstance } from './adapters.shared-runtime' +import { adaptForAppRouterInstance } from './adapters' import { NextRouter } from './router' describe('adaptForAppRouterInstance', () => { diff --git a/packages/next/src/shared/lib/router/adapters.shared-runtime.tsx b/packages/next/src/shared/lib/router/adapters.tsx similarity index 95% rename from packages/next/src/shared/lib/router/adapters.shared-runtime.tsx rename to packages/next/src/shared/lib/router/adapters.tsx index 29f92dda8dc08..ce68a8bec1e8b 100644 --- a/packages/next/src/shared/lib/router/adapters.shared-runtime.tsx +++ b/packages/next/src/shared/lib/router/adapters.tsx @@ -1,10 +1,7 @@ import type { ParsedUrlQuery } from 'node:querystring' import React, { useMemo, useRef } from 'react' -import type { - AppRouterInstance, - NavigateOptions, -} from '../app-router-context.shared-runtime' -import { PathnameContext } from '../hooks-client-context.shared-runtime' +import type { AppRouterInstance, NavigateOptions } from '../app-router-context' +import { PathnameContext } from '../hooks-client-context' import type { NextRouter } from './router' import { isDynamicRoute } from './utils' diff --git a/packages/next/src/shared/lib/runtime-config.shared-runtime.ts b/packages/next/src/shared/lib/runtime-config.ts similarity index 100% rename from packages/next/src/shared/lib/runtime-config.shared-runtime.ts rename to packages/next/src/shared/lib/runtime-config.ts diff --git a/packages/next/src/shared/lib/server-inserted-html.shared-runtime.tsx b/packages/next/src/shared/lib/server-inserted-html.tsx similarity index 100% rename from packages/next/src/shared/lib/server-inserted-html.shared-runtime.tsx rename to packages/next/src/shared/lib/server-inserted-html.tsx diff --git a/packages/next/src/shared/lib/utils.ts b/packages/next/src/shared/lib/utils.ts index 4e8036a6894a2..f967be459022b 100644 --- a/packages/next/src/shared/lib/utils.ts +++ b/packages/next/src/shared/lib/utils.ts @@ -1,4 +1,4 @@ -import type { HtmlProps } from './html-context.shared-runtime' +import type { HtmlProps } from './html-context' import type { ComponentType } from 'react' import type { DomainLocale } from '../../server/config' import type { Env } from '@next/env' diff --git a/packages/next/src/trace/index.ts b/packages/next/src/trace/index.ts index e3928f775f613..e242e19c9041f 100644 --- a/packages/next/src/trace/index.ts +++ b/packages/next/src/trace/index.ts @@ -1,5 +1,4 @@ import { trace, flushAllTraces, Span, SpanStatus } from './trace' import { SpanId, setGlobal } from './shared' -export { trace, flushAllTraces, Span, setGlobal, SpanStatus } -export type { SpanId } +export { trace, flushAllTraces, SpanId, Span, SpanStatus, setGlobal } diff --git a/packages/next/taskfile-webpack.js b/packages/next/taskfile-webpack.js deleted file mode 100644 index 04495d7b3621c..0000000000000 --- a/packages/next/taskfile-webpack.js +++ /dev/null @@ -1,35 +0,0 @@ -const webpack = require('webpack') - -module.exports = function (task) { - task.plugin('webpack', {}, function* (_, options) { - options = options || {} - - const compiler = webpack(options.config) - - if (options.watch) { - compiler.watch({}, (err, stats) => { - if (err || stats.hasErrors()) { - console.error(err || stats.toString()) - } else { - console.log(`${options.name} compiled successfully.`) - } - }) - } else { - yield new Promise((resolve, reject) => { - compiler.run((err, stats) => { - if (err || stats.hasErrors()) { - console.error(err || stats.toString()) - reject(err || stats.toString()) - } - if (process.env.ANALYZE) { - require('fs').writeFileSync( - require('path').join(__dirname, options.name + '-stats.json'), - JSON.stringify(stats.toJson()) - ) - } - resolve() - }) - }) - } - }) -} diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 321490234153b..f38289c3d4984 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2357,7 +2357,7 @@ export async function ncc(task, opts) { ) } -export async function next_compile(task, opts) { +export async function compile(task, opts) { await task.parallel( [ 'cli', @@ -2388,16 +2388,12 @@ export async function next_compile(task, opts) { ], opts ) -} - -export async function compile(task, opts) { - await task.serial(['next_compile', 'next_bundle'], opts) - await task.serial([ 'ncc_react_refresh_utils', 'ncc_next__react_dev_overlay', 'ncc_next_font', 'capsize_metrics', + 'minimal_next_server', ]) } @@ -2662,38 +2658,157 @@ export async function release(task) { await task.clear('dist').start('build') } -export async function next_bundle_prod(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - dev: false, - }), - name: 'next-bundle-prod', +export async function minimal_next_server(task) { + const outputName = 'next-server.js' + const cachedOutputName = `${outputName}.cache` + + const minimalExternals = [ + 'react', + 'react/package.json', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + 'react-dom', + 'react-dom/package.json', + 'react-dom/client', + 'react-dom/server', + 'react-dom/server.browser', + 'react-dom/server.edge', + 'react-server-dom-webpack/client', + 'react-server-dom-webpack/client.edge', + 'react-server-dom-webpack/server.edge', + 'react-server-dom-webpack/server.node', + 'styled-jsx', + 'styled-jsx/style', + '@opentelemetry/api', + 'next/dist/compiled/@next/react-dev-overlay/dist/middleware', + 'next/dist/compiled/@ampproject/toolbox-optimizer', + 'next/dist/compiled/edge-runtime', + 'next/dist/compiled/@edge-runtime/ponyfill', + 'next/dist/compiled/undici', + 'next/dist/compiled/raw-body', + 'next/dist/server/capsize-font-metrics.json', + 'critters', + 'next/dist/compiled/node-html-parser', + 'next/dist/compiled/compression', + 'next/dist/compiled/jsonwebtoken', + 'next/dist/compiled/@mswjs/interceptors/ClientRequest', + ].reduce((acc, pkg) => { + acc[pkg] = pkg + return acc + }, {}) + + Object.assign(minimalExternals, { + '/(.*)config$/': 'next/dist/server/config', + './web/sandbox': 'next/dist/server/web/sandbox', }) -} -export async function next_bundle_dev(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - dev: true, - }), - name: 'next-bundle-dev', + const webpack = require('webpack') + const TerserPlugin = require('terser-webpack-plugin') + // const BundleAnalyzerPlugin = + // require('webpack-bundle-analyzer').BundleAnalyzerPlugin + /** @type {webpack.Configuration} */ + const config = { + entry: join(__dirname, 'dist/server/next-server.js'), + target: 'node', + mode: 'production', + output: { + path: join(__dirname, 'dist/compiled/minimal-next-server'), + filename: outputName, + libraryTarget: 'commonjs2', + }, + // left in for debugging + optimization: { + moduleIds: 'named', + // minimize: false, + minimize: true, + minimizer: [ + new TerserPlugin({ + extractComments: false, + terserOptions: { + format: { + comments: false, + }, + compress: { + passes: 2, + }, + }, + }), + ], + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production'), + 'process.env.NEXT_MINIMAL': JSON.stringify('true'), + 'process.env.NEXT_RUNTIME': JSON.stringify('nodejs'), + }), + // new BundleAnalyzerPlugin({}), + ], + externals: [minimalExternals], + } + + await new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) return reject(err) + if (stats.hasErrors()) { + return reject(new Error(stats.toString('errors-only'))) + } + resolve() + }) }) -} -export async function next_bundle_turbo_prod(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - turbo: true, - }), - name: 'next-bundle-prod-turbo', + const wrappedTemplate = ` +const filename = ${JSON.stringify(outputName)} +const { readFileSync } = require('fs'), + { Script } = require('vm'), + { wrap } = require('module'), + { join } = require('path'); +const basename = join(__dirname, filename) + +const source = readFileSync(basename, 'utf-8') + +const cachedData = + !process.pkg && + require('process').platform !== 'win32' && + readFileSync(join(__dirname, '${cachedOutputName}')) + +const scriptOpts = { filename: basename, columnOffset: 0 } + +const script = new Script( + wrap(source), + cachedData ? Object.assign({ cachedData }, scriptOpts) : scriptOpts +) + +script.runInThisContext()(exports, require, module, __filename, __dirname) +` + + await fs.writeFile( + join(__dirname, `dist/compiled/minimal-next-server/next-server-cached.js`), + wrappedTemplate + ) + + const Module = require('module') + const vm = require('vm') + const filename = resolve( + __dirname, + 'dist/compiled/minimal-next-server', + outputName + ) + + const content = require('fs').readFileSync(filename, 'utf8') + + const wrapper = Module.wrap(content) + var script = new vm.Script(wrapper, { + filename: filename, + lineOffset: 0, + displayErrors: true, }) -} -export async function next_bundle(task, opts) { - await task.parallel( - ['next_bundle_prod', 'next_bundle_dev', 'next_bundle_turbo_prod'], - opts + + script.runInThisContext()(exports, require, module, __filename, __dirname) + + const buffer = script.createCachedData() + + await fs.writeFile( + join(__dirname, `dist/compiled/minimal-next-server/${cachedOutputName}`), + buffer ) } diff --git a/packages/next/webpack.config.js b/packages/next/webpack.config.js deleted file mode 100644 index 8e7c3063fa5ed..0000000000000 --- a/packages/next/webpack.config.js +++ /dev/null @@ -1,145 +0,0 @@ -const webpack = require('webpack') -const path = require('path') -const TerserPlugin = require('terser-webpack-plugin') -const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') - -const minimalExternals = [ - 'react', - 'react/package.json', - 'react/jsx-runtime', - 'react/jsx-dev-runtime', - 'react-dom', - 'react-dom/package.json', - 'react-dom/client', - 'react-dom/server', - 'react-dom/server.browser', - 'react-dom/server.edge', - 'react-server-dom-webpack/client', - 'react-server-dom-webpack/client.edge', - 'react-server-dom-webpack/server.edge', - 'react-server-dom-webpack/server.node', - 'styled-jsx', - 'styled-jsx/style', - '@opentelemetry/api', - 'next/dist/compiled/@next/react-dev-overlay/dist/middleware', - 'next/dist/compiled/@ampproject/toolbox-optimizer', - 'next/dist/compiled/edge-runtime', - 'next/dist/compiled/@edge-runtime/ponyfill', - 'next/dist/compiled/undici', - 'next/dist/compiled/raw-body', - 'next/dist/server/capsize-font-metrics.json', - 'critters', - 'next/dist/compiled/node-html-parser', - 'next/dist/compiled/compression', - 'next/dist/compiled/jsonwebtoken', - 'next/dist/compiled/@opentelemetry/api', - 'next/dist/compiled/@mswjs/interceptors/ClientRequest', -] - -const externalsMap = { - './web/sandbox': 'next/dist/server/web/sandbox', -} - -const externalsRegexMap = { - '(.*)trace/tracer$': 'next/dist/server/lib/trace/tracer', -} - -module.exports = ({ dev, turbo }) => { - const externalHandler = ({ context, request, getResolve }, callback) => { - ;(async () => { - if ( - ((dev || turbo) && request.endsWith('.shared-runtime')) || - request.endsWith('.external') - ) { - const resolve = getResolve() - const resolved = await resolve(context, request) - const relative = path.relative( - path.join(__dirname, '..'), - resolved.replace('esm' + path.sep, '') - ) - callback(null, `commonjs ${relative}`) - } else { - const regexMatch = Object.keys(externalsRegexMap).find((regex) => - new RegExp(regex).test(request) - ) - if (regexMatch) { - return callback(null, 'commonjs ' + externalsRegexMap[regexMatch]) - } - callback() - } - })() - } - - /** @type {webpack.Configuration} */ - return { - entry: { - server: path.join(__dirname, 'dist/esm/server/next-server.js'), - 'app-page': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-page/module.js' - ), - 'app-route': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-route/module.js' - ), - pages: path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages/module.js' - ), - 'pages-api': path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages-api/module.js' - ), - }, - target: 'node', - mode: 'production', - output: { - path: path.join(__dirname, 'dist/compiled/next-server'), - filename: `[name]${turbo ? '-turbo' : ''}.runtime.${ - dev ? 'dev' : 'prod' - }.js`, - libraryTarget: 'commonjs2', - }, - optimization: { - moduleIds: 'named', - minimize: true, - // splitChunks: { - // chunks: 'all', - // }, - concatenateModules: true, - minimizer: [ - new TerserPlugin({ - extractComments: false, - terserOptions: { - format: { - comments: false, - }, - compress: { - passes: 2, - }, - }, - }), - ], - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env.NEXT_MINIMAL': JSON.stringify('true'), - 'this.serverOptions.experimentalTestProxy': JSON.stringify(false), - 'this.minimalMode': JSON.stringify(true), - 'this.renderOpts.dev': JSON.stringify(dev), - 'process.env.NODE_ENV': JSON.stringify( - dev ? 'development' : 'production' - ), - 'process.env.NEXT_RUNTIME': JSON.stringify('nodejs'), - }), - !!process.env.ANALYZE && - new BundleAnalyzerPlugin({ - analyzerPort: 8888 + (dev ? 0 : 1) + (turbo ? 1 : 0), - }), - ].filter(Boolean), - stats: { - optimizationBailout: true, - }, - externals: [...minimalExternals, externalsMap, externalHandler], - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68790eaa3a0aa..50f7630acfd82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1381,9 +1381,6 @@ importers: terser: specifier: 5.14.1 version: 5.14.1 - terser-webpack-plugin: - specifier: 5.3.9 - version: 5.3.9(@swc/core@1.3.55)(webpack@5.86.0) text-table: specifier: 0.2.0 version: 0.2.0 diff --git a/scripts/minimal-server.js b/scripts/minimal-server.js index 08f9125a4f0cc..f4f30ac97ce25 100644 --- a/scripts/minimal-server.js +++ b/scripts/minimal-server.js @@ -1,4 +1,3 @@ -console.time('next-wall-time') // Usage: node scripts/minimal-server.js // This script is used to run a minimal Next.js server in production mode. @@ -45,13 +44,11 @@ if (process.env.LOG_READFILE) { require('fs').readFile = function (path, options, callback) { readFileCount++ - console.log(`readFile: ${path}`) return originalReadFile.apply(this, arguments) } require('fs').readFileSync = function (path, options) { readFileSyncCount++ - console.log(`readFileSync: ${path}`) return originalReadFileSync.apply(this, arguments) } } @@ -59,9 +56,10 @@ if (process.env.LOG_READFILE) { console.time('next-cold-start') const NextServer = process.env.USE_BUNDLED_NEXT - ? require('next/dist/compiled/next-server/server.runtime.prod').default + ? require('next/dist/compiled/minimal-next-server/next-server-cached').default : require('next/dist/server/next-server').default +console.timeEnd('next-cold-start') if (process.env.LOG_READFILE) { console.log(`readFileCount: ${readFileCount + readFileSyncCount}`) } @@ -103,20 +101,9 @@ require('http') if (process.env.LOG_READFILE) { console.log(`readFileCount: ${readFileCount + readFileSyncCount}`) } + require('process').exit(0) }) }) .listen(3000, () => { console.timeEnd('next-cold-start') - fetch('http://localhost:3000/') - .then((res) => res.text()) - .then((text) => { - console.log(text) - }) - .catch((err) => { - console.error(err) - }) - .finally(() => { - console.timeEnd('next-wall-time') - require('process').exit(0) - }) }) diff --git a/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts b/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts index 3e5e6b82ea050..a61e222c3872e 100644 --- a/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts +++ b/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts @@ -113,7 +113,7 @@ createNextDescribe( await check(() => { const fullLog = logs.join('') - return fullLog.includes('[Error]: Body exceeded 1.5mb limit') && + return fullLog.includes('Error: Body exceeded 1.5mb limit') && fullLog.includes( 'To configure the body size limit for Server Actions, see' ) diff --git a/test/e2e/getserversideprops/app/pages/index.js b/test/e2e/getserversideprops/app/pages/index.js index da17edc01839d..4433c9c2ee84e 100644 --- a/test/e2e/getserversideprops/app/pages/index.js +++ b/test/e2e/getserversideprops/app/pages/index.js @@ -1,6 +1,6 @@ import Link from 'next/link' import ReactDOM from 'react-dom/server' -import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime' +import { RouterContext } from 'next/dist/shared/lib/router-context' import { useRouter } from 'next/router' function RouterComp(props) { diff --git a/test/e2e/opentelemetry/opentelemetry.test.ts b/test/e2e/opentelemetry/opentelemetry.test.ts index 13e0fefea2787..ae798ec7c5c2d 100644 --- a/test/e2e/opentelemetry/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/opentelemetry.test.ts @@ -77,80 +77,80 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.url": "https://vercel.com/", - "net.peer.name": "vercel.com", - "next.span_name": "fetch GET https://vercel.com/", - "next.span_type": "AppRender.fetch", - }, - "kind": 2, - "name": "fetch GET https://vercel.com/", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/app/[param]/rsc-fetch", - "next.span_name": "render route (app) /app/[param]/rsc-fetch", - "next.span_type": "AppRender.getBodyResult", - }, - "kind": 0, - "name": "render route (app) /app/[param]/rsc-fetch", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/app/[param]/rsc-fetch", - "http.status_code": 200, - "http.target": "/app/param/rsc-fetch", - "next.route": "/app/[param]/rsc-fetch", - "next.span_name": "GET /app/[param]/rsc-fetch", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /app/[param]/rsc-fetch", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.page": "/app/[param]/layout", - "next.span_name": "generateMetadata /app/[param]/layout", - "next.span_type": "ResolveMetadata.generateMetadata", - }, - "kind": 0, - "name": "generateMetadata /app/[param]/layout", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.page": "/app/[param]/rsc-fetch/page", - "next.span_name": "generateMetadata /app/[param]/rsc-fetch/page", - "next.span_type": "ResolveMetadata.generateMetadata", - }, - "kind": 0, - "name": "generateMetadata /app/[param]/rsc-fetch/page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.url": "https://vercel.com/", + "net.peer.name": "vercel.com", + "next.span_name": "fetch GET https://vercel.com/", + "next.span_type": "AppRender.fetch", + }, + "kind": 2, + "name": "fetch GET https://vercel.com/", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/app/[param]/rsc-fetch", + "next.span_name": "render route (app) /app/[param]/rsc-fetch", + "next.span_type": "AppRender.getBodyResult", + }, + "kind": 0, + "name": "render route (app) /app/[param]/rsc-fetch", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/app/[param]/rsc-fetch", + "http.status_code": 200, + "http.target": "/app/param/rsc-fetch", + "next.route": "/app/[param]/rsc-fetch", + "next.span_name": "GET /app/[param]/rsc-fetch", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /app/[param]/rsc-fetch", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/layout", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.page": "/app/[param]/rsc-fetch/page", + "next.span_name": "generateMetadata /app/[param]/rsc-fetch/page", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/rsc-fetch/page", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -160,39 +160,37 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "next.route": "/api/app/[param]/data/route", - "next.span_name": "executing api route (app) /api/app/[param]/data/route", - "next.span_type": "AppRouteRouteHandlers.runHandler", - }, - "kind": 0, - "name": "executing api route (app) /api/app/[param]/data/route", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, + Array [ + Object { + "attributes": Object { + "next.route": "/api/app/[param]/data/route", + "next.span_name": "executing api route (app) /api/app/[param]/data/route", + "next.span_type": "AppRouteRouteHandlers.runHandler", + }, + "kind": 0, + "name": "executing api route (app) /api/app/[param]/data/route", + "parentId": "[parent-id]", + "status": Object { + "code": 0, }, - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/api/app/[param]/data/route", - "http.status_code": 200, - "http.target": "/api/app/param/data", - "next.route": "/api/app/[param]/data/route", - "next.span_name": "GET /api/app/[param]/data/route", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /api/app/[param]/data/route", - "parentId": undefined, - "status": Object { - "code": 0, - }, + }, + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/api/app/param/data", + "next.span_name": "GET /api/app/param/data", + "next.span_type": "BaseServer.handleRequest", }, - ] - `) + "kind": 1, + "name": "GET /api/app/param/data", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -204,52 +202,52 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/pages/[param]/getServerSideProps", - "http.status_code": 200, - "http.target": "/pages/param/getServerSideProps", - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "GET /pages/[param]/getServerSideProps", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/[param]/getServerSideProps", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "getServerSideProps /pages/[param]/getServerSideProps", - "next.span_type": "Render.getServerSideProps", - }, - "kind": 0, - "name": "getServerSideProps /pages/[param]/getServerSideProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "render route (pages) /pages/[param]/getServerSideProps", - "next.span_type": "Render.renderDocument", - }, - "kind": 0, - "name": "render route (pages) /pages/[param]/getServerSideProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/pages/[param]/getServerSideProps", + "http.status_code": 200, + "http.target": "/pages/param/getServerSideProps", + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "GET /pages/[param]/getServerSideProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/[param]/getServerSideProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "getServerSideProps /pages/[param]/getServerSideProps", + "next.span_type": "Render.getServerSideProps", + }, + "kind": 0, + "name": "getServerSideProps /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "render route (pages) /pages/[param]/getServerSideProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -259,52 +257,52 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/pages/[param]/getStaticProps", - "http.status_code": 200, - "http.target": "/pages/param/getStaticProps", - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "GET /pages/[param]/getStaticProps", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/[param]/getStaticProps", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "getStaticProps /pages/[param]/getStaticProps", - "next.span_type": "Render.getStaticProps", - }, - "kind": 0, - "name": "getStaticProps /pages/[param]/getStaticProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "render route (pages) /pages/[param]/getStaticProps", - "next.span_type": "Render.renderDocument", - }, - "kind": 0, - "name": "render route (pages) /pages/[param]/getStaticProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/pages/[param]/getStaticProps", + "http.status_code": 200, + "http.target": "/pages/param/getStaticProps", + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "GET /pages/[param]/getStaticProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/[param]/getStaticProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "getStaticProps /pages/[param]/getStaticProps", + "next.span_type": "Render.getStaticProps", + }, + "kind": 0, + "name": "getStaticProps /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "render route (pages) /pages/[param]/getStaticProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -314,38 +312,38 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/api/pages/[param]/basic", - "http.status_code": 200, - "http.target": "/api/pages/param/basic", - "next.route": "/api/pages/[param]/basic", - "next.span_name": "GET /api/pages/[param]/basic", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /api/pages/[param]/basic", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.span_name": "executing api route (pages) /api/pages/[param]/basic", - "next.span_type": "Node.runHandler", - }, - "kind": 0, - "name": "executing api route (pages) /api/pages/[param]/basic", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/api/pages/[param]/basic", + "http.status_code": 200, + "http.target": "/api/pages/param/basic", + "next.route": "/api/pages/[param]/basic", + "next.span_name": "GET /api/pages/[param]/basic", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /api/pages/[param]/basic", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.span_name": "executing api route (pages) /api/pages/[param]/basic", + "next.span_type": "Node.runHandler", + }, + "kind": 0, + "name": "executing api route (pages) /api/pages/[param]/basic", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) diff --git a/test/e2e/prerender-native-module.test.ts b/test/e2e/prerender-native-module.test.ts index 34adb36ce5bd8..c23b1d2d05cd0 100644 --- a/test/e2e/prerender-native-module.test.ts +++ b/test/e2e/prerender-native-module.test.ts @@ -85,6 +85,8 @@ describe('prerender native module', () => { /node_modules\/sqlite3\/.*?\.node/, /node_modules\/sqlite\/.*?\.js/, /node_modules\/next/, + /next\/router\.js/, + /next\/dist\/client\/router\.js/, /\/data\.sqlite/, ], notTests: [], @@ -97,6 +99,7 @@ describe('prerender native module', () => { ) const { version, files } = JSON.parse(contents) expect(version).toBe(1) + expect( check.tests.every((item) => files.some((file) => item.test(file))) ).toBe(true) diff --git a/test/e2e/prerender.test.ts b/test/e2e/prerender.test.ts index 1ff677e583b15..f21b4224fe236 100644 --- a/test/e2e/prerender.test.ts +++ b/test/e2e/prerender.test.ts @@ -2070,6 +2070,7 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, ], notTests: [], }, @@ -2081,6 +2082,7 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, /\/world.txt/, ], notTests: [ @@ -2096,6 +2098,9 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, + /next\/router\.js/, + /next\/dist\/client\/router\.js/, /node_modules\/@firebase\/firestore\/.*?\.js/, ], notTests: [/\/world.txt/], diff --git a/test/integration/externalize-next-server/app/node_modules/comps/index.js b/test/integration/externalize-next-server/app/node_modules/comps/index.js new file mode 100644 index 0000000000000..74c3153f1b835 --- /dev/null +++ b/test/integration/externalize-next-server/app/node_modules/comps/index.js @@ -0,0 +1,5 @@ +const react = require('react') + +module.exports = function() { + return react.createElement('p', null, 'MyComp:', typeof window) +} diff --git a/test/integration/externalize-next-server/app/node_modules/comps/package.json b/test/integration/externalize-next-server/app/node_modules/comps/package.json new file mode 100644 index 0000000000000..6e665b646a6ad --- /dev/null +++ b/test/integration/externalize-next-server/app/node_modules/comps/package.json @@ -0,0 +1,6 @@ +{ + "name": "comps", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/test/integration/externalize-next-server/app/package.json b/test/integration/externalize-next-server/app/package.json new file mode 100644 index 0000000000000..c5bd706a3a950 --- /dev/null +++ b/test/integration/externalize-next-server/app/package.json @@ -0,0 +1,6 @@ +{ + "name": "externalize-next-server-app", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/test/integration/externalize-next-server/app/pages/index.js b/test/integration/externalize-next-server/app/pages/index.js new file mode 100644 index 0000000000000..9ceb7bee3db17 --- /dev/null +++ b/test/integration/externalize-next-server/app/pages/index.js @@ -0,0 +1,12 @@ +import MyComp from 'comps' + +const Page = () => ( + <> +

Hello {typeof window}

+ + +) + +Page.getInitialProps = () => ({}) + +export default Page diff --git a/test/integration/externalize-next-server/test/index.test.js b/test/integration/externalize-next-server/test/index.test.js new file mode 100644 index 0000000000000..bba968de16585 --- /dev/null +++ b/test/integration/externalize-next-server/test/index.test.js @@ -0,0 +1,19 @@ +/* eslint-env jest */ +import path from 'path' +import { nextBuild, readNextBuildServerPageFile } from 'next-test-utils' + +const appDir = path.join(__dirname, '../app') + +describe('externalize next/dist/shared', () => { + beforeAll(async () => { + await nextBuild(appDir) + }) + + it('Bundle next/dist/shared/lib/head.js but not next/dist/shared/lib/head-manager-context.js in _error', async () => { + const content = readNextBuildServerPageFile(appDir, '/_error') + expect(content).toContain( + `require("next/dist/shared/lib/head-manager-context.js")` + ) + expect(content).not.toContain(`require("next/dist/shared/lib/head.js")`) + }) +}) diff --git a/test/integration/jsconfig-baseurl/test/index.test.js b/test/integration/jsconfig-baseurl/test/index.test.js index 4ad014d0e8f03..91f084ce1d55e 100644 --- a/test/integration/jsconfig-baseurl/test/index.test.js +++ b/test/integration/jsconfig-baseurl/test/index.test.js @@ -72,6 +72,12 @@ describe('TypeScript Features', () => { const helloTrace = await fs.readJSON( join(appDir, '.next/server/pages/hello.js.nft.json') ) + const appTrace = await fs.readJSON( + join(appDir, '.next/server/pages/_app.js.nft.json') + ) + expect( + appTrace.files.some((file) => file.includes('node_modules/next')) + ).toBe(true) expect( helloTrace.files.some((file) => file.includes('components/world.js')) ).toBe(false) diff --git a/test/integration/jsconfig-paths/test/index.test.js b/test/integration/jsconfig-paths/test/index.test.js index bc3c635b9ce96..77c84e7edfbb4 100644 --- a/test/integration/jsconfig-paths/test/index.test.js +++ b/test/integration/jsconfig-paths/test/index.test.js @@ -89,6 +89,9 @@ function runTests() { await nextBuild(appDir) }) it('should trace correctly', async () => { + const appTrace = await fs.readJSON( + join(appDir, '.next/server/pages/_app.js.nft.json') + ) const singleAliasTrace = await fs.readJSON( join(appDir, '.next/server/pages/single-alias.js.nft.json') ) @@ -104,7 +107,9 @@ function runTests() { const basicAliasTrace = await fs.readJSON( join(appDir, '.next/server/pages/basic-alias.js.nft.json') ) - + expect( + appTrace.files.some((file) => file.includes('node_modules/next')) + ).toBe(true) expect( singleAliasTrace.files.some((file) => file.includes('components/hello.js') From 2b514ea8e33041b820be498c8a6eef5b99303b9f Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 7 Sep 2023 16:08:53 -0600 Subject: [PATCH 3/5] Strip internal routing headers (#55114) This strips the internal routing headers added by the routing server. Based on some of the changes being introduced in https://github.com/vercel/next.js/pull/54813 this strips the headers, but this also adds some internal flags to turn this off during testing to validate correct routing beheviour. --- packages/next/src/server/base-server.ts | 27 ++++++++++++++++++ packages/next/src/server/internal-utils.ts | 28 ++++++++++++++++++- packages/next/src/server/next-server.ts | 3 ++ .../i18n-data-route/i18n-data-route.test.ts | 4 +++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index d826f2bdd4e04..bacb1cc38e4ff 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -124,6 +124,7 @@ import { } from './web/spec-extension/adapters/next-request' import { matchNextDataPathname } from './lib/match-next-data-pathname' import getRouteFromAssetPath from '../shared/lib/router/utils/get-route-from-asset-path' +import { stripInternalHeaders } from './internal-utils' export type FindComponentsResult = { components: LoadComponentsReturnType @@ -1538,6 +1539,28 @@ export default abstract class Server { ) } + protected stripInternalHeaders(req: BaseNextRequest): void { + // Skip stripping internal headers in test mode while the header stripping + // has been explicitly disabled. This allows tests to verify internal + // routing behavior. + if ( + process.env.__NEXT_TEST_MODE && + process.env.__NEXT_NO_STRIP_INTERNAL_HEADERS === '1' + ) { + return + } + + // Strip the internal headers from both the request and the original + // request. + stripInternalHeaders(req.headers) + if ( + 'originalRequest' in req && + 'headers' in (req as NodeNextRequest).originalRequest + ) { + stripInternalHeaders((req as NodeNextRequest).originalRequest.headers) + } + } + private async renderToResponseWithComponentsImpl( { req, res, pathname, renderOpts: opts }: RequestContext, { components, query }: FindComponentsResult @@ -1546,6 +1569,10 @@ export default abstract class Server { // For edge runtime 404 page, /_not-found needs to be treated as 404 page (process.env.NEXT_RUNTIME === 'edge' && pathname === '/_not-found') || pathname === '/404' + + // Strip the internal headers. + this.stripInternalHeaders(req) + const is500Page = pathname === '/500' const isAppPath = components.isAppPath const hasServerProps = !!components.getServerSideProps diff --git a/packages/next/src/server/internal-utils.ts b/packages/next/src/server/internal-utils.ts index 1ae559ea09db8..1e712b16379a4 100644 --- a/packages/next/src/server/internal-utils.ts +++ b/packages/next/src/server/internal-utils.ts @@ -1,6 +1,8 @@ -import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' +import type { IncomingHttpHeaders } from 'http' import type { NextParsedUrlQuery } from './request-meta' +import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' + const INTERNAL_QUERY_NAMES = [ '__nextFallback', '__nextLocale', @@ -36,3 +38,27 @@ export function stripInternalSearchParams( return (isStringUrl ? instance.toString() : instance) as T } + +/** + * Headers that are set by the Next.js server and should be stripped from the + * request headers going to the user's application. + */ +const INTERNAL_HEADERS = [ + 'x-invoke-path', + 'x-invoke-status', + 'x-invoke-error', + 'x-invoke-query', + 'x-invoke-output', + 'x-middleware-invoke', +] as const + +/** + * Strip internal headers from the request headers. + * + * @param headers the headers to strip of internal headers + */ +export function stripInternalHeaders(headers: IncomingHttpHeaders) { + for (const key of INTERNAL_HEADERS) { + delete headers[key] + } +} diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 087752225090f..0fe80339d1a0f 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -1585,6 +1585,9 @@ export default class NextNodeServer extends BaseServer { ReturnType > + // Strip the internal headers. + this.stripInternalHeaders(req) + try { await this.ensureMiddleware() diff --git a/test/e2e/i18n-data-route/i18n-data-route.test.ts b/test/e2e/i18n-data-route/i18n-data-route.test.ts index a25d8e8adad2d..1231f78f02670 100644 --- a/test/e2e/i18n-data-route/i18n-data-route.test.ts +++ b/test/e2e/i18n-data-route/i18n-data-route.test.ts @@ -17,6 +17,10 @@ createNextDescribe( 'i18n-data-route', { files: __dirname, + env: { + // Disable internal header stripping so we can test the invoke output. + __NEXT_NO_STRIP_INTERNAL_HEADERS: '1', + }, }, ({ next }) => { describe('with locale prefix', () => { From 904d8eed3958be3a0c4167a858f06029aac42c65 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 7 Sep 2023 23:18:04 +0000 Subject: [PATCH 4/5] v13.4.20-canary.21 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 9473ac4b6bb84..a589ef7b023c6 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.4.20-canary.20" + "version": "13.4.20-canary.21" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index cca799bdb09c9..93dd0606ab6e7 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8e028a9ab6d75..d8032af352f66 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "13.4.20-canary.20", + "@next/eslint-plugin-next": "13.4.20-canary.21", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 61d7b0aa5012f..2d2c6da7a230c 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 590100e487387..20b38c3da5458 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 11e767e1d13e3..ba98bb5b04259 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 42ac260ab258e..60c2888bcfe50 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index dbac7a4a5d26e..38d1e9f40a0bd 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 75739c7731f17..01daaf6790025 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1af2a0530ad19..fd6347ce0ca81 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index f333bb9010080..d7bb163c02bc2 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index c7b23dcd1e426..63889fce9a931 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 87ac07c84398a..47906ad8c2f6c 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 28fbd949a8972..058280c68b63f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -89,7 +89,7 @@ ] }, "dependencies": { - "@next/env": "13.4.20-canary.20", + "@next/env": "13.4.20-canary.21", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -144,11 +144,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.4.20-canary.20", - "@next/polyfill-nomodule": "13.4.20-canary.20", - "@next/react-dev-overlay": "13.4.20-canary.20", - "@next/react-refresh-utils": "13.4.20-canary.20", - "@next/swc": "13.4.20-canary.20", + "@next/polyfill-module": "13.4.20-canary.21", + "@next/polyfill-nomodule": "13.4.20-canary.21", + "@next/react-dev-overlay": "13.4.20-canary.21", + "@next/react-refresh-utils": "13.4.20-canary.21", + "@next/swc": "13.4.20-canary.21", "@opentelemetry/api": "1.4.1", "@playwright/test": "^1.35.1", "@segment/ajv-human-errors": "2.1.2", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index cc6d2a5b422a3..d760b0ff82191 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 20e4acbdcca74..2db27f44e1e96 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json index 7677d8733511c..4e69590dcd618 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "private": true, "repository": { "url": "vercel/next.js", @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "13.4.20-canary.20", + "next": "13.4.20-canary.21", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50f7630acfd82..ecefb2db79ec1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -729,7 +729,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -790,7 +790,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-env '@swc/helpers': specifier: 0.5.1 @@ -917,19 +917,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../react-refresh-utils '@next/swc': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-swc '@opentelemetry/api': specifier: 1.4.1 @@ -1685,7 +1685,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next outdent: specifier: 0.8.0 From 8076d0c68a327869b088559587565708c75f7b71 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Fri, 8 Sep 2023 01:58:09 +0200 Subject: [PATCH 5/5] Add option to support log full request url in verbose mode (#55111) Fixes #52239 Closes NEXT-1604 Change the logging option to object for flexibility ```js experimental: { logging: { level: 'verbose', // control log level fullUrl: true, // console fetching url logging } } ``` ### After vs Before --- packages/next/src/server/config-schema.ts | 10 +++++- packages/next/src/server/config-shared.ts | 5 ++- packages/next/src/server/next-server.ts | 36 +++++++++++-------- .../app-static/app-fetch-logging.test.ts | 7 ++-- test/e2e/app-dir/app-static/next.config.js | 4 ++- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 31cb19a7b2649..5b7b5ae9f1b58 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -501,7 +501,15 @@ const configSchema = { }, }, logging: { - type: 'string', + type: 'object', + properties: { + level: { + type: 'string', + }, + fullUrl: { + type: 'boolean', + }, + }, }, serverMinification: { type: 'boolean', diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 94ef73429f416..a44d576098143 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -149,7 +149,10 @@ export interface ExperimentalConfig { useDeploymentId?: boolean useDeploymentIdServerActions?: boolean deploymentId?: string - logging?: 'verbose' + logging?: { + level?: 'verbose' + fullUrl?: false + } appDocumentPreloading?: boolean strictNextHead?: boolean clientRouterFilter?: boolean diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 0fe80339d1a0f..d6ad6edaea41d 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -108,6 +108,12 @@ function writeStdoutLine(text: string) { process.stdout.write(' ' + text + '\n') } +function formatRequestUrl(url: string, maxLength: number | undefined) { + return maxLength !== undefined && url.length > maxLength + ? url.substring(0, maxLength) + '..' + : url +} + export interface NodeRequestHandler { ( req: IncomingMessage | BaseNextRequest, @@ -1010,7 +1016,9 @@ export default class NextNodeServer extends BaseServer { const normalizedRes = this.normalizeRes(res) const enabledVerboseLogging = - this.nextConfig.experimental.logging === 'verbose' + this.nextConfig.experimental.logging?.level === 'verbose' + const shouldTruncateUrl = !this.nextConfig.experimental.logging?.fullUrl + if (this.renderOpts.dev) { const _req = req as NodeNextRequest | IncomingMessage const _res = res as NodeNextResponse | ServerResponse @@ -1098,20 +1106,18 @@ export default class NextNodeServer extends BaseServer { if (url.length > 48) { const parsed = new URL(url) - const truncatedHost = - parsed.host.length > 16 - ? parsed.host.substring(0, 16) + '..' - : parsed.host - - const truncatedPath = - parsed.pathname.length > 24 - ? parsed.pathname.substring(0, 24) + '..' - : parsed.pathname - - const truncatedSearch = - parsed.search.length > 16 - ? parsed.search.substring(0, 16) + '..' - : parsed.search + const truncatedHost = formatRequestUrl( + parsed.host, + shouldTruncateUrl ? 16 : undefined + ) + const truncatedPath = formatRequestUrl( + parsed.pathname, + shouldTruncateUrl ? 24 : undefined + ) + const truncatedSearch = formatRequestUrl( + parsed.search, + shouldTruncateUrl ? 16 : undefined + ) url = parsed.protocol + diff --git a/test/e2e/app-dir/app-static/app-fetch-logging.test.ts b/test/e2e/app-dir/app-static/app-fetch-logging.test.ts index 7ce5f33e6732f..44b0888499df8 100644 --- a/test/e2e/app-dir/app-static/app-fetch-logging.test.ts +++ b/test/e2e/app-dir/app-static/app-fetch-logging.test.ts @@ -32,7 +32,6 @@ function parseLogsFromCli(cliOutput: string) { } parsedLogs.push(parsedLog) } - // console.log('parsedLogs', parsedLogs) return parsedLogs }, [] as any[]) } @@ -46,7 +45,7 @@ createNextDescribe( 'app/default-cache/page.js': new FileRef( path.join(__dirname, 'app/default-cache/page.js') ), - 'next.config.js': `module.exports = { experimental: { logging: 'verbose' } }`, + 'next.config.js': `module.exports = { experimental: { logging: { level: 'verbose', fullUrl: true } } }`, }, }, ({ next, isNextDev }) => { @@ -81,6 +80,9 @@ createNextDescribe( log.url.includes('api/random?no-cache') ) + // expend full url + expect(logs.every((log) => log.url.includes('..'))).toBe(false) + if (logEntry?.cache === 'cache: no-cache') { return 'success' } @@ -115,7 +117,6 @@ createNextDescribe( log.url.includes('api/random?auto-cache') ) - console.log('logEntry?.cache', logEntry?.cache) if (logEntry?.cache === 'cache-control: no-cache (hard refresh)') { return 'success' } diff --git a/test/e2e/app-dir/app-static/next.config.js b/test/e2e/app-dir/app-static/next.config.js index a575f6b793e2f..8a101145f40b9 100644 --- a/test/e2e/app-dir/app-static/next.config.js +++ b/test/e2e/app-dir/app-static/next.config.js @@ -1,7 +1,9 @@ /** @type {import('next').NextConfig} */ module.exports = { experimental: { - logging: 'verbose', + logging: { + level: 'verbose', + }, incrementalCacheHandlerPath: process.env.CUSTOM_CACHE_HANDLER, },