hrgui
5/9/2024

Vite and its environment variables

When Vite will not statically replace environment variables

Input

import "./App.css";

function App() {
  return (
    <>
      <div>A: {import.meta.env.VITE_A}</div>
    </>
  );
}

export default App;
  • Important:
  • There is no .env file.
  • VITE_A is not defined in the environment.

Output

var Rd = { BASE_URL: "/", MODE: "production", DEV: !1, PROD: !0, SSR: !1 };
function Od() {
  return (
    el.useState(0),
    St.jsx(St.Fragment, {
      children: St.jsxs("div", { children: ["A: ", Rd.VITE_A] }),
    })
  );
}

Note that anything that was in import.meta.env and anything that was prefixed with VITE_ will be in the Rd var. It won’t get every single variable in process.env, which would be dangerous!

Unless you make it do so, but I will not be writing any of that code as that is a bad practice.

When Vite will statically replace env variables

Input

Either VITE_A is defined prior to running the build

VITE_A=foo yarn build

OR

VITE_A is defined within a .env file.

VITE_A="foo"
import "./App.css";

function App() {
  return (
    <>
      <div>A: {import.meta.env.VITE_A}</div>
    </>
  );
}

export default App;

Output

function Rd() {
  return St.jsx(St.Fragment, {
    children: St.jsxs("div", { children: ["A: ", "foo"] }),
  });
}

Why is this distinction important?

This can be used for removing code. Suppose we have the following example:

Input

config.js

export const isDevToolsEnabled = () => import.meta.env.VITE_DEVTOOLS === "1";

App.jsx

import { DevTools } from "./DevTools";
import { isDevToolsEnabled } from "./config";

function App() {
  return <>{isDevToolsEnabled() && <DevTools />}</>;
}

export default App;

Devtools.jsx

export function DevTools() {
  return <div>Imagine if this was some fancy devtools</div>;
}

Output

  • This is VITE_DEVTOOLS is never defined
function Rd() {
  return Wn.jsx("div", { children: "Imagine if this was some fancy devtools" });
}
var Od = { BASE_URL: "/", MODE: "production", DEV: !1, PROD: !0, SSR: !1 };
const Dd = () => Od.VITE_DEVTOOLS === "1";
function Md() {
  return Wn.jsx(Wn.Fragment, { children: Dd() && Wn.jsx(Rd, {}) });
}
Wl.createRoot(document.getElementById("root")).render(
  Wn.jsx(gc.StrictMode, { children: Wn.jsx(Md, {}) })
);

Notice how Od doesn’t have VITE_DEVTOOLS, but it includes the entire import.meta.env - and also includes <DevTools /> in Rd.

  • This is VITE_DEVTOOLS defined as "" in a .env file:
VITE_DEVTOOLS=""
const Rd = () => !1;
function Od() {
  return zr.jsx(zr.Fragment, { children: Rd() });
}

Now, what if isDevToolsEnabled wasn’t a function?

export const isDevToolsEnabled = import.meta.env.VITE_DEVTOOLS === "1";

then…

the output becomes

const Rd = !1;
function Od() {
  return zr.jsx(zr.Fragment, { children: Rd });
}

Which is fine… but it doesn’t always work that way.

Now do this in Vue.

Input

Let’s suppose we use Vue instead of React.

Here’s another example.

App.vue

<script setup>
import DevTools from "./components/DevTools.vue";
import { isDevToolsEnabled } from "./config";
</script>

<template>Some text here: <DevTools v-if="isDevToolsEnabled" /></template>

DevTools.vue

<template>
  <div>Imagine if this was some fancy devtools</div>
</template>

config.js

export const isDevToolsEnabled = import.meta.env.VITE_DEVTOOLS === "1";

Output

  • Without VITE_DEVTOOLS defined
function qo(e, t) {
  return St(), lr("div", null, "Imagine if this was some fancy devtools");
}
const zo = Ko(Wo, [["render", qo]]);
var Go = { BASE_URL: "/", MODE: "production", DEV: !1, PROD: !0, SSR: !1 };
const Jo = Go.VITE_DEVTOOLS === "1",
  Yo = {
    __name: "App",
    setup(e) {
      return (t, n) => (
        St(),
        lr(
          pe,
          null,
          [
            ar("Some text here: "),
            Ns(Jo) ? (St(), cr(zo, { key: 0 })) : so("", !0),
          ],
          64
        )
      );
    },
  };
Uo(Yo).mount("#app");

Notice the variable Go, notice qo is our DevTools… so it’ll still include DevTools by default if VITE_DEVTOOLS env var is not defined.

Now suppose if it was defined to VITE_DEVTOOLS=""

function qo(e, t) {
  return St(), lr("div", null, "Imagine if this was some fancy devtools");
}
const zo = Ko(Wo, [["render", qo]]),
  Go = !1,
  Jo = {
    __name: "App",
    setup(e) {
      return (t, n) => (
        St(),
        lr(
          pe,
          null,
          [
            ar("Some text here: "),
            Ns(Go) ? (St(), cr(zo, { key: 0 })) : so("", !0),
          ],
          64
        )
      );
    },
  };

That ain’t good! It’s <DevTools /> is still there! How do we get rid of it in the bundle?

Now suppose if we inlined the isDevToolsEnabled var instead:

<script setup>
import DevTools from "./components/DevTools.vue";

const isDevToolsEnabled = import.meta.env.VITE_DEVTOOLS === "1";
</script>

<template>Some text here: <DevTools v-if="isDevToolsEnabled" /></template>

Output

const Ko = {
  __name: "App",
  setup(e) {
    return (t, n) => (
      rr(), Qi(pe, null, [cr("Some text here: "), so("", !0)], 64)
    );
  },
};
Vo(Ko).mount("#app");

Key Takeaways

  • Always define VITE_* environment variables, otherwise the output in Vite is always going to be something like this:
var Go = { BASE_URL: "/", MODE: "production", DEV: !1, PROD: !0, SSR: !1 };
const Jo = Go.VITE_DEVTOOLS === "1";

This makes it very difficult for code to be removed if the environment variable is not defined.

  • For Vue, it’s always best to inline environment variable checks. It makes it easier to statically replace.

For example:

Instead of doing this:

App.vue

<script setup>
import DevTools from "./components/DevTools.vue";
import { isDevToolsEnabled } from "./config";
</script>

<template>Some text here: <DevTools v-if="isDevToolsEnabled" /></template>

DevTools.vue

<template>
  <div>Imagine if this was some fancy devtools</div>
</template>

config.js

export const isDevToolsEnabled = import.meta.env.VITE_DEVTOOLS === "1";

It should be:

<script setup>
import DevTools from "./components/DevTools.vue";

const isDevToolsEnabled = import.meta.env.VITE_DEVTOOLS === "1";
</script>

<template>Some text here: <DevTools v-if="isDevToolsEnabled" /></template>

This will make sure <DevTools /> is not included if VITE_DEVTOOLS is a value other than "".

hrgui

Harman Goei (hrgui) is a developer that loves to make cool and awesome web applications. His strength is in HTML, CSS, JavaScript, but he is willing to code anywhere in the stack to make the web be awesome.

© 2024 Harman Goei