zetachang / react-native-dotenv

A Babel preset let you import application configs from .env file (zero runtime dependency)
MIT License
915 stars 68 forks source link

Use ENVFILE=.env.XXX with Debug/Release #55

Open bars0um opened 5 years ago

bars0um commented 5 years ago

I was wondering if I can control which .env is picked up by the assembleRelease/assembleDebug build processes. At the moment, it seems to me that I cannot choose which environment file is applied. Is it possible to do this:

.env.- has staging URL .env.production - has prod URL

I would like to generate a release(staging) APK that has the dev URL like so:

ENVFILE=../.env ./gradlew assembleRelease

At the moment it looks like ENVFILE is ignored and if I do assembleRelease my .env.production is picked up and if I do assembleDebug my .env file is picked up...Although react-native-config picks up the right ones ( I use that for modifying some of the values passed into Info.plist and grade.build)

bars0um commented 5 years ago

Ok I think I have a solution. I modified my gradle.build file to force-feed the bundler my environment variable as set by react-native-config.

So here's what I did:

Inside my .env file I added a variable named as per the environment:

environment=development

In the grade.build file I check what it is set to (basically if not production then it must be development) and accordingly pass on the appropriate --dev argument configuration (false/true)

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

def myExtraPackagerArgs=["--dev","true" ]

if(project.env.get("environment")=='production'){
        myExtraPackagerArgs= ["--dev","false" ]
    }

project.ext.react = [
    entryFile: "index.js",
    bundleInDebug: true,
    bundleInStaging: true,
    extraPackagerArgs: myExtraPackagerArgs
]
bars0um commented 5 years ago

Additional note about the limitation for env files.

I would like to suggest the following change to make it possible for someone to pass ENVFILE to the plugin rather than modifying the gradle file which is bound to end in tears.

basically in babel-plugin-dotenv replace platformPath and configFile with/or give precedence to/ process.env.ENVFILE over in your script when ENVFILE is defined...it's really made my life easier in having three configs:

test->staging->prod

For my purposes I just replaced configFile and platformPath with process.env.ENVFILE and pas only the name of the env file I want used.

So now I can run

ENVFILE=.env.test ./gradlew assembleRelease

and end up with a binary that has picked up it's own configurations from my env file (react-native-config) as well as a bundle with some transpiled configs (react-native-dotenv)...

most importantly though is the --reset-cache so that configs reset properly between each env's build config.

So instead of the changes made in gradle now I only have the following

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

project.ext.react = [
    entryFile: "index.js",
    bundleInDebug: true,
    bundleInStaging: true,
    extraPackagerArgs: ['--reset-cache']
]

and the modified plugin to pick up the ENVFILE as per my command line... Need to try on iOS.

Thank you!

bars0um commented 5 years ago

And here's the suggested patch... a77576b1d29ab015ccd4cfbcc2ea0b3a6a6be756

bars0um commented 5 years ago

For iOS, I'm seeing that at present the easiest way to specify ENVFILE is in

Build Phases -> Bundle React Native code and images -> Shell dialog

export ENVFILE=.env.staging

# needed for react-native-config to work in concert with react-native-dotenv
echo $ENVFILE > /tmp/envfile 

Ideally you would want to have schemes for each type of build but I guess I'm not terribly upset just changing that one line for each type of deployment while everything else falls into place...

bars0um commented 5 years ago

https://stackoverflow.com/questions/18776626/get-current-scheme-name-from-run-script-phase describes a better approach to use Xcode schemes to manage build environment

echo ".env.production" > /tmp/envfile # for react-native-config
echo ".env.production" > /tmp/dotenv  # for react-native-dotenv

In BuildPhases shell script read the variable back out as necessary:

export ENVFILE=$(cat /tmp/dotenv)

Remember to clean your builds in between to cause a -reset-cache

dreallday commented 5 years ago

Thanks @bars0um this is great!

gianpaj commented 5 years ago

@bars0um I have an issue using your fork and making a release build on Android, though debug builds work fine.

Path must be a string. Received undefined

Trying to debug this looks like process.env.ENVFILE is undefined on https://github.com/zetachang/react-native-dotenv/commit/a77576b1d29ab015ccd4cfbcc2ea0b3a6a6be756#diff-e7f4e9cc9febf61d49934276e91477abL18

this is the /app/build.gradle

project.ext.envConfigFiles = [
    onovaDebug: ".env.onova",
    onovaRelease: ".env.onova",
    dropDebug: ".env.drop",
    dropRelease: ".env.drop"
]

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle";

Command to make a build

ENVFILE=.env.drop cd android/ && ./gradlew assembleDropRelease
bars0um commented 5 years ago

@gianpaj I normally cd into the android folder first and then run. In your case the ENVFILE is being set for the first process (the cd) and not making it to the second...

cd android
ENVFILE=.env.drop ./gradlew assembleDropRelease
gianpaj commented 5 years ago

AH! I think you're absolutely right. Thanks for catching that 🙏

Ankarrr commented 4 years ago

@bars0um Hey! May I know how to use your patch?

bars0um commented 4 years ago

@bars0um Hey! May I know how to use your patch?

I mainly added my fork to my dependencies as follows:

npm install bars0um/react-native-dotenv --save
Ankarrr commented 4 years ago

Thank you @bars0um !

I install it.

After that, I do ENVFILE=.env.production react-native run-ios and then I get this error:

螢幕快照 2019-12-11 下午12 43 08

Do you know this problem? Do I need any other setting?