diff --git a/packages/docusaurus/src/commands/serve/requestHandler.ts b/packages/docusaurus/src/commands/serve/requestHandler.ts index 8437b0ccca2c..5ac45c8c26c1 100644 --- a/packages/docusaurus/src/commands/serve/requestHandler.ts +++ b/packages/docusaurus/src/commands/serve/requestHandler.ts @@ -24,38 +24,23 @@ export function createServeRequestHandler({ 'baseUrl' | 'trailingSlash' >): ServeRequestHandler { return async (req, res) => { - // Automatically redirect requests to /baseUrl/ - if (!req.url?.startsWith(baseUrl)) { - redirect(res, baseUrl); + const redirectLocation = getRedirectLocation(req.url, { + baseUrl, + trailingSlash, + }); + if (redirectLocation !== undefined) { + redirect(res, redirectLocation); return; } - // We do the redirect ourselves for a good reason - // server-handler is annoying and won't include /baseUrl/ in redirects - // See https://github.com/meta/docusaurus/issues/10078#issuecomment-2084932934 - if (baseUrl !== '/') { - // Not super robust, but should be good enough for our use case - // See https://github.com/meta/docusaurus/pull/10090 - const looksLikeAsset = !!req.url.match(/\.[a-z\d]{1,4}$/i); - if (!looksLikeAsset) { - const normalizedUrl = applyTrailingSlash(req.url, { - trailingSlash, - baseUrl, - }); - if (req.url !== normalizedUrl) { - redirect(res, normalizedUrl); - return; - } - } - } - // Remove baseUrl before calling serveHandler, because /baseUrl/ should // serve /build/index.html, not /build/baseUrl/index.html (does not exist) // Note server-handler is really annoying here: // - no easy way to do rewrites such as "/baseUrl/:path" => "/:path" // - no easy way to "reapply" the baseUrl to the redirect "Location" header // See also https://github.com/meta/docusaurus/pull/10090 - req.url = req.url.replace(baseUrl, '/'); + // Requests without url were redirected to the baseUrl + req.url = req.url!.replace(baseUrl, '/'); await serveHandler(req, res, { cleanUrls: true, @@ -66,6 +51,36 @@ export function createServeRequestHandler({ }; } +function getRedirectLocation( + url: string | undefined, + {baseUrl, trailingSlash}: Pick, +): string | undefined { + // Automatically redirect requests to /baseUrl/ + if (!url?.startsWith(baseUrl)) { + return baseUrl; + } + + // We do the redirect ourselves for a good reason + // server-handler is annoying and won't include /baseUrl/ in redirects + // See https://github.com/meta/docusaurus/issues/10078#issuecomment-2084932934 + if (baseUrl !== '/') { + // Not super robust, but should be good enough for our use case + // See https://github.com/meta/docusaurus/pull/10090 + const looksLikeAsset = !!url.match(/\.[a-z\d]{1,4}$/i); + if (!looksLikeAsset) { + const normalizedUrl = applyTrailingSlash(url, { + trailingSlash, + baseUrl, + }); + if (url !== normalizedUrl) { + return normalizedUrl; + } + } + } + + return undefined; +} + function redirect(res: http.ServerResponse, location: string) { res.writeHead(302, { Location: location,