I have a chrome-extension React project that gets built with gulp. I'd like to propagate configuration values based on environment. for example, with CHROME_ENV=staging I'd like to have config.oauth_client_id = '<some ceratain thing>' and be able to change it per-environment. So the question is two-fold:
* how do I build different files with gulp based on environment variable?
* how do I structure my React project so there is a config module or varuable that is quite global that stores my configuration.
In your gulpfile.js you could use dotenv, (https://github.com/motdotla/dotenv) to set environment variables or simply pass the gulp script them:
NODE_ENV=staging gulp some-command
In node you can reference this as process.env.NODE_ENV.
To pass environment variables to your build depends on what you're using.
For webpack here is a good answer: Passing environment-dependent variables in webpack
For browserify you would most likely look at:
https://github.com/hughsk/envify
I bootstrap my client side scripts with environment variables set at starting the script or with .env, and from there send it up from the server by rendering json in a script tag. This may not work for you as it's a browser extension and needs to be executed without a server and should be injected at build time.
Related
React noob here. I'm currently migrating an app from Next.js to React.
In Next, we had certain environment variables (such as root URLs) defined in our Jenkinsfile that would be called from our UI via process.env.[var].
Now that we're migrating to React, I can't use process.env in the UI side, as this is a Node property. I also can't store these environment variables on the API side and call them from the UI side, as React doesn't allow references to be made outside the UI's /src directory.
Is there a way to use our environment variables (defined in Jenkinsfile) from our UI? I'm considering creating a GET endpoint in the API side to return the environment variables to the UI when it loads, but would like to know if there are any alternative solutions.
Probably obvious, but here's the basic layout of our app
-api
-src
-ui/react
-src
-utils
constants.js <- trying to store the env vars here
jenkinsfile
Technically, we can't use environment variables in browser context, that's why we usually use DefinePlugin or EnvironmentPlugin in webpack based projects like CRA and Vue-CLI to statically replace process.env.* with environment variables.
But this way will forces us to rebuild the whole application multiple times for different stages.
To fix this, without compromises., I recommend trying import-meta-env.
During production, this plugin statically replaces import.meta.env.* with placeholders (we use import.meta because process.env is a Node specific object), then we can run the built-in script and replace the placeholders with real environment variables later.
I also created an example for Docker. For Jenkins, I think it can be done in the same way.
Hope this helps someone who needs it.
If you are using create-react-app you can define your env variables in the .env file, just prefix them with REACT_APP_.
If not, you can use build tools like webpack to add them for you
So I have a file named .env with the following contents
NODE_PATH=./src
NODE_ENV=what
TEST=test
And I am calling that in my index.js in my react app.
require("dotenv").config();
console.log(process.env);
...
shows the following output
NODE_ENV: "development"
PUBLIC_URL: ""
I thought maybe I declared another .env file somewhere else, but thats not the case. I searched my project for the PUBLIC_URL and it's not located anywhere in my project. I don't even know what else to check at this point.
In react code you have to compile the environment variables in at, well, compile time because at run-time there it is only possible to access a fake process.env object. Unless you are using server side rendering.
See also: Passing environment-dependent variables in webpack
If you're using CRA then you'll need to do: REACT_APP_TEST=test and reload the dev server to have it show up as expected in your app.
If you have used create-react-app for bootstrap your project then you have to use environment variables like REACT_APP_NODE_ENV=development.
After adding any new environment variable, you have to restart the development server.
There are several blog posts that explain why switching from grunt or gulp to building with just plain npm is a good idea for example this one by Cory Hourse or this one by Keith Cirkle. One thing these blog posts do not explain is how I can easily do environment configuration. For example a common requirement is to have different REST API locations. During development the server might be running on localhost:8080, but on production it should be accessed through a relative URL such as /api or /rest/api and the port or protocol are different for development and production.
There are several solutions for this. For example grunt supports template strings like <% %> and <%= %> and there are grunt or gulp plugins like in this question about grunt-ng-config. These solutions are specific to Angular (which I am using), but I am not necessary looking for an AngularJS specific solution.
I also know of the angular-environment plugin, but as far as I can see this does configuration at run time and I am looking for something that can do this at build time.
So what I am looking for is something that allows me to configure my application at build time either by replacing some template strings or by generating a Javascript file with some variables that I can read at run time.
One requirement is that it should be OS independent. So I do not want to use UNIX specific tools such as sed to rewrite a file. And due to different variable expansion (e.g. % vs. $) a solution should not rely on environment variables.
Is there an existing solution or a best-practice for this?
due to different variable expansion (e.g. % vs. $) a solution should
not rely on environment variables
this cuts off your best solution. Why not rely on env vars? node provides
process.env
to access env vars. You could create custom gulp / grunt tasks that use process.env instead of the "different variable expansions" you refer to.
You can use, for example, Jade templating to pass env var values to your HTML at build time. This would generate your index.html on the fly as part of the build process and add relevant classes based on env vars.
For example, according to the value of an env var you might set a class on the HTML tag.
This might reflect the customer.
Then you could have some CSS
.customer1 .myimage {
background-image: url("customer1.png");
}
.customer2 .myimage {
background-image: url("customer2.png");
}
or you could use JavaScript to detect which class was added to head during the build.
Like most js web apps we have a config.js file that contains global config information about the app, base api urls and such. These values are often different in local development than in production.
I've looked at answers like: Development mode for AngularJS using GruntJS, and also things like grunt-replace for creating an on-the-fly config file.
My issue is that the "development" part varies from developer to developer, we all need a version of the API setup so the base api urls will be different. I'd like to allow each developer to override specific variables in the config in a way that doesn't require them to commit that info to the git repo (I agree that this isn't best practice, everything should be in the repo, but as this is only 1/2 variables for this project I can overlook it)
Any ideas on how to achieve this setup?
You can use grunt-preprocess. I would have production (and dev-server, etc) values in a file, say env.json. You could use grunt to look for an optional file, say overrides.json or developer.json, which would extend/overwrite the values from env.json.
var envFile = require('./env.json');
You can create command line options to grunt with grunt.option, e.g. var env = grunt.option('env') || undefined;, which could be used to turn off overriding.
You can get data from the optional file using fs.existsSync:
var fs = require('fs');
var developerFile;
if (fs.existsSync('./developer.json')) {
developerFile = require('./developer.json');
}
The simplest way to define the grunt-preprocess context would be to use the developer.json file if present, or the env.json file if not:
context: developerFile ? developerFile : envFile;
This requires the developer file to be complete. An alternative is to extend the envFile with options from developerFile if it's present.
In my project, we use different config files (which are basically files with JS object). So every developer has his app/configs/developer/config.js file, which is not comited in the source control, so every developer has his own setup. Project uses link to app/scripts/config.js by default and this file is just a soft link to developers config file. However, there are also app/configs/staging/config.js and app/configs/production/config.js files, which are replaced when using gruntjj to build project. Those configs are just copied to build solution instead of soft linked file.
I hope that makes sense..
I am using angular/yeoman and my service is using a different url in DEV then in PROD. How can I automate this with grunt running build? Also, is there a way to have two different "dist" folders created (to deploy for two different servers, again same app some blocks of code needed to be excluded in DEV, but slightly changed for build)
// Development only for testing
var promise = $http.get('/fauxService/content.json')
// Build
var promise = $http.get('/realService/content.json')
You could use grunt-html-build and create different sections in your index.html for dev, test, uat, production environment.
In your case, I would probably use a "setting" service (where to put your constants to define your environment), with different versions depending on environment and choose the right configurations with specific grunt task (for example: https://github.com/williamverdolini/discitur-web/blob/master/Gruntfile.js#L392)
it could be a way