Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Setting Environment Variables #82

Closed
fredguest opened this issue Feb 28, 2017 · 11 comments
Closed

Setting Environment Variables #82

fredguest opened this issue Feb 28, 2017 · 11 comments

Comments

@fredguest
Copy link

In order to have custom variables available per environment for API keys and such, without committing anything to version control, in https://github.com/facebookincubator/create-react-app for example I can do the following:

  1. add the following scripts to package.json:
  "start": "sh -ac '. .env.dev; react-scripts start'",
  "stage": "sh -ac '. .env.stg; react-scripts build'",
  "build": "sh -ac '. .env.prd; react-scripts build'",
  1. add the following files to the root: .env.dev, .env.stg, .env.prd

  2. define unique variables per environment to the .env files such as:

  REACT_APP_FOO='128376918237691287'
  REACT_APP_BAR='8476547869547955948'
  1. access those variables anywhere in the source js as follows:
  console.log(process.env.REACT_APP_FOO);
  console.log(process.env.REACT_APP_BAR);

How would I accomplish this using Neutrino? I've tried replicating the same process using the neutrino start and neutrino build scripts but the environment variables end up undefined.

@pleunv
Copy link

pleunv commented Feb 28, 2017

You could do this with DefinePlugin:

const globals = {
  __REACT_APP_FOO__: process.env.REACT_APP_FOO
  __REACT_APP_BAR__: process.env.REACT_APP_BAR
};

module.exports = ({ config }) => {
  config.plugin('globals')
    .use(webpack.DefinePlugin, globals);
});

If you use ESLint you'll also have to add them to the globals there. The snippet below is not entirely correct as they will be defined as writable but I don't know the correct way of doing it due to differences between the eslintrc and ES CLI syntax. One expects an array while the other wants an object, but any attempt at setting writable to false has failed. I think @eliperelman might have a bit more knowledge on this subject :)

config.module.rule('lint')
  .loader('eslint', props => merge(props, {
    options: {
      globals: Object.keys(globals)
    }
  }));

@pleunv
Copy link

pleunv commented Feb 28, 2017

Rereading your question, I think webpack.EnvironmentPlugin might be better suited to that.

In your case, assuming the environment variables get set during the CI process, you can pass them to your code like this:

config
  .plugin('env')
  .use(webpack.EnvironmentPlugin, ['REACT_APP_FOO', 'REACT_APP_BAR']);

After which you have them available in code as process.env.REACT_APP_FOO and process.env.REACT_APP_BAR.

However, EnvironmentPlugin is already being used to inject NODE_ENV, so it will have to be merged with the existing arguments, which you can do like this (pulled from webpack-chain docs):

config
  .plugin('env')
  .inject((Plugin, args) => new Plugin([...args, 'REACT_APP_FOO', 'REACT_APP_BAR']));

@fredguest
Copy link
Author

thanks for the help @pleunv! the goal is to have the environment variables read from hidden, uncommitted files files during the execution of the start or build scripts if possible, but the technique you suggested looks great for different requirements.

@eliperelman
Copy link
Member

I wrote the original implementation of environment variables in create-react-app, and am sad to say that I just haven't put this in a preset yet. This doesn't really make sense for a Node.js preset, since it can read from the environment at execution time. For the web preset, maybe it'd be nice if there was a way to specify additional environment variables in package.json.

Extending the environment variables used in EnvironmentPlugin right now would not be fun. I think the best workaround solution right now is to extend the plugin to read from those files at build time and inject them.

@fredguest
Copy link
Author

Ha! That's awesome, I'm a fan of your work on create-react-app :). Ok cool, the only problem with defining variables in package.json would be that they'd be committed to version control obviously, but the EnvironmentPlugin solution is workable.

@trusktr
Copy link
Contributor

trusktr commented Sep 15, 2017

My Ops team needs to assign those at runtime. How can we do that? I'm using neutrino-preset-node to run a server. It'd be great for the server to receive those env vars at runtime, dynamically, while still using process.env.WHATEVER, not transpiled-in at build time.

New issue for it: #319

@u0078867
Copy link

You can add @neutrinojs/env:

module.exports = {
  use: [
    ...
    ['@neutrinojs/env', ['MY_VAR']], // 1
    //['@neutrinojs/env'],  // 2 - does not work
  ]
};

For case 1, however, if MY_VAR is not set, you will get a warning from webpack.EnvironmentPlugin that there is no default value;

@edmorley
Copy link
Member

edmorley commented Aug 30, 2018

Hi! The ability to set default values has been added to the web preset in #983, which will be in the upcoming Neutrino 9.

In the meantime (or for presets that don't inherit from web, so don't have the built-in env preset option), you can use the Neutrino API to add EnvironmentPlugin:

const { EnvironmentPlugin } = require('webpack');

module.exports = {
  use: [
    ['<existing preset name>', {
      // Options
    }],
    (neutrino) => {
      neutrino.config
        .plugin('env')
        .use(EnvironmentPlugin, [{
          MY_VAR: 'default-value',
        }]);
    }
  ]
};

@u0078867
Copy link

Oh lovely, this is precious!

@WhoAteDaCake
Copy link

WhoAteDaCake commented Sep 3, 2018

I am using

const { EnvironmentPlugin } = require("webpack");
module.exports = {
  use: [
    [
      "@neutrinojs/react-components",
      {
        devServer: {
          // Disabling options.hot will also disable devServer.hot
          hot: true,
          // Proxy requests that don't match a known file to the specified backend.
          proxy: "https://127.0.0.1:9000/v1"
        }
      }
    ],
    neutrino => {
      neutrino.config
        .plugin("env")
        .use(EnvironmentPlugin, [{ TEST: JSON.stringify("test") }]);
      // .use(EnvironmentPlugin, ["URL", "TOKEN", "PROJECT"]);
    }
  ]
};

However it does not inject variables to process.env on the frontend

Update

Using

 .use(DefinePlugin, [
  { "process.env": { test: JSON.stringify("test") } }
 ]);

Works just fine

@edmorley
Copy link
Member

edmorley commented Sep 3, 2018

Hi! Testing your snippet works for me locally using Neutrino 8.3.0?

Though note the EnvironmentPlugin docs say:

Unlike DefinePlugin, default values are applied to JSON.stringify by the EnvironmentPlugin.

...so the JSON.stringify() is unnecessary (and adds extra quotes). Without knowing how you're testing this, it's hard to know if that fixes your issue (eg if you were checking for the exact value, as opposed to whether it was set at all)?

Failing that, I would:

  • check that you're using a webpack version that includes this upstream fix (webpack 3.11+), which should be the case since Neutrino 8.3.0 sets the webpack dependency as ^3.12.0.
  • look at the output from --inspect for further clues:
    https://neutrinojs.org/cli/#-inspect

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

7 participants