t3-oss / t3-env

https://env.t3.gg
MIT License
2.74k stars 86 forks source link

Run build time environment variables validations using Vitejs #87

Closed juanzitelli closed 1 year ago

juanzitelli commented 1 year ago

Problem

I can't get build-time validation working on a vitejs app. I want to run the schema validation on build time so I can check if all required environment variables are defined or not.

Repro

  1. Generate a TS React app using npm create vite@latest
  2. Run npm install @t3-oss/env-core zod
  3. Create a .env file with the following content

VITE_TEST_VAR="ABC" VITE_MISSING="123"

  1. Create the @t3-oss/env-core required env.ts file with the following content
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

export const env = createEnv({
  /*
   * Specify what prefix the client-side variables must have.
   * This is enforced both on type-level and at runtime.
   */
  clientPrefix: "VITE_",
  client: {
    VITE_TEST_VAR: z.string(),
    VITE_MISSING: z.string(), // I used this variable to test the build time validation works
  },
  /**
   * What object holds the environment variables at runtime.
   * Often `process.env` or `import.meta.env`
   */
  runtimeEnv: import.meta.env,
});
  1. Import the exported env object from the t3 env file inside App.tsx (so we verify that env vars are actually usable within the client app)
// App.tsx
import "./App.css";
import { env } from "./env.ts";

function App() {
  return (
    <>
      <h1>{env.VITE_TEST_VAR}</h1>
    </>
  );
}

export default App;
  1. Run "npm run build" and the build should fail with the following error message
❌ Invalid environment variables: { VITE_TEST_VAR: [ 'Required' ], VITE_MISSING: [ 'Required' ] }
failed to load config from /Users/user/dev/project/vite.config.ts
error during build:
Error: Invalid environment variables
    at f (file:///Users/user/dev/project/node_modules/@t3-oss/env-core/dist/index.mjs:1:426)
    at g (file:///Users/user/dev/project/node_modules/@t3-oss/env-core/dist/index.mjs:1:616)
    at file:///Users/user/dev/project/vite.config.ts.timestamp-1686946000230-87681b7d7ccd5.mjs:8:11
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
error Command failed with exit code 1.
chungweileong94 commented 1 year ago

In order to trigger the validation during build time, you can import the env.ts in vite.config.ts like import "./env";.

juanzitelli commented 1 year ago

In order to trigger the validation during build time, you can import the env.ts in vite.config.ts like import "./env";.

I know, the thing is that whenever I try to run the build or dev command, the package cannot read import.meta.env saying it's undefined, therefore it's not loading .env file

chungweileong94 commented 1 year ago

Hmm, wasn't realize that Vite doesn't load env in configuration file.

However, there's a workaround for that, it feels hacky but it get the job done. You can manually load the env in vote.config.ts via Vite loadEnv function.

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig(async ({ mode }) => {
  import.meta.env = loadEnv(mode, process.cwd());
  await import("./src/env");

  return {
    plugins: [react()],
  };
});
juanzitelli commented 1 year ago

Hmm, wasn't realize that Vite doesn't load env in configuration file.

However, there's a workaround for that, it feels hacky but it get the job done. You can manually load the env in vote.config.ts via Vite loadEnv function.


import { defineConfig, loadEnv } from "vite";

import react from "@vitejs/plugin-react";

export default defineConfig(async ({ mode }) => {

  import.meta.env = loadEnv(mode, process.cwd());

  await import("./src/env");

  return {

    plugins: [react()],

  };

});

I realized that I missed the import of the "./env.ts" file on the example. Sorry about that! I will try your solution and let you know if it worked or not. Thanks in advance!

juanzitelli commented 1 year ago

I've tried @chungweileong94's workaround and it solved the issue! Now import.meta.env is loaded correctly so it can be then parsed using zod. Thanks!

MuhammadBilal1234 commented 10 months ago

"import.meta" is not available with the "cjs" output format and will be empty

I am getting the above error while trying to do the following.

import.meta.env = loadEnv(mode, process.cwd());

I have my env file in src/env/env.ts and I am using vue with vite.