From 4738a3215090e2fb5e38d8f84bc69454b1aa3062 Mon Sep 17 00:00:00 2001 From: Shinya Fujino Date: Fri, 6 Nov 2026 16:44:36 +0900 Subject: [PATCH] fix(deploy): keep local .env values out of native framework Worker bundles `void deploy --platform cloudflare` bundles a framework's Worker output with Vite once more before uploading it. That build used the project root as its env directory, so Vite read the local `.env` and put every `VITE_*` value from it into `import.meta.env`, including keys that `env.ts` does not declare. A SvelteKit D1 app keeps an installed `void/env` as an import in its server output, so this build is where that module's `import.meta.env` is replaced. The uploaded Worker then returned the local `.env` value for `env.VITE_*` keys that the build shell does not set, while the browser bundle used the schema default. Managed deploys bundle from `.void/bundle` and were not affected. The bundle now sets `envDir: false`, as documented: builds ignore client values from `.env`. Shell values still apply. Co-Authored-By: Claude Opus 5.5 --- packages/void/src/cli/cf-build-output.ts | 4 ++ .../void/test/unit/cf-build-output.test.ts | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/void/src/cli/cf-build-output.ts b/packages/void/src/cli/cf-build-output.ts index 316357f34..594aefaf2 100644 --- a/packages/void/src/cli/cf-build-output.ts +++ b/packages/void/src/cli/cf-build-output.ts @@ -554,6 +554,10 @@ async function prepareBundledBuildOutput(options: { configFile: false, root: options.projectRoot, publicDir: false, + // `.env` is local-only. The framework build drops its client values, but modules it left + // as imports (an installed `void/env` in a SvelteKit D1 app) are compiled here, and Vite + // would fill their `import.meta.env` from the project's `.env`. Shell values still apply. + envDir: false, logLevel: 'error', plugins: [additionalModulesPlugin()], // Like @cloudflare/vite-plugin: Worker conditions plus the build mode. A deploy diff --git a/packages/void/test/unit/cf-build-output.test.ts b/packages/void/test/unit/cf-build-output.test.ts index 0638abad6..c85ef6a01 100644 --- a/packages/void/test/unit/cf-build-output.test.ts +++ b/packages/void/test/unit/cf-build-output.test.ts @@ -800,6 +800,61 @@ it( CF_BUILD_TIMEOUT_MS, ); +it( + 'keeps local .env client values out of framework Worker output', + async () => { + const root = mkdtempSync(join(tmpdir(), 'void-cf-framework-env-test-')); + roots.push(root); + const output = join(root, 'framework'); + mkdirSync(output); + writeFileSync(join(root, 'package.json'), JSON.stringify({ type: 'module' })); + writeFileSync( + join(root, 'wrangler.json'), + JSON.stringify({ + name: 'void-framework-test', + account_id: 'account-id', + main: 'framework/_worker.js', + compatibility_date: '2026-09-29', + assets: { directory: 'framework', binding: 'ASSETS' }, + }), + ); + writeFileSync(join(root, '.env'), 'VITE_ORIGIN=http://localhost:5173\n'); + vi.stubEnv('VITE_SHELL_ORIGIN', 'https://shell.example.com'); + // Reads Vite's env object as a whole, like an installed void/env that the framework build + // left as an import. + const reader = join(root, 'node_modules/env-reader'); + mkdirSync(reader, { recursive: true }); + writeFileSync( + join(reader, 'package.json'), + JSON.stringify({ name: 'env-reader', type: 'module', exports: './index.js' }), + ); + writeFileSync(join(reader, 'index.js'), 'export const values = import.meta.env;\n'); + writeFileSync( + join(output, '_worker.js'), + "import { values } from 'env-reader';\n" + + 'export default { fetch() { return Response.json(values) } };\n', + ); + writeFileSync(join(output, '.assetsignore'), '_worker.js\n'); + + await withPrepared( + prepareCfFrameworkBuildOutput({ + projectRoot: root, + configPath: join(root, 'wrangler.json'), + accountId: 'account-id', + }), + async (prepared) => { + const bundle = readFileSync( + join(getWorkerBundleDir(prepared.directory), 'index.js'), + 'utf8', + ); + expect(bundle).toContain('https://shell.example.com'); + expect(bundle).not.toContain('http://localhost:5173'); + }, + ); + }, + CF_BUILD_TIMEOUT_MS, +); + it( 'accepts a nested hashed Worker entry with a relative module import', async () => {