When setting prerender to auto, $env/dynamic/public contains build-time environment variables
lovasoa opened this issue · comments
Describe the bug
$env/dynamic/public
is supposed to contain the environment variables set at runtime.
However, when setting export const prerender = 'auto'
, it contains static build-time environment variable values instead.
Reproduction
src/routes/+page.js
export const prerender = 'auto';
export const ssr = false;
src/routes/+page.svelte
<script>
import { env } from '$env/dynamic/public';
</script>
{JSON.stringify(env)}
build & run
/tmp/bug-env-app via v16.20.2
❯ PUBLIC_XXX='I am the build-time value' npm run build
[...] ✓ built in 1.54s
/tmp/bug-env-app via v16.20.2
✦ ❯ PUBLIC_XXX='I am the runtime value' PORT=8484 node build &
[1] 1272893
Listening on 0.0.0.0:8484
/tmp/bug-env-app via v16.20.2
✦ ❯ curl http://localhost:8484
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="./favicon.png" />
<meta name="viewport" content="width=device-width" />
<link rel="modulepreload" href="./_app/immutable/entry/start.04cafb74.js">
<link rel="modulepreload" href="./_app/immutable/chunks/scheduler.e108d1fd.js">
<link rel="modulepreload" href="./_app/immutable/chunks/singletons.768d08d3.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.5f6f258b.js">
<link rel="modulepreload" href="./_app/immutable/chunks/index.7cf2deec.js">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
__sveltekit_17vb3pv = {
base: new URL(".", location).pathname.slice(0, -1),
env: {"PUBLIC_XXX":"I am the build-time value"}
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.04cafb74.js"),
import("./_app/immutable/entry/app.5f6f258b.js")
]).then(([kit, app]) => {
kit.start(app, element);
});
}
</script>
</div>
</body>
</html>
Logs
No response
System Info
System:
OS: Linux 6.2 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-11390H @ 3.40GHz
Memory: 2.56 GB / 15.36 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 16.20.2 - /usr/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 8.19.4 - /usr/bin/npm
pnpm: 8.6.3 - /usr/bin/pnpm
Browsers:
Chrome: 116.0.5845.187
npmPackages:
@sveltejs/adapter-auto: ^2.0.0 => 2.1.0
@sveltejs/adapter-node: ^1.3.1 => 1.3.1
@sveltejs/kit: ^1.20.4 => 1.25.0
svelte: ^4.0.5 => 4.2.0
vite: ^4.4.2 => 4.4.9
Severity
serious, but I can work around it
Additional Information
No response
This is the correct behaviour. The 'auto'
option is meant for dynamic pages such as /post/[id]
where the value of [id]
can change over time. It will prerender the pages with known values from entries or links it finds while crawling your app, but still SSR any unknown ID values (the long tail) instead of throwing a 404 immediately. If you disable SSR, it will be unable to server-side render the long tail in these cases.
In some cases you might want to prerender a route but also include it in the manifest (for example, with a route like /blog/[slug] where you want to prerender your most recent/popular content but server-render the long tail) — for these cases, there's a third option, 'auto':
https://kit.svelte.dev/docs/page-options#prerender
Admittedly, we can produce a dev time warning for this that could make it clearer.
Do you think this is a good behavior to keep ? I understand the logic from the point of view of the framework developer, but I doubt there is any case in which the application developer would want that. In my opinion, the correct behavior would be not to prerender pages that depend of runtime environment variables, instead of prerendering with incorrect (and potentially confidential) values for the variables. If the documentation says the values will be populated with runtime env variables, using build-time env variables instead is clearly a bug to me, whatever the situation.
Hello guys, I would like to contribute on this one
In my opinion, the correct behavior would be not to prerender pages that depend of runtime environment variables, instead of prerendering with incorrect (and potentially confidential) values for the variables.
Perhaps we can throw an error if a page is being prerendered with the runtime environment variables module? This would ensure expectations are aligned (that the env data will be static).
Hello guys, I would like to contribute on this one
Please feel free to submit a PR @baterson
@lovasoa @s3812497 Could you give me a hint on that please
I've been trying to understand the codebase but still couldn't figure it out what is the best place to put the bug fixing logic.
I checked postbuild/prerender
thought is a good place to start, maybe in a visit
call
But I couldn't find a convenient way to find out if module is using dynamic env variables, rather the reading it's file body.
But during
visit
files are compiled already so I can't check whether it was an import from $env/dynamic/
I also checked exports/vite
where prerender
is called and also could find a good way to solve the problem
kit/packages/kit/src/exports/vite/index.js
Line 763 in 6bfcff2
@baterson I haven't fleshed this out but maybe a check for state.prerendering
and public_env
in https://github.com/sveltejs/kit/blob/master/packages/kit/src/runtime/server/page/render.js could do the trick?
public_env
should be populated with runtime env variables and state.prerendering
should be true if we're currently prerendering the page (I may be wrong though)
It works, thanks! This is a good place to throw the Error. I'll open a PR after fixing falling tests
I'm not sure if we should throw an error in this case. Runtime variables can also be added at built time, for example you could set a node env variable in your Vercel project dashboard which is used at build time. So while yes, in some cases it's a mistake, it's also needed in other cases - so we can't just throw an error.
@dummdidumm @s3812497 Maybe show a Warning with the same message, instead of throwing the Error?
@s3812497 I've opened a PR. Haven't found a good place to add a test though
closed as duplicate of #10008
Did a bit of digging and found this older issue. I think just providing a warning might not be the solution we want.
See #10008 (comment)