Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e43c6f1
WIP
Rich-Harris Aug 14, 2026
97bfc18
WIP
Rich-Harris Aug 14, 2026
b2e68c8
fix
Rich-Harris Aug 14, 2026
6bc54ad
move resolveId logic
Rich-Harris Aug 14, 2026
af831de
fix
Rich-Harris Aug 14, 2026
2ff3309
tweak
Rich-Harris Aug 14, 2026
3db6f87
remove
Rich-Harris Aug 14, 2026
2276854
fix
Rich-Harris Aug 14, 2026
24156fe
tweak
Rich-Harris Aug 14, 2026
857c04a
Fix: On Windows, the `env-vars` plugin builds module ids from a non-p…
vercel[bot] Aug 14, 2026
fd1e17f
Fix: Creating or deleting `src/env.(js|ts)` while the dev server is r…
vercel[bot] Aug 14, 2026
47a9eeb
use alias to differentiate between config.js and config-dev.js
Rich-Harris Aug 14, 2026
e26f614
guard against race condition
Rich-Harris Aug 14, 2026
598c3e3
reinstate shared helper
Rich-Harris Aug 14, 2026
a44eb36
only run buildStart logic once
Rich-Harris Aug 14, 2026
ff2b537
use configResolved
Rich-Harris Aug 14, 2026
e15b257
Update packages/kit/src/exports/vite/utils.js
Rich-Harris Aug 14, 2026
8bd25e8
Merge branch 'generated-env-modules' of github.com:sveltejs/kit into …
Rich-Harris Aug 14, 2026
f8133a3
Update packages/kit/src/exports/vite/plugins/env-vars.js
Rich-Harris Aug 14, 2026
bf48406
Merge branch 'generated-env-modules' of github.com:sveltejs/kit into …
Rich-Harris Aug 14, 2026
4e26091
posixify
Rich-Harris Aug 14, 2026
7949863
Update packages/kit/src/exports/vite/plugins/env-vars.js
Rich-Harris Aug 14, 2026
ecda69e
Merge branch 'generated-env-modules' of github.com:sveltejs/kit into …
Rich-Harris Aug 14, 2026
58eb6b5
rename file, since no dev version exists
Rich-Harris Aug 14, 2026
db6b534
unused
Rich-Harris Aug 14, 2026
5a9a991
Update packages/kit/src/exports/vite/index.js
Rich-Harris Aug 14, 2026
b79d0ec
unused
Rich-Harris Aug 14, 2026
4ab53e9
remove comment
Rich-Harris Aug 14, 2026
2f8f6f1
generate in buildStart, not configResolved — postbuild forks resolve …
Nic-Polumeyv Aug 14, 2026
ea22879
gate generate on a memo, not the environment name — adapter environme…
Nic-Polumeyv Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/warm-boats-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@sveltejs/kit": patch
---

chore: emit env modules to disk

6 changes: 3 additions & 3 deletions packages/kit/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import fs from 'node:fs';
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_env_entry } from './core/env.js';

/** @param {unknown} e */
function handle_error(e) {
Expand Down Expand Up @@ -105,8 +105,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(vite, sveltekit_config, explicit_env_entry, vite_config.root, values.mode);
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);
} finally {
Expand Down
65 changes: 43 additions & 22 deletions packages/kit/src/core/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,44 @@
/** @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';
import { import_peer } from '../utils/import.js';

/**
* @typedef {'public' | 'private'} EnvType
*/

/**
* @param {ValidatedConfig} config
* @param {string} root
* @returns {string | null}
*/
export function resolve_explicit_env_entry(config) {
return resolve_entry(path.join(config.files.src, 'env')) ?? null;
export function resolve_env_entry(config, root) {
return resolve_entry(path.resolve(root, config.files.src, 'env'));
}

/**
* @param {typeof import('vite')} vite
* @param {ValidatedConfig} kit
* @param {string | null} file
* @param {string} root
* @param {string} mode
* @returns {Promise<Record<string, EnvVarConfig<any>> | null>}
* @returns {Promise<{ variables: Record<string, EnvVarConfig<any>> | null, deps: Set<string> }>}
*/
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<string>} */
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,
Expand All @@ -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<string, EnvVarConfig<any>>} */
Expand Down Expand Up @@ -92,17 +108,16 @@ export async function load_explicit_env(vite, kit, file, root, mode) {
await server.close();
}

return variables;
return { variables, deps };
}

/**
* Creates the `__sveltekit/env` module
* @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
* @param {Record<string, string>} 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)};`,
Expand Down Expand Up @@ -139,7 +154,6 @@ export function create_sveltekit_env(variables, env, entry, is_dev) {
handle_issues(issues);

const blocks = [
GENERATED_COMMENT,
imports.join('\n'),
`const issues = {};`,
'export { variables }',
Expand All @@ -156,22 +170,29 @@ export function create_sveltekit_env(variables, env, entry, is_dev) {
}`
];

return blocks.join('\n\n');
}

/**
* @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
* @param {Record<string, string>} 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<string, string>} */
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<string, string>} */
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');
}

/**
Expand Down
7 changes: 3 additions & 4 deletions packages/kit/src/core/sync/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading
Loading