From e43c6f1d4e9658a35d6568e3b2c23c41aa94bb37 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 14:27:01 -0400 Subject: [PATCH 01/27] WIP --- packages/kit/src/cli.js | 2 +- packages/kit/src/core/env.js | 28 ++++- packages/kit/src/core/sync/sync.js | 7 +- packages/kit/src/exports/vite/index.js | 113 +++++------------ packages/kit/src/exports/vite/module_ids.js | 3 - .../kit/src/exports/vite/plugins/env-vars.js | 116 ++++++++++++++++++ packages/kit/src/exports/vite/utils.js | 5 +- 7 files changed, 174 insertions(+), 100 deletions(-) create mode 100644 packages/kit/src/exports/vite/plugins/env-vars.js diff --git a/packages/kit/src/cli.js b/packages/kit/src/cli.js index d5aa39564a92..6a588403aaaf 100755 --- a/packages/kit/src/cli.js +++ b/packages/kit/src/cli.js @@ -106,7 +106,7 @@ if (command === 'sync') { sync.all_types(sveltekit_config, vite_config.root); const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config); - await sync.env(vite, sveltekit_config, explicit_env_entry, vite_config.root, values.mode); + await sync.env(sveltekit_config, explicit_env_entry, vite_config.root, values.mode); } catch (error) { handle_error(error); } finally { diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index 372a1aeb525d..9c42fac73c10 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -10,6 +10,7 @@ import { resolve_entry } from '../utils/filesystem.js'; import { handle_issues, validate } from '../exports/internal/env.js'; import { get_config_aliases } from '../exports/vite/utils.js'; import { get_runner } from '../runner.js'; +import { import_peer } from '../utils/import.js'; /** * @typedef {'public' | 'private'} EnvType @@ -24,15 +25,22 @@ export function resolve_explicit_env_entry(config) { } /** - * @param {typeof import('vite')} vite * @param {ValidatedConfig} kit * @param {string | null} file * @param {string} root * @param {string} mode - * @returns {Promise> | null>} + * @returns {Promise<{ variables: Record> | null, deps: Set }>} */ -export async function load_explicit_env(vite, kit, file, root, mode) { - if (!file) return null; +export async function load_explicit_env(kit, file, root, mode) { + /** @type {Set} */ + const deps = new Set(); + + if (!file) { + return { variables: null, deps }; + } + + /** @type {typeof import('vite')} */ + const vite = await import_peer('vite', root); const server = await vite.createServer({ configFile: false, @@ -49,7 +57,15 @@ export async function load_explicit_env(vite, kit, file, root, mode) { { find: '$app/env', replacement: `${runtime_directory}/app/env` }, ...get_config_aliases(kit, root) ] - } + }, + plugins: [ + { + name: 'dependency-scanner', + load(id) { + deps.add(id); + } + } + ] }); /** @type {Record>} */ @@ -92,7 +108,7 @@ export async function load_explicit_env(vite, kit, file, root, mode) { await server.close(); } - return variables; + return { variables, deps }; } /** diff --git a/packages/kit/src/core/sync/sync.js b/packages/kit/src/core/sync/sync.js index 50d3e53a4101..2a089e2a0e76 100644 --- a/packages/kit/src/core/sync/sync.js +++ b/packages/kit/src/core/sync/sync.js @@ -102,16 +102,15 @@ export function all_types(config, root) { /** * Generate modules and types for explicit env vars - * @param {typeof import('vite')} vite * @param {import('types').ValidatedConfig} kit * @param {string | null} entry * @param {string} root The Vite root * @param {string} mode The Vite mode */ -export async function env(vite, kit, entry, root, mode) { - const env_config = await load_explicit_env(vite, kit, entry, root, mode); +export async function env(kit, entry, root, mode) { + const env_config = await load_explicit_env(kit, entry, root, mode); - write_env(entry, env_config, root); + write_env(entry, env_config.variables, root); return env_config; } diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 8cd15c9e170d..5404b14d5c88 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -24,12 +24,9 @@ import { copy, read, resolve_entry } from '../../utils/filesystem.js'; import { posixify } from '../../utils/os.js'; import { to_fs } from '../../utils/vite.js'; import { - create_sveltekit_env, - create_sveltekit_env_public, resolve_explicit_env_entry, create_sveltekit_env_service_worker, create_sveltekit_env_service_worker_dev, - create_sveltekit_env_private, create_exported_declarations } from '../../core/env.js'; import * as sync from '../../core/sync/sync.js'; @@ -66,12 +63,9 @@ import { get_import_aliases, get_hash_import_keys } from '../../utils/imports.js import { app_env_private, app_server, - sveltekit_env, - sveltekit_env_private, sveltekit_env_service_worker, sveltekit_manifest_data, - sveltekit_env_public_client, - sveltekit_env_public_server + sveltekit_env_public_client } from './module_ids.js'; import { import_peer } from '../../utils/import.js'; import { compact } from '../../utils/array.js'; @@ -79,6 +73,7 @@ import { should_ignore, has_children } from './static_analysis/utils.js'; import { process_config, split_config, validate_config } from '../../core/config/index.js'; import { treeshake_prerendered_remotes } from './build/remote.js'; import { get_runner } from '../../runner.js'; +import { plugin_env_vars } from './plugins/env-vars.js'; /** @type {import('./types.js').EnforcedConfig} */ const enforced_config = { @@ -663,38 +658,6 @@ function kit({ svelte_config }) { const plugin_virtual_modules = { name: 'vite-plugin-sveltekit-virtual-modules', - async configResolved(config) { - explicit_env_entry = resolve_explicit_env_entry(kit); - explicit_env_config = await sync.env(vite, kit, explicit_env_entry, config.root, config.mode); - }, - - configureServer(server) { - server.watcher.on('all', async (_, file) => { - if (!file.includes('env')) { - return; - } - - const resolved = resolve_explicit_env_entry(kit); - - if (file === explicit_env_entry || file === resolved) { - explicit_env_entry = resolved; - explicit_env_config = await sync.env( - vite, - kit, - explicit_env_entry, - vite_config.root, - vite_config.mode - ); - - for (const id of [sveltekit_env, sveltekit_env_public_client]) { - invalidate_module(server, id); - } - - server.hot.send({ type: 'full-reload' }); - } - }); - }, - applyToEnvironment(environment) { return environment.name !== 'serviceWorker'; }, @@ -708,6 +671,22 @@ function kit({ svelte_config }) { return `${out_dir}/generated/client-optimized/app.js`; } + if (id === '__sveltekit/env') { + return `${out_dir}/generated/env/config.js`; + } + + if (id === '__sveltekit/env/public/client') { + return `${out_dir}/generated/env/public/client.js`; + } + + if (id === '__sveltekit/env/public/server') { + return `${out_dir}/generated/env/public/server.js`; + } + + if (id === '__sveltekit/env/private') { + return `${out_dir}/generated/env/private/server.js`; + } + if (id === '__sveltekit/remote') { return `${runtime_directory}/client/remote-functions/index.js`; } @@ -718,40 +697,13 @@ function kit({ svelte_config }) { load: { filter: { - id: [ - exactRegex(sveltekit_env), - exactRegex(sveltekit_env_private), - exactRegex(sveltekit_env_public_client), - exactRegex(sveltekit_env_public_server), - exactRegex(sveltekit_env_service_worker), - exactRegex(sveltekit_manifest_data) - ] + id: [exactRegex(sveltekit_env_service_worker), exactRegex(sveltekit_manifest_data)] }, handler(id) { switch (id) { case sveltekit_manifest_data: return create_manifest_data_module(is_build, manifest_data); - case sveltekit_env: - return create_sveltekit_env(explicit_env_config, env, explicit_env_entry, !is_build); - - case sveltekit_env_public_client: - return create_sveltekit_env_public( - explicit_env_config, - env, - `import { payload } from ${s(`${runtime_directory}/client/payload.js`)};\nconst env = payload.env;` - ); - - case sveltekit_env_public_server: - return create_sveltekit_env_public( - explicit_env_config, - env, - `import { rendered_env as env } from '__sveltekit/env';` - ); - - case sveltekit_env_private: - return create_sveltekit_env_private(explicit_env_config, env); - case sveltekit_env_service_worker: return is_build ? create_sveltekit_env_service_worker( @@ -1201,6 +1153,10 @@ function kit({ svelte_config }) { id: prefixRegex('__sveltekit/') }, handler(id) { + if (id === '__sveltekit/env/public/client') { + return `${out_dir}/generated/env/public/service-worker.js`; + } + return `\0virtual:${id}`; } }, @@ -1210,8 +1166,7 @@ function kit({ svelte_config }) { id: [ exactRegex('\0virtual:app/manifest'), exactRegex(sveltekit_manifest_data), - exactRegex(sveltekit_env_service_worker), - exactRegex(sveltekit_env_public_client) + exactRegex(sveltekit_env_service_worker) ] }, handler(id) { @@ -1264,14 +1219,6 @@ function kit({ svelte_config }) { kit_global ); } - - if (id === sveltekit_env_public_client) { - return create_sveltekit_env_public( - explicit_env_config, - env, - `const env = ${kit_global}.env;` - ); - } } }, @@ -2174,13 +2121,10 @@ function kit({ svelte_config }) { fs.mkdirSync(out, { recursive: true }); explicit_env_entry = resolve_explicit_env_entry(kit); - explicit_env_config = await sync.env( - vite, - kit, - explicit_env_entry, - vite_config.root, - vite_config.mode - ); + + const synced = await sync.env(kit, explicit_env_entry, vite_config.root, vite_config.mode); + + explicit_env_config = synced.variables; await load_and_validate_params({ routes: manifest_data.routes, @@ -2244,6 +2188,7 @@ function kit({ svelte_config }) { plugin_setup, plugin_remote_guard, plugin_remote, + plugin_env_vars(svelte_config), plugin_virtual_modules, process.env.TEST !== 'true' ? plugin_guard : undefined, plugin_service_worker, diff --git a/packages/kit/src/exports/vite/module_ids.js b/packages/kit/src/exports/vite/module_ids.js index 065df4df902e..cff661849d97 100644 --- a/packages/kit/src/exports/vite/module_ids.js +++ b/packages/kit/src/exports/vite/module_ids.js @@ -1,10 +1,7 @@ import { fileURLToPath } from 'node:url'; import { posixify } from '../../utils/os.js'; -export const sveltekit_env = '\0virtual:__sveltekit/env'; export const sveltekit_env_public_client = '\0virtual:__sveltekit/env/public/client'; -export const sveltekit_env_public_server = '\0virtual:__sveltekit/env/public/server'; -export const sveltekit_env_private = '\0virtual:__sveltekit/env/private'; export const sveltekit_env_service_worker = '\0virtual:__sveltekit/env/service-worker'; export const sveltekit_server = '\0virtual:__sveltekit/server'; export const service_worker = '\0virtual:service-worker'; diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js new file mode 100644 index 000000000000..2f7a7fe145d6 --- /dev/null +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -0,0 +1,116 @@ +/** @import { Plugin, ResolvedConfig } from 'vite' */ +/** @import { ValidatedConfig } from 'types' */ +import path from 'node:path'; +import * as sync from '../../../core/sync/sync.js'; +import { resolve_entry } from '../../../utils/filesystem.js'; +import { + create_sveltekit_env, + create_sveltekit_env_private, + create_sveltekit_env_public +} from '../../../core/env.js'; +import { import_peer } from '../../../utils/import.js'; +import { runtime_directory } from '../../../core/utils.js'; +import { s } from '../../../utils/misc.js'; +import { write_if_changed } from '../../../core/sync/utils.js'; +import { hash } from '../../../utils/hash.js'; + +/** + * Generate (and, in dev, maintain) a `${outDir}/generated/env/config.js` module + * derived from `src/env.ts` + * + * @param {ValidatedConfig} config + * @returns {Plugin} + */ +export function plugin_env_vars(config) { + // grab these values eagerly because they get mutated (TODO stop mutating them) + const entry = path.join(config.files.src, 'env'); + const dir = config.env.dir; + const out = config.outDir; + + /** @type {Record} */ + let env; + + /** @type {ResolvedConfig} */ + let resolved_config; + + /** @type {string | null} */ + let resolved_entry = null; + + let is_build = false; + + /** @type {Set} */ + let deps; + + /** @type {string} */ + let kit_global; + + async function generate() { + const synced = await sync.env( + config, + resolved_entry, + resolved_config.root, + resolved_config.mode + ); + + deps = synced.deps; + + write_if_changed( + `${out}/generated/env/config.js`, + create_sveltekit_env(synced.variables, env, resolved_entry, !is_build) + ); + + write_if_changed( + `${out}/generated/env/public/client.js`, + create_sveltekit_env_public( + synced.variables, + env, + `import { payload } from ${s(`${runtime_directory}/client/payload.js`)};\nconst env = payload.env;` + ) + ); + + write_if_changed( + `${out}/generated/env/public/server.js`, + create_sveltekit_env_public( + synced.variables, + env, + `import { rendered_env as env } from '../config.js';` + ) + ); + + write_if_changed( + `${out}/generated/env/public/service-worker.js`, + create_sveltekit_env_public(synced.variables, env, `const env = ${kit_global}.env;`) + ); + + write_if_changed( + `${out}/generated/env/private/server.js`, + create_sveltekit_env_private(synced.variables, env) + ); + } + + return { + name: 'vite-plugin-sveltekit-env-vars', + async configResolved(c) { + resolved_config = c; + + const vite = await import_peer('vite', c.root); + env = vite.loadEnv(c.mode, dir, ''); + + is_build = c.command === 'build'; + + const version_hash = hash(config.version.name); + + kit_global = is_build + ? `globalThis.__sveltekit_${version_hash}` + : 'globalThis.__sveltekit_dev'; + }, + async buildStart() { + resolved_entry = resolve_entry(path.join(resolved_config.root, entry)) ?? null; + await generate(); + }, + async handleHotUpdate(update) { + if (!deps.has(update.file)) return; + await generate(); + } + }; +} diff --git a/packages/kit/src/exports/vite/utils.js b/packages/kit/src/exports/vite/utils.js index a9ddf2279206..06cdc8b18bea 100644 --- a/packages/kit/src/exports/vite/utils.js +++ b/packages/kit/src/exports/vite/utils.js @@ -6,7 +6,7 @@ import { escape_html } from '../../utils/escape.js'; import { escape_for_regexp } from '../../utils/regex.js'; import { stackless } from '../../utils/error.js'; import { dedent } from '../../core/sync/utils.js'; -import { app_server, app_env_private, sveltekit_env_private } from './module_ids.js'; +import { app_server, app_env_private } from './module_ids.js'; /** * Transforms alias to a valid vite.resolve.alias array. @@ -119,7 +119,8 @@ export function normalize_id(id, aliases, cwd) { return '$app/server'; } - if (id === app_env_private || id === sveltekit_env_private) { + // TODO is this right? + if (id === app_env_private || id === '__sveltekit/env/private') { return '$app/env/private'; } From 97bfc18bfcf8960245540e58633598bb4ace0615 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 14:49:27 -0400 Subject: [PATCH 02/27] WIP --- packages/kit/src/exports/vite/index.js | 64 +++++-------------- packages/kit/src/exports/vite/module_ids.js | 1 - .../kit/src/exports/vite/plugins/env-vars.js | 54 ++++++++++++---- 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 5404b14d5c88..7857131ef622 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -23,12 +23,7 @@ import MagicString from 'magic-string'; import { copy, read, resolve_entry } from '../../utils/filesystem.js'; import { posixify } from '../../utils/os.js'; import { to_fs } from '../../utils/vite.js'; -import { - resolve_explicit_env_entry, - create_sveltekit_env_service_worker, - create_sveltekit_env_service_worker_dev, - create_exported_declarations -} from '../../core/env.js'; +import { resolve_explicit_env_entry, create_exported_declarations } from '../../core/env.js'; import * as sync from '../../core/sync/sync.js'; import { load_and_validate_params } from '../../utils/params.js'; import { runtime_directory, logger } from '../../core/utils.js'; @@ -63,7 +58,6 @@ import { get_import_aliases, get_hash_import_keys } from '../../utils/imports.js import { app_env_private, app_server, - sveltekit_env_service_worker, sveltekit_manifest_data, sveltekit_env_public_client } from './module_ids.js'; @@ -687,6 +681,12 @@ function kit({ svelte_config }) { return `${out_dir}/generated/env/private/server.js`; } + if (id === '__sveltekit/env/service-worker') { + return is_build + ? `${out_dir}/generated/env/service-worker-prod.js` + : `${out_dir}/generated/env/service-worker-dev.js`; + } + if (id === '__sveltekit/remote') { return `${runtime_directory}/client/remote-functions/index.js`; } @@ -697,29 +697,12 @@ function kit({ svelte_config }) { load: { filter: { - id: [exactRegex(sveltekit_env_service_worker), exactRegex(sveltekit_manifest_data)] + id: [exactRegex(sveltekit_manifest_data)] }, handler(id) { switch (id) { case sveltekit_manifest_data: return create_manifest_data_module(is_build, manifest_data); - - case sveltekit_env_service_worker: - return is_build - ? create_sveltekit_env_service_worker( - explicit_env_config, - env, - kit.version.name, - kit_global, - kit.paths.base, - kit.appDir - ) - : create_sveltekit_env_service_worker_dev( - explicit_env_config, - env, - kit.version.name, - kit_global - ); } } } @@ -1157,17 +1140,19 @@ function kit({ svelte_config }) { return `${out_dir}/generated/env/public/service-worker.js`; } + if (id === '__sveltekit/env/service-worker') { + return is_build + ? `${out_dir}/generated/env/service-worker-prod.js` + : `${out_dir}/generated/env/service-worker-dev.js`; + } + return `\0virtual:${id}`; } }, load: { filter: { - id: [ - exactRegex('\0virtual:app/manifest'), - exactRegex(sveltekit_manifest_data), - exactRegex(sveltekit_env_service_worker) - ] + id: [exactRegex('\0virtual:app/manifest'), exactRegex(sveltekit_manifest_data)] }, handler(id) { if (!manifest_data_code) { @@ -1201,24 +1186,6 @@ function kit({ svelte_config }) { if (id === sveltekit_manifest_data) { return manifest_data_code; } - - if (id === sveltekit_env_service_worker) { - return is_build - ? create_sveltekit_env_service_worker( - explicit_env_config, - env, - kit.version.name, - kit_global, - kit.paths.base, - kit.appDir - ) - : create_sveltekit_env_service_worker_dev( - explicit_env_config, - env, - kit.version.name, - kit_global - ); - } } }, @@ -1836,6 +1803,7 @@ function kit({ svelte_config }) { const uses_env_dynamic_public = has_explicit_dynamic_public_env && client_chunks.some( + // TODO need to update this (chunk) => chunk.type === 'chunk' && chunk.modules[sveltekit_env_public_client] ); diff --git a/packages/kit/src/exports/vite/module_ids.js b/packages/kit/src/exports/vite/module_ids.js index cff661849d97..8810be4deaaf 100644 --- a/packages/kit/src/exports/vite/module_ids.js +++ b/packages/kit/src/exports/vite/module_ids.js @@ -2,7 +2,6 @@ import { fileURLToPath } from 'node:url'; import { posixify } from '../../utils/os.js'; export const sveltekit_env_public_client = '\0virtual:__sveltekit/env/public/client'; -export const sveltekit_env_service_worker = '\0virtual:__sveltekit/env/service-worker'; export const sveltekit_server = '\0virtual:__sveltekit/server'; export const service_worker = '\0virtual:service-worker'; diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 2f7a7fe145d6..a0a71c809b47 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -6,7 +6,9 @@ import { resolve_entry } from '../../../utils/filesystem.js'; import { create_sveltekit_env, create_sveltekit_env_private, - create_sveltekit_env_public + create_sveltekit_env_public, + create_sveltekit_env_service_worker, + create_sveltekit_env_service_worker_dev } from '../../../core/env.js'; import { import_peer } from '../../../utils/import.js'; import { runtime_directory } from '../../../core/utils.js'; @@ -27,6 +29,8 @@ export function plugin_env_vars(config) { const dir = config.env.dir; const out = config.outDir; + const version_hash = hash(config.version.name); + /** @type {Record} */ let env; @@ -41,9 +45,6 @@ export function plugin_env_vars(config) { /** @type {Set} */ let deps; - /** @type {string} */ - let kit_global; - async function generate() { const synced = await sync.env( config, @@ -78,14 +79,49 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/public/service-worker.js`, - create_sveltekit_env_public(synced.variables, env, `const env = ${kit_global}.env;`) + `${out}/generated/env/public/service-worker-prod.js`, + create_sveltekit_env_public( + synced.variables, + env, + `const env = globalThis.__sveltekit_${version_hash}.env;` + ) + ); + + write_if_changed( + `${out}/generated/env/public/service-worker-dev.js`, + create_sveltekit_env_public( + synced.variables, + env, + `const env = globalThis.__sveltekit_dev.env;` + ) ); write_if_changed( `${out}/generated/env/private/server.js`, create_sveltekit_env_private(synced.variables, env) ); + + write_if_changed( + `${out}/generated/env/service-worker-prod.js`, + create_sveltekit_env_service_worker( + synced.variables, + env, + config.version.name, + `globalThis.__sveltekit_${version_hash}`, + config.paths.base, + config.appDir + ) + ); + + write_if_changed( + `${out}/generated/env/service-worker-dev.js`, + create_sveltekit_env_service_worker_dev( + synced.variables, + env, + config.version.name, + 'globalThis.__sveltekit_dev' + ) + ); } return { @@ -97,12 +133,6 @@ export function plugin_env_vars(config) { env = vite.loadEnv(c.mode, dir, ''); is_build = c.command === 'build'; - - const version_hash = hash(config.version.name); - - kit_global = is_build - ? `globalThis.__sveltekit_${version_hash}` - : 'globalThis.__sveltekit_dev'; }, async buildStart() { resolved_entry = resolve_entry(path.join(resolved_config.root, entry)) ?? null; From b2e68c8594870f7dd1ea4ce92789cdde8d386a0b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 14:58:19 -0400 Subject: [PATCH 03/27] fix --- packages/kit/src/exports/vite/index.js | 4 +++- packages/kit/src/exports/vite/plugins/env-vars.js | 2 +- playgrounds/basic/src/env.ts | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 playgrounds/basic/src/env.ts diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 7857131ef622..4eb059da5cf1 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -1137,7 +1137,9 @@ function kit({ svelte_config }) { }, handler(id) { if (id === '__sveltekit/env/public/client') { - return `${out_dir}/generated/env/public/service-worker.js`; + return is_build + ? `${out_dir}/generated/env/public/service-worker-prod.js` + : `${out_dir}/generated/env/public/service-worker-dev.js`; } if (id === '__sveltekit/env/service-worker') { diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index a0a71c809b47..486c2d80685c 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -130,7 +130,7 @@ export function plugin_env_vars(config) { resolved_config = c; const vite = await import_peer('vite', c.root); - env = vite.loadEnv(c.mode, dir, ''); + env = vite.loadEnv(c.mode, path.resolve(c.root, dir), ''); is_build = c.command === 'build'; }, diff --git a/playgrounds/basic/src/env.ts b/playgrounds/basic/src/env.ts new file mode 100644 index 000000000000..33dc10c2ddfa --- /dev/null +++ b/playgrounds/basic/src/env.ts @@ -0,0 +1,11 @@ +import { defineEnvVars } from '@sveltejs/kit/env'; + +export const variables = defineEnvVars({ + MESSAGE: { + public: true + }, + SECRET: {}, + STATIC: { + static: true + } +}); From 6bc54ad57830656bd18feeaf1657549d2f5ab8f3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 15:11:09 -0400 Subject: [PATCH 04/27] move resolveId logic --- packages/kit/src/exports/vite/index.js | 35 +----------- .../kit/src/exports/vite/plugins/env-vars.js | 56 ++++++++++++++++--- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 4eb059da5cf1..cdd35e9c8cec 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -665,28 +665,6 @@ function kit({ svelte_config }) { return `${out_dir}/generated/client-optimized/app.js`; } - if (id === '__sveltekit/env') { - return `${out_dir}/generated/env/config.js`; - } - - if (id === '__sveltekit/env/public/client') { - return `${out_dir}/generated/env/public/client.js`; - } - - if (id === '__sveltekit/env/public/server') { - return `${out_dir}/generated/env/public/server.js`; - } - - if (id === '__sveltekit/env/private') { - return `${out_dir}/generated/env/private/server.js`; - } - - if (id === '__sveltekit/env/service-worker') { - return is_build - ? `${out_dir}/generated/env/service-worker-prod.js` - : `${out_dir}/generated/env/service-worker-dev.js`; - } - if (id === '__sveltekit/remote') { return `${runtime_directory}/client/remote-functions/index.js`; } @@ -1136,18 +1114,7 @@ function kit({ svelte_config }) { id: prefixRegex('__sveltekit/') }, handler(id) { - if (id === '__sveltekit/env/public/client') { - return is_build - ? `${out_dir}/generated/env/public/service-worker-prod.js` - : `${out_dir}/generated/env/public/service-worker-dev.js`; - } - - if (id === '__sveltekit/env/service-worker') { - return is_build - ? `${out_dir}/generated/env/service-worker-prod.js` - : `${out_dir}/generated/env/service-worker-dev.js`; - } - + // TODO do we still need this? return `\0virtual:${id}`; } }, diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 486c2d80685c..fc7ca8cbdac0 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -15,6 +15,7 @@ import { runtime_directory } from '../../../core/utils.js'; import { s } from '../../../utils/misc.js'; import { write_if_changed } from '../../../core/sync/utils.js'; import { hash } from '../../../utils/hash.js'; +import { prefixRegex } from '@rolldown/pluginutils'; /** * Generate (and, in dev, maintain) a `${outDir}/generated/env/config.js` module @@ -31,6 +32,9 @@ export function plugin_env_vars(config) { const version_hash = hash(config.version.name); + /** @type {string} */ + let out_dir; + /** @type {Record} */ let env; @@ -56,12 +60,12 @@ export function plugin_env_vars(config) { deps = synced.deps; write_if_changed( - `${out}/generated/env/config.js`, + `${out_dir}/generated/env/config.js`, create_sveltekit_env(synced.variables, env, resolved_entry, !is_build) ); write_if_changed( - `${out}/generated/env/public/client.js`, + `${out_dir}/generated/env/public/client.js`, create_sveltekit_env_public( synced.variables, env, @@ -70,7 +74,7 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/public/server.js`, + `${out_dir}/generated/env/public/server.js`, create_sveltekit_env_public( synced.variables, env, @@ -79,7 +83,7 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/public/service-worker-prod.js`, + `${out_dir}/generated/env/public/service-worker-prod.js`, create_sveltekit_env_public( synced.variables, env, @@ -88,7 +92,7 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/public/service-worker-dev.js`, + `${out_dir}/generated/env/public/service-worker-dev.js`, create_sveltekit_env_public( synced.variables, env, @@ -97,12 +101,12 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/private/server.js`, + `${out_dir}/generated/env/private/server.js`, create_sveltekit_env_private(synced.variables, env) ); write_if_changed( - `${out}/generated/env/service-worker-prod.js`, + `${out_dir}/generated/env/service-worker-prod.js`, create_sveltekit_env_service_worker( synced.variables, env, @@ -114,7 +118,7 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out}/generated/env/service-worker-dev.js`, + `${out_dir}/generated/env/service-worker-dev.js`, create_sveltekit_env_service_worker_dev( synced.variables, env, @@ -126,21 +130,57 @@ export function plugin_env_vars(config) { return { name: 'vite-plugin-sveltekit-env-vars', + async configResolved(c) { resolved_config = c; const vite = await import_peer('vite', c.root); env = vite.loadEnv(c.mode, path.resolve(c.root, dir), ''); + out_dir = path.resolve(c.root, out); + is_build = c.command === 'build'; }, + async buildStart() { resolved_entry = resolve_entry(path.join(resolved_config.root, entry)) ?? null; await generate(); }, + async handleHotUpdate(update) { if (!deps.has(update.file)) return; await generate(); + }, + + resolveId: { + filter: { + id: prefixRegex('__sveltekit/env') + }, + handler(id) { + if (id === '__sveltekit/env') { + return `${out_dir}/generated/env/config.js`; + } + + if (id === '__sveltekit/env/private') { + return `${out_dir}/generated/env/private/server.js`; + } + + if (id === '__sveltekit/env/public/server') { + return `${out_dir}/generated/env/public/server.js`; + } + + if (id === '__sveltekit/env/public/client') { + return this.environment.name === 'serviceWorker' + ? `${out_dir}/generated/env/public/service-worker-prod.js` + : `${out_dir}/generated/env/public/client.js`; + } + + if (id === '__sveltekit/env/service-worker') { + return is_build + ? `${out_dir}/generated/env/service-worker-prod.js` + : `${out_dir}/generated/env/service-worker-dev.js`; + } + } } }; } From af831ded280742f4add10ee8ab930cb6b851eb00 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 15:24:18 -0400 Subject: [PATCH 05/27] fix --- .changeset/warm-boats-taste.md | 6 ++ packages/kit/src/core/env.js | 34 ++++++---- .../kit/src/exports/vite/plugins/env-vars.js | 65 +++++++++---------- 3 files changed, 57 insertions(+), 48 deletions(-) create mode 100644 .changeset/warm-boats-taste.md diff --git a/.changeset/warm-boats-taste.md b/.changeset/warm-boats-taste.md new file mode 100644 index 000000000000..b381aecec82d --- /dev/null +++ b/.changeset/warm-boats-taste.md @@ -0,0 +1,6 @@ +--- +"@sveltejs/kit": patch +--- + +chore: emit env modules to disk + \ No newline at end of file diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index 9c42fac73c10..c6725e119fed 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -116,9 +116,8 @@ export async function load_explicit_env(kit, file, root, mode) { * @param {Record | undefined> | null} variables * @param {Record} env * @param {string | null} entry - * @param {boolean} is_dev */ -export function create_sveltekit_env(variables, env, entry, is_dev) { +export function create_sveltekit_env(variables, env, entry) { const imports = entry ? [ `import { variables } from ${JSON.stringify(entry)};`, @@ -172,22 +171,31 @@ export function create_sveltekit_env(variables, env, entry, is_dev) { }` ]; + const module = blocks.join('\n\n'); + + return module; +} + +/** + * @param {Record | undefined> | null} variables + * @param {Record} env + */ +export function create_sveltekit_env_dev(variables, env) { // In dev, initialise the env immediately. Tools like `vite-node` load modules // through the Vite config but don't run the SvelteKit dev server, which is what // normally calls `set_env`. Without this, dynamic env vars imported from // `$app/env/public` and `$app/env/private` would be `undefined` in such contexts. - if (is_dev) { - /** @type {Record} */ - const dev_env = {}; - for (const name of Object.keys(variables ?? {})) { - if (name in env) dev_env[name] = env[name]; - } - blocks.push(`set_env(${devalue.uneval(dev_env)});`); + /** @type {Record} */ + const dev_env = {}; + for (const name of Object.keys(variables ?? {})) { + if (name in env) dev_env[name] = env[name]; } - const module = blocks.join('\n\n'); - - return module; + return [ + `import { set_env } from './config.js';`, + `set_env(${devalue.uneval(dev_env)});`, + `export * from './config.js';` + ].join('\n\n'); } /** @@ -218,7 +226,7 @@ export function create_sveltekit_env_private(variables, env) { handle_issues(issues); - return `import { dynamic_private_env as env } from '__sveltekit/env';\n\n${exports.join('')}`; + return `import { dynamic_private_env as env } from '../config.js';\n\n${exports.join('')}`; } /** diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index fc7ca8cbdac0..e8d267fa0366 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -5,6 +5,7 @@ import * as sync from '../../../core/sync/sync.js'; import { resolve_entry } from '../../../utils/filesystem.js'; import { create_sveltekit_env, + create_sveltekit_env_dev, create_sveltekit_env_private, create_sveltekit_env_public, create_sveltekit_env_service_worker, @@ -59,56 +60,50 @@ export function plugin_env_vars(config) { deps = synced.deps; + const vars = synced.variables; + const dir = `${out_dir}/generated/env`; + write_if_changed( - `${out_dir}/generated/env/config.js`, - create_sveltekit_env(synced.variables, env, resolved_entry, !is_build) + `${dir}/config.js`, + create_sveltekit_env(vars, env, resolved_entry && path.relative(dir, resolved_entry)) ); + write_if_changed(`${dir}/config-dev.js`, create_sveltekit_env_dev(vars, env)); + write_if_changed( - `${out_dir}/generated/env/public/client.js`, + `${dir}/public/client.js`, create_sveltekit_env_public( - synced.variables, + vars, env, - `import { payload } from ${s(`${runtime_directory}/client/payload.js`)};\nconst env = payload.env;` + `import { payload } from ${s(path.relative(`${dir}/client`, `${runtime_directory}/client/payload.js`))};\nconst env = payload.env;` ) ); write_if_changed( - `${out_dir}/generated/env/public/server.js`, - create_sveltekit_env_public( - synced.variables, - env, - `import { rendered_env as env } from '../config.js';` - ) + `${dir}/public/server.js`, + create_sveltekit_env_public(vars, env, `import { rendered_env as env } from '../config.js';`) ); write_if_changed( - `${out_dir}/generated/env/public/service-worker-prod.js`, + `${dir}/public/service-worker-prod.js`, create_sveltekit_env_public( - synced.variables, + vars, env, `const env = globalThis.__sveltekit_${version_hash}.env;` ) ); write_if_changed( - `${out_dir}/generated/env/public/service-worker-dev.js`, - create_sveltekit_env_public( - synced.variables, - env, - `const env = globalThis.__sveltekit_dev.env;` - ) + `${dir}/public/service-worker-dev.js`, + create_sveltekit_env_public(vars, env, `const env = globalThis.__sveltekit_dev.env;`) ); - write_if_changed( - `${out_dir}/generated/env/private/server.js`, - create_sveltekit_env_private(synced.variables, env) - ); + write_if_changed(`${dir}/private/server.js`, create_sveltekit_env_private(vars, env)); write_if_changed( - `${out_dir}/generated/env/service-worker-prod.js`, + `${dir}/service-worker-prod.js`, create_sveltekit_env_service_worker( - synced.variables, + vars, env, config.version.name, `globalThis.__sveltekit_${version_hash}`, @@ -118,9 +113,9 @@ export function plugin_env_vars(config) { ); write_if_changed( - `${out_dir}/generated/env/service-worker-dev.js`, + `${dir}/service-worker-dev.js`, create_sveltekit_env_service_worker_dev( - synced.variables, + vars, env, config.version.name, 'globalThis.__sveltekit_dev' @@ -157,28 +152,28 @@ export function plugin_env_vars(config) { id: prefixRegex('__sveltekit/env') }, handler(id) { + const dir = `${out_dir}/generated/env`; + if (id === '__sveltekit/env') { - return `${out_dir}/generated/env/config.js`; + return is_build ? `${dir}/config.js` : `${dir}/config-dev.js`; } if (id === '__sveltekit/env/private') { - return `${out_dir}/generated/env/private/server.js`; + return `${dir}/private/server.js`; } if (id === '__sveltekit/env/public/server') { - return `${out_dir}/generated/env/public/server.js`; + return `${dir}/public/server.js`; } if (id === '__sveltekit/env/public/client') { return this.environment.name === 'serviceWorker' - ? `${out_dir}/generated/env/public/service-worker-prod.js` - : `${out_dir}/generated/env/public/client.js`; + ? `${dir}/public/service-worker-prod.js` + : `${dir}/public/client.js`; } if (id === '__sveltekit/env/service-worker') { - return is_build - ? `${out_dir}/generated/env/service-worker-prod.js` - : `${out_dir}/generated/env/service-worker-dev.js`; + return is_build ? `${dir}/service-worker-prod.js` : `${dir}/service-worker-dev.js`; } } } From 2ff33094792784eefc6b401ba8747391ac7993de Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 15:27:02 -0400 Subject: [PATCH 06/27] tweak --- packages/kit/src/exports/vite/plugins/env-vars.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index e8d267fa0366..95acbf1a440f 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -45,11 +45,11 @@ export function plugin_env_vars(config) { /** @type {string | null} */ let resolved_entry = null; - let is_build = false; - /** @type {Set} */ let deps; + let is_build = false; + async function generate() { const synced = await sync.env( config, From 3db6f87e7c15d8713448735a18ecdadc20334d12 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 15:27:49 -0400 Subject: [PATCH 07/27] remove --- playgrounds/basic/src/env.ts | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 playgrounds/basic/src/env.ts diff --git a/playgrounds/basic/src/env.ts b/playgrounds/basic/src/env.ts deleted file mode 100644 index 33dc10c2ddfa..000000000000 --- a/playgrounds/basic/src/env.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineEnvVars } from '@sveltejs/kit/env'; - -export const variables = defineEnvVars({ - MESSAGE: { - public: true - }, - SECRET: {}, - STATIC: { - static: true - } -}); From 22768541234b48f85eb5fcbfd4daef1409c41db3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 15:52:27 -0400 Subject: [PATCH 08/27] fix --- packages/kit/src/exports/vite/index.js | 24 +++++-------------- packages/kit/src/exports/vite/module_ids.js | 1 - .../kit/src/exports/vite/plugins/env-vars.js | 6 ++++- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index cdd35e9c8cec..7fc15c7f8ba7 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -55,12 +55,7 @@ import { is_page_route } from '../../core/sync/create_manifest_data/index.js'; import { get_import_aliases, get_hash_import_keys } from '../../utils/imports.js'; -import { - app_env_private, - app_server, - sveltekit_manifest_data, - sveltekit_env_public_client -} from './module_ids.js'; +import { app_env_private, app_server, sveltekit_manifest_data } from './module_ids.js'; import { import_peer } from '../../utils/import.js'; import { compact } from '../../utils/array.js'; import { should_ignore, has_children } from './static_analysis/utils.js'; @@ -642,9 +637,6 @@ function kit({ svelte_config }) { } }; - /** @type {string | null} */ - let explicit_env_entry = null; - /** @type {Record> | null} */ let explicit_env_config = null; @@ -1772,8 +1764,8 @@ function kit({ svelte_config }) { const uses_env_dynamic_public = has_explicit_dynamic_public_env && client_chunks.some( - // TODO need to update this - (chunk) => chunk.type === 'chunk' && chunk.modules[sveltekit_env_public_client] + (chunk) => + chunk.type === 'chunk' && chunk.modules[`${out_dir}/generated/env/public/client.js`] ); if (kit.output.bundleStrategy === 'split') { @@ -2057,12 +2049,6 @@ function kit({ svelte_config }) { fs.mkdirSync(out, { recursive: true }); - explicit_env_entry = resolve_explicit_env_entry(kit); - - const synced = await sync.env(kit, explicit_env_entry, vite_config.root, vite_config.mode); - - explicit_env_config = synced.variables; - await load_and_validate_params({ routes: manifest_data.routes, params_path: manifest_data.params, @@ -2125,7 +2111,9 @@ function kit({ svelte_config }) { plugin_setup, plugin_remote_guard, plugin_remote, - plugin_env_vars(svelte_config), + plugin_env_vars(svelte_config, (vars) => { + explicit_env_config = vars; + }), plugin_virtual_modules, process.env.TEST !== 'true' ? plugin_guard : undefined, plugin_service_worker, diff --git a/packages/kit/src/exports/vite/module_ids.js b/packages/kit/src/exports/vite/module_ids.js index 8810be4deaaf..a1a07875e4c9 100644 --- a/packages/kit/src/exports/vite/module_ids.js +++ b/packages/kit/src/exports/vite/module_ids.js @@ -1,7 +1,6 @@ import { fileURLToPath } from 'node:url'; import { posixify } from '../../utils/os.js'; -export const sveltekit_env_public_client = '\0virtual:__sveltekit/env/public/client'; export const sveltekit_server = '\0virtual:__sveltekit/server'; export const service_worker = '\0virtual:service-worker'; diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 95acbf1a440f..75a038c99494 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -1,4 +1,5 @@ /** @import { Plugin, ResolvedConfig } from 'vite' */ +/** @import { EnvVarConfig } from '@sveltejs/kit/env' */ /** @import { ValidatedConfig } from 'types' */ import path from 'node:path'; import * as sync from '../../../core/sync/sync.js'; @@ -23,9 +24,10 @@ import { prefixRegex } from '@rolldown/pluginutils'; * derived from `src/env.ts` * * @param {ValidatedConfig} config + * @param {(variables: Record> | null) => void} callback * @returns {Plugin} */ -export function plugin_env_vars(config) { +export function plugin_env_vars(config, callback) { // grab these values eagerly because they get mutated (TODO stop mutating them) const entry = path.join(config.files.src, 'env'); const dir = config.env.dir; @@ -121,6 +123,8 @@ export function plugin_env_vars(config) { 'globalThis.__sveltekit_dev' ) ); + + callback(vars); } return { From 24156fe6fce3a1483fb53dbad1eba14cd2e5f232 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 16:03:48 -0400 Subject: [PATCH 09/27] tweak --- packages/kit/src/cli.js | 7 ++++--- packages/kit/src/core/env.js | 14 +------------- packages/kit/src/exports/vite/index.js | 2 +- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/kit/src/cli.js b/packages/kit/src/cli.js index 6a588403aaaf..e256d09db43b 100755 --- a/packages/kit/src/cli.js +++ b/packages/kit/src/cli.js @@ -1,10 +1,11 @@ import fs from 'node:fs'; +import path from 'node:path'; import process from 'node:process'; import { parseArgs, styleText } from 'node:util'; import { extract_svelte_config, load_vite_config } from './core/config/index.js'; -import { resolve_explicit_env_entry } from './core/env.js'; import { coalesce_to_error } from './utils/error.js'; import { import_peer } from './utils/import.js'; +import { resolve_entry } from './utils/filesystem.js'; /** @param {unknown} e */ function handle_error(e) { @@ -105,8 +106,8 @@ if (command === 'sync') { const sync = await import('./core/sync/sync.js'); sync.all_types(sveltekit_config, vite_config.root); - const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config); - await sync.env(sveltekit_config, explicit_env_entry, vite_config.root, values.mode); + const entry = resolve_entry(path.join(sveltekit_config.files.src, 'env')); + await sync.env(sveltekit_config, entry, vite_config.root, values.mode); } catch (error) { handle_error(error); } finally { diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index c6725e119fed..2fdfad908c10 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -1,12 +1,10 @@ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ /** @import { EnvVarConfig } from '@sveltejs/kit/env' */ /** @import { ValidatedConfig } from 'types' */ -import path from 'node:path'; import * as devalue from 'devalue'; import { GENERATED_COMMENT } from '../constants.js'; import { dedent } from './sync/utils.js'; import { runtime_directory } from './utils.js'; -import { resolve_entry } from '../utils/filesystem.js'; import { handle_issues, validate } from '../exports/internal/env.js'; import { get_config_aliases } from '../exports/vite/utils.js'; import { get_runner } from '../runner.js'; @@ -16,14 +14,6 @@ import { import_peer } from '../utils/import.js'; * @typedef {'public' | 'private'} EnvType */ -/** - * @param {ValidatedConfig} config - * @returns {string | null} - */ -export function resolve_explicit_env_entry(config) { - return resolve_entry(path.join(config.files.src, 'env')) ?? null; -} - /** * @param {ValidatedConfig} kit * @param {string | null} file @@ -171,9 +161,7 @@ export function create_sveltekit_env(variables, env, entry) { }` ]; - const module = blocks.join('\n\n'); - - return module; + return blocks.join('\n\n'); } /** diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 7fc15c7f8ba7..3d3312427412 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -23,7 +23,7 @@ import MagicString from 'magic-string'; import { copy, read, resolve_entry } from '../../utils/filesystem.js'; import { posixify } from '../../utils/os.js'; import { to_fs } from '../../utils/vite.js'; -import { resolve_explicit_env_entry, create_exported_declarations } from '../../core/env.js'; +import { create_exported_declarations } from '../../core/env.js'; import * as sync from '../../core/sync/sync.js'; import { load_and_validate_params } from '../../utils/params.js'; import { runtime_directory, logger } from '../../core/utils.js'; From 857c04acd5f467c8430a9e21945a46c9c4e4d8fb Mon Sep 17 00:00:00 2001 From: "vercel[bot]" <35613825+vercel[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 20:12:58 +0000 Subject: [PATCH 10/27] Fix: On Windows, the `env-vars` plugin builds module ids from a non-posixified `out_dir` (backslashes), so index.js's posix-keyed `chunk.modules` lookup for the dynamic public env module never matches, forcing `uses_env_dynamic_public` to always be false. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the issue reported at packages/kit/src/exports/vite/plugins/env-vars.js:139 ## Bug `packages/kit/src/exports/vite/plugins/env-vars.js` computed: ```js out_dir = path.resolve(c.root, out); // native separators ``` and its `resolveId` handler returns module ids derived from that value, e.g.: ```js const dir = ` ``` On **Windows**, `path.resolve` produces backslash-separated paths (`C:\proj.svelte-kit`), so the base of the returned module id contains backslashes: `C:\proj.svelte-kit/generated/env/public/client.js`. Rollup/rolldown store the module id exactly as returned by `resolveId`, so `chunk.modules` is keyed with that mixed-separator string. Meanwhile `packages/kit/src/exports/vite/index.js` (~line 1768) looks the module up using a fully posix key: ```js out_dir = posixify(kit.outDir); // line 386, forward slashes // ... const uses_env_dynamic_public = has_explicit_dynamic_public_env && client_chunks.some( (chunk) => chunk.type === 'chunk' && chunk.modules[` ``` Because the two keys differ in the base separators on Windows (`` vs `/`), the lookup never matches. **Trigger:** a Windows build with `bundleStrategy: 'split'` and a project that imports `$app/env/public` / uses a dynamic (non-static) public env var. `uses_env_dynamic_public` is forced to `false`, so the code that arranges correct preloading/loading of dynamic public env for the split bundle is skipped, breaking runtime public env vars on Windows. The rest of the codebase consistently uses `posixify(kit.outDir)` for `out_dir` precisely so module ids match — this plugin was the sole divergence. ## Fix Posixify `out_dir` in the plugin so the generated module ids use forward slashes and match index.js's lookup key: ```js import { posixify } from '../../../utils/os.js'; // ... out_dir = posixify(path.resolve(c.root, out)); ``` `posixify` (from `packages/kit/src/utils/os.js`) simply replaces `\` with `/`, which is a no-op on POSIX systems and corrects the separators on Windows, restoring the key match. Co-authored-by: Vercel Co-authored-by: Rich-Harris --- packages/kit/src/exports/vite/plugins/env-vars.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 75a038c99494..251b3d64dd16 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -17,6 +17,7 @@ import { runtime_directory } from '../../../core/utils.js'; import { s } from '../../../utils/misc.js'; import { write_if_changed } from '../../../core/sync/utils.js'; import { hash } from '../../../utils/hash.js'; +import { posixify } from '../../../utils/os.js'; import { prefixRegex } from '@rolldown/pluginutils'; /** @@ -136,7 +137,7 @@ export function plugin_env_vars(config, callback) { const vite = await import_peer('vite', c.root); env = vite.loadEnv(c.mode, path.resolve(c.root, dir), ''); - out_dir = path.resolve(c.root, out); + out_dir = posixify(path.resolve(c.root, out)); is_build = c.command === 'build'; }, From fd1e17f354b224ac828f81daad60f1379e463b84 Mon Sep 17 00:00:00 2001 From: "vercel[bot]" <35613825+vercel[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 20:13:03 +0000 Subject: [PATCH 11/27] Fix: Creating or deleting `src/env.(js|ts)` while the dev server is running is no longer handled: new env files are ignored until restart, and deleting an existing env file throws because `resolved_entry` is never re-resolved. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the issue reported at packages/kit/src/exports/vite/plugins/env-vars.js:149 ## Bug The `plugin_env_vars` plugin in `packages/kit/src/exports/vite/plugins/env-vars.js` computes `resolved_entry` only once, in `buildStart`, and only regenerates env modules via `handleHotUpdate` when the changed file is already in `deps`: ```js async buildStart() { resolved_entry = resolve_entry(path.join(resolved_config.root, entry)) ?? null; await generate(); }, async handleHotUpdate(update) { if (!deps.has(update.file)) return; await generate(); }, ``` This replaced a watcher previously in `plugin_virtual_modules.configureServer` (in `index.js`) that listened to `server.watcher.on('all', ...)`, re-resolved the entry via `resolve_explicit_env_entry`, regenerated, and triggered a full reload on any add/remove/change of the env entry. (`resolve_explicit_env_entry` is now only imported in `index.js`, never called.) Vite's `handleHotUpdate` only fires for `change` events on files it already tracks — it is **not** called for file `add`/`unlink`. That produces two concrete dev regressions: 1. **Creating `src/env.ts` after start**: If it didn't exist at startup, `resolved_entry` is `null` and `deps` is empty (`load_explicit_env` returns an empty dep set when `file` is null). The `add` event doesn't reach `handleHotUpdate`, and even if it did the file isn't in `deps`, so the new env vars are never generated until a manual restart. 2. **Deleting an existing `src/env.ts`**: The entry file is in `deps` (the dependency-scanner `load` hook records it). On delete, `handleHotUpdate` fires with the deleted file in `deps`, calling `generate()` → `sync.env(config, resolved_entry, ...)` with the stale, now-nonexistent `resolved_entry`, so `load_explicit_env` does `runner.import(file)` on a missing module and throws (`ERR_MODULE_NOT_FOUND`). `resolved_entry` is never reset to `null`. The dev watcher in `dev/index.js` handles app/error templates, service worker and hooks, but not `src/env`, so it doesn't compensate. ## Fix Added a `configureServer` hook to the env-vars plugin that listens for `add`/`unlink` events, re-resolves the entry, updates `resolved_entry`, regenerates the modules, and sends a `full-reload` — mirroring the removed watcher. `change` events remain handled by `handleHotUpdate` (for the entry and its transitive deps), so there is no double processing. ```js configureServer(server) { const on_entry_add_unlink = async (file) => { const resolved = resolve_entry(path.join(resolved_config.root, entry)) ?? null; if (file === resolved_entry || file === resolved) { resolved_entry = resolved; await generate(); server.hot.send({ type: 'full-reload' }); } }; server.watcher.on('add', on_entry_add_unlink); server.watcher.on('unlink', on_entry_add_unlink); }, ``` This restores dev handling for both creating (case 1) and deleting (case 2, `resolved` becomes `null` so `generate()` runs with a null entry and produces empty env modules instead of throwing) the env entry. The `server.watcher`/`server.hot` usage matches existing patterns in `dev/index.js`. Co-authored-by: Vercel Co-authored-by: Rich-Harris --- .../kit/src/exports/vite/plugins/env-vars.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 251b3d64dd16..c17273c3341f 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -147,6 +147,25 @@ export function plugin_env_vars(config, callback) { await generate(); }, + configureServer(server) { + // `handleHotUpdate` only fires for `change` events on files Vite already knows about, + // so it doesn't cover the env entry being created or deleted while the dev server is + // running. Watch for those events explicitly, re-resolve the entry, regenerate the + // modules and trigger a full reload (mirroring the previous behaviour). + const on_entry_add_unlink = async (/** @type {string} */ file) => { + const resolved = resolve_entry(path.join(resolved_config.root, entry)) ?? null; + + if (file === resolved_entry || file === resolved) { + resolved_entry = resolved; + await generate(); + server.hot.send({ type: 'full-reload' }); + } + }; + + server.watcher.on('add', on_entry_add_unlink); + server.watcher.on('unlink', on_entry_add_unlink); + }, + async handleHotUpdate(update) { if (!deps.has(update.file)) return; await generate(); From 47a9eeb3216011066c171cafe697ed8117f005c3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 16:42:52 -0400 Subject: [PATCH 12/27] use alias to differentiate between config.js and config-dev.js --- packages/kit/src/core/env.js | 2 +- packages/kit/src/exports/vite/plugins/env-vars.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index 2fdfad908c10..a370252663f2 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -214,7 +214,7 @@ export function create_sveltekit_env_private(variables, env) { handle_issues(issues); - return `import { dynamic_private_env as env } from '../config.js';\n\n${exports.join('')}`; + return `import { dynamic_private_env as env } from '__sveltekit/env';\n\n${exports.join('')}`; } /** diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index c17273c3341f..295517f83f89 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -84,7 +84,11 @@ export function plugin_env_vars(config, callback) { write_if_changed( `${dir}/public/server.js`, - create_sveltekit_env_public(vars, env, `import { rendered_env as env } from '../config.js';`) + create_sveltekit_env_public( + vars, + env, + `import { rendered_env as env } from '__sveltekit/env';` + ) ); write_if_changed( From e26f614840c4c8fdbfbab8036dd45b6908f5784d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 16:43:52 -0400 Subject: [PATCH 13/27] guard against race condition --- packages/kit/src/exports/vite/plugins/env-vars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 295517f83f89..6ecf2c4fe9a4 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -49,7 +49,7 @@ export function plugin_env_vars(config, callback) { let resolved_entry = null; /** @type {Set} */ - let deps; + let deps = new Set(); let is_build = false; From 598c3e3b837b980f18a476fb8e2222fcbf69efaf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 16:47:35 -0400 Subject: [PATCH 14/27] reinstate shared helper --- packages/kit/src/cli.js | 5 ++--- packages/kit/src/core/env.js | 11 +++++++++++ packages/kit/src/exports/vite/plugins/env-vars.js | 7 ++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/kit/src/cli.js b/packages/kit/src/cli.js index e256d09db43b..d3eae6b4fd01 100755 --- a/packages/kit/src/cli.js +++ b/packages/kit/src/cli.js @@ -1,11 +1,10 @@ import fs from 'node:fs'; -import path from 'node:path'; import process from 'node:process'; import { parseArgs, styleText } from 'node:util'; import { extract_svelte_config, load_vite_config } from './core/config/index.js'; import { coalesce_to_error } from './utils/error.js'; import { import_peer } from './utils/import.js'; -import { resolve_entry } from './utils/filesystem.js'; +import { resolve_env_entry } from './core/env.js'; /** @param {unknown} e */ function handle_error(e) { @@ -106,7 +105,7 @@ if (command === 'sync') { const sync = await import('./core/sync/sync.js'); sync.all_types(sveltekit_config, vite_config.root); - const entry = resolve_entry(path.join(sveltekit_config.files.src, 'env')); + const entry = resolve_env_entry(sveltekit_config, vite_config.root); await sync.env(sveltekit_config, entry, vite_config.root, values.mode); } catch (error) { handle_error(error); diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index a370252663f2..f97a08b768cf 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -1,10 +1,12 @@ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ /** @import { EnvVarConfig } from '@sveltejs/kit/env' */ /** @import { ValidatedConfig } from 'types' */ +import path from 'node:path'; import * as devalue from 'devalue'; import { GENERATED_COMMENT } from '../constants.js'; import { dedent } from './sync/utils.js'; import { runtime_directory } from './utils.js'; +import { resolve_entry } from '../utils/filesystem.js'; import { handle_issues, validate } from '../exports/internal/env.js'; import { get_config_aliases } from '../exports/vite/utils.js'; import { get_runner } from '../runner.js'; @@ -14,6 +16,15 @@ import { import_peer } from '../utils/import.js'; * @typedef {'public' | 'private'} EnvType */ +/** + * @param {ValidatedConfig} config + * @param {string} root + * @returns {string | null} + */ +export function resolve_env_entry(config, root) { + return resolve_entry(path.resolve(root, config.files.src, 'env')); +} + /** * @param {ValidatedConfig} kit * @param {string | null} file diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 6ecf2c4fe9a4..75e6c358b7cc 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -10,7 +10,8 @@ import { create_sveltekit_env_private, create_sveltekit_env_public, create_sveltekit_env_service_worker, - create_sveltekit_env_service_worker_dev + create_sveltekit_env_service_worker_dev, + resolve_env_entry } from '../../../core/env.js'; import { import_peer } from '../../../utils/import.js'; import { runtime_directory } from '../../../core/utils.js'; @@ -147,7 +148,7 @@ export function plugin_env_vars(config, callback) { }, async buildStart() { - resolved_entry = resolve_entry(path.join(resolved_config.root, entry)) ?? null; + resolved_entry = resolve_env_entry(config, resolved_config.root); await generate(); }, @@ -157,7 +158,7 @@ export function plugin_env_vars(config, callback) { // running. Watch for those events explicitly, re-resolve the entry, regenerate the // modules and trigger a full reload (mirroring the previous behaviour). const on_entry_add_unlink = async (/** @type {string} */ file) => { - const resolved = resolve_entry(path.join(resolved_config.root, entry)) ?? null; + const resolved = resolve_env_entry(config, resolved_config.root); if (file === resolved_entry || file === resolved) { resolved_entry = resolved; From a44eb36f0d5ebb7ec82fe36c8b68b920f84ca6cd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:05:29 -0400 Subject: [PATCH 15/27] only run buildStart logic once --- packages/kit/src/exports/vite/plugins/env-vars.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 75e6c358b7cc..2fe2d971d933 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -148,6 +148,9 @@ export function plugin_env_vars(config, callback) { }, async buildStart() { + // we only need to run this once + if (this.environment.name !== 'ssr') return; + resolved_entry = resolve_env_entry(config, resolved_config.root); await generate(); }, From ff2b53783ff3686699a5153fc8abcfbe2ef96f1d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:14:45 -0400 Subject: [PATCH 16/27] use configResolved --- packages/kit/src/exports/vite/plugins/env-vars.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 2fe2d971d933..bf7d34b3b8fd 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -145,13 +145,8 @@ export function plugin_env_vars(config, callback) { out_dir = posixify(path.resolve(c.root, out)); is_build = c.command === 'build'; - }, - - async buildStart() { - // we only need to run this once - if (this.environment.name !== 'ssr') return; - resolved_entry = resolve_env_entry(config, resolved_config.root); + resolved_entry = resolve_env_entry(config, c.root); await generate(); }, From e15b257ecf24a6cfbf7c68a3621e4cb8266ce0ac Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:15:32 -0400 Subject: [PATCH 17/27] Update packages/kit/src/exports/vite/utils.js Co-authored-by: Nic Polumeyv --- packages/kit/src/exports/vite/utils.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/utils.js b/packages/kit/src/exports/vite/utils.js index 06cdc8b18bea..81a6960a2676 100644 --- a/packages/kit/src/exports/vite/utils.js +++ b/packages/kit/src/exports/vite/utils.js @@ -119,8 +119,7 @@ export function normalize_id(id, aliases, cwd) { return '$app/server'; } - // TODO is this right? - if (id === app_env_private || id === '__sveltekit/env/private') { + if (id === app_env_private) { return '$app/env/private'; } From f8133a373f518e4f5379f09711f98de2962622ca Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:17:05 -0400 Subject: [PATCH 18/27] Update packages/kit/src/exports/vite/plugins/env-vars.js Co-authored-by: Nic Polumeyv --- packages/kit/src/exports/vite/plugins/env-vars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 2fe2d971d933..f63334d2d940 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -69,7 +69,7 @@ export function plugin_env_vars(config, callback) { write_if_changed( `${dir}/config.js`, - create_sveltekit_env(vars, env, resolved_entry && path.relative(dir, resolved_entry)) + create_sveltekit_env(vars, env, resolved_entry && posixify(path.relative(dir, resolved_entry))) ); write_if_changed(`${dir}/config-dev.js`, create_sveltekit_env_dev(vars, env)); From 4e2609122465b73c536d8bfdcb3204d7d88a9848 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:17:35 -0400 Subject: [PATCH 19/27] posixify --- packages/kit/src/exports/vite/plugins/env-vars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 748fadbc5198..d5ed8cab7d79 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -79,7 +79,7 @@ export function plugin_env_vars(config, callback) { create_sveltekit_env_public( vars, env, - `import { payload } from ${s(path.relative(`${dir}/client`, `${runtime_directory}/client/payload.js`))};\nconst env = payload.env;` + `import { payload } from ${s(posixify(path.relative(`${dir}/public`, `${runtime_directory}/client/payload.js`)))};\nconst env = payload.env;` ) ); From 7949863522a7f11194d0ee34c1dbcc1ed9f9e9cd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:18:13 -0400 Subject: [PATCH 20/27] Update packages/kit/src/exports/vite/plugins/env-vars.js Co-authored-by: Nic Polumeyv --- packages/kit/src/exports/vite/plugins/env-vars.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index f63334d2d940..b8292deee41f 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -101,11 +101,6 @@ export function plugin_env_vars(config, callback) { ) ); - write_if_changed( - `${dir}/public/service-worker-dev.js`, - create_sveltekit_env_public(vars, env, `const env = globalThis.__sveltekit_dev.env;`) - ); - write_if_changed(`${dir}/private/server.js`, create_sveltekit_env_private(vars, env)); write_if_changed( From 58eb6b5583cb4772234ac10cb2af298f4245341f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:18:58 -0400 Subject: [PATCH 21/27] rename file, since no dev version exists --- packages/kit/src/exports/vite/plugins/env-vars.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index c8c6e3fd0c71..2f91086d3db0 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -69,7 +69,11 @@ export function plugin_env_vars(config, callback) { write_if_changed( `${dir}/config.js`, - create_sveltekit_env(vars, env, resolved_entry && posixify(path.relative(dir, resolved_entry))) + create_sveltekit_env( + vars, + env, + resolved_entry && posixify(path.relative(dir, resolved_entry)) + ) ); write_if_changed(`${dir}/config-dev.js`, create_sveltekit_env_dev(vars, env)); @@ -93,7 +97,7 @@ export function plugin_env_vars(config, callback) { ); write_if_changed( - `${dir}/public/service-worker-prod.js`, + `${dir}/public/service-worker.js`, create_sveltekit_env_public( vars, env, @@ -190,7 +194,7 @@ export function plugin_env_vars(config, callback) { if (id === '__sveltekit/env/public/client') { return this.environment.name === 'serviceWorker' - ? `${dir}/public/service-worker-prod.js` + ? `${dir}/public/service-worker.js` : `${dir}/public/client.js`; } From db6b5349896ad4131d0febfcc3493385c115c585 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:19:48 -0400 Subject: [PATCH 22/27] unused --- packages/kit/src/exports/vite/plugins/env-vars.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index 2f91086d3db0..d0ed8d9b6649 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -31,7 +31,6 @@ import { prefixRegex } from '@rolldown/pluginutils'; */ export function plugin_env_vars(config, callback) { // grab these values eagerly because they get mutated (TODO stop mutating them) - const entry = path.join(config.files.src, 'env'); const dir = config.env.dir; const out = config.outDir; From 5a9a991b67ebf30cf528ab863ca0b7b88ab3bc24 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:22:26 -0400 Subject: [PATCH 23/27] Update packages/kit/src/exports/vite/index.js Co-authored-by: Nic Polumeyv --- packages/kit/src/exports/vite/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 3d3312427412..47a067e51548 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -1103,10 +1103,9 @@ function kit({ svelte_config }) { resolveId: { filter: { - id: prefixRegex('__sveltekit/') + id: exactRegex('__sveltekit/manifest-data') }, handler(id) { - // TODO do we still need this? return `\0virtual:${id}`; } }, From b79d0ec3636915a2612d9532efa96927729aca51 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:29:51 -0400 Subject: [PATCH 24/27] unused --- packages/kit/src/exports/vite/plugins/env-vars.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index d0ed8d9b6649..c771f438ecdf 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -3,7 +3,6 @@ /** @import { ValidatedConfig } from 'types' */ import path from 'node:path'; import * as sync from '../../../core/sync/sync.js'; -import { resolve_entry } from '../../../utils/filesystem.js'; import { create_sveltekit_env, create_sveltekit_env_dev, From 4ab53e900e13a6f11f5fc4497f4f428b96453c87 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 14 Aug 2026 17:32:32 -0400 Subject: [PATCH 25/27] remove comment --- packages/kit/src/core/env.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index f97a08b768cf..c70f50502bb7 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -3,7 +3,6 @@ /** @import { ValidatedConfig } from 'types' */ import path from 'node:path'; import * as devalue from 'devalue'; -import { GENERATED_COMMENT } from '../constants.js'; import { dedent } from './sync/utils.js'; import { runtime_directory } from './utils.js'; import { resolve_entry } from '../utils/filesystem.js'; @@ -155,7 +154,6 @@ export function create_sveltekit_env(variables, env, entry) { handle_issues(issues); const blocks = [ - GENERATED_COMMENT, imports.join('\n'), `const issues = {};`, 'export { variables }', From 2f8f6f1f5fe3f93118f08dcbe10f7239ff1e35d0 Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Fri, 14 Aug 2026 17:48:58 -0400 Subject: [PATCH 26/27] =?UTF-8?q?generate=20in=20buildStart,=20not=20confi?= =?UTF-8?q?gResolved=20=E2=80=94=20postbuild=20forks=20resolve=20the=20con?= =?UTF-8?q?fig=20with=20the=20wrong=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/kit/src/exports/vite/plugins/env-vars.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index c771f438ecdf..bebae4a59cb0 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -142,8 +142,14 @@ export function plugin_env_vars(config, callback) { out_dir = posixify(path.resolve(c.root, out)); is_build = c.command === 'build'; + }, + + async buildStart() { + // we only need to run this once, and not in postbuild forks that + // resolve the config without building (analyse/prerender) + if (this.environment.name !== 'ssr') return; - resolved_entry = resolve_env_entry(config, c.root); + resolved_entry = resolve_env_entry(config, resolved_config.root); await generate(); }, From ea22879896bb09108bee6035c22288ce6b795c5a Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Fri, 14 Aug 2026 17:54:41 -0400 Subject: [PATCH 27/27] =?UTF-8?q?gate=20generate=20on=20a=20memo,=20not=20?= =?UTF-8?q?the=20environment=20name=20=E2=80=94=20adapter=20environments?= =?UTF-8?q?=20aren't=20always=20called=20'ssr'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kit/src/exports/vite/plugins/env-vars.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/kit/src/exports/vite/plugins/env-vars.js b/packages/kit/src/exports/vite/plugins/env-vars.js index bebae4a59cb0..45bbd6cfcb77 100644 --- a/packages/kit/src/exports/vite/plugins/env-vars.js +++ b/packages/kit/src/exports/vite/plugins/env-vars.js @@ -52,6 +52,9 @@ export function plugin_env_vars(config, callback) { let is_build = false; + /** @type {Promise | undefined} */ + let generated; + async function generate() { const synced = await sync.env( config, @@ -145,12 +148,13 @@ export function plugin_env_vars(config, callback) { }, async buildStart() { - // we only need to run this once, and not in postbuild forks that - // resolve the config without building (analyse/prerender) - if (this.environment.name !== 'ssr') return; - - resolved_entry = resolve_env_entry(config, resolved_config.root); - await generate(); + // runs once via the memo — per-process, whichever environment starts first + // (environment names vary by adapter), and never in the postbuild forks, + // which resolve the config without building + await (generated ??= (async () => { + resolved_entry = resolve_env_entry(config, resolved_config.root); + await generate(); + })()); }, configureServer(server) {