Add import.meta.env.* inlining support

- Add support for inlining import.meta.env.* patterns similar to process.env.*
- Support both --env=inline and --env=prefix* modes for import.meta.env
- Add comprehensive tests for import.meta.env inlining in bundler_env.test.ts
- Tests include inline mode, disable mode, prefix matching, and mixed usage
- Implementation creates import.meta.env defines by copying from process.env defines
- Framework defaults now support import.meta.env.* keys in addition to process.env.* keys

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Bot
2025-08-11 23:42:07 +00:00
parent 8e6184707d
commit 9d150f1d64
2 changed files with 112 additions and 0 deletions

View File

@@ -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];

View File

@@ -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",
},
});
});
}