A demo project for vite-envs
This is a starter setup to demonstrate how to set up vite-envs
in a Vite
/TypeScript
/Docker
WebApp.
Declare the variables that your app will accept.
.env
(Should be added to Git, if your .env
is gitignored you can use another file)
TITLE=Default title
DESCRIPTION=
Set the values for your dev environment.
.env.local
(Should be gitignored, it can also be the .env
file if you decided to use another file for declaring your variables)
TITLE=Custom title
DESCRIPTION="Custom description"
src/main.tsx
console.log(`The title of the page is ${import.meta.env.TITLE}`);
index.html
<!doctype html>
<html lang="en">
<head>
<!-- ... -->
<title>%TITLE%</title>
<meta name="description" content="%DESCRIPTION%">
</head>
Optionally, define computed variables.
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteEnvs } from 'vite-envs'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
viteEnvs({
computedEnv: async ({ resolvedConfig, env, envLocal }) => {
const path = await import('path')
const fs = await import('fs/promises')
const packageJson = JSON.parse(
await fs.readFile(
path.resolve(__dirname, 'package.json'),
'utf-8'
)
)
// Here you can define any arbitrary values they will be available
// in `import.meta.env` and it's type definitions.
// You can also compute defaults for variable declared in `.env` files.
return {
BUILD_TIME: Date.now(),
VERSION: packageJson.version
}
}
})
]
})
Run build and run your docker image with environment variables.:
docker build -t garronej/vite-envs-starter:main .
docker run -it -p 8083:8080 \
--env TITLE='Title from container env' \
--env DESCRIPTION='Description from container env' \
garronej/vite-envs-starter:main
Reach http://localhost:8083 🚀.
Here are listed the configurations that diverges from a vanilla Vite/Docker setup.
package.json
"devDependencies": {
+ "vite-envs": "^3.5.4",
}
vite.config.ts
import { defineConfig } from 'vite'
+import { viteEnvs } from 'vite-envs'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ viteEnvs({
+ declarationFile: ".env"
+ })
]
})
package.json
"scripts": {
+ "postinstall": "vite-envs update-types",
"dev": "vite",
"build": "tsc && vite build"
}
npx vite-envs update-types
updates src/vite-envs.d.ts
to make TypeScript aware of the
environment variables you have declared in you .env
file.
This script is not strictly required it's just for a better development experience.
Dockerfile
# build environment
FROM node:20-alpine as build
WORKDIR /app
COPY package.json yarn.lock .env ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
# production environment
FROM nginx:stable-alpine
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf
WORKDIR /usr/share/nginx/html
COPY --from=build /app/dist .
-ENTRYPOINT sh -c "nginx -g 'daemon off;'"
+ENTRYPOINT sh -c "./vite-envs.sh && nginx -g 'daemon off;'"
.env
file gitignoredIf you don't want to add the .env
file to Git you can use another file
for declaring the variables names and default values.
vite.config.ts
import { defineConfig } from 'vite'
import { viteEnvs } from 'vite-envs'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
viteEnvs({
+ declarationFile: ".env.declaration"
})
]
})
If you use another file that .env
as your declaration files feel free to use the .env
file in place of the .env.local
file.
Caveats: Enabling EJS requires to have Node available in you Docker container this will add an extra 20MB to your docker image size. Be also aware that it won't work if you use other vite plugin that transform the
index.html
.
For some usecases placeholder substitution like %FOO%
in the index.html
is not enough.
vite-envs
let you use EJS expressions in your index.html
file.
This enables you to generate different HTML based on the environment variables values.
This is useful if you want to perform operation like the following:
``html
💡: YAML.parse() is also available in the EJS global scope if you need it.
To enable this feature:
vite.config.ts
import { defineConfig } from 'vite'
import { viteEnvs } from 'vite-envs'
export default defineConfig({
plugins: [
viteEnvs({
+ indexAsEjs: true
})
]
})
Dockerfile
# production environment
FROM nginx:stable-alpine
+RUN apk add --update nodejs npm
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf
WORKDIR /usr/share/nginx/html
COPY --from=build /app/dist .
+RUN npm i -g vite-envs@`node -e 'console.log(require("./.vite-envs.json").version)'`
-ENTRYPOINT sh -c "./vite-envs.sh && nginx -g 'daemon off;'"
+ENTRYPOINT sh -c "npx vite-envs && nginx -g 'daemon off;'"
Warning
vite-envs does not provide a great solution for accessing your env variables from your service worker files at the moment. I have to work on that. The solution below is a workaround that you'll have to adapt to make it work in dev mode. Please open an issue if it's a deal breaker for you, I'll prioritize working on it.
You can use the dist/swEnv.js
file generated by vite-envs
to access your env from your service worker.
Assuming you have my-worker.js
files that get copied over to your dist/
directory you can do:
// Adjust the argument depending on where is the swEnv.js relative to your
// service worker file in the final distribution.
importScripts("swEnv.js");
self.__VITE_ENVS.MY_VAR;
It can be challenging to define some values in the .env files due to the lack of escaping capabilities.
Especially when you need to use a combination of "
, '
and #
characters.
To tackle this cases vite-envs enable you to passes your envs as b64 values like:
.env
or .env.local
FOO="vite-envs:b64Decode(VmFsdWUgb2YgRk9P)" # In your code `import.meta.env.FOO will === "Value of FOO"`
There's nothing else you need to know to start using vite-envs
, however if you're interested,
here are some instruction that you can follow to publish your Docker image on DockerHub with GitHub Actions
and deploying the image using Railway, all for Free.
👉 Step by step Guide.
This starter comes with a fully generic CI workflow that
publishes the Docker image of your Vite App of DockerHub automatically.
You can copy past the ci.yaml
file into your repo, there is nothing to change.
It will publish the Docker image <your github username>/<your vite repo name>
.
To enable it simply create two GitHub secrets:
DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
To trigger the workflow just bump the version number in the package.json
and push!