diff --git a/src/config/loader.ts b/src/config/loader.ts index e280e40804..ca27a4925a 100644 --- a/src/config/loader.ts +++ b/src/config/loader.ts @@ -79,6 +79,7 @@ async function _loadUserConfig( let preset: string | undefined = (configOverrides.preset as string) || process.env.NITRO_PRESET || process.env.SERVER_PRESET const _dotenv = opts.dotenv ?? (configOverrides.dev && { fileName: [".env", ".env.local"] }); + const envName = opts.c12?.envName ?? (configOverrides.dev ? "development" : "production"); const loadedConfig = await ( opts.watch ? watchConfig @@ -87,6 +88,7 @@ async function _loadUserConfig( name: "nitro", cwd: configOverrides.rootDir, dotenv: _dotenv, + envName, extend: { extendKey: ["extends", "preset"] }, defaults: NitroDefaults, async overrides({ rawConfigs }) { diff --git a/test/unit/config-loader-env.test.ts b/test/unit/config-loader-env.test.ts new file mode 100644 index 0000000000..a44fa45d23 --- /dev/null +++ b/test/unit/config-loader-env.test.ts @@ -0,0 +1,76 @@ +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "pathe"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +vi.mock("nitro/meta", () => ({ + version: "0.0.0-test", + runtimeDir: "/tmp", + presetsDir: "/tmp", + pkgDir: "/tmp", + runtimeDependencies: [], +})); + +const originalNodeEnv = process.env.NODE_ENV; +const tempDirs: string[] = []; + +async function createFixtureConfig() { + const rootDir = await mkdtemp(join(tmpdir(), "nitro-config-env-")); + tempDirs.push(rootDir); + + await writeFile( + join(rootDir, "nitro.config.ts"), + `export default defineNitroConfig({ + preset: 'node-server', + routeRules: { + '/base': { headers: { 'x-env': 'base' } } + }, + $production: { + routeRules: { + '/prod': { headers: { 'x-env': 'production' } } + } + }, + $development: { + routeRules: { + '/dev': { headers: { 'x-env': 'development' } } + } + } +}) +` + ); + + return rootDir; +} + +afterEach(async () => { + process.env.NODE_ENV = originalNodeEnv; + for (const dir of tempDirs.splice(0, tempDirs.length)) { + await rm(dir, { recursive: true, force: true }); + } +}); + +describe("config loader env layers", () => { + it("applies $production when NODE_ENV is unset and dev=false", async () => { + delete process.env.NODE_ENV; + const rootDir = await createFixtureConfig(); + + const { loadOptions } = await import("../../src/config/loader.ts"); + const options = await loadOptions({ rootDir, dev: false }); + + expect(options.routeRules["/prod"]?.headers?.["x-env"]).toBe("production"); + expect(options.routeRules["/dev"]).toBeUndefined(); + expect(options.routeRules["/base"]?.headers?.["x-env"]).toBe("base"); + }); + + it("applies $development when NODE_ENV is unset and dev=true", async () => { + delete process.env.NODE_ENV; + const rootDir = await createFixtureConfig(); + + const { loadOptions } = await import("../../src/config/loader.ts"); + const options = await loadOptions({ rootDir, dev: true }); + + expect(options.routeRules["/dev"]?.headers?.["x-env"]).toBe("development"); + expect(options.routeRules["/prod"]).toBeUndefined(); + expect(options.routeRules["/base"]?.headers?.["x-env"]).toBe("base"); + }); +});