fix: keep vite out of the $app/env runtime validator#15953
Conversation
🦋 Changeset detectedLatest commit: e32358b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
691d402 to
978edfb
Compare
`@sveltejs/kit/internal/env` runs at server startup but imported `stackless` from `exports/vite/utils.js`, which imports `vite` — pulling Vite into the production server bundle and breaking deploys that compile/bundle the server without `node_modules` (e.g. `bun build --compile`). Move `stackless` to a dependency-free `utils/stackless.js` (re-exported from the vite utils so build-time callers are unchanged) and add a regression test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
978edfb to
2814641
Compare
| import { negotiate } from '../../utils/http.js'; | ||
| import { filter_env } from '../../utils/env.js'; | ||
| import { escape_html } from '../../utils/escape.js'; | ||
| import { stackless } from '../../utils/stackless.js'; |
There was a problem hiding this comment.
Can we avoid the re-export and instead change the files to import directly?
There was a problem hiding this comment.
Is it possible to rename this to error.js if there isn’t one already?
teemingc
left a comment
There was a problem hiding this comment.
We might need a changeset now. Explicit env vars was just released
Addresses review feedback: drop the re-export from exports/vite/utils.js and import `stackless` directly from utils/stackless.js in exports/vite/index.js. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- merge stackless into the existing utils/error.js (per review) and import it directly from there; delete the standalone utils/stackless.js - harden the regression test to follow @sveltejs/kit/* self-imports, so a Vite pull reaching internal/env *through* @sveltejs/kit/internal can't slip past - add the patch changeset (explicit env vars is now released) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @teemingc, all addressed in the latest commits:
One extra thing: since |
|
Thank you so much! I’ll have another look once I can get to my laptop if another maintainer doesn’t beat me to it |
There was a problem hiding this comment.
I'll let other maintainers weigh in on this but I wonder if this should just be a custom ESLint rule -- we typically shouldn't be importing from the vite folder in other places in the first place.
There was a problem hiding this comment.
This hit me while working on another PR too. Might be worth adding one. We already have one for kit internals
There was a problem hiding this comment.
It'd probably be better than adding it as a test because it'd give us much broader coverage
There was a problem hiding this comment.
I agree. I tried to build this just now but I don't have the patience to coax ESLint into doing something useful. (I don't think I'd run pnpm eslint 'packages/kit/src/**/*.js' locally before just now; hooboy is it slow. We really should switch to Oxlint if we can.)
For now I'll remove this test so that we can fix the immediate issue but we should definitely follow this up
Problem
Enabling explicit environment variables (
experimental.explicitEnvironmentVariables) pulls Vite into the production server runtime, which breaks any deployment that compiles or bundles the server into a self-contained artifact withoutnode_modules.The runtime env validator
@sveltejs/kit/internal/envruns at server startup —Server.init()→set_env()→validate()/handle_issues(). It importsstacklessfromexports/vite/utils.js, whose top-level imports includeimport { loadEnv } from 'vite'. So importing the validator drags all of Vite into the server bundle.Concretely, compiling the SvelteKit server to a standalone binary with
bun build --compile:import("esbuild")(esbuild is an optional peer of Vite 8), andnew URL('../../package.json', import.meta.url), which resolves to/package.jsoninside the compiled binary's virtual filesystem →ENOENT.This very likely also affects pruned production runtimes (e.g.
adapter-nodedeployed withnpm ci --omit=dev), where Vite — a build-time/dev dependency — isn't installed but the runtime tries to import it.Fix
stacklessis a tiny, dependency-free helper (it just creates anErrorwith no stack trace). Move it tosrc/utils/stackless.jsand import it from there ininternal/env.js.exports/vite/utils.jsre-exports it, so the build-time caller (exports/vite/index.js) is unchanged. This removes Vite from the runtime env validator's import graph entirely.Test
Adds
packages/kit/src/exports/internal/env.spec.js, which statically walks the import graph ofinternal/env.js(viaacorn) and asserts it reaches neithervitenor any module underexports/vite/. It fails onmain(internal/env.js → ../vite/utils.js → vite) and passes with this change.main, passes here).