I have an Angular application that will have multiple installations (for different customers) and I'd like to use system environment variables to hold things like the URL for the back end service.
I've read lots of questions on here that talk about using config files to hold those settings, but it's not feasible for me to add files to the source code each time a customer wants to install the application.
I know I can bring an environment variable into Grunt (for development purposes) and Express using e.g. process.env.URL, but how do I get that variable into Angular itself?
Related
I'm finding inspiration from the twelve-factor app approach to organize the deployment process of small applications. I'm stuck on the release stage on guidelines that sound contradictory.
The twelve factor app says that the config should not be stored in files but in the environment, like environment variables. (I imagine that files sitting somewhere on the host can also serve as "config stored in the environment", such as a ssh private key in .ssh/private_key that will give access to some protected resource through ssh.)
I thus imagine just setting up my various hosts manually by setting those environment variables by hand (or in .bashrc or similar so I don't have to do it again every time they reboot). I only usually have 2 hosts: my laptop for development and a server for showing my work to others. If I had more hosts, I could think of a way to automate this, but this is out of the scope of my question.
Then the twelve factor app guidelines define the release stage as producing a release that contains both the build and the config. This could simply mean sending your build (for example docker images of your app) to the target host. The built app and the target host configuration being at the same place (on the same host), they are de facto combined.
I don't however have any way to uniquely identify a release or have the possibility to rollback. In order to do that, I would have to store the config with the build somewhere so that I can get back to them if I need to. That's where I'm stuck: I can't figure out how one approaches this in practice.
What sounds contradictory is that config should be read from the environment and the possibility to rollback to a previous release, which implies a previous config.
Perhaps the following workflow would be an answer, but maybe convoluted:
send the build to the host,
read the host config (environment variables, etc.) and copy them to make a snapshot of this host's config at that moment,
store both the build and the config copy in a uniquely identified place
Such that when you want to run a particular release on a given host, you :
apply that release config to the host environment
run the build which will read the config from the environment
The step of making a snapshot of the environment's config to apply it again seem somewhat convoluted and I'd like to know if there is a more sensible way to think about the release stage.
Sorry if you think this has been asked before but there doesn't seem like a good solution anywhere.
I have a build pipeline that packages up my react app into a single artifact.
The release pipeline pushes that artifact to different Azure storage accounts for each environment (Dev, UAT, Live).
Surely there is a way to use DevOps variables to configure variables in my package per environment.
Other solutions:
One build per environment - I don't want to do this because I would need to create a branch for each environment, a pipeline for each, the env configs for each, and a release pipeline for each. This means a change to 1 environment takes 3 times as long. Also, the time to build these environments trebles.
Using a JSON file and swapping this out on deployment. - This didn't work because webpack imported the JSON file into the build so whilst I transformed the config.json files. It was too late. This seems similar to using env.development and env.live and would mean 3 builds
Pull environment out of the request URL and call an endpoint - seems like my only option but definitely has flaws.
This isn't an issue in .NET (or Java I believe, .NET is my background) and was solved years ago with web.config and appSettings.
Please let me know if you have solved this and how?
Thanks for your help
Runtime Environment Variables in React for UAT and Live for a single build devops
We could use the task Replace Tokens to use DevOps variables to configure variables in the package per environment:
The format of variable in .json file is #{TestVar}#.
And define the key's values on the Variables based on the stages:
Hope this helps.
I have a Create React App Project that will be pointed to two different domains: .com and .co.uk.
I want do some localisation eg if .co.uk currency will be set as punds, email address will go to uk mailboxes etc.
What is the best way to do this? I thought window.location.href value passed by wrapping my routes in the context in App.js but having some issues with use effect and not sure if this is the most efficient approach.
The best way would be to use environment variables - this also allows for easy debugging for either version. This will require you to build the project twice for every website update - one version for .co.uk and the other for .com.
Setting an environment variable can be done through the .env file (depending on if you want it to be local you can use .env.local, if you want it to be only on production you can use .env.production and if you want to keep your production values local you can use .env.production.local) or via prepending the environment value before build, like so REACT_APP_COUNTRY=uk yarn build.
For the variables to be accessible in your application you will have to make sure they start with REACT_APP_. You can access them in your project with process.env.REACT_APP_COUNTRY (you do not need to import/install any libraries).
If you have a CI/CD set up this will be easier - you just need to create two separate pipelines to deploy a version with REACT_APP_COUNTRY=uk to the .co.uk site and a version with REACT_APP_COUNTRY=us to the .com site.
I have an AngularJS application that talks to a NodeJS backend. I have recently just hard-coded in the API address in my front-end as there has only been one environment (i.e. my development environment has been the same as my production environment).
However, as the project has expanded, I now have three environments: development, staging and production.
My development and staging environments talk to the same API (let's say dev.fooapi.com), but my production environment should be talking to a different API (let's say prod.fooapi.com).
My question is: what are some 'elegant' (I put this in quotes because who is to say what is elegant and what isn't) ways of achieving this in my application? I currently have a string placeholder in my source files that looks like 'API_PLACEHOLDER' and a Grunt task that performs a string replace anywhere in my codebase where it matches that string. Obviously this isn't ideal because the files where these placeholders are substituted are source controlled, and I don't really want to do a string replace and then accidentally commit some code that has hard coded developer API addresses because that will break in production.
Extra information: I do make use of Grunt in my application, I deploy to Windows (can't be changed, unfortunately), I use Git for source control and I do builds/deployment using Bamboo.
More than happy to answer any other questions about my issue.
Note: I need to substitute config values not only for my front end but also the back end (i.e. when I start my node server I want the port that it starts on to be configurable.
Thanks!
I'm using gulp-ng-config which allows dynamically generated angular constants to be added to my application based off the node environment variable.
In the docs from link above is an example of supply a different api url to front end app, I'm sure there is a grunt version, in fact grunt-ng-config looks like the equivalent. The values config option takes a function where you can return something based on the node environment variable
I've slightly "abused" the front-end "version" concept in App Engine (java), to implement modules before they were introduced. I have a configuration consisting of: module1-dot-myapp.appspot.com, module2-dot-myapp.appspot.com, module3-dot-myapp.appspot.com, etc., based on the version concept (more commonly used with numbers: 1-dot-myapp, etc.).
Specifically, the code in all versions is identical, but each is practically used for different purposes. This separation allows different clients to use different api versions, separate deployment schedule, staging versions, logs separation, etc.
My question is, under theses conditions, what is the best way to convert my application to "real" modules? such that "module1" is an actual module (still mapped to the same url - module1-dot-appspot.com)?
Note: my answer comes from a somehow similar exercise but in the python GAE runtime, there is likely aditional Java-specific stuff to look at as well.
First things to look at (possible show stoppers) are the app-level configs - those will need to be merged in from your different old app versions (if they exist) and will be shared by all your modules (or directed to the default module only), so they might not work as before, best to revisit the latest documentation on these configs:
dispatch file
queue
cron
DB indexes
Note: in multi-module python apps these configs might not be updated automatically at app upload, each of them may need to be uploaded explicitly, using the respective app configuration utility options.
The separate deployment schedule is almost free (each module can be deployed independently). But there may be some impact due to the app-level configs (multiple CLI invocations instead of a single one, for example)
The logs separation comes for free.
The staging story might need to be revisited, depending on what exactly you mean by that.
Other than that - you'd bring the different old versions of your app in separate module sub-directories in your new app. Check if your version control system supports this easier. The old app config file(s) would need to be "translated" into the respective module's config file(s) and some of the info would go into the new app's top dir config file.
The module URL routing should allow transparent URL mapping, but note that the URLs will actually be <module>-dot-<appname>.appspot.com and the only way to get exactly the same URLs would be to delete all older app versions before deploying the new one (due to conflicting URLs: <module>-dot-<appname> vs <appversion>-dot-<appname>, not sure if you'll get the old or the new code serving or if it's even possible to deploy the new code without error). You could use a new appname at first, just to get all ducks lined up before the switchover (possibly a new staging story you might consider going forward).
You might find helpful complementing URL routing with a dispatch file if you didn't have one before.
Finally, if you have identical files shared across modules you may consider a single per-app copy of the file, symlinked into the respective modules, if that's easier or makes sense from your source code management prospective.