Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment variables #57

Closed
hartmamt opened this issue Mar 14, 2017 · 44 comments
Closed

Environment variables #57

hartmamt opened this issue Mar 14, 2017 · 44 comments

Comments

@hartmamt
Copy link

Is there support for adding in environment variables like create-react-app allows? I tried it the way I usually do and it didn't work, but not sure if there is something in expo that allows it.

@anp
Copy link
Contributor

anp commented Mar 14, 2017

We can definitely look at adding some. Which environment variables were you trying to set?

@inyono
Copy link

inyono commented Mar 15, 2017

Would love that, too. I'm trying to switch between two possible entry points (namely the real app and https://github.com/storybooks/react-native-storybook). Currently, I work around this issue by commenting out the respective component in App.js. IMHO, it would be much cleaner if I could set an environment variable in my npm tasks and choose the component depending on that, though.

@hartmamt
Copy link
Author

We use environment variables a lot when we build so that we don't have to hardcode things like REST endpoints.

@scmx
Copy link
Contributor

scmx commented Mar 17, 2017

Also looking for this. My use case is that I need a url that leads to my host machine where I have an api server running. I would then like to be able do something like
API_HOST=http://$(ipconfig getifaddr en0):4000 npm start. Perhaps there's a better solution?

@hartmamt
Copy link
Author

I believe Create React App just exposes any variables that start with REACT_APP. I figured this would just work the same.

@anp
Copy link
Contributor

anp commented Mar 17, 2017

Thanks for the input everyone! I think we have a plan to implement this, I'll post here with updates.

@anp
Copy link
Contributor

anp commented Mar 21, 2017

Update: the path to implementing this is a little trickier than I initially thought. Specifically, it's difficult to support this in a way that will continue to work after ejecting. Keeping this open so that it's still on our radar, but it might take a little while to figure out the right way to do implement.

@ericnograles
Copy link

Thanks for the update, @dikaiosune! Quick and silly question -- with "vanilla" React Native, I simply would use babel-plugin-transform-inline-environment-variables in my .babelrc to handle this. I see that this won't work for CRNA/Expo, as I modified my CRNA .babelrc like so:

{
  "presets": ["babel-preset-expo"],
  "plugins": ["transform-inline-environment-variables"],
  "env": {
    "development": {
      "plugins": ["transform-react-jsx-source"]
    }
  }
}

I'm just curious as to how/where the Babel transformations of our CRNA/Expo code occur? I assumed that the Packager would pick up the .babelrc on my project's root, but that doesn't appear to be the case. I tried reading through the source but couldn't find the answer.

My best guess is that the Babel transforms occur right on the Expo Client itself, or the Packager has its own Babel config that is not overridable?

@anp
Copy link
Contributor

anp commented Mar 27, 2017

@ericnograles I don't see why that wouldn't work in principle -- can you upload a minimal repro project somewhere so that I can try?

@ericnograles
Copy link

ericnograles commented Mar 28, 2017

Sorry for the delay, @dikaiosune, here's a sample repo: https://github.com/ericnograles/crna-sample-env-variables

You'll notice my .babelrc has the line for transform-inline-environment-variables. Basically, I have a value in /common/constants.js that should resolve to the ENVIRONMENT_CURRENT environment variable, but defaults to Dangit it didn't work! if the swap doesn't happen.

I set the environment variable like so and run yarn start

image

Also, I tried setting the environment variable as part of the start script like below:

"start": "ENVIRONMENT_CURRENT=YO react-native-scripts start",

And still no luck. I don't think I'm doing anything silly here, but you be the judge. Let me know if that's enough info to go by.

Thanks for your help!

@ericnograles
Copy link

ericnograles commented Mar 28, 2017

@dikaiosune so I'm an idiot. I completely forgot that the CRA process ignores all env variables that didn't start with REACT_ and looks like you guys applied the same thing, except you expect a REACT_NATIVE_ to start after I rtfm in the Environment Variables section 🤣

So, it works, huzzah!

TL;DR: For anybody following my thread, you can do this via the start script like so:

"start": "REACT_NATIVE_ENVIRONMENT_CURRENT=YO react-native-scripts start",

And it works! Be sure to set environment variables to start with REACT_NATIVE_ or it will be ignored, similar to how environment variables that don't start with REACT_ are ignored by CRA.

Note: You don't actually need to add the babel-plugin-transform-inline-environment-variables plugin above, it seems to work fine without it.

Update: Got a PR out to address the documentation gap. Hope it helps someone! #125

@anp
Copy link
Contributor

anp commented Mar 28, 2017

@ericnograles you're right! I left a comment on the PR, but for the benefit of anyone who finds this thread:

As of today (3/28/17), the functionality @ericnograles described above only works in development mode within CRNA -- if you eject or publish to Expo then your code will no longer see the environment variables. Please treat this feature as experimental until we can work out ejection support and provide stable documentation.

@nsisodiya
Copy link

@ericnograles @dikaiosune
Many people like me want to store environment variables in .env file instead of passing on command line or package.json. May you give us the proper way to do it.

I have tried package like zoo , react-native-config but not working.

@brentvatne
Copy link
Member

@nsisodiya - can you explain why you would like to store config for a client app in a .env file rather than a json file? As far as I can tell the only difference is that you use a different parser to load the config file. It's not like you deploy to production and then suddenly you have some server environment where your env vars are already set and available, you still need to deploy your config with your app. I'm genuinely confused.

@nsisodiya
Copy link

@brentvatne I am fine with storing variable in JSON file too.
you mean, I should store in .env.json file and do

import Config from '.env.json' in js files?

I do not want to put env variable in package.json. That is my main concern !!
Also, I want to keep .env or .env.json file as git-ignored file.

@brentvatne
Copy link
Member

You could just call it config.json or something, no need for .env. And then just add that to your gitignore. import Config from './config.json'

@nsisodiya
Copy link

@brentvatne @dikaiosune - My biggest pain right now is, Do I need to commit this config.json or not ?
I do not want to commit this because this config.json has Server API url. now this server API url changes while development.
CAse 1 - If I do not commit this config.json file, and put in gitignore then - everybody will be able to write their local API server path, but in this case, I do not know if this uncommited and gitignored file will be picked while publishing standalone app build. I am using expo.
Case 2 - If I commit this config.json file, then everybody will have to overwrite this file and by they by mistake commit this file with path of local environment.

====

I am unable to get a differentiating factor where I can decide whether this app is working at my local dev environment or in published environment so that I can choose right API server.

@brentvatne
Copy link
Member

CAse 1 - If I do not commit this config.json file, and put in gitignore then - everybody will be able to write their local API server path, but in this case, I do not know if this uncommited and gitignored file will be picked while publishing standalone app build. I am using expo.

yes, it will be picked up when publishing, Expo has nothing to do with git or gitignores

Case 2 - If I commit this config.json file, then everybody will have to overwrite this file and by they by mistake commit this file with path of local environment

it's common practice to commit something like config.json.example and then explain in the project README under a setup section that you need to copy that and call it config.json and add your secrets to it

@slorber
Copy link

slorber commented Jun 13, 2017

Hey, I'd like to inject the build date / build version / git commit hash and things like that as variables of my app. What's the best way to do that? It should work for dev and prod.

@Palisand
Copy link

Palisand commented Jun 14, 2017

@nsisodiya If you insist on using a .env file, then react-native-dotenv might come in handy. @brentvatne's suggestion is probably the way to go though.

@brentvatne
Copy link
Member

@slorber - so this isn't really related to Create React Native App, it's more of an Expo thing, but Expo gives you 1) build date 2) a revisionId for every build, which is unique and we generate for you 3) the version that you put in app.json/exp.json. You can access these through Expo.Constants.manifest -- 1) publishedTime 2) revisionId 3) version.

As for a commit hash -- you'd need to add that somewhere in your app.json/exp.json (under the extra key) or drop it into a js file before publishing.

@slorber
Copy link

slorber commented Jun 14, 2017

Thanks this will solve my usecase, but it would be nice to have a flexible option where we can compute with JS the vars to inject. It can become a bit messy to modify/revert the exp.json file on every publish

@brentvatne
Copy link
Member

@slorber - it sounds like what you want is some kind of prePublish hook where you can add metadata to the extra field in exp.json at the time of publishing?

@slorber
Copy link

slorber commented Jun 15, 2017

yes it probably works but exp.json is versionned and I don't necessarily want to persist this change

@joelbowen
Copy link

joelbowen commented Sep 18, 2017

For @slorber and anyone else who may find this useful, this is how I have resolved to handle not tracking my environment variables but still generating an app.json file from a tracked configuration source. Feedback welcome!

https://gist.github.com/joelbowen/1d2f2dfa471efad2154e6318c195b77e

TL;DR I create a base-app.json that is the configuration source, and a .env file that has environment variable declarations. Then I untrack both .env and app.json files and generate app.json before the important scripts run.

@SrdjanCosicPrica
Copy link

SrdjanCosicPrica commented Feb 14, 2018

To anyone who has scrolled down here still having issues with environment variables for different scripts. I have made a solution that worked for myself for React Native

Versions

"react": "16.2.0",
"react-native": "0.52.0",
"babel-plugin-transform-inline-environment-variables": "0.3.0",

Package.json

Following @ericnograles solution

"scripts": {
    "start-a": "REACT_NATIVE_A=X react-native start --reset-cache",
    "start-b": "REACT_NATIVE_A=Y react-native start --reset-cache",
    ...
}

Code

// variable.js
export const VARIABLE = process.env.REACT_NATIVE_A;

I had to add --reset-cache because when running a different script it would still have the previous scripts variable if the file variable.js did not change. Using --reset-cache removed everything so it takes a minute to reload everything again but at least it works.

Use babel transform-inline-environment-variables plugin.

EDIT

If you don't want to add --reset-cache in your package.json. You can also run this by doing

npm run start-a -- --reset-cache

facebook/react-native#1924 (comment)

@q3e
Copy link

q3e commented Feb 20, 2018

@SrdjanCosicPrica are you using CRNA by any chance?

@SrdjanCosicPrica
Copy link

@fatahn Yes and it is ejected. Any reason why you ask?

@byCedric
Copy link
Member

I'm just leaving this here for people to not ruin their night when trying to get the basic .env work in an un-ejected CRNA app. React Native actually passes any environment variable prefixed with REACT_NATIVE_, just like web. But these variables have to be loaded in the process running CRNA. There is a way to actually achieve this.

First, you have to choose a library that can parse the .env file. I chose the dotenv package because it can load the file by simply including a module. Now, we have to load this module before CRNA actually starts. After searching the internet I found out that Node has an -r option (to require a module) and NPX has an -n option (to pass an option to node). These two combined can load the dotenv module in the same process as an executable node binary.

Combining these methods, .env parser, node cli require module and npx pass node option, we can setup our scripts similar to this.

// package.json
{
    "scripts": {
        "start": "npx -n='-r dotenv/config' react-native-scripts start",
        "test": "node -r dotenv/config node_modules/jest/bin/jest.js"
    }
}

It might not be the best solution, but this works in the current environment when starting CRNA from cli (not Expo XDE). I also have no clue what happens when creating an Android or iOS standalone app. But if you are looking for a working .env without including it in actual project code, this is a way to do that...

@NachtRitter
Copy link

Just use https://github.com/luggit/react-native-config
I use it for my published applications. It allows to use variables from .env file even in Java and Swift code.

@byCedric
Copy link
Member

@NachtRitter As much as I like how it's supposed to work, it still doesn't work for non-ejected expo apps. I really don't want to eject as it will become harder to maintain it myself. If only there was a way to use luggit without ejecting! 😢

@officert
Copy link

officert commented Apr 4, 2018

@byCedric Can you show how you access your .env variables in your code after setting things up with NPX and dotenv?

@officert
Copy link

officert commented Apr 4, 2018

I was able to get it working, I had to fully restart Expo so that it would reload my .env file and now I can access environment variables with process.env.REACT_NATIVE_BASE_URL.

The hot reloading doesn't reload the .env file though so after the first run my environment variable go away. Haven't found a solution for that yet, but thanks @byCedric!

@ericnograles
Copy link

Hey guys,

So, I ended up using react-native-dotenv for my CI needs and local dev, and it works like a charm. So, assuming you have setup a CI provider of your choice (Circle, Travis, Codeship, GitLab, BB, Heroku, whatever), I took the following steps

  1. Add .env to the .gitignore
  2. Define environment variables for your various configurations (dev, stage, prod, etc)
  3. As a prebuild step for each, execute printenv > .env at the root of the repo
  4. Run the following in a bash file as my build step (I use a localized version of exp hence the yarn run's)
# Login to expo
yarn run exp login -u $EXP_USERNAME -p $EXP_PASSWORD

# Deploy to the right release channel
yarn run exp publish --release-channel $EXP_RELEASE_CHANNEL

...of course, assuming I've defined the env vars defined above.

Anyway, it works great, and I've got auto publishes to the various release channels I've got defined.

For my local developers, I just have a standard .env file stored off in a Google Drive that I share for any new dev that I onboard to my project -- i.e. I have them download it and save it to the root of their local repo. Since it's ignored, the SCM stays clean.

@byCedric
Copy link
Member

byCedric commented Apr 4, 2018

@ericnograles You might want to add a .env.example containing the names (not values) for all existing environment variables. You can commit that one to the repo and maintain it when it expands. From there everyone should be able to check for updates and its project scoped 😄 I also have the same CI command that everyone can trigger on the main branches, works like a charm!

@officert I'm glad you got that one working! Now we had some trouble in with the environment when publishing it to Expo. After intensive testing en prototyping we decided to go for babel-plugin-inline-dotenv. This one has some really good advantages, some of them:

  • uses dotenv to set a "default" value for environment values that doesnt exists at runtime
  • can use CI/host environment values too
  • doesn't need to be prefixed with REACT_NATIVE_
  • and last but not least, this works when asking an Android or iOS build from Expo 😬

Hope this helps anyone! Cheers

@kiorq
Copy link

kiorq commented Apr 11, 2018

I've tried adding transform-inline-environment-variables to my babelrc file and i've tried REACT_NATIVE_***=*** npm start -- --reset-cache. Nothing works. All i have in my process.env is {"NODE_ENV": "production"} even in development mode... (using react-native-scripts)

@Sunil6591
Copy link

@kiorq any update, i have same issue nothing works

@kiorq
Copy link

kiorq commented May 8, 2018

Nope, not any luck what so ever. I have to manually change a const in a config.js file that switches between config.dev.js or config.prod.js depending on the value of the const. :/

@christophehurpeau
Copy link

@kiorq @Sunil6591 with transform-inline-environment-variables, process.env is left untouched, you have to use process.env.YOUR_VARIABLE

@p1Machado
Copy link

p1Machado commented Jun 2, 2018

In a web react app it's possible to set env variables through .env, thanks to create-react-app, wich contains react-scripts.

With create-react-app:
"start": "react-scripts start"

With ejected create-react-native-app:
"start": "node node_modules/react-native/local-cli/cli.js start",

It's possible to setup something like this in a ejected create-react-native-app?

@SilencerWeb
Copy link

any updates?

@krish14011995
Copy link

https://github.com/luggit/react-native-config I have done something like which is mentioned in this link. But when I change the .env file on the fly and just reload the application it won’t work because it bundles with the earlier env variables. Can you suggest a way to change that?

@fredrivett
Copy link

For folks still reading this, if you just need a simple "is dev or prod" check, looks like you can use the __DEV__ flag, which is set to true in dev, and false on prod.

expo/expo#507

@sinpaout
Copy link

sinpaout commented Sep 23, 2018

Its works with restarting ios simulator at my environment.
My script is like below.
"ios": "REACT_NATIVE_SOME_VAL=1 react-native-scripts ios",

Run it with yarn:
$ yarn ios

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests