diff --git a/src/core/dev-server/server.ts b/src/core/dev-server/server.ts index 7fd90cef37..4f4046548c 100644 --- a/src/core/dev-server/server.ts +++ b/src/core/dev-server/server.ts @@ -8,6 +8,7 @@ import { type FSWatcher, watch } from "chokidar"; import { type H3Error, type H3Event, + appendResponseHeaders, createApp, createError, eventHandler, @@ -22,15 +23,18 @@ import type { Nitro, NitroBuildInfo, NitroDevServer, + NitroRouteRules, NitroWorker, } from "nitropack/types"; import { resolve } from "pathe"; import { debounce } from "perfect-debounce"; import { servePlaceholder } from "serve-placeholder"; import serveStatic from "serve-static"; -import { joinURL } from "ufo"; +import { joinURL, withoutBase } from "ufo"; import defaultErrorHandler from "./error"; import { createVFSHandler } from "./vfs"; +import { createRouter as createRadixRouter, toRouteMatcher } from "radix3"; +import defu from "defu"; function initWorker(filename: string): Promise | undefined { if (!existsSync(filename)) { @@ -166,6 +170,20 @@ export function createDevServer(nitro: Nitro): NitroDevServer { // Debugging endpoint to view vfs app.use("/_vfs", createVFSHandler(nitro)); + // Apply headers based on routeRules. In cases where the dev server is being + // used, these would otherwise fail to be applied to public assets. + const routeRulesMatcher = toRouteMatcher( + createRadixRouter({ routes: nitro.options.routeRules }) + ); + app.use("/", eventHandler((event) => { + const baseUrl = nitro.options.runtimeConfig.app.baseURL; + const normPath = withoutBase(event.path.split("?")[0], baseUrl); + const rules: NitroRouteRules = defu({}, ...routeRulesMatcher.matchAll(normPath).reverse()); + if (rules.headers) { + appendResponseHeaders(event, rules.headers); + } + })); + // Serve asset dirs for (const asset of nitro.options.publicAssets) { const url = joinURL(