Files
next.js/test/e2e/app-dir/segment-cache/export/server.mjs
Andrew ClarkandGitHub 5557bdda51 [Segment Cache] Support third-party redirects in output: "export" mode (#81247)
In output: "export" mode, we can't use headers to request a particular
segment. Instead, we encode the extra request information into the URL.
This is not part of the "public" interface of the app; it's an internal
Next.js implementation detail that the app developer should not need to
concern themselves with.

For example, to request a segment:

- Path passed to <Link>:   /path/to/page
- Path passed to fetch:    /path/to/page/__next-segments/_tree

*(This is not the exact protocol, just an illustration.)*

Before we do that, though, we need to account for redirects. Even in
output: "export" mode, a proxy might redirect the page to a different
location, but we shouldn't assume or expect that they also redirect all
the segment files, too.

To check whether the page is redirected, we perform a range request of
the first N bytes of the HTML document, just enough to verify the
document comes from the same build. The canonical URL is determined from
the response.

Then we can use the canonical URL to request the route tree.

Note: We could embed the route tree into the HTML document, to avoid a
second request. We're not doing that currently because it would make the
HTML document larger and affect normal page loads.
2025-07-03 14:03:33 -04:00

42 lines
1.5 KiB
JavaScript

// import express from 'express'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { createServer } from 'node:http'
// output: "export" mode was originally designed to work seamlessly with the
// "serve" package, which uses "server-handler" internally. It has built-in
// conventions for things like .html extensions and trailing slashes. Apps that
// use a different server like ngnix need configuration to match this behavior.
// TODO: We should improve our documentation around this.
import handler from 'serve-handler'
const OUT_DIR = join(dirname(fileURLToPath(import.meta.url)), 'out')
export const server = createServer((request, response) => {
// Redirect /redirect-to-target-page to /target-page. Notice that we only have
// to redirect the path of the page, not any other resources.
if (request.url === '/redirect-to-target-page') {
console.log('Redirecting to /target-page')
response.writeHead(302, { Location: '/target-page' })
response.end()
return
}
// Rewrite /rewrite-to-target-page to /target-page
// NOTE: This simulates a rewrite using a proxy, which is not something we
// officially support or document. It's just here to illustrate how it would
// be done in theory.
if (/^\/rewrite-to-target-page\/?[^/]*$/.test(request.url)) {
const newUrl = request.url.replace(
'/rewrite-to-target-page',
'/target-page'
)
console.log(`Rewriting ${request.url} to ${newUrl}`)
request.url = newUrl
}
return handler(request, response, {
public: OUT_DIR,
})
})