From 8c9ad3d984db02d4656029bd7dc7925874c28dd0 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Mon, 16 Mar 2026 23:22:41 +0800 Subject: [PATCH 1/6] feat: add `env:*` --- packages/start/src/config/env.ts | 66 ++++++++++++++++++++++++++++++ packages/start/src/config/index.ts | 3 ++ 2 files changed, 69 insertions(+) create mode 100644 packages/start/src/config/env.ts diff --git a/packages/start/src/config/env.ts b/packages/start/src/config/env.ts new file mode 100644 index 000000000..721aac535 --- /dev/null +++ b/packages/start/src/config/env.ts @@ -0,0 +1,66 @@ +import { loadEnv, type Plugin } from "vite"; + +export interface EnvPluginOptions { + server?: { + load?: () => Record; + prefix?: string; + }; + client?: { + load?: () => Record; + prefix?: string; + }; +} + +const SERVER_ENV = "env:server"; +const CLIENT_ENV = "env:client"; + +const DEFAULT_SERVER_PREFIX = "SERVER_"; +const DEFAULT_CLIENT_PREFIX = "CLIENT_"; + +const SERVER_ONLY_MODULE = `throw new Error('Attempt to load server-only environment variables in client runtime.');`; + +function convertObjectToModule(object: Record): string { + let result = ""; + for (const key in object) { + result += `export const ${key} = ${JSON.stringify(object[key])};`; + } + return result; +} + +export function envPlugin(options?: EnvPluginOptions): Plugin { + const currentOptions = options ?? {}; + let env: string; + const serverPrefix = currentOptions.server?.prefix ?? DEFAULT_SERVER_PREFIX; + const clientPrefix = currentOptions.client?.prefix ?? DEFAULT_CLIENT_PREFIX; + return { + name: "solid-start:env", + enforce: "pre", + configResolved(config) { + env = config.mode !== "production" ? "development" : "production"; + }, + resolveId(id) { + if (id === SERVER_ENV || id === CLIENT_ENV) { + return id; + } + return null; + }, + load(id, opts) { + if (id === SERVER_ENV) { + if (!opts?.ssr) { + return SERVER_ONLY_MODULE; + } + const vars = currentOptions.server?.load + ? currentOptions.server.load() + : loadEnv(env, false, clientPrefix); + return convertObjectToModule(vars); + } + if (id === CLIENT_ENV) { + const vars = currentOptions.client?.load + ? currentOptions.client.load() + : loadEnv(env, false, serverPrefix); + return convertObjectToModule(vars); + } + return null; + }, + }; +} diff --git a/packages/start/src/config/index.ts b/packages/start/src/config/index.ts index b8cf5bf58..01d3b3940 100644 --- a/packages/start/src/config/index.ts +++ b/packages/start/src/config/index.ts @@ -8,6 +8,7 @@ import solid, { type Options as SolidOptions } from "vite-plugin-solid"; import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.ts"; import { devServer } from "./dev-server.ts"; +import { EnvPluginOptions, envPlugin } from "./env.ts"; import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.ts"; import { fsRoutes } from "./fs-routes/index.ts"; import type { BaseFileSystemRouter } from "./fs-routes/router.ts"; @@ -32,6 +33,7 @@ export interface SolidStartOptions { */ mode?: "js" | "json"; }; + env?: EnvPluginOptions; } const absolute = (path: string, root: string) => @@ -175,6 +177,7 @@ export function solidStart(options?: SolidStartOptions): Array { }, }), lazy(), + envPlugin(options?.env), // Must be placed after fsRoutes, as treeShake will remove the // server fn exports added in by this plugin TanStackServerFnPlugin({ From 4bb956e5f5bf06affbc5ee2e56db93f043375d54 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Mon, 16 Mar 2026 23:48:54 +0800 Subject: [PATCH 2/6] feat(env): add runtime --- .../src/functions/use-server-function-meta.ts | 3 ++ packages/start/src/config/env.ts | 39 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/tests/src/functions/use-server-function-meta.ts b/apps/tests/src/functions/use-server-function-meta.ts index 36b07363b..80dd244f4 100644 --- a/apps/tests/src/functions/use-server-function-meta.ts +++ b/apps/tests/src/functions/use-server-function-meta.ts @@ -2,6 +2,9 @@ import { getServerFunctionMeta } from "@solidjs/start"; +import { SERVER_EXAMPLE } from 'env:server'; + export function serverFnWithMeta() { + console.log(SERVER_EXAMPLE); return typeof getServerFunctionMeta()?.id; } diff --git a/packages/start/src/config/env.ts b/packages/start/src/config/env.ts index 721aac535..b2475abf4 100644 --- a/packages/start/src/config/env.ts +++ b/packages/start/src/config/env.ts @@ -1,7 +1,14 @@ import { loadEnv, type Plugin } from "vite"; +const LOADERS = { + node: `export default key => process.env[key];`, + "cloudflare-workers": `import { env } from 'cloudflare:workers';export default key => env[key];`, + "netlify-edge": `export default key => Netlify.env.get(key);`, +}; + export interface EnvPluginOptions { server?: { + runtime: keyof typeof LOADERS | (string & {}); load?: () => Record; prefix?: string; }; @@ -14,11 +21,23 @@ export interface EnvPluginOptions { const SERVER_ENV = "env:server"; const CLIENT_ENV = "env:client"; +const SERVER_RUNTIME_ENV = `${SERVER_ENV}/runtime`; + +const SERVER_RUNTIME_LOADER = `${SERVER_RUNTIME_ENV}/loader`; + const DEFAULT_SERVER_PREFIX = "SERVER_"; const DEFAULT_CLIENT_PREFIX = "CLIENT_"; const SERVER_ONLY_MODULE = `throw new Error('Attempt to load server-only environment variables in client runtime.');`; +const SERVER_RUNTIME_CODE = `import load from '${SERVER_RUNTIME_LOADER}'; + +export default new Proxy({}, { + get(_, key) { + return load(key); + }, +})`; + function convertObjectToModule(object: Record): string { let result = ""; for (const key in object) { @@ -32,6 +51,9 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { let env: string; const serverPrefix = currentOptions.server?.prefix ?? DEFAULT_SERVER_PREFIX; const clientPrefix = currentOptions.client?.prefix ?? DEFAULT_CLIENT_PREFIX; + const runtime = options?.server?.runtime ?? "node"; + const runtimeCode = runtime in LOADERS ? LOADERS[runtime as keyof typeof LOADERS] : runtime; + return { name: "solid-start:env", enforce: "pre", @@ -39,7 +61,12 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { env = config.mode !== "production" ? "development" : "production"; }, resolveId(id) { - if (id === SERVER_ENV || id === CLIENT_ENV) { + if ( + id === SERVER_ENV || + id === CLIENT_ENV || + id === SERVER_RUNTIME_ENV || + SERVER_RUNTIME_LOADER + ) { return id; } return null; @@ -51,15 +78,21 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { } const vars = currentOptions.server?.load ? currentOptions.server.load() - : loadEnv(env, false, clientPrefix); + : loadEnv(env, false, serverPrefix); return convertObjectToModule(vars); } if (id === CLIENT_ENV) { const vars = currentOptions.client?.load ? currentOptions.client.load() - : loadEnv(env, false, serverPrefix); + : loadEnv(env, false, clientPrefix); return convertObjectToModule(vars); } + if (id === SERVER_RUNTIME_LOADER) { + return runtimeCode; + } + if (id === SERVER_RUNTIME_ENV) { + return SERVER_RUNTIME_CODE; + } return null; }, }; From cdbfb5903a1bb128f61c4a5ae795afdac9d86065 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Mon, 16 Mar 2026 23:49:33 +0800 Subject: [PATCH 3/6] fix(env): add guards --- packages/start/src/config/env.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/start/src/config/env.ts b/packages/start/src/config/env.ts index b2475abf4..68a8a923f 100644 --- a/packages/start/src/config/env.ts +++ b/packages/start/src/config/env.ts @@ -88,9 +88,15 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { return convertObjectToModule(vars); } if (id === SERVER_RUNTIME_LOADER) { + if (!opts?.ssr) { + return SERVER_ONLY_MODULE; + } return runtimeCode; } if (id === SERVER_RUNTIME_ENV) { + if (!opts?.ssr) { + return SERVER_ONLY_MODULE; + } return SERVER_RUNTIME_CODE; } return null; From 44cfda7ce361d7c8ffe599289286225f33ed9cd9 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Tue, 17 Mar 2026 00:04:34 +0800 Subject: [PATCH 4/6] fix(env): resolver --- packages/start/src/config/env.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/start/src/config/env.ts b/packages/start/src/config/env.ts index 68a8a923f..5c1d74ed6 100644 --- a/packages/start/src/config/env.ts +++ b/packages/start/src/config/env.ts @@ -43,6 +43,7 @@ function convertObjectToModule(object: Record): string { for (const key in object) { result += `export const ${key} = ${JSON.stringify(object[key])};`; } + console.log(result); return result; } @@ -65,26 +66,27 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { id === SERVER_ENV || id === CLIENT_ENV || id === SERVER_RUNTIME_ENV || - SERVER_RUNTIME_LOADER + id === SERVER_RUNTIME_LOADER ) { return id; } - return null; + return undefined; }, load(id, opts) { if (id === SERVER_ENV) { if (!opts?.ssr) { return SERVER_ONLY_MODULE; } + console.log('LOAD SERVER'); const vars = currentOptions.server?.load ? currentOptions.server.load() - : loadEnv(env, false, serverPrefix); + : loadEnv(env, '.', serverPrefix); return convertObjectToModule(vars); } if (id === CLIENT_ENV) { const vars = currentOptions.client?.load ? currentOptions.client.load() - : loadEnv(env, false, clientPrefix); + : loadEnv(env, '.', clientPrefix); return convertObjectToModule(vars); } if (id === SERVER_RUNTIME_LOADER) { @@ -99,7 +101,7 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { } return SERVER_RUNTIME_CODE; } - return null; + return undefined; }, }; } From 0ce8739739773aa76a35d84721ec86cef60fc64c Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Tue, 17 Mar 2026 14:22:25 +0800 Subject: [PATCH 5/6] remove unnecessary code --- apps/tests/src/functions/use-server-function-meta.ts | 3 --- packages/start/src/config/env.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/apps/tests/src/functions/use-server-function-meta.ts b/apps/tests/src/functions/use-server-function-meta.ts index 80dd244f4..36b07363b 100644 --- a/apps/tests/src/functions/use-server-function-meta.ts +++ b/apps/tests/src/functions/use-server-function-meta.ts @@ -2,9 +2,6 @@ import { getServerFunctionMeta } from "@solidjs/start"; -import { SERVER_EXAMPLE } from 'env:server'; - export function serverFnWithMeta() { - console.log(SERVER_EXAMPLE); return typeof getServerFunctionMeta()?.id; } diff --git a/packages/start/src/config/env.ts b/packages/start/src/config/env.ts index 5c1d74ed6..dc3a0dff2 100644 --- a/packages/start/src/config/env.ts +++ b/packages/start/src/config/env.ts @@ -77,7 +77,6 @@ export function envPlugin(options?: EnvPluginOptions): Plugin { if (!opts?.ssr) { return SERVER_ONLY_MODULE; } - console.log('LOAD SERVER'); const vars = currentOptions.server?.load ? currentOptions.server.load() : loadEnv(env, '.', serverPrefix); From 7415042580a0b5b59759c8ab3f063ef869c97e08 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Tue, 17 Mar 2026 14:22:58 +0800 Subject: [PATCH 6/6] Update index.ts --- packages/start/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/start/src/config/index.ts b/packages/start/src/config/index.ts index 01d3b3940..653018db4 100644 --- a/packages/start/src/config/index.ts +++ b/packages/start/src/config/index.ts @@ -8,7 +8,7 @@ import solid, { type Options as SolidOptions } from "vite-plugin-solid"; import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.ts"; import { devServer } from "./dev-server.ts"; -import { EnvPluginOptions, envPlugin } from "./env.ts"; +import { type EnvPluginOptions, envPlugin } from "./env.ts"; import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.ts"; import { fsRoutes } from "./fs-routes/index.ts"; import type { BaseFileSystemRouter } from "./fs-routes/router.ts";