I want a modern way to manage environment variables for a react native mobile app.
The answer here explains the twelve-factor method style (which I love) which involves installing a babel plugin that transpiles references to
const apiKey = process.env.API_KEY;
to their corresponding values as found in the process's environment
const apiKey = 'my-app-id';
The problem is that in order to run this with a populated environment, I need to set it like
API_KEY=my-app-id react-native run-ios
If I have a .env file with 10-20 environment variables in it, this method becomes unwieldy. The best method I've found so far is to run
env $(cat .env | xargs) react-native run-ios
This is a bit undesirable because developers who want to work on this package have to set up custom shell aliases to do this. This isn't conducive to a good development environment, and also complicates the build and deploy flow for releases.
Is there a way to add a hook to the react-native-cli (or a config file) that populates the process environment first? Like an npm "pre" script, but for react-native.
You can use react-native-config which is a native library and requires a link to work or react-native-dotenv which works just like react-native-config but doesn't require any native link.
It'll work fine with .env files set up, e.g. .env.development with environment variables for process.env.NODE_ENV === 'development'.
Related
I have NPM scripts that build and run our app with mocked backend data (used for component testing). They set ENVs inline using the cross-env npm package.
"android-mock": "cross-env MOCK_BACKEND=1 NODE_ENV=development node generate-config.js && react-native run-android -- --reset-cache", - emulator runs on Windows
"ios-mock": "cross-env MOCK_BACKEND=1 NODE_ENV=development node generate-config.js && react-native run-ios -- --reset-cache", - simulator runs on MacOS
Metro bundler looks for the MOCK_BACKEND env and based on that, it resolves paths so that the app uses mocked data instead of relying on the backend to get it.
Problem: Metro can read the process.env.MOCK_BACKEND value only when bundling Android apps, on iOS, the value returns undefined.
What is the correct way to define ENVs so that Metro can read them properly also for iOS bundling?
I don't know why, but it seems like Metro overwrites set ENVs when bundling iOS apps.
Elsewhere ENVs are defined.
If anyone comes over this problem, this is how I solved it.
Solution
1. In the generate-config.js script that is in NPM scrips above, I have added NODE_ENV checks. The script generates the config.js inside the public folder, based on NODE_ENV.
const fs = require("fs");
console.log( process.env.NODE_ENV);
if(process.env.NODE_ENV === 'production'){
fs.copyFile("config.runtime.js","public/config.js",(err) => {if(!err){console.log(err)}});
} else if (process.env.NODE_ENV === 'mock'){
fs.copyFile("config.mock.js","public/config.js",(err) => {if(!err){console.log(err)}});
} else {
fs.copyFile("config.debug.js","public/config.js",(err) =>{if(!err){console.log(err)}});
}
2. I have imported generated config.js into Metro.config and used it as needed.
const config = require(path.resolve(__dirname, 'public/config.js'));
config.js for reference:
module.exports = {
isProduction : false,
disableCache: true,
API:"http://alanj.bs.local:15455/",
/////////////////////////////////////
// ENVs
/////////////////////////////////////
MOCKED_BACKEND: 1,
/////////////////////////////////////
}
We ran into the same issue, we have no solution yet but interesting observations after approximately 1 day of trial and error:
Start Packager Script
The 'Start Packager' script in Xcode is responsible for the mess.
It does not pass the environment variables to the packager.
The problem lies within Mac OS open:
Create a new file /tmp/test.command:
#!/bin/bash
echo "Environment Variable XXX='$XXX'"
Now use
XXX="visible" /tmp/test.command
This will print
Environment Variable XXX='visible'
Whereas when called with open:
XXX="not visible" open /tmp/test.command
will just yield:
Environment Variable XXX=''
Even with
XXX="not visible" open --env XXX="abc" /tmp/test.command
we just get:
Environment Variable XXX=''
Not sure if we should file a support ticket at Apple
We are working on a Dockerized NextJS application that is thought to be built once and deployed to several environments for which we will have different configuration. This configuration is to be set in the Docker container when deployed as environment variables.
In order to achieve this, we are using next.config.js file, splitting the vars on serverRuntimeConfig and publicRuntimeConfig as suggested here, and we are getting the values for the environment variables from process.env. i.e.:
module.exports = {
serverRuntimeConfig: {
mySecret: process.env.MY_SECRET,
secondSecret: process.env.SECOND_SECRET,
},
publicRuntimeConfig: {
staticFolder: process.env.STATIC_FOLDER_URL,
},
}
The problem we have is that these variables are not set on build time (when we run next build), as they are environment specific and supposed to be set on deployment. Because of this, the build fails complaining about the missing variables.
Making a build per environment is not an option: as referred before, we want to build it once (with next build), put the output of the build in a docker container, and use that docker container deploy in several environments.
Is there any way to solve this so that the application builds without environment vars and we pass them afterwards on runtime (deployment)?
We finally found the issue.
We were importing code in a helper that was being used in the isomorphic side and was relaying on serverRuntimeConfig variables, being then required on build time in order to create the bundle.
Removing the import from the helper fixed the issue.
I would like to utilize pipenv as my virtual environment manager and for my dependency management for my Python cdk projects, upon running 'cdk init'. I read that you can specify a 'custom' application template but could not find documentation on creating one. Is it possible and can the virtual environment/dependency manager be controlled using this feature?
I would like to be able to run 'cdk init hello-world --language python' and have the scaffolding for the project be generated BUT using pipenv.
It's not possible to do that without modifying the source code for the CDK package itself. You likely won't want to manage your own divergent version of the standard package.
I've shoe-horned CDK to work with PipEnv a couple of times, and it's more work than it's worth at this point. The problem is that PipEnv forces the . delimiter in the package name to a -; pipenv install aws-cdk.aws-rds is listed as aws-cdk-aws-rds in the Pipfile, and the package installations don't actually work.
There's an open issue on the repo for this though (https://github.com/aws/aws-cdk/issues/3671), so you could +1 there in hopes that they can address it. It really is an issue with Pipenv though.
Following the link from Scott for the open issue, it looks like this works now, provided the package name is in quotes.
I need to test my app on windows, but I am using a mac. It is very easy to package the app to run on windows, but I cannot package the app in dev-mode. I am using electron-is-dev to decide if I am running in dev or not. I need to run my tests on windows because I am testing a very specific windows hardware functionality. I don't want to comment my if(isDev){doSomething} just to run these test, and then uncomment it before I push the change. I was hoping there is some flag I can set in the electron-build cli, or maybe run electon . -windows?
Parse the parameter by adding sample code below to your electron main.js
const args = process.argv.slice(1);
windows = args.some(val => val === '-windows');
It can still be parsed on electron executable app by running in cmd like "electronapp.exe -windows"
The best way to do this so as to use the IsDev is to add the ELECTRON_IS_DEV environment variable to the app kinda like #carlokid suggested. I used: https://stackoverflow.com/a/34769146/3966009. This is the target I used for my app:
C:\Windows\System32\cmd.exe /c "SET ELECTRON_IS_DEV=1 && START ^"^" ^"C:\Program Files (x86)\My App\Fun Time.exe^""
I'm working on an app with vuejs frontend and nodejs backend. My frontend makes API https requests to the backend. I've started my projet with vue-cli and webpack.
I need to get the backend API url from env variable (BACKEND_URL).
Since i'm using webpack, I added this line to config/prod.env.js :
module.exports = {
NODE_ENV: '"production"',
-> BACKEND_URL: JSON.stringify(process.env.BACKEND_URL)
}
It works flawlessly in dev mode using webpack-dev-server. I pass the env var throught docker-compose file:
environment:
- BACKEND_URL=https://whatever:3000
But when I run build, I use nginx to serve the static files (but the problem is the same using visual studio code live server extension). I send BACKEND_URL env var the same way as before. The thing is now the process.env.BACKEND_URL is undefined in the app (but defined in the container)!! So I cant make backend http calls :(
I'm struggling finding the problem, please don't be rude with the responses. Thank you
They aren not "translated" during build time, this is what is happening with you. On a node environment, when you ask for process.env it will show all environment variables available in the system, that is true. But a web application does not have access to process.env when it is executing. You need a way to translate them during build time.
To achieve that you have to use DefinePlugin. It translates anything during build time and writes a magical string where this other thing was.
Using you own example:
module.exports = {
NODE_ENV: '"production"',
BACKEND_URL: JSON.stringify(process.env.BACKEND_URL)
}
If you do this during build time, without DefinePlugin, webpack won't know what to do with it, and it is going to be a simple string.
If you use DefinePlugin:
new webpack.DefinePlugin({
"process.env.BACKEND_URL": JSON.stringify(process.env.BACKEND_URL)
});
By doing this, you are allowing webpack to translate this during build time.
Give this a shot: https://www.brandonbarnett.io/blog/2018/05/accessing-environment-variables-from-a-webpack-bundle-in-a-docker-container/
If I'm understanding your problem correctly, you're serving a webpack bundle using nginx, and trying to access an environment variable from that bundle.
Unfortunately, it doesn't quite work that way. Your JS file has no access to the environment since it's a resource that has been delivered to the client. I've proposed a solution that also delivers those env variables alongside the bundle in a separate JS file that gets created on container start.
From VueJS Docs: https://cli.vuejs.org/guide/mode-and-env.html
Using Env Variables in Client-side Code
Only variables that start with VUE_APP_ will be statically embedded into the client bundle with webpack.DefinePlugin. You can access them in your application code:
console.log(process.env.VUE_APP_SECRET)
During build, process.env.VUE_APP_SECRET will be replaced by the corresponding value. In the case of VUE_APP_SECRET=secret, it will be replaced by "secret".
So in your case, the following should do the trick. I had the same problem once in my project, which I started with vue/cli and vue create project ...
VUE_APP_BACKEND_URL=https://whatever:3000