t3-oss / t3-env

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

Shared variables from an extended config throw when used on the client #240

Open GRA0007 opened 6 months ago

GRA0007 commented 6 months ago

Say I have a common env config, and one specific to a Next.js site in my monorepo:

const common = createEnv({
  shared: {
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  },
  experimental__runtimeEnv: {
    NODE_ENV: process.env.NODE_ENV,
  },
})

const siteEnv = createEnv({
  extends: [common],
  // Assume other variables here...
})

If I now try and use that shared NODE_ENV variable from my siteEnv config like siteEnv.NODE_ENV on the client side, t3-env will throw the Attempted to access a server-side environment variable on the client error, as I assume the proxy used to detect this doesn't take into account configs in the extends option when checking shared.shape:

https://github.com/t3-oss/t3-env/blob/5975abe1c91c04277565e06763bec2530eb44473/packages/core/src/index.ts#L276-L279

ryanagillie commented 2 months ago

+1 here, just ran into it today with the exact same configuration

chertik77 commented 3 weeks ago

+1, but without extending

yeuem1vannam commented 2 weeks ago

I'm not sure this is the same behavior, but when uses extends with createEnv from env-next, a type error occurred when trying to

import { createEnv as coreCreateEnv  } from '@t3-oss/env-core'
import { createEnv as nextCreateEnv } from '@t3-oss/env-nextjs'
import { z } from 'zod'

// Shared environment variables created with env-core
export const sharedEnv = coreCreateEnv({
  clientPrefix: 'NEXT_PUBLIC_',
  server: {
    SERVER_VAR: z.string(),
  },
  client: {
    NEXT_PUBLIC_CORE_VAR: z.string(),
  },
  runtimeEnvStrict: {
    SERVER_VAR: process.env.SERVER_VAR,
    NEXT_PUBLIC_CORE_VAR: process.env.NEXT_PUBLIC_CORE_VAR,
  }
})

// Extending in env-nextjs has no problem if there is no new variable
export const nextEnv1 = nextCreateEnv({
  extends: [sharedEnv],
  runtimeEnv: {
    SERVER_VAR: process.env.SERVER_VAR,
    NEXT_PUBLIC_CORE_VAR: process.env.NEXT_PUBLIC_CORE_VAR,
  },
})

// There will be a problem if there is a new variable
export const nextEnv2 = nextCreateEnv({
  extends: [sharedEnv],
  client: {
    NEXT_PUBLIC_CLIENT_VAR: z.string(),
  },
  runtimeEnv: {
    SERVER_VAR: process.env.SERVER_VAR,
    NEXT_PUBLIC_CORE_VAR: process.env.NEXT_PUBLIC_CORE_VAR,
    NEXT_PUBLIC_CLIENT_VAR: process.env.NEXT_PUBLIC_CLIENT_VAR,
  },
})

// But if you want to use env-core, it works fine
export const coreEnv = coreCreateEnv({
  clientPrefix: 'NEXT_PUBLIC_',
  extends: [sharedEnv],
  client: {
    NEXT_PUBLIC_CLIENT_VAR: z.string(),
  },
  runtimeEnv: {
    SERVER_VAR: process.env.SERVER_VAR,
    NEXT_PUBLIC_CORE_VAR: process.env.NEXT_PUBLIC_CORE_VAR,
    NEXT_PUBLIC_CLIENT_VAR: process.env.NEXT_PUBLIC_CLIENT_VAR,
  },
})

The one created with createEnv from env-nextjs complains

image
Object literal may only specify known properties, and 'SERVER_VAR' does not exist in type 'Record<"NEXT_PUBLIC_CLIENT_VAR", string | number | boolean | undefined>'.ts(2353)
index.d.ts(10, 5): The expected type comes from property 'runtimeEnv' which is declared here on type 'Options<{}, { NEXT_PUBLIC_CLIENT_VAR: ZodString; }, {}, [Readonly<{ SERVER_VAR: string; NEXT_PUBLIC_CORE_VAR: string; }>]>'

while the one created by createEnv from env-core works normally

image

My workaround at the moment is switching to use @t3-oss/env-core with clientPrefix: 'NEXT_PUBLIC_'

P/S: I use