diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 23272df2ec9f8ec..e6f5fc1d11d8ebc 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -207,7 +207,7 @@ export function getEdgeServerEntry(opts: { // The Edge bundle includes the server in its entrypoint, so it has to // be in the SSR layer — we later convert the page request to the RSC layer // via a webpack rule. - layer: WEBPACK_LAYERS.client, + layer: opts.appDirLoader ? WEBPACK_LAYERS.client : undefined, } } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 050ee856dae7c6f..ee2e54d80fe26a8 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -887,6 +887,15 @@ export default async function getBaseWebpackConfig( 'next/dist/client': 'next/dist/esm/client', 'next/dist/shared': 'next/dist/esm/shared', 'next/dist/pages': 'next/dist/esm/pages', + 'next/dist/lib': 'next/dist/esm/lib', + + // Alias the usage of next public APIs + [require.resolve('next/link')]: 'next/dist/esm/client/link', + [require.resolve('next/image')]: 'next/dist/esm/client/image', + [require.resolve('next/router')]: 'next/dist/esm/client/router', + [require.resolve('next/script')]: 'next/dist/esm/client/script', + [require.resolve('next/dynamic')]: 'next/dist/shared/lib/dynamic', + [require.resolve('next/head')]: 'next/dist/shared/lib/head', } : undefined), @@ -1107,7 +1116,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)$)|string-hash|private-next-rsc-mod-ref-proxy$)/ + /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|router|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-mod-ref-proxy$)/ if (notExternalModules.test(request)) { return } @@ -1132,7 +1141,7 @@ export default async function getBaseWebpackConfig( // Treat next internals as non-external for server layer layer === WEBPACK_LAYERS.server ? false - : /next[/\\]dist[/\\](shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic))/.test( + : /next[/\\]dist[/\\](esm[\\/])?(shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic))/.test( localRes ) @@ -1198,7 +1207,9 @@ export default async function getBaseWebpackConfig( const externalType = isEsm ? 'module' : 'commonjs' if ( - /next[/\\]dist[/\\]shared[/\\](?!lib[/\\]router[/\\]router)/.test(res) || + /next[/\\]dist[/\\](esm[\\/])?shared[/\\](?!lib[/\\]router[/\\]router)/.test( + res + ) || /next[/\\]dist[/\\]compiled[/\\].*\.[mc]?js$/.test(res) ) { return `${externalType} ${request}` diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts index 010a94f6fa5af92..59ebcf17f55d113 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts @@ -97,28 +97,29 @@ export default async function edgeSSRLoader(this: any) { ${ isAppDir ? ` + import { renderToHTMLOrFlight as appRenderToHTML } from 'next/dist/esm/server/app-render' + import * as pageMod from ${JSON.stringify(pageModPath)} const Document = null - const appRenderToHTML = require('next/dist/esm/server/app-render').renderToHTMLOrFlight const pagesRenderToHTML = null - const pageMod = require(${JSON.stringify(pageModPath)}) const appMod = null const errorMod = null const error500Mod = null ` : ` - const Document = require(${stringifiedDocumentPath}).default - const appRenderToHTML = null - const pagesRenderToHTML = require('next/dist/esm/server/render').renderToHTML - const pageMod = require(${stringifiedPagePath}) - const appMod = require(${stringifiedAppPath}) - const errorMod = require(${stringifiedErrorPath}) - const error500Mod = ${ - stringified500Path ? `require(${stringified500Path})` : 'null' + import Document from ${stringifiedDocumentPath} + import { renderToHTML as pagesRenderToHTML } from 'next/dist/esm/server/render' + import * as pageMod from ${stringifiedPagePath} + import * as appMod from ${stringifiedAppPath} + import * as errorMod from ${stringifiedErrorPath} + ${ + stringified500Path + ? `import * as error500Mod from ${stringified500Path}` + : `const error500Mod = null` } + const appRenderToHTML = null ` } - const buildManifest = self.__BUILD_MANIFEST const reactLoadableManifest = self.__REACT_LOADABLE_MANIFEST const rscManifest = self.__RSC_MANIFEST diff --git a/packages/next/client/dev/error-overlay/hot-dev-client.js b/packages/next/client/dev/error-overlay/hot-dev-client.js index 8d128e38b21984d..697c99945c21adc 100644 --- a/packages/next/client/dev/error-overlay/hot-dev-client.js +++ b/packages/next/client/dev/error-overlay/hot-dev-client.js @@ -119,7 +119,7 @@ function handleWarnings(warnings) { }) if (typeof console !== 'undefined' && typeof console.warn === 'function') { - for (let i = 0; i < formatted.warnings.length; i++) { + for (let i = 0; i < formatted.warnings?.length; i++) { if (i === 5) { console.warn( 'There were more warnings in other files.\n' + diff --git a/packages/next/script.js b/packages/next/script.js index 6d257fa56f1572d..4e0f885ac60a388 100644 --- a/packages/next/script.js +++ b/packages/next/script.js @@ -1,4 +1 @@ -module.exports = - process.env.NEXT_RUNTIME === 'edge' - ? require('./dist/esm/client/script') - : require('./dist/client/script') +module.exports = require('./dist/client/script') diff --git a/test/e2e/streaming-ssr/index.test.ts b/test/e2e/streaming-ssr/index.test.ts index 58466bdd5ba07ca..958bec7e0a5c9e8 100644 --- a/test/e2e/streaming-ssr/index.test.ts +++ b/test/e2e/streaming-ssr/index.test.ts @@ -65,6 +65,11 @@ describe('react 18 streaming SSR with custom next configs', () => { expect(html).toContain('home') }) + it('should render next/router correctly in edge runtime', async () => { + const html = await renderViaHTTP(next.url, '/router') + expect(html).toContain('link') + }) + it('should render multi-byte characters correctly in streaming', async () => { const html = await renderViaHTTP(next.url, '/multi-byte') expect(html).toContain('マルチバイト'.repeat(28)) diff --git a/test/e2e/streaming-ssr/streaming-ssr/pages/router.js b/test/e2e/streaming-ssr/streaming-ssr/pages/router.js new file mode 100644 index 000000000000000..5b848e819e46569 --- /dev/null +++ b/test/e2e/streaming-ssr/streaming-ssr/pages/router.js @@ -0,0 +1,11 @@ +import { useRouter } from 'next/router' +import Link from 'next/link' + +export default () => { + // useRouter() + return link +} + +export const config = { + runtime: 'experimental-edge', +}