diff --git a/docs/pages/blog/vike-server/+Page.mdx b/docs/pages/blog/vike-server/+Page.mdx index 2dad7c053ab..3c8725407ec 100644 --- a/docs/pages/blog/vike-server/+Page.mdx +++ b/docs/pages/blog/vike-server/+Page.mdx @@ -1,4 +1,4 @@ -import { Link } from '@brillout/docpress' +import { Link, ImportMeta } from '@brillout/docpress' import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' import '../../../components/tabs.css' import { BlogHeader } from '../BlogHeader' @@ -8,7 +8,7 @@ import { BlogHeader } from '../BlogHeader' We (Joël, Dani, and Rom) have been working on a new Vike extension `vike-server` which can integrate Vite with any server (Express.js, Hono, Fastify, Elysia, H3, ...) and any deployment (VPS, Netlify, Cloudflare, Vercel, ...). With `vike-server` you get: - - Server code **transpiled by Vite** (say goodbye to `ts-node`/`tsx`/`vavite` and hello to Vite utilities such as `import.meta.env`) + - Server code **transpiled by Vite** (say goodbye to `ts-node`/`tsx`/`vavite` and hello to Vite utilities such as ) - **Zero-config** (Vike is automatically added to your server) - **HMR** (no more full server reloads) diff --git a/docs/pages/env/+Page.mdx b/docs/pages/env/+Page.mdx index a97bf9bd9d2..0e456e9fd50 100644 --- a/docs/pages/env/+Page.mdx +++ b/docs/pages/env/+Page.mdx @@ -43,7 +43,7 @@ DATABASE_URL=postgresql://database.example.com:5432 ## Access -Use `import.meta.env` to access environment variables. +Use to access environment variables. ```ts // /pages/movies/+data.ts @@ -79,12 +79,12 @@ function ContactUs() { > Keep in mind that {'import.meta.env.SOME_ENV'} is statically replaced: > ```ts +> // ✅ Works +> import.meta.env.SOME_ENV > // ❌ Won't work > import.meta.env['SOME_ENV'] > // ❌ Won't work > const { SOME_ENV } = import.meta.env -> // ✅ Works -> import.meta.env.SOME_ENV > ``` @@ -102,7 +102,7 @@ For improved DX, consider using [`zod`](https://github.com/colinhacks/zod), for For better [tree shaking](https://rollupjs.org/introduction/#tree-shaking) (aka dead code elimination), `import.meta.env.SOME_ENV` is statically replaced with its value. For example: ```js -// src/someFile.js [source code in Git repository] +// src/someFile.js [source code in your Git repository] console.log('value:', import.meta.env.DISABLE_TRACKING) @@ -128,14 +128,14 @@ console.log("value:", "true"); console.log("Tracking is disabled"); ``` -Note how the `import()` is completely removed, resulting in more lightweight production bundles. +Note how `import()` is completely removed, resulting in a more lightweight production bundle. ## Config files -In config files, [`import.meta.env` isn't available](https://github.com/vikejs/vike/issues/1726#issuecomment-2208626928) (neither `vite.config.js` nor `+config.js`). +In config files, [ isn't available](https://github.com/vikejs/vike/issues/1726#issuecomment-2208626928) (neither `vite.config.js` nor `+config.js`). -Use [`process.env`](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs) instead of `import.meta.env`. +Use [`process.env`](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs) instead of . ## Public allowlist diff --git a/packages/vike/src/node/vite/plugins/pluginReplaceConstantsEnvVars.ts b/packages/vike/src/node/vite/plugins/pluginReplaceConstantsEnvVars.ts index 2dd3e053b76..cb8ebbce656 100644 --- a/packages/vike/src/node/vite/plugins/pluginReplaceConstantsEnvVars.ts +++ b/packages/vike/src/node/vite/plugins/pluginReplaceConstantsEnvVars.ts @@ -14,6 +14,7 @@ import { getFilePathToShowToUserModule } from '../shared/getFilePath.js' import { normalizeId } from '../shared/normalizeId.js' import { isViteServerSide_extraSafe } from '../shared/isViteServerSide.js' import { getMagicString } from '../shared/getMagicString.js' +import pc from '@brillout/picocolors' const PUBLIC_ENV_PREFIX = 'PUBLIC_ENV__' const PUBLIC_ENV_ALLOWLIST = [ @@ -29,7 +30,7 @@ const PUBLIC_ENV_ALLOWLIST = [ // - Or stop using Vite's `mode` implementation and have Vike implement its own `mode` feature? (So that the only dependencies are `$ vike build --mode staging` and `$ MODE=staging vike build`.) // === Rolldown filter -const skipIrrelevant = 'import.meta.env.' +const skipIrrelevant = 'import.meta.env' const filterRolldown = { /* We don't do that, because vike-react-sentry uses import.meta.env.PUBLIC_ENV__SENTRY_DSN id: { @@ -118,6 +119,22 @@ function pluginReplaceConstantsEnvVars(): Plugin[] { magicString.replaceAll(new RegExp(regExpStr, 'g'), JSON.stringify(replacement)) }) + // Replace bare `import.meta.env` expression with `null` in the user-land. + // - Otherwise Vite replaces it with an object missing PUBLIC_ENV__ variables which is confusing for users. + // - We purposely don't support replacing `import.meta.env` with an object to incentivize users to write tree-shaking friendly code. + // - `define: { 'import.meta.env': JSON.stringify(null) }` doesn't work because it also replaces `import.meta.env` inside `import.meta.env.SONE_ENV` + const bareImportMetaEnvRegex = /\bimport\.meta\.env(?!\.)/g + const isUserLand = !id.includes('node_modules') && id.startsWith(config.root) // skip node_modules/ as well as linked dependencies + if (isUserLand && bareImportMetaEnvRegex.test(code)) { + assertWarning( + false, + `The bare ${pc.cyan('import.meta.env')} expression in ${getFilePathToShowToUserModule(id, config)} is replaced with ${pc.cyan('null')} — use ${pc.cyan('import.meta.env.SONE_ENV')} instead ${pc.underline('https://vike.dev/env')}`, + { onlyOnce: true }, + ) + bareImportMetaEnvRegex.lastIndex = 0 // Reset state after .test() since the /g flag makes the RegExp stateful + magicString.replaceAll(bareImportMetaEnvRegex, JSON.stringify(null)) + } + return getMagicStringResult() }, }, diff --git a/packages/vike/src/node/vite/plugins/pluginReplaceConstantsGlobalThis.ts b/packages/vike/src/node/vite/plugins/pluginReplaceConstantsGlobalThis.ts index 3ab34518da7..c2fba67272c 100644 --- a/packages/vike/src/node/vite/plugins/pluginReplaceConstantsGlobalThis.ts +++ b/packages/vike/src/node/vite/plugins/pluginReplaceConstantsGlobalThis.ts @@ -22,6 +22,8 @@ declare global { /** Like `import.meta.env.SSR` but works for `node_modules/` packages with `ssr.external` */ var __VIKE__IS_CLIENT: boolean var __VIKE__IS_DEBUG: boolean + /** Whether the code is processed by Vite, e.g. `true` when server code is `ssr.noExternal` */ + var __VIKE__NO_EXTERNAL: true | undefined } const VIRTUAL_FILE_ID_constantsGlobalThis = 'virtual:vike:server:constantsGlobalThis' @@ -55,6 +57,7 @@ function pluginReplaceConstantsGlobalThis(): Plugin[] { define: { 'globalThis.__VIKE__IS_DEV': JSON.stringify(isDev), 'globalThis.__VIKE__IS_DEBUG': JSON.stringify(isDebugVal), + 'globalThis.__VIKE__NO_EXTERNAL': 'true', }, } }, diff --git a/packages/vike/src/shared-server-client/route/abort.ts b/packages/vike/src/shared-server-client/route/abort.ts index fbbaba21046..de3917db7b5 100644 --- a/packages/vike/src/shared-server-client/route/abort.ts +++ b/packages/vike/src/shared-server-client/route/abort.ts @@ -265,13 +265,11 @@ function assertStatusCode(statusCode: number, expected: number[], caller: 'rende assert(import.meta.env.DEV === globalThis.__VIKE__IS_DEV) } else { assert(!isBrowser()) - if (import.meta.env) { + if (globalThis.__VIKE__NO_EXTERNAL) { assert(typeof globalThis.__VIKE__IS_DEV === 'boolean') assert(typeof globalThis.__VIKE__IS_CLIENT === 'boolean') assert(import.meta.env.SSR === true) assert(import.meta.env.DEV === globalThis.__VIKE__IS_DEV) - } else { - // import.meta.env isn't defined when 'vike' is ssr.external } }