diff --git a/src/env_loader.zig b/src/env_loader.zig index fb1787f758..1be85e4e4b 100644 --- a/src/env_loader.zig +++ b/src/env_loader.zig @@ -346,6 +346,9 @@ pub const Loader = struct { if (key.len > "process.env.".len and strings.eqlComptime(key[0.."process.env.".len], "process.env.")) { const hashable_segment = key["process.env.".len..]; string_map_hashes[i] = bun.hash(hashable_segment); + } else if (key.len > "import.meta.env.".len and strings.eqlComptime(key[0.."import.meta.env.".len], "import.meta.env.")) { + const hashable_segment = key["import.meta.env.".len..]; + string_map_hashes[i] = bun.hash(hashable_segment); } } @@ -467,6 +470,23 @@ pub const Loader = struct { } } + // Create import.meta.env defines by copying from process.env defines + if (behavior != .disable and behavior != .load_all_without_inlining) { + var process_env_iter = to_string.iterator(); + while (process_env_iter.next()) |entry| { + const process_key = entry.key_ptr.*; + + // Check if this is a process.env key + if (process_key.len > "process.env.".len and strings.eqlComptime(process_key[0.."process.env.".len], "process.env.")) { + const var_name = process_key["process.env.".len..]; + const meta_key = try std.fmt.allocPrint(allocator, "import.meta.env.{s}", .{var_name}); + + // Copy the define value + _ = try to_string.getOrPutValue(meta_key, entry.value_ptr.*); + } + } + } + for (framework_defaults.keys, 0..) |key, i| { const value = framework_defaults.values[i]; diff --git a/test/bundler/bundler_env.test.ts b/test/bundler/bundler_env.test.ts index b87ab47ab6..001f1e920b 100644 --- a/test/bundler/bundler_env.test.ts +++ b/test/bundler/bundler_env.test.ts @@ -116,5 +116,97 @@ for (let backend of ["api", "cli"] as const) { stdout: "process.env.BASE_URL\n$BASE_URL", }, }); + // import.meta.env tests + if (backend === "cli") + itBundled("import-meta-env/inline", { + env: { + VITE_FOO: "vite_bar", + VITE_BAZ: "vite_123", + }, + backend: backend, + dotenv: "inline", + files: { + "/a.js": ` + console.log(import.meta.env.VITE_FOO); + console.log(import.meta.env.VITE_BAZ); + `, + }, + run: { + env: { + VITE_FOO: "vite_barz", + VITE_BAZ: "vite_123z", + }, + stdout: "vite_bar\nvite_123\n", + }, + }); + + itBundled("import-meta-env/disable", { + env: { + VITE_FOO: "vite_bar", + VITE_BAZ: "vite_123", + }, + backend: backend, + dotenv: "disable", + files: { + "/a.js": ` + console.log(import.meta.env.VITE_FOO); + console.log(import.meta.env.VITE_BAZ); + `, + }, + run: { + stdout: "undefined\nundefined\n", + }, + }); + + if (backend === "cli") + itBundled("import-meta-env/pattern-matching", { + env: { + VITE_PUBLIC_FOO: "vite_public_value", + VITE_PUBLIC_BAR: "vite_another_public", + VITE_PRIVATE_SECRET: "vite_secret_value", + }, + dotenv: "VITE_PUBLIC_*", + backend: backend, + files: { + "/a.js": ` + console.log(import.meta.env.VITE_PUBLIC_FOO); + console.log(import.meta.env.VITE_PUBLIC_BAR); + console.log(import.meta.env.VITE_PRIVATE_SECRET); + `, + }, + run: { + env: { + VITE_PUBLIC_FOO: "VITE_BAD_FOO", + VITE_PUBLIC_BAR: "VITE_BAD_BAR", + }, + stdout: "vite_public_value\nvite_another_public\nundefined\n", + }, + }); + + // Test mixing process.env and import.meta.env + if (backend === "cli") + itBundled("mixed-env/inline", { + env: { + NODE_ENV: "production", + VITE_API_URL: "https://api.prod.com", + }, + backend: backend, + dotenv: "inline", + files: { + "/a.js": ` + console.log(process.env.NODE_ENV); + console.log(import.meta.env.VITE_API_URL); + console.log(import.meta.env.NODE_ENV); + console.log(process.env.VITE_API_URL); + `, + }, + run: { + env: { + NODE_ENV: "development", + VITE_API_URL: "https://api.dev.com", + }, + stdout: "production\nhttps://api.prod.com\nproduction\nhttps://api.prod.com\n", + }, + }); }); }