26

I am trying to inject some strings into the index.html of a Vite app (using vue3 template). In a vue-cli project for example we would have

<link rel="icon" href="<%= BASE_URL %>favicon.ico">

What is the Vite way to do that? (I know that BASE_URL is just '/' in this case. I am asking for the general solution) I would be fine with a solution that covers environment variables only, but it would be great to know an even more general solution that can use JS code as in

<title><%= htmlWebpackPlugin.options.title %></title>

And I would really appreciate a solution that doesn't require installing an npm package

v-moe
  • 1,203
  • 1
  • 8
  • 25
  • Can't affirm but on the Vite website it says: " URLs inside index.html are automatically rebased so there's no need for special %PUBLIC_URL% placeholders." https://vitejs.dev/guide/ – Dave Oct 18 '22 at 06:02

3 Answers3

20

Had to lower my expectations considerably:

  1. I install a package
  2. I "cheat" and use process.env
// vite.config.js
import vue from '@vitejs/plugin-vue'

import { loadEnv } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'

export default ({ mode }) => {
  const env = loadEnv(mode, process.cwd())
  return {
    plugins: [
      vue(),
      createHtmlPlugin({
        minify: true,
        inject: {
          data: {
            title: env.VITE_MY_FOO,
          }
        }
      }),
    ],
  }
}

then in .env

VITE_MY_FOO="Hello vite ejs"

and in index.html

<title><%= title %></title>

Can't say I like it, but it works

Bob Fanger
  • 28,949
  • 7
  • 62
  • 78
v-moe
  • 1,203
  • 1
  • 8
  • 25
  • 1
    Surprised to see that Vite doesn't have this pretty basic feature that its competitors (Create React App, Vue CLI, etc.) all have. – V. Rubinetti Nov 06 '22 at 17:42
  • 1
    `createHtmlPlugin({ inject: { data: env } })` also works as a terser syntax if you want to have access to all your env variables (I usually do). – V. Rubinetti Dec 13 '22 at 20:28
17

Update 2023-03-20:

Vite supports HTML Env replacement out of the box starting with version 4.2! So if that's all you're looking for, you should be set.


Older answer:

Wanted to do the same for a project. Used vite-plugin-html for a bit, but I ran into an issue with the plugin and the author of the plugin seems to have stopped maintaining it, so I had to look into an alternative solution.

Luckily this is easy enough, as Vite has a hook for it.

So I ended up writing this tiny plugin:

const transformHtmlPlugin = data => ({
    name: 'transform-html',
    transformIndexHtml: {
        enforce: 'pre',
        transform(html) {
            return html.replace(
                /<%=\s*(\w+)\s*%>/gi,
                (match, p1) => data[p1] || ''
            );
        }
    }
});

In the Vite config, just add it to the plugins array and pass it key/value pairs of things you'd like to be replaced in the HTML:

plugins: [transformHtmlPlugin({ key: 'value' })]

Then in your index.html, add the tags like in the original question: <%= key %>, and they will be replaced by whatever you passed into the plugin.

If you wanted to pass in all of your env variables, get them using loadEnv (example is in v-moe's post) and just unpack the object: transformHtmlPlugin({ ...env }).

So that's how I solved my issue. Maybe it's useful to someone out there!

Brother Woodrow
  • 6,092
  • 3
  • 18
  • 20
1

The previous answers work fine until you set some env variables into a href of a link and bump. You got this error when building

error during build:
URIError: URI malformed

I don't find any concrete solution for this problem, so I think of a workaround like this. Instead of using % (or /%) in href, I use k instead (the key here is to use something that doesn't lead to the bug above). Here is my demo

In the html

<link ref="_k_VITE_PUBLIC_URL_k_"" />

In vite.config.ts

import { defineConfig, loadEnv } from "vite";
import { visualizer } from "rollup-plugin-visualizer";

export default defineConfig(({ mode }) => {
    process.env = {...process.env, ...loadEnv(mode, process.cwd())};
    // import.meta.env.VITE_NAME available here with: process.env.VITE_NAME

    const htmlPlugin = () => {
        return {
            name: "html-transform",
            transformIndexHtml(html: string) {
                // notice the regex pattern below
                return html.replace(/_k_(.*?)_k_/g, function (match, p1) {
                    return process.env[p1] ?? '';
                });
            },
        };
    };

    return {
        plugins: [
            htmlPlugin(),
            visualizer(),
        ],
    };
});

And in the .env

VITE_PUBLIC_URL = "http://your-url.com"

Hope it helps.

khoi nguyen
  • 416
  • 3
  • 7