Skip to content

Commit

Permalink
Expose environment variables also on import.meta.env (#8928)
Browse files Browse the repository at this point in the history
For compatability with webpack, and for consistency with node/server
environment we want to support reading env vars from `process.env`. But
we also want to support Vite's way of doing it, which is exposing them
on `import.meta.env`.

And this is a copy/paste from the code
```
// Vite can automatically expose environment variables, but we
// disable that in `buildFeServer.ts` by setting `envFile: false`
// because we want to use our own logic for loading .env,
// .env.defaults, etc
// The two object spreads below will expose all environment
// variables listed in redwood.toml and all environment variables
// prefixed with REDWOOD_ENV_
```

Note: This does not work for Vite's html `%%` replacement because of
vitejs/vite#13424
But we've got a separate PR that takes care of that in #8929
  • Loading branch information
Tobbe authored Jul 19, 2023
1 parent 7f4dbca commit 04fc76c
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 65 deletions.
1 change: 0 additions & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
"react": "18.3.0-canary-035a41c4e-20230704",
"react-server-dom-webpack": "18.3.0-canary-035a41c4e-20230704",
"vite": "4.4.4",
"vite-plugin-environment": "1.1.3",
"yargs-parser": "21.1.1"
},
"devDependencies": {
Expand Down
123 changes: 69 additions & 54 deletions packages/vite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import path from 'path'
import react from '@vitejs/plugin-react'
import type { ConfigEnv, UserConfig, PluginOption } from 'vite'
import { normalizePath } from 'vite'
import EnvironmentPlugin from 'vite-plugin-environment'

import { getWebSideDefaultBabelConfig } from '@redwoodjs/internal/dist/build/babel/web'
import { getConfig, getPaths } from '@redwoodjs/project-config'
Expand All @@ -29,6 +28,45 @@ export default function redwoodPluginVite(): PluginOption[] {
const relativeEntryPath = path.relative(rwPaths.web.src, clientEntryPath)

return [
{
name: 'redwood-plugin-vite-html-env',

// Vite can support replacing environment variables in index.html but
// there are currently two issues with that:
// 1. It requires the environment variables to be exposed on
// `import.meta.env`, but we expose them on `process.env` in Redwood.
// 2. There's an open issue on Vite where it adds extra quotes around
// the replaced values, which breaks trying to use environment
// variables in src attributes for example.
// Until those issues are resolved, we'll do the replacement ourselves
// instead using transformIndexHtml. Doing it this was was also the
// recommended way until Vite added built-in support for it.
//
// Extra quotes issue: https://github.com/vitejs/vite/issues/13424
// transformIndexHtml being the recommended way:
// https://github.com/vitejs/vite/issues/3105#issuecomment-1059975023
transformIndexHtml: {
// Setting order: 'pre' so that it runs before the built-in
// html env replacement.
order: 'pre',
handler: (html: string) => {
let newHtml = html

rwConfig.web.includeEnvironmentVariables.map((envName) => {
newHtml = newHtml.replaceAll(
`%${envName}%`,
process.env[envName] || ''
)
})

Object.entries(process.env).forEach(([envName, value]) => {
newHtml = newHtml.replaceAll(`%${envName}%`, value || '')
})

return newHtml
},
},
},
{
name: 'redwood-plugin-vite',

Expand Down Expand Up @@ -109,6 +147,36 @@ export default function redwoodPluginVite(): PluginOption[] {
process.env.REDWOOD_ENV_EDITOR
),
},
// Vite can automatically expose environment variables, but we
// disable that in `buildFeServer.ts` by setting `envFile: false`
// because we want to use our own logic for loading .env,
// .env.defaults, etc
// The two object spreads below will expose all environment
// variables listed in redwood.toml and all environment variables
// prefixed with REDWOOD_ENV_
...Object.fromEntries(
rwConfig.web.includeEnvironmentVariables.flatMap((envName) => [
[
`import.meta.env.${envName}`,
JSON.stringify(process.env[envName]),
],
[
`process.env.${envName}`,
JSON.stringify(process.env[envName]),
],
])
),
...Object.entries(process.env).reduce<Record<string, any>>(
(acc, [key, value]) => {
if (key.startsWith('REDWOOD_ENV_')) {
acc[`import.meta.env.${key}`] = JSON.stringify(value)
acc[`process.env.${key}`] = JSON.stringify(value)
}

return acc
},
{}
),
},
css: {
// @NOTE config path is relative to where vite.config.js is if you use relative path
Expand Down Expand Up @@ -190,20 +258,6 @@ export default function redwoodPluginVite(): PluginOption[] {
}
},
},
// Loading Environment Variables, to process.env in the browser
// This maintains compatibility with Webpack. We can choose to switch to import.meta.env at a later stage
EnvironmentPlugin('all', { prefix: 'REDWOOD_ENV_', loadEnvFiles: false }),
EnvironmentPlugin(
Object.fromEntries(
rwConfig.web.includeEnvironmentVariables.map((envName) => [
envName,
JSON.stringify(process.env[envName]),
])
),
{
loadEnvFiles: false, // to prevent vite from loading .env files
}
),
// -----------------
handleJsAsJsx(),
react({
Expand All @@ -213,44 +267,5 @@ export default function redwoodPluginVite(): PluginOption[] {
}),
},
}),
{
name: 'redwood-plugin-vite-html-env',

// Vite can support replacing environment variables in index.html but
// there are currently two issues with that:
// 1. It requires the environment variables to be exposed on
// `import.meta.env`, but we expose them on `process.env` in Redwood.
// 2. There's an open issue on Vite where it adds extra quotes around
// the replaced values, which breaks trying to use environment
// variables in src attributes for example.
// Until those issues are resolved, we'll do the replacement ourselves
// instead using transformIndexHtml. Doing it this was was also the
// recommended way until Vite added built-in support for it.
//
// Extra quotes issue: https://github.com/vitejs/vite/issues/13424
// transformIndexHtml being the recommended way:
// https://github.com/vitejs/vite/issues/3105#issuecomment-1059975023
transformIndexHtml: {
// Setting order: 'pre' so that it runs before the built-in
// html env replacement.
order: 'pre',
handler: (html: string) => {
let newHtml = html

rwConfig.web.includeEnvironmentVariables.map((envName) => {
newHtml = newHtml.replaceAll(
`%${envName}%`,
process.env[envName] || ''
)
})

Object.entries(process.env).forEach(([envName, value]) => {
newHtml = newHtml.replaceAll(`%${envName}%`, value || '')
})

return newHtml
},
},
},
]
}
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8261,7 +8261,6 @@ __metadata:
react-server-dom-webpack: 18.3.0-canary-035a41c4e-20230704
typescript: 5.1.6
vite: 4.4.4
vite-plugin-environment: 1.1.3
yargs-parser: 21.1.1
bin:
rw-dev-fe: ./dist/devFeServer.js
Expand Down Expand Up @@ -31289,15 +31288,6 @@ __metadata:
languageName: node
linkType: hard

"vite-plugin-environment@npm:1.1.3":
version: 1.1.3
resolution: "vite-plugin-environment@npm:1.1.3"
peerDependencies:
vite: ">= 2.7"
checksum: 225986450220bdc6b109be4d05deeb94013d41cc235fe3064bd6c5a1b33c047ba59cac3a34aa240ae735fee6a77ab9ce033053c5ab7c152497bd7136bd3f3a6d
languageName: node
linkType: hard

"vite@npm:4.4.4":
version: 4.4.4
resolution: "vite@npm:4.4.4"
Expand Down

0 comments on commit 04fc76c

Please sign in to comment.