How to build once and deployed multiple environmen

2019-01-18 07:51发布

问题:

We planned to deploy angular into amazon S3 static website, currently we are doing separate build for each environments(development/production). Is any solution to build once and deployed to all environment.

Thanks in advance.

回答1:

As I understand you right you want to have one build (e.g. a continuous integration build) for several stacks (develop, test, production and so on). If you have different settings in your environment file for each stack you will have different builds. You have only one option to achieve that with only one build.

In your develop environment file keep your developing settings, which you need for developing locally. In your production environment file use Placeholders for the settings, which are different to your developing settings.

Then you can always build your application for production and you will have your application with the Placeholders compiled inside the main.*.bundle.js.

For Deployment you have to manipulate the main.*.bundle.js file (there are the Placeholders):

  1. Pre-Deploy: run a script which manipulates the main.*.bundle.js to set the e.g. production settings.
  2. Deploy: Deploy the application to your App Service
  3. Post-Deploy: run a script which manipulates the main.*.bundle.js to set the placeholders again

Yes that isn't a nice solution, but after 3 days of researching this is the best option. You can then deploy your application for several stacks with running the scripts.

I did this with powershell scripts on Visuals Studio Team Services to use the release functionality there to deploy the application to Microsoft Azure.



回答2:

Just finished a solution to this issue for use in a number of departmental apps at work.

The basic idea (inspired by the "config" section of the "12 factor application" documentation, is to store the configuration on the server, separate from the application itself.

When you deploy the application to a server, it gets it's configuration from the server, rather than having it bundled into the application.

This completely obviates the need to rebuild the application for different environments / deployment scenarios.

Doing this requires a change in the way the Angular application consumes the configuration.

With the usual approach of putting configuration in the application's environment.ts file, the configuration is always available at runtime, and can be injected wherever needed.

With a server-side configuration, the Angular application needs to make an http call to get the configuration, so it is not available right away.

My approach was to create a ConfigurationService that loads the configuration via an http call. This service publishes the configuration via an rxjs AsyncSubject. I inject this service into all classes that need configuration.

AsyncSubject only emits a value after it's onComplete method has been called, so consumers of the config can flatMap over the AsyncSubject, and then use the resulting configuration to, for example, get the URL for an API call that they need to make.

The remaining issue is how to initialize the ConfigurationService...assuming that all API URLs are in the configuration, how does the ConfigurationService know what URL to use to get the configuration?

My solution to this is to arrange for the configuration file to be available at the same base url as the Angular application's index.html (e.g. if the index.html is at https://example.com/someapp/index.html, then the configuration file is at https://example.com/someapp/config/ui-config.json)

This allows the ConfigurationService to reference the configuration url relatively. In the previous example, it would use the url "config/ui-config.json", or "./config/ui-config.json".

For testing without a back-end service, I store the config file in app/assets/config, and then set up Angular's proxy to intercept the request for the config an return it from the assets/config folder.

For non-dev deployment (QA, Production, etc.), you need to arrange for the config file to be made available at the same location as the Angular app's index.html.

If you are deploying the Angular application separately from the back-end, this means simply putting the config file in the same folder as the index.html file.

For deployment with the front-end and back-end bundled together, as with my Java-based SpringBoot applications, with the Angular app served by the Java application, you need to arrange for the back-end to serve the config file at the expected url.

For the SpringBoot applications, I do this by using a WebMvcConfigurerAdapter that adds a ResourceHandler that makes the 'config' directory (wherever you chose to store that) and it's contents available as if it were a 'static' file, just like the Angular application's index.html