3

I'm building a simple react app that I'm deploying to S3. I used's facebook's create-react-app as a starting point. I want to add a conditional in my index.html so that I'm only including Google Analytics in production.

To test that it's working I have code like this: (I intend to change the string below to 'production' once I validate that everything is working correclty)

<%= '%NODE_ENV%' %>
<% if ('%NODE_ENV%' == 'development') { %>
  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=XXX"></script>
<% } %>

When I load my app locally using npm run start. I see that it prints development on the page but that the Google Analytics script tag is NOT on the page. How is it possible that on my first line of webpack JS %NODE_ENV% is equal to 'development' and then on the very next line that condition fails??

Here's is the HTML that is output locally:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
    development

  <script type="text/javascript" src="/static/js/bundle.js"></script></body>
</html>

As you can see it prints 'development' but then has an empty line where the script tag would have gone had the condition passed.

I'm new to webpack and I'm very confused about this behavior. Any help would be much appreciated!

Adam Langsner
  • 1,276
  • 1
  • 15
  • 23
  • can you share your `package.json` , which version of webpack are you using – Aaqib Apr 13 '18 at 14:57
  • here's the relevant lines from my package.json: `"html-webpack-plugin": "2.29.0", "extract-text-webpack-plugin": "3.0.2", "case-sensitive-paths-webpack-plugin": "2.1.1", "webpack": "3.8.1", "webpack-dev-server": "2.9.4", "webpack-manifest-plugin": "1.3.2", "sw-precache-webpack-plugin": "0.11.4",` – Adam Langsner Apr 13 '18 at 15:01
  • not sure how to do newlines in SO comments. sorry for the mess in there. – Adam Langsner Apr 13 '18 at 15:03
  • I should also note that I haven't changed any of the webpack config files that came with `create-react-app` – Adam Langsner Apr 13 '18 at 15:06

2 Answers2

2

After much investigation, I think I've figured out what's going on here. The reason the first line is correct and then the second isn't has nothing to do with your code, but with the way create-react-app actually inserts those environment variables.

create-react-app is using a plugin call InterpolateHtmlPlugin, which calls a hook from HtmlWebpackPlugin. Basically what InterpolateHtmlPlugin does is look for %env_var_name% in the HTML and replace it with the corresponding value in the environment object in the app.

The issue is by the time the HTML makes it to the InterpolateHtmlPlugin the template code has already been processed (after my tests, I'm pretty sure this is true). Since it's already been processed that conditional has evaluated to false and doesn't show up in the HTML anymore. For the first line, it shows up at %NODE_ENV%, so Interpolate picks it up and replaces it.

I think the easiest thing to do is to add the NODE_ENV to your HtmlWebpackPlugin in your webpack configs and reference it that way. So your new HtmlWebpackPlugin configuration would look like this:

new HtmlWebpackPlugin({
  inject: true,
  template: paths.appHtml,
  NODE_ENV: env.raw.NODE_ENV
})

and the conditional in your index.html file would look like this:

<% if (htmlWebpackPlugin.options.NODE_ENV == 'development') { %>
  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=XXX"></script>
<% } %>
callmeroot
  • 552
  • 4
  • 15
  • Got it. maybe the InterpolateHtmlPlugin is running too late? i.e. it's hooking into the wrong phase in the lifecycle. regardless, your solution worked. and to be honest I don't really need the %VAR_NAME% sugar. I'm perfectly happy doing `htmlWebpackPlugin.options`. seems like it gives me more control with less magic. Thanks again!! – Adam Langsner Apr 13 '18 at 18:46
  • Yeah, I think it might be running during the wrong hook if it wants to support using the variables as a real part of the template HtmlWebpackPlugin uses. – callmeroot Apr 13 '18 at 18:49
0
<% if (process.env.NODE_ENV == 'development') { %>
  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=XXX"></script>
<% } %>
Codler
  • 10,951
  • 6
  • 52
  • 65