Change favicon based on environment (dev, stage, or prod) in React

Viewed 560

I'm attempting to change favicons based on environments so that users know if they are on dev, stage, or prod.

Tutorials such as this one and this one usually show how to change favicons based on button push callbacks, and not by accessing env variables.

The react docs on custom env variables make it seem like this is achievable, but I'm not sure how to access the env variables in the index.html properly to conditionally change my favicon.

Below is my current attempt

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/app-icon.svg" id="favicon" />
 ...
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <script>

    //returns Uncaught ReferenceError: REACT_APP_APP_ENV is not defined
    console.log(REACT_APP_APP_ENV);
    //returns nothing
    console.log(PUBLIC_URL);
    //returns nothing
    console.log(process.REACT_APP_APP_ENV === 'dev' ? 'yep!' : 'nope!');
    //returns nothing
    console.log(process.PUBLIC_URL)

    const getFaviconEl = () => {
      return document.getElementById("favicon");
    }

    const getFaviconByEnv = (env) => {
      const favicon = getFaviconEl();
      switch (env) {
        case 'dev':
          favicon.href = "%PUBLIC_URL%/app-icon.svg"
        case 'prod':
          favicon.href = "%PUBLIC_URL%/app-icon-prod.svg"
        case 'stage':
          favicon.href = "%PUBLIC_URL%/app-icon-stage.svg"
        default:
          "%PUBLIC_URL%/app-icon.svg";
      }
    };
    getFaviconByEnv(process.REACT_APP_APP_ENV)
  </script>
  ...
</head>
2 Answers

React specific Solution

As you mentioned in your question, React has a neat feature that is Custom Environment Variables,

These environment variables can be useful for displaying information conditionally based on where the project is deployed or consuming sensitive data that lives outside of version control.

You can actually define a variable in env file and reference that in your title like so:

<link rel="icon" type="image/png" href={proccess.env.REACT_APP_MY_FAVICON_URL}>

you can also change the title of your site using this method:

<title>%REACT_APP_WEBSITE_NAME%</title>

This way you can define different titles for different envs like env.local, env.production e.t.c

General Solution

this solution assumes your develop and production urls are different

You can use the following logic:

let's say this is your favicon tag:

<link rel="icon" type="image/png" href="favicon.png">

to change it based on your env, use this in your JS:

if (location.hostname === "localhost" 
 || location.hostname === "127.0.0.1" 
 || location.hostname.search("local") != -1) {
    $("link[rel=icon]").attr("href", "favicon_dev.png");
} else {
    $("link[rel=icon]").attr("href", "favicon.png");
}

Note: the following test location.hostname.search("local") != -1 matches the local aliases like http://mywebsite.com.local. If you have troubles with this - read this. you can also just get the URL using window.location.href and condition by it

Here's how I achieved it:

<head>
  <meta charset="utf-8" />
   //href left blank; will be dynamically generated based on env 
  <link rel="icon" href="" id="favicon" />
 ...
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <script>
    const getFaviconEl = () => {
      return document.getElementById("favicon");
    }
    const getFaviconByEnv = (env) => {
      const favicon = getFaviconEl();

      switch (env) {
        //icons files public directory accessed with %PUBLIC_URL% prefix
        case 'prod':
          return favicon.href = "%PUBLIC_URL%/app-icon-prod.svg";
        case 'stage':
          return favicon.href = "%PUBLIC_URL%/app-icon-stage.svg";
        default:
        return favicon.href = "%PUBLIC_URL%/app-icon-dev.svg";
      }
    };
    //defined in .env file, where, in my case, the env names are changed to 'dev', 'stage', 'prod', or 'local'
    getFaviconByEnv('%REACT_APP_SOME_ENV_VARIABLE_DEFINED_IN_.ENV%')
  </script>
 ...
</head>
Related