React native require relative path file - react-native

I am trying React Native iOS and I was trying to setup project environments. I create a file called config.js so later I can just
import config from 'env'
to load the variables based on different environments. The following is the config.js file
let configFile = 'dev.js'
if (NODE_ENV === 'production') {
configFile = 'prod.js'
}
export default require('./env/' + configFile)
Somehow this won't work. the error message is:
Requiring unknown module "./env/dev.js". If you are sure the module is there, try restarting the packager or running "npm install"
When I changed my code to the following it would not give me errors. But it is not what I wanted to do.
export default require('./env/dev.js')
So does anyone know why is that?

Firstly, require calls are not dynamic. They are statically analyzed and bundled. So you would want something like this
let prodConfig = require('./env/prod.js');
let devConfig = require('./env/dev.js');
let config;
if (process.env.NODE_ENV === 'production') {
config = prodConfig;
}else {
config = devConfig;
}
export default config;

Related

mongoose and express not reading from .env file

I am having some trouble importing a .env file into my project. I have fallbacks in place so I didn't notice the issue until I was almost done with my project and was having trouble implementing a paypal button that wouldn't load. Now I am testing and I realize that all my env files have not been importing :/
I am new to using express but I think I did everything correctly as far as I can tell (but obviously not lol). I have imported all my dependencies and I am using dotenv:
import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
My code for importing my paypal .env file:
app.get("/api/config/paypal", (req, res) => {
res.send(process.env.PAYPAL_CLIENT_ID || "sb");
});
my .env file (located at the root of my folder structure)
PAYPAL_CLIENT_ID= my key info here without quotes
Where the code is eventually being called
const addPayPalScript = async () => {
}, [dispatch, orderId]); const { data } = await Axios.get('/api/config/paypal');
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = `https://www.paypal.com/sdk/js?client-id=${data}`;
script.async = true;
I am not sure why this configuration is not working. I have tried to move the env file to the same folder as the file that is calling it but this just fails to compile with an error. (I have a frontend and a backend folder) I have tried to move the env file to the root of the backend folder and it fails to compile with the same error message. It seems like the root of the project file is the correct location for the env file and all the information I can find online seems like my code is okay, but I still can not load the link for the paypal button when it is clicked on.
Any help would be greatly appreciated. Thank you!
Here is what you should do :
Instead of import dotenv from "dotenv";
Use :
import {config} from "dotenv";
config()
The only function you need from the dotenv library to read your .env configuration is config, to invoke it i've done config()
Now you can access values by doing : process.env.YOUR_ENV_VARIABLE_NAME

Vue local config file per App installation

I am new the Vue.js and I am trying first steps with an app. So for understanding the basics, I want a local config file per App installation to customise some needed variables in the code.
So in my main.js I tried the following:
import Vue from 'vue'
import App from './App.vue'
let config;
try {
config = require('../config.json');
} catch (e) {
config = require('../public/config.json');
}
Vue.config.productionTip = false;
Vue.prototype.$localConfig = config;
new Vue({
render: h => h(App)
}).$mount('#app');
This is working, until I build the production version with the dist folder. If I open the config.json in the root of the dist and change a property value, I see always the first defined values from the development env. So is webpack making there some caching? Is this at all the right way of handling such a local config file per App installation?
Maybe someone could give me some tips on this.
Doing config = require('../config.json'); is the same as import config from "../config.json" in a way that it takes the content of your json file at build time, transform it into JS object and make's it part of your app bundle.
You can do what you propose in a comment (include the file in a script tag in your index.html) but that means your app is doing additional request to the server to load the config and by doing so increasing "time to render" (time user have to wait until the page is fully rendered)
Most common way to handle app configuration in Vue/Webpack world is by using Environment Variables - those also "work" at build time tho so you need to build your app separately for each environment
let config
const configPromise =
process.env.NODE_ENV === 'development'
? import('../config.json')
: import('../public/config.json')
configPromise.then(res => {
config = res.default
})

React Native Expo Environment Variables

So I'm happy with the concept of environment variables as explained in this article and others
https://www.freecodecamp.org/news/how-to-gracefully-use-environment-variables-in-a-react-native-app/
Great, I've got my SOMETHING="something" stored so I can just use env.SOMETHING or whatever
The part I'm a little lost on is where you keep the live variables?
I would rather not do a solution like this as it seems you are still keeping your keys quite public and that you are just choosing based on the environment with if statements
Manage environment with expo react native
For example with an Express App deployment we have, we specify
let endPointURL = env.endPointURL
and then we keep a versoin of that variable locally and when it sits with AWS it is overridden by AWS servers as explained here
I was just wondering does something like that exist for Android and iOS builds (on the respective stores) or through Expo?
Thanks all
Honestly I think the way they go about it is a little silly. There may be a better way to go about than this, but I think I followed their documentation suggestions.
https://docs.expo.io/versions/latest/distribution/release-channels/#using-release-channels-for-environment-variable-configuration
They have a code snippet suggesting you create a function to look at the release configuration itself.
I interpreted it that you might do something like the code below and store your environment variables in a variables.js file and pull in your environment variables as such.
import Constants from 'expo-constants';
export const prodUrl = "https://someapp.herokuapp.com";
const ENV = {
dev: {
apiUrl: "http://localhost:3000"
},
staging: {
apiUrl: prodUrl
},
prod: {
apiUrl: prodUrl
}
};
function getEnvVars(env = "") {
if (env === null || env === undefined || env === "") return ENV.dev;
if (env.indexOf("dev") !== -1) return ENV.dev;
if (env.indexOf("staging") !== -1) return ENV.staging;
if (env.indexOf("prod") !== -1) return ENV.prod;
}
export default getEnvVars(Constants.manifest.releaseChannel);
Edit:
Now that Expo supports config file as app.config.js or app.config.ts, we can use the dotenv. Check this: https://docs.expo.io/guides/environment-variables/#using-a-dotenv-file
A simpler approach would be to export the env object instead of the function:
import Constants from 'expo-constants';
import { Platform } from "react-native";
const localhost =
Platform.OS === "ios" ? "localhost:8080" : "10.0.2.2:8080";
const ENV = {
dev: {
apiUrl: localhost,
amplitudeApiKey: null,
},
staging: {
apiUrl: "[your.staging.api.here]",
amplitudeApiKey: "[Enter your key here]",
// Add other keys you want here
},
prod: {
apiUrl: "[your.production.api.here]",
amplitudeApiKey: "[Enter your key here]",
// Add other keys you want here
}
};
const getEnvVars = (env = Constants.manifest.releaseChannel) => {
if (env === null || env === undefined || env === "" || env.indexOf("dev") !== -1) return ENV.dev;
if (env.indexOf("staging") !== -1) return ENV.staging;
if (env.indexOf("prod") !== -1) return ENV.prod;
}
const selectedENV = getEnvVars();
export default selectedENV;
// Import
import env from '..xxx/utility/env';
Get it in your ios-generated file, based on .env file:
In .env, write down GOOGLE_MAPS_API=abcde...
yarn add react-native-config
cd ios
pod install
In your Objective-C-compiled code, for example, AppDelegate.m:
#import "ReactNativeConfig.h"
NSString *mapsApiKey = [ReactNativeConfig envFor:#"GOOGLE_MAPS_API"];
[GMSServices provideAPIKey:mapsApiKey];
Credits to: ReactNative: Pass JS variable to AppDelegate based on https://github.com/luggit/react-native-config.
Android should work as well, but haven't tested / followed https://github.com/luggit/react-native-config.
Edit: required steps for Android:
<meta-data android:name="com.google.android.geo.API_KEY" android:value="#string/GOOGLE_MAPS_API"/> in AndroidManifest.xml.
In settings.gradle:
include ':react-native-config'
project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android')
right after rootProject.name = 'XYZ'
In build.gradle:
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" right below import com.android.build.OutputFile and implementation project(':react-native-config') right below implementation "com.facebook.react:react-native:+" // From node_modules
Regarding "normal" usage in .ts, .tsx, .js files I'm declaring variables in .env based on https://github.com/goatandsheep/react-native-dotenv by declaring "module:react-native-dotenv" in babel.config.js in plugins, and it works like a charm like so:
import { ACCESS_TOKEN } from "#env";
...
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`,
Accept: "application/json",
},
Edit: important the eas build ignores .gitignore-declared variable, so if your .env is in .gitignore the production bundle won't have it included.
Surprised there weren't any answers that involved storing environment variables in a .env file with Expo.
I prefer storing my environment variables in a .env file because I don't want to commit certain variables to version control and hardwire them into my application code.
Create your .env file and add your environment variables
Install dotenv
npm install dotenv
In your app.config.js file, load the environment variables from the .env file via dotenv:
require("dotenv").config();
export default {
// config...
}
Expose the environment variables to the Expo runtime in the config in app.config.js:
require("dotenv").config();
export default {
// rest of config...
extra: {
ENV_VAR: process.env.ENV_VAR
}
}
Now you can access your environment variables through the following:
import Constants from "expo-constants";
const ENV_VAR = Constants.expoConfig.extra.ENV_VAR
OPTIONAL: TypeScript
To make using environment variables in our code a little nicer, lets create a typed helper utility to access the environment variables:
import Constants from "expo-constants";
export interface Env {
ENV_VAR: string;
}
/**
* Environment variables exposed through `app.config.js`
* An environment variable not there? Make sure it is explicitly defined in `app.config.js`
*/
export const env = Constants.expoConfig?.extra as Env;
Then you can simply access your environment variables from the env object:
const ENV_VAR = env.ENV_VAR
OPTIONAL: Throw an error if an environment variable is not set
This can be handy to prevent your app from running if an environment variable required for your app to properly function is not set.
In your app.config.js:
// Validate all necessary environment variables are set
const checkForEnvVariable = (envVar) => {
if (!process.env[envVar]) {
throw Error(`${envVar} not set! Check env.md for more information`);
}
};
[
"ENV_VAR",
// ...
].forEach((envVar) => checkForEnvVariable(envVar));

Place to put assets for dev/test in emberjs

I'm using mirage to mock some data and I'd like to mock an <img> with the appropriate file.
The problem is that I will have to place the image in /public/assets and the images placed there will be deployed later on as well.
Is there a way to avoid this? I couldn't find a recommendation in the ember cli website (https://ember-cli.com/user-guide/#asset-compilation)
I found one addon that could do this (ember-test-assets), but I'd like to avoid installing extra addons as much as possible.
Thanks!
You can exclude files in ember-cli-build.js with some help of Broccoli
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const Funnel = require('broccoli-funnel');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
// Add options here
});
// Filter your test files in 'production'
if (EmberApp.env() === 'production') {
return new Funnel(app.toTree(), {
exclude: ['**/test-*'] // e.g. any file prefixxed with 'test-'
});
}
return app.toTree();
};
References:
EmberApp.env(): https://github.com/ember-cli/ember-cli/blob/d97d96aa016fbe8108c2d2744c9823a0ea086b94/lib/broccoli/ember-app.js#L469
broccoli-funnel: https://github.com/broccolijs/broccoli-funnel (see exclude)

How to manage different config files for development and production with react-native

For testing my app locally I put dummy values in the code. Several times, I have forgotten to remove these values and pushed the changes, which is fine in development, but not in production. To avoid that this happens, I wanted to have a local config that overwrites the global config file. Something like :
const config = {
'auth.initial.email': '',
'auth.initial.password': '',
}
// Override defaults with local config
let extraConfig = null
try {
extraConfig = require('./config.local')
} catch(err) {}
Object.assign(config, extraConfig.default)
export default config
I believe this would work in node, but in react-native I get an error "Unable to resolve module". Is there a standard solution for this, or a simple way to catch and ignore import errors from JS in react-native?
You could use the __DEV__ variable from react-native.
This variable is set to true if you are in development mode.
It's set to false if your app is in production.