Inject Environment Variables into index.html file in Vite
While we can easily import and use .env
values in our JS/TS files, Vue
<script>
etc. in Vite, there isn’t exactly a
straightforward way to inject these values in our index.html
file since we
cannot directly access import.meta.env
in that file.
Let’s say we have an .env
file from which we need to access a specific
variable value and use it in a <meta>
property or maybe a script
tag where
the api key needs to be appended to src
url.
For Example,
.env
file:
VITE_API_KEY=foo
index.html
file:
<meta name="SOME_THIRD_PARTY" content="foo" />
<script src="https://awesomethirdparty.library/v1/script.js?VITE_API_KEY=foo"></script>
<!-- or a <div data-xyz-api-key="foo"> somewhere in the html file -->
Method 1: Using Vite Plugin API
Vite.js comes with a highly configurable
plugin API system. Let’s create a
custom vite plugin that utilises
transformIndexHtml
hook which gives us access to contents of index.html
file as string. We’ll
also use loadEnv
function from vite to load the required .env
file and access its values in our
custom plugin.
Also note the prefix VITE_
to our environment variables, by default vite
will only return the environment variables prefixed with VITE_
you can
customise that (not recommended) using
envPrefix config.
In the index.html
file let’s add a placeholder text that is unique across our
html file and can be replaced easily with
String.prototype.replace()
in our custom vite plugin.
index.html
file:
<meta name="SOME_THIRD_PARTY" content="$API_KEY_PLACEHOLDER" />
<script src="https://awesomethirdparty.library/v1/script.js?API_KEY=$API_KEY_PLACEHOLDER"></script>
<!-- or a <div data-xyz-api-key="$API_KEY_PLACEHOLDER"> somewhere in the html file -->
Let’s create an injectHtml.ts
file in the root of the project directory. (you
also might need to add this files into include
array in your
tsconfig.node.json
file if you’re using Typescript)
injectHtml.ts
:
import type { PluginOption } from "vite";
import { loadEnv } from "vite";
export const injectEnvIntoHtmlPlugin = (): PluginOption => {
const env = loadEnv("production", ".");
return {
name: "inject-env-html",
transformIndexHtml(html: string) {
return html.replace("$API_KEY_PLACEHOLDER", env["VITE_API_KEY"]);
},
};
};
tsconfig.node.json
file:
{
"compilerOptions": {
//...
},
"include": ["vite.config.ts", "injectHtml.ts"]
}
Add the plugin to vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { injectEnvIntoHtmlPlugin } from "./injectHtml";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), injectEnvIntoHtmlPlugin()],
});
If we run the vite server and check index.html file in the browser:
Note: loadEnv
only
returns env values prefixed with VITE_
and also since we are using
.env
as the name for
our environment variable file it’s loaded into both production
and
development
modes vite is running in and you might want to change based on
your requirement.
Method 2: Teleport/Portal into index.html
We can utilise frameworks
Teleport
(Portal in react) to easily insert html
content anywhere in the index.html with a selector
. First we load the required
env value into our script
and then use teleport to inject it into the html.
<script setup lang="ts">
const apiKey = import.meta.env.VITE_API_KEY;
</script>
<template>
<Teleport to="head">
<meta name="SOME_THIRD_PARTY" :content="apiKey" />
</Teleport>
<!-- you could also document.getElementById and appendChild instead of Teleport at this point -->
</template>
Drawbacks of this approach is your api key won’t be available on initial page
load (i.e here the meta
tag with apiKey
would be loaded into html only
after vue is loaded and initialised). Also at this point instead of Teleport you
could also just document.getElementById
or document.querySelector
in your
framework and inject the apiKey
too.
Method 3: vite-plugin-html-env
Using vite-plugin-html-env, this works similar to Method 1. Just install the plugin and add a comment in index.html file that includes .env KEY.
yarn add -D vite-plugin-html-env
vite.config.ts
:
import VitePluginHtmlEnv from "vite-plugin-html-env";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [VitePluginHtmlEnv(), vue()],
});
index.html
:
<meta name="SOME_THIRD_PARTY" content="<{ VITE_API_KEY }>" />
Update Vite 4.2 and above
Since
Vite 4.2,
this feature is supported
natively and
we can use %VITE_API_KEY%
syntax in our HTML.
Further Reading / References: