Skip to content

Commit 2355ef6

Browse files
Rich-Harriseltigerchino
authored andcommitted
fix: only disallow dynamic env access when prerendering (#11436)
* only disallow dynamic env access when prerendering * changeset * add test * sigh --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 9d93465 commit 2355ef6

File tree

11 files changed

+59
-18
lines changed

11 files changed

+59
-18
lines changed

.changeset/perfect-eyes-brush.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: allow dynamic env access when building but not prerendering

packages/kit/src/core/postbuild/analyse.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async function analyse({ manifest_path, env }) {
3939

4040
// configure `import { building } from '$app/environment'` —
4141
// essential we do this before analysing the code
42-
internal.set_building(true);
42+
internal.set_building();
4343

4444
// set env, in case it's used in initialisation
4545
const { publicPrefix: public_prefix, privatePrefix: private_prefix } = config.env;

packages/kit/src/core/postbuild/fallback.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async function generate_fallback({ manifest_path, env }) {
3030
/** @type {import('@sveltejs/kit').SSRManifest} */
3131
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
3232

33-
set_building(true);
33+
set_building();
3434

3535
const server = new Server(manifest);
3636
await server.init({ env });

packages/kit/src/core/postbuild/prerender.js

+19-10
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
3636

3737
// configure `import { building } from '$app/environment'` —
3838
// essential we do this before analysing the code
39-
internal.set_building(true);
39+
internal.set_building();
40+
internal.set_prerendering();
4041

4142
/**
4243
* @template {{message: string}} T
@@ -98,9 +99,6 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
9899
/** @type {Map<string, string>} */
99100
const saved = new Map();
100101

101-
const server = new Server(manifest);
102-
await server.init({ env });
103-
104102
const handle_http_error = normalise_error_handler(
105103
log,
106104
config.prerender.handleHttpError,
@@ -413,16 +411,27 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
413411
}
414412
}
415413

414+
let has_prerenderable_routes = false;
415+
416+
for (const value of prerender_map.values()) {
417+
if (value) {
418+
has_prerenderable_routes = true;
419+
break;
420+
}
421+
}
422+
416423
if (
417-
config.prerender.entries.length > 1 ||
418-
config.prerender.entries[0] !== '*' ||
419-
route_level_entries.length > 0 ||
420-
prerender_map.size > 0
424+
(config.prerender.entries.length === 0 && route_level_entries.length === 0) ||
425+
!has_prerenderable_routes
421426
) {
422-
// Only log if we're actually going to do something to not confuse users
423-
log.info('Prerendering');
427+
return { prerendered, prerender_map };
424428
}
425429

430+
log.info('Prerendering');
431+
432+
const server = new Server(manifest);
433+
await server.init({ env });
434+
426435
for (const entry of config.prerender.entries) {
427436
if (entry === '*') {
428437
for (const [id, prerender] of prerender_map) {

packages/kit/src/core/sync/write_server.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const server_template = ({
2626
error_page
2727
}) => `
2828
import root from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}';
29-
import { set_building } from '__sveltekit/environment';
29+
import { set_building, set_prerendering } from '__sveltekit/environment';
3030
import { set_assets } from '__sveltekit/paths';
3131
import { set_private_env, set_public_env, set_safe_public_env } from '${runtime_directory}/shared-server.js';
3232
@@ -63,7 +63,7 @@ export function get_hooks() {
6363
return ${hooks ? `import(${s(hooks)})` : '{}'};
6464
}
6565
66-
export { set_assets, set_building, set_private_env, set_public_env, set_safe_public_env };
66+
export { set_assets, set_building, set_prerendering, set_private_env, set_public_env, set_safe_public_env };
6767
`;
6868

6969
// TODO need to re-run this whenever src/app.html or src/error.html are

packages/kit/src/exports/vite/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,15 @@ function kit({ svelte_config }) {
442442
return dedent`
443443
export const version = ${s(version.name)};
444444
export let building = false;
445+
export let prerendering = false;
445446
446447
export function set_building() {
447448
building = true;
448449
}
450+
451+
export function set_prerendering() {
452+
prerendering = true;
453+
}
449454
`;
450455
}
451456
}

packages/kit/src/runtime/server/index.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { set_private_env, set_public_env, set_safe_public_env } from '../shared-
33
import { options, get_hooks } from '__SERVER__/internal.js';
44
import { DEV } from 'esm-env';
55
import { filter_private_env, filter_public_env } from '../../utils/env.js';
6-
import { building } from '../app/environment.js';
6+
import { prerendering } from '__sveltekit/environment';
77

88
/** @type {ProxyHandler<{ type: 'public' | 'private' }>} */
99
const prerender_env_handler = {
@@ -47,8 +47,12 @@ export class Server {
4747
const private_env = filter_private_env(env, prefixes);
4848
const public_env = filter_public_env(env, prefixes);
4949

50-
set_private_env(building ? new Proxy({ type: 'private' }, prerender_env_handler) : private_env);
51-
set_public_env(building ? new Proxy({ type: 'public' }, prerender_env_handler) : public_env);
50+
set_private_env(
51+
prerendering ? new Proxy({ type: 'private' }, prerender_env_handler) : private_env
52+
);
53+
set_public_env(
54+
prerendering ? new Proxy({ type: 'public' }, prerender_env_handler) : public_env
55+
);
5256
set_safe_public_env(public_env);
5357

5458
if (!this.#options.hooks) {

packages/kit/src/types/ambient.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,16 @@ declare module '__sveltekit/environment' {
8686
* SvelteKit analyses your app during the `build` step by running it. During this process, `building` is `true`. This also applies during prerendering.
8787
*/
8888
export const building: boolean;
89+
/**
90+
* True during prerendering, false otherwise.
91+
*/
92+
export const prerendering: boolean;
8993
/**
9094
* The value of `config.kit.version.name`.
9195
*/
9296
export const version: string;
9397
export function set_building(): void;
98+
export function set_prerendering(): void;
9499
}
95100

96101
/** Internal version of $app/paths */

packages/kit/src/types/internal.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ export interface ServerModule {
2727
}
2828

2929
export interface ServerInternalModule {
30-
set_building(building: boolean): void;
3130
set_assets(path: string): void;
31+
set_building(): void;
32+
set_prerendering(): void;
3233
set_private_env(environment: Record<string, string>): void;
3334
set_public_env(environment: Record<string, string>): void;
3435
set_safe_public_env(environment: Record<string, string>): void;

packages/kit/test/apps/options/source/hooks.server.js

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
import { env } from '$env/dynamic/private';
2+
3+
// this verifies that dynamic env vars can be read during analysis phase
4+
// (it would fail if this app contained prerendered routes)
5+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
6+
const FOO = env.FOO;
7+
18
/** @type {import('@sveltejs/kit').Handle} */
29
export function handle({ event, resolve }) {
310
return resolve(event, {

packages/kit/types/index.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -2192,11 +2192,16 @@ declare module '__sveltekit/environment' {
21922192
* SvelteKit analyses your app during the `build` step by running it. During this process, `building` is `true`. This also applies during prerendering.
21932193
*/
21942194
export const building: boolean;
2195+
/**
2196+
* True during prerendering, false otherwise.
2197+
*/
2198+
export const prerendering: boolean;
21952199
/**
21962200
* The value of `config.kit.version.name`.
21972201
*/
21982202
export const version: string;
21992203
export function set_building(): void;
2204+
export function set_prerendering(): void;
22002205
}
22012206
22022207
/** Internal version of $app/paths */

0 commit comments

Comments
 (0)