diff --git a/packages/next/src/client/components/router-reducer/fetch-server-response.ts b/packages/next/src/client/components/router-reducer/fetch-server-response.ts index b6e93ee6c1..8a1efbbae7 100644 --- a/packages/next/src/client/components/router-reducer/fetch-server-response.ts +++ b/packages/next/src/client/components/router-reducer/fetch-server-response.ts @@ -39,12 +39,14 @@ export async function fetchServerResponse( try { let fetchUrl = url - if (process.env.__NEXT_CONFIG_OUTPUT === 'export') { - fetchUrl = new URL(url) // clone - if (fetchUrl.pathname.endsWith('/')) { - fetchUrl.pathname += 'index.txt' - } else { - fetchUrl.pathname += '.txt' + if (process.env.NODE_ENV === 'production') { + if (process.env.__NEXT_CONFIG_OUTPUT === 'export') { + fetchUrl = new URL(url) // clone + if (fetchUrl.pathname.endsWith('/')) { + fetchUrl.pathname += 'index.txt' + } else { + fetchUrl.pathname += '.txt' + } } } const res = await fetch(fetchUrl, { @@ -59,9 +61,11 @@ export async function fetchServerResponse( const contentType = res.headers.get('content-type') || '' let isFlightResponse = contentType === RSC_CONTENT_TYPE_HEADER - if (process.env.__NEXT_CONFIG_OUTPUT === 'export') { - if (!isFlightResponse) { - isFlightResponse = contentType.startsWith('text/plain') + if (process.env.NODE_ENV === 'production') { + if (process.env.__NEXT_CONFIG_OUTPUT === 'export') { + if (!isFlightResponse) { + isFlightResponse = contentType.startsWith('text/plain') + } } } diff --git a/packages/next/src/server/dev/next-dev-server.ts b/packages/next/src/server/dev/next-dev-server.ts index 0500b7772e..31fa6b388d 100644 --- a/packages/next/src/server/dev/next-dev-server.ts +++ b/packages/next/src/server/dev/next-dev-server.ts @@ -535,6 +535,7 @@ export default class DevServer extends Server { }) if ( + !isAppPath && pageName.startsWith('/api/') && this.nextConfig.output === 'export' ) { @@ -1535,6 +1536,7 @@ export default class DevServer extends Server { staticPaths?: string[] fallbackMode?: false | 'static' | 'blocking' }> { + const isAppPath = Boolean(originalAppPath) // we lazy load the staticPaths to prevent the user // from waiting on them for the page to load in dev mode @@ -1561,7 +1563,7 @@ export default class DevServer extends Server { locales, defaultLocale, originalAppPath, - isAppPath: !!originalAppPath, + isAppPath, requestHeaders, incrementalCacheHandlerPath: this.nextConfig.experimental.incrementalCacheHandlerPath, @@ -1579,7 +1581,7 @@ export default class DevServer extends Server { ) .then((res) => { const { paths: staticPaths = [], fallback } = res.value - if (this.nextConfig.output === 'export') { + if (!isAppPath && this.nextConfig.output === 'export') { if (fallback === 'blocking') { throw new Error( 'getStaticPaths with "fallback: blocking" cannot be used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' diff --git a/test/integration/app-dir-export/test/index.test.ts b/test/integration/app-dir-export/test/index.test.ts index 832991f55e..380978e7ae 100644 --- a/test/integration/app-dir-export/test/index.test.ts +++ b/test/integration/app-dir-export/test/index.test.ts @@ -7,6 +7,9 @@ import webdriver from 'next-webdriver' import globOrig from 'glob' import { File, + findPort, + killApp, + launchApp, nextBuild, nextExport, startStaticServer, @@ -20,12 +23,13 @@ const distDir = join(__dirname, '.next') const exportDir = join(appDir, 'out') const nextConfig = new File(join(appDir, 'next.config.js')) const slugPage = new File(join(appDir, 'app/another/[slug]/page.js')) -const delay = 100 async function runTests({ + isDev, trailingSlash, dynamic, }: { + isDev?: boolean trailingSlash?: boolean dynamic?: string }) { @@ -43,12 +47,18 @@ async function runTests({ } await fs.remove(distDir) await fs.remove(exportDir) - await nextBuild(appDir) - await nextExport(appDir, { outdir: exportDir }) - const app = await startStaticServer(exportDir) - const address = app.address() - const appPort = typeof address !== 'string' ? address.port : 3000 - + const delay = isDev ? 500 : 100 + const appPort = await findPort() + let stopOrKill: () => Promise + if (isDev) { + const app = await launchApp(appDir, appPort) + stopOrKill = async () => await killApp(app) + } else { + await nextBuild(appDir) + await nextExport(appDir, { outdir: exportDir }) + const app = await startStaticServer(exportDir, null, appPort) + stopOrKill = async () => await stopApp(app) + } try { const a = (n: number) => `li:nth-child(${n}) a` console.log('[navigate]') @@ -108,15 +118,20 @@ async function runTests({ '/test.3f1a293b.png' ) } finally { - await stopApp(app) + await stopOrKill() nextConfig.restore() slugPage.restore() } } -describe('app dir with next export', () => { - it.each([{ trailingSlash: false }, { trailingSlash: true }])( - "should work with trailingSlash '$trailingSlash'", +describe('app dir with output export', () => { + it.each([ + { isDev: true, trailingSlash: false }, + { isDev: true, trailingSlash: true }, + { isDev: false, trailingSlash: false }, + { isDev: false, trailingSlash: true }, + ])( + "should work with isDev '$isDev' and trailingSlash '$trailingSlash'", async ({ trailingSlash }) => { await runTests({ trailingSlash }) }