I am working Azure DevOps Pipeline to build and deploy React JS application. It contains config.js file which some variables that needs to modified for different environments. Anyone help me how to handle the config.js in Release pipeline while deploying to different stages?
I marked this question as duplicate because I think there is already a suitable answer. Nevertheless, I remembered two other approaches for achieving what you are looking for:
1. Storing your variables in .env files
You can easily store your variables in .env files like described here. You then need to give each .env file a different name for each environment. You could end up having a .env.developemt, a .env.production, ... and so on in your repository. Then you can use the following YAML for building according to your desired environments:
# Node.js with React
# Build a Node.js project that uses React.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/languages/javascript
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool#0
inputs:
versionSpec: '10.x'
displayName: 'Install Node.js'
- script: |
npm install
npm run build:staging
displayName: 'npm install and build'
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: 'build'
ArtifactName: 'drop'
publishLocation: 'Container'
For each build pipeline, you then use a adjusted YAML. In the shown YAML, you can add custom triggers and stuff. And of course, you need to change the staging to the environment name that you want to build. In that concrete example, if you have a .env.development and a .env.production, you will end up with two YAMLs, one where the staging is replaced by production and one where the staging is replaced by development.
2. Store your variables in JSON files
You could store you variables in JSON files and then use the JavaScript files (which previously stored your variables) to load the data out of those JSON files. Here is how this can be done in detail:
Create a file JSON file which contains all the variables you need to change depending on the environment, e.g. config.json with the following content:
{
"key1":"",
"key2":"",
"key3":""
}
Now you can use the File Transform Task of Microsoft in you Release Pipeline to modify this JSON file. The task will take the variables defined in the pipeline (as described here) and will overwrite any value in the JSON file which has a matching key. For example, you define key2 = "foo" in your pipeline. The File Transform Task will produce this JSON:
{
"key1":"",
"key2":"foo",
"key3":""
}
Last but not least, you need to get the variables defined in your JSON file into your react app. Therefore, you can simply load the config.json into your JavaScript file (which contained those variables before) with the following command:
export const config = "./config.json";
I hope this helps. If anything is unclear, just leave a comment and I can try to explain it :)
Related
I've been working on this for several hours and have been trying out a number of suggestions in similar questions here.
I can run my gatsby site develop build just fine, but when I run "gatsby build" I'm running into this error.
Invalid plugin options for "gatsby-source-contentful":
- "accessToken" is required
- "spaceId" is required
not finished open and validate gatsby-configs, load plugins - 1.427s
I have one .env file named ".env" with both of the necessary env variables, and in my gatsby-config file, I have it configured like this...
resolve: 'gatsby-source-contentful',
options: {
spaceId: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
}
I've tested out the accessToken and spaceId by manually adding them into my gatsby-config plugins options and ran "gatsby build" and they are working fine. When I change the config back to the env variables though, it's no good and I get the error I mentioned previously.
One thing I tried just recently was to make another .env file and name it ".env.production" and it threw a different error like this...
“error Cannot access Contentful space “*********ab” on environment “master” with access token “***************************************1234”. Make sure to double check them! (value)”
This led me to look into the master environment on contentful but I'm pretty new to it and it's got me confused.
I can find a lot of questions here with the same type of problem but I'm yet to find a solution that works. Any gatsby experts out there who've had this problem?
According to Environment variables docs:
In development, Gatsby will load environment variables from a file
named .env.development. For builds, it will load from .env.production.
So, in your scenario, just duplicate and rename your .env file to .env.development and .env.production. Gatsby will take the needed data depending on the fired command.
Originally, I had my distDir set to a folder within my Firebase Functions directory for deployment, however, the duplication of React when running the app in dev mode led to some errors, so I've had to comment it out.
Is there a way to specify the next build commands output directory within the command? Like next build dir='../functions/next'.
Or is there a way to separate dev builds directory (from the next command) from the production builds (next build) within the config?
I found following solution for this problem:
You can set custom environment variable that decides where your build will be generated:
BUILD_DIR=myBuilds/buildXYZ yarn build
OR
BUILD_DIR=myBuilds/buildXYZ npm build
In the next.config.js you can use your environment variable like this:
module.exports = {
distDir: process.ENV.BUILD_DIR || '.next',
}
Now your build will be dynamically generated in the myBuilds/buildXYZ directory defined in the BUILD_DIR variable.
One thing to notice: If you want to use the next export command (or any other command using the build directory), you should also add the environment variable before it, e.g.:
BUILD_DIR=myBuilds/buildXYZ yarn export
According to https://github.com/zeit/next.js/issues/1513, this may need you to update to the next version. But it looks like they added a feature to next.config.js file. All you have to do is add the destination for your dist:
module.exports = {
options: {
dist: '.next'
}
}
Haven't tested it, but it was successfully merged to master and marked as resolved.
The build files generated through create react app have different names(hash code) every time.
I would like to give a custom names for the generated files.
Is there any possibility to do the same?
You can change the output filename by customizing the filename property in webpack config -- refer to https://webpack.js.org/guides/caching/
The default implementation is kept like this because, because every time you build an asset, it generates a new name and browsers won't be able to serve a cached response.
If you change the name to a constant you might need to clear the browser cache manually/ disable cache to see your changes immediately. (I think...Applicable only in prod mode as dev mode makes use of Hot module replacement)
Steps to change file name in CRA.
npm run eject This will unwind the hidden configs from CRA and show some additional config folders
Move to the config folder.
Edit file webpack.config.js (Somewhere around line 172 - 180 you can see filename: section where this is defined)
Following up to my comment, if you absolutely must change Webpack configuration you can also consider libraries such as:
Craco
Rescripts
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.
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..