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: