بنقرة واحدة
frontend-environment-variables
Use when working with environment variables in frontend code
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Use when working with environment variables in frontend code
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Use when deploying Cloudflare Workers, managing R2 storage, or working with Cloudflare infrastructure
Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal)
Use when adding, referencing, or serving static assets (images, fonts, videos, 3D models) through the R2 CDN pipeline with type-safe imports
Use when writing or reviewing JavaScript/TypeScript code for style patterns like concise arrows, inline handlers, expression formatting, or when tempted to use eslint-disable
Use when creating or modifying keyboard shortcuts/hotkeys in frontend code
Use when creating or using TanStack Query mutations for data modifications
| name | frontend-environment-variables |
| description | Use when working with environment variables in frontend code |
⚠️ CRITICAL: ZERO TOLERANCE FOR DIRECT ENV ACCESS ⚠️
ALL environment variable access MUST go through the ENVs utility. NO EXCEPTIONS.
Centralized, type-safe environment variable access through ENVs.ts utility. NEVER access environment variables directly via import.meta.env.* (including import.meta.env.DEV, import.meta.env.PROD, or import.meta.env.MODE) in TypeScript files.
Philosophy: Single source of truth for ALL environment variables with runtime validation and type safety via jet-env.
import.meta.env.* usage in TypeScript files (anti-pattern)import.meta.env.DEV, import.meta.env.PROD, or import.meta.env.MODE (anti-pattern)import.meta.env.VITE_* in TypeScript files (anti-pattern)process.env.* anywhere in frontend code (doesn't work in Vite)Location: spark/frontend/my-vite-app/src/utils/ENVs/ENVs.ts
import jetEnv, { str } from "jet-env";
const baseENVs = jetEnv(
{
ViteSupabaseUrl: str,
ViteSupabaseAnonKey: str,
ViteCdnBaseUrl: str,
},
{ getValue: (key) => import.meta.env[key] }
);
/**
* Typesafe environment variables utility.
* ALL environment variable access MUST go through this utility.
* NEVER use import.meta.env directly in your code.
*/
const ENVs = {
...baseENVs,
/** Development mode - Use instead of import.meta.env.DEV */
get isDev(): boolean {
return import.meta.env.DEV;
},
/** Production mode - Use instead of import.meta.env.PROD */
get isProd(): boolean {
return import.meta.env.PROD;
},
/** Current mode string - Use instead of import.meta.env.MODE */
get mode(): string {
return import.meta.env.MODE;
},
} as const;
export { ENVs };
Pattern:
jet-env for runtime validationstr, num, bool)isDev, isProd, mode)import.meta.env directly// ✅ CORRECT - Using ENVs utility
import { ENVs } from "@/utils/ENVs/ENVs";
const supabaseUrl = ENVs.ViteSupabaseUrl;
const supabaseKey = ENVs.ViteSupabaseAnonKey;
const cdnUrl = ENVs.ViteCdnBaseUrl;
// ✅ CORRECT - Using ENVs.isDev
import { ENVs } from "@/utils/ENVs/ENVs";
if (ENVs.isDev) {
console.debug("[Debug] Development mode only");
}
// ✅ CORRECT - Using ENVs.mode
if (ENVs.mode === "development") {
console.debug("[Dev] Development mode");
}
// ✅ CORRECT - Production check
if (ENVs.isProd) {
// Production-only code
}
Available ENVs Properties:
ENVs.mode - Current mode string ('development' | 'production')ENVs.isDev - boolean (true when mode === 'development')ENVs.isProd - boolean (true when mode === 'production')Rule: ALL environment access (including mode checks) goes through ENVs utility.
Step-by-step:
Add to .env file with VITE_ prefix
VITE_API_URL=https://api.example.com
VITE_CDN_BASE_URL=https://cdn.example.com
Add to baseENVs schema in src/utils/ENVs/ENVs.ts
import jetEnv, { str } from "jet-env";
const baseENVs = jetEnv(
{
ViteSupabaseUrl: str,
ViteSupabaseAnonKey: str,
ViteCdnBaseUrl: str,
ViteApiUrl: str, // New variable
},
{ getValue: (key) => import.meta.env[key] }
);
const ENVs = {
...baseENVs,
get isDev(): boolean {
return import.meta.env.DEV;
},
get isProd(): boolean {
return import.meta.env.PROD;
},
get mode(): string {
return import.meta.env.MODE;
},
} as const;
export { ENVs };
Access via ENVs throughout app
import { ENVs } from "@/utils/ENVs/ENVs";
const apiUrl = ENVs.ViteApiUrl;
const cdnUrl = ENVs.ViteCdnBaseUrl;
Naming Convention:
.env file: VITE_API_URL (SCREAMING*SNAKE_CASE with VITE* prefix)ViteApiUrl (PascalCase)ENVs.ViteApiUrlImportant: ALL frontend environment variables MUST have VITE_ prefix (Vite requirement for security).
// ❌ FORBIDDEN
const url = import.meta.env.VITE_SUPABASE_URL;
// ✅ CORRECT
import { ENVs } from "@/utils/ENVs/ENVs";
const url = ENVs.ViteSupabaseUrl;
// ❌ FORBIDDEN - Even Vite built-ins must go through ENVs
if (import.meta.env.DEV) {
console.log("This is forbidden!");
}
if (import.meta.env.PROD) {
console.log("This is also forbidden!");
}
// ✅ CORRECT - Use ENVs helpers
import { ENVs } from "@/utils/ENVs/ENVs";
if (ENVs.isDev) {
console.log("This is correct");
}
if (ENVs.isProd) {
console.log("This is also correct");
}
// ❌ FORBIDDEN - process.env doesn't work in Vite browser code
if (process.env.NODE_ENV === "development") {
console.log("This will NOT work correctly");
}
// ✅ CORRECT - Use ENVs.isDev
import { ENVs } from "@/utils/ENVs/ENVs";
if (ENVs.isDev) {
console.log("This works correctly");
}
Why process.env.NODE_ENV fails:
process.env is Node.js-only, not available in browserprocess.env to frontend codeENVs.isDev or ENVs.mode instead// ❌ WRONG - New variable not added to ENVs.ts
const apiUrl = import.meta.env.VITE_NEW_API_URL; // No type safety
// ✅ CORRECT - First add to ENVs.ts, then use
import { ENVs } from "@/utils/ENVs/ENVs";
const apiUrl = ENVs.ViteNewApiUrl; // Type-safe, validated
🚫 Violations to find and fix:
import.meta.env.* usage in TypeScript files (except in ENVs.ts itself)import.meta.env.VITE_* in TypeScript files (except in ENVs.ts itself)import.meta.env.DEV in TypeScript files (except in ENVs.ts itself)import.meta.env.PROD in TypeScript files (except in ENVs.ts itself)import.meta.env.MODE in TypeScript files (except in ENVs.ts itself)process.env.NODE_ENV in TypeScript filesprocess.env.* anywhere in frontend code✅ Correct patterns to enforce:
ENVs.* (including mode checks)ENVs.isDev (NOT import.meta.env.DEV)ENVs.isProd (NOT import.meta.env.PROD)ENVs.mode (NOT import.meta.env.MODE).env have VITE_ prefiximport.meta.env accessFiles where direct env access is acceptable:
vite.config.js - Vite configuration (Node.js environment)src/utils/ENVs/ENVs.ts - The utility file itself.eslintrc.js)Rule: Only TypeScript/TSX files in src/ directory must use ENVs utility.
🚫 NO EXCEPTIONS - All env access goes through ENVs:
Development/Production Checks (use ENVs helpers):
import.meta.env.DEV ❌ → Use ENVs.isDev ✅import.meta.env.PROD ❌ → Use ENVs.isProd ✅import.meta.env.MODE ❌ → Use ENVs.mode ✅Custom Variables (use ENVs properties):
import.meta.env.VITE_* ❌ → Use ENVs.* ✅The ONLY exception: The ENVs.ts file itself, which is the single source of truth.
When fixing violations:
import.meta.env.DEV → Replace with ENVs.isDevimport.meta.env.PROD → Replace with ENVs.isProdimport.meta.env.MODE → Replace with ENVs.modeimport.meta.env.VITE_* → Replace with ENVs.*process.env.NODE_ENV → Replace with ENVs.isDevbaseENVs schema in ENVs.ts firstENVs.*import { ENVs } from '@/utils/ENVs/ENVs'docs/spark/frontend/my-vite-app/practices.md (Environment Variables section)spark/frontend/my-vite-app/src/utils/ENVs/ENVs.ts