Angular CLI has a fantastic setup that includes Webpack, all preconfigured and ready to go. If you’ve never used it, here is the most basic thing you’ll need: And API Endpoint that changes for development to production (and, yes, you should have a happy QA in there too, but that’s not hard);
First, you’ll need to locate the environment files:
/environments/environment.prod.ts /environments/environment.ts
each of them have a simple class:
environment.ts:
// The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. export const environment = { production: false };
environment.prod.ts:
export const environment = { production: true };
Pretty basic. What’s going to happen is, during the build process, webpack will be scripted to use the prod file if it is flagged accordingly:
ng b -prod
will build your site using the environment.prod.ts file, placing the compiled files in the /dist folder and ignore the other.
ng s -prod
will build your site in memory using the environment.prod.ts file and serve it up on localhost:4200 (unless you’ve configured a different port)
So, how do you actually use it? Simple. Angular CLI automatically imported it in your main.ts file that starts your app
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule);
you’ll see, it does a check to see if you want production mode right at the get-go. So, it’s already in there. You can just add to the environment object like this:
environment.ts:
// The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. export const environment = { production: false, API_URL : 'http://192.168.168.141:53035/' //my dev api server };
environment.prod.ts:
export const environment = { production: true, API_URL : 'https://supersecretapiserver.com/' //my production api server };
Now that they are added, I like to keep all my site settings in a single file and use it as an injectable for other services.
So, I have a file called app.settings.ts
import { Injectable } from '@angular/core'; /* now, I grab that environment object from the file */ import { environment } from '../environments/environment'; @Injectable() export class Settings { /* I like to use "get" so these are treated like constants. I just return the value here. */ get ApiEndpoint(){return environment.API_URL } }
It’s basically a simple object full of constants and “global” configurations. Although this is probably enough, here’s an example of using this:
import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import { Observable } from 'rxjs/Observable'; import { Book } from "./models/book"; /* Here is me pulling in that Settings object from app.settings.ts */ import { Settings } from './app.settings'; @Injectable() export class LibraryService { public books: Observable; /* and boom, I've got the API endpoint I defined in my environment file as a read-only value that I can access anywhere in my app. */ public apiHost: string = this.Settings.ApiEndpoint; /* notice I had to include it int the constructor. don't forget that! */ constructor(private http: Http, private Settings: Settings) { } getBook(prefix: string, booknumber: string): Observable { let url = `/api/library/catalog/${prefix}/${booknumber}`; return this.http.get(this.apiHost + url) .map(res => res.json()); } }
If I use the “ng build –prod” command, It will target my production server, but my normal development which I kick off with “ng serve” will use the development server.
Obviously, if I only had one single thing which was different between the files, I could always just keep it in the comments or something and just uncomment it, but that webpack environment file tends to expand pretty quickly. I have different accounts with SalesForce, Amazon, Azure, etc… for dev as opposed to production. that Environment class is just like any other class, so you can add some major functionality to it.
Even More:
The CLI is super configurable. Go open up angular.cli.json and you’ll find this:
"environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", "prod": "environments/environment.prod.ts" }
the “environmentSource” is the default. Under the others, you can add other environments. My developers actually define one for their own machines because they keep a copy of the API server on their own box and might use different settings for their own API servers to mess with so people don’t get confused when working with the same develompent account.
So, you can do this:
"environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", "dan": "environments/environment.dan.ts" "john": "environments/environment.john.ts" "charles": "environments/environment.charles.ts" "prod": "environments/environment.prod.ts" }
then, you can call each with the associated flag, just as you would production:
serve with
ng s -charles
or build with
ng b -charles
You just have to set it up a single time and you’re done. It took me about an hour to figure it out and decide how best to use it. I hope this saves some people a bit of time.
And, kudos to John Papa (@John_Papa) for all his hard work on the CLI and his great class on @pluralsight