Okay, I made it work.
The env.ts file:
import { createIsomorphicFn } from "@tanstack/react-start";
import { z } from "zod";
const envSchemaPublic = z.object({
PUBLIC_VARIABLE1: z.string(),
PUBLIC_VARIABLE2: z.string(),
});
const PUBLIC_VARS_ID = "__PUBLIC_VARIABLES__";
const injectPublicVars = `window.${PUBLIC_VARS_ID} = JSON.parse(document.getElementById('${PUBLIC_VARS_ID}').textContent)`;
export const getPublicEnv = createIsomorphicFn()
.server(() => {
const env = envSchemaPublic.parse(process.env);
const children = JSON.stringify(env);
return [
{
type: "application/json",
id: PUBLIC_VARS_ID,
children,
},
{
children: injectPublicVars,
},
];
})
.client(() => []);
export const env = createIsomorphicFn()
.server(() => envSchemaPublic.parse(process.env))
.client(() => envSchemaPublic.parse(window[PUBLIC_VARS_ID]))();
And the in __root.tsx for createRootRoute :
export const Route = createRootRoute({
...other options
scripts() {
return getPublicEnv();
},
})
In this way the env variable contains all public vars and accessible anywhere in sync way. I can import it in any file and use it on server or client side because it is immediately invoked isomorphic function.