So far, we have learned the essentials of Angular. Every application needs to be deployed and that’s the topic of this article. So here, we will cover how to -
And if you’ve not read my previous articles of Angular series, you can start your journey with Angular from the following links.
Let’s get started.
Preparing App for Deployment
So, in this article, we’ll deploy a very simple application. And I have attached the application code with this article. Download the source file and run
- PS C:\Users\Ami Jan\deploy-demo\deploy-demo> npm install
- PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve
So in this application, we have 2 pages. 1 is the home page and the other one is the list of GitHub followers page. So, this application includes routing and consuming HTTP Services. So here, we have only front-end and back-end, in this case, the GitHub API is provided by a 3rd party. In your application, you may build the backend yourself. So in this article, we’ll also discuss how to deploy the frontend and backend.
In terms of deployment, here we have a couple of options. The simplest option is to copy this entire folder with all its files into the non-development machine.
So, copy this folder and paste it into production machine and there, run the following command.
ng serve
But there are a couple of problems with this approach.
- It may have a huge number of files. And if you look at node_modules folder, here we might have 23000 files and the total size of this folder is more than 230 MB approximately.
And, of course, we can exclude this folder and we can run the command on the target machine.
npm install
It installs all the npm packages referencing into this project. But still, we have a problem with this approach as well.
Here, in the terminal, look at the size of the vendor bundle.
Yes, it is 2.63 MB. And even it is a very simple application. Moreover, we’re not using any 3rd party libraries. We’re just using Angular.
We can do much better. So, let’s see few optimization techniques we can apply here. These techniques have been around for more than a decade and they are not specific to Angular. You might be familiar with these techniques as well.
- Minification
Removes all the comments and whitespaces from the files.
Before | After |
//// This is my comment//public class HomeComponent{onClick() {}} | public class HomeComponent { onClick() { } } |
- Uglification
This involves renaming long descriptive variables and function names into short and descriptive names. And we don’t need to do this manually, a lot of tools out there that do this for us.
Before | After |
public class HomeComponent { onClick() { } } | public class HC { oC() { } } |
- Bundling
We also knew this already. So when we serve our application through Angular CLI, it automatically creates a few bundles for us. And each bundle is a combination of multiple javascript files.
Without the bundle, if we serve our application exactly the way we’ve structured the project into different files and folders. The client has to send hundreds of requests to download the application from the server. And it is very inefficient. By combining multiple files into a bundle, the client can get a large portion of the application's code using 1 HTTP request. And this means the application loads faster on the client. And it also allows the server to serve more clients. Because instead of serving let’s say 500 requests from one client, it can serve 5 requests from that client and at the same time it can serve several clients.
- Dead Code Elimination
It involves removing any code that is not part of the application. For example, you might have created a few classes. But perhaps we have not used them anywhere in the application, it doesn’t make sense to include these classes in our final bundle. So, we wanna exclude this. Similarly, if we have reference a few other 3rd party libraries in our package.json but we’re not using them. We don’t wanna bring them all these 3rd party libraries in our bundles. So this is Dead Code Elimination.
- Ahead of Time (AOT) Compilation
This involves pre-compiling Angular components and their templates and this will have significant improvements in the performance of our application.
Good News
We can apply all these optimization techniques using a single command in Angular CLI.
ng build –prod
So when we build our application using Angular CLI with this command. Angular will produce highly optimized bundles. And then we can simply deploy these files to a non-development machine.
JIT vs AOT Compilation
Every application is in compilation step. So far you’ve not seen compilation because it happens behind the scene. In the Angular framework, we have a compiler. The job of the compiler is a little bit different from other compilers you might be familiar with. For example, a C++ compiler takes C++ code and converts it to a different language like machine code. Angular compiler, in contrast, takes javascript code and use javascript code. It might be confusing for you at the beginning but honestly speaking it is very easy to understand.
Let’s discuss using an example.
- <div>
- <p *ngIf="authService.isLoggedIn()">
- Welcome {{ authService.currentUser.name }}
- </p>
- </div>
Look this is the template HTML code of our home.component.html here we have interpolation string for rendering the username field. If we load this HTML file in a browser. Are we going to see the value of the current Username in the browser? Of course not, we’re going to see this as static text exactly as it is here. So this curly braces syntax is only meaningful to Angular. The same is true for the property and even binding expressions. Browsers don’t understand them.
So when our application starts compiler is going to kick in, it’s going to walk down the tree of the component and for each component it is going to parse its templates. So in this case, it is going to look at the template of the home component and it seems that here in the top, we have a div and inside the div, we have p tag and inside this p tag we have some static text plus some dynamic text in interpolation string. So, based on this template, it's going to produce some JavaScript code to create the structure in the DOM. So here is a very simplified example, when Angular compiler parses the template for our home component it may produce some javascript code like this.
- var div = document.createElement(‘div’);
- var p = document.createElement(‘p’);
- div.appendChild(p);
- ….
This is how we create the elements and append them according to the structure of the component template HTML. And after append, there will be some code to take the value of the createUser.name field from our component and displayed it in the DOM. And also there is more code for detecting the changes then the value of this field and refreshing the DOM as necessary. So Angular compiler produce this javascript code at runtime and then this code will be executed and as a result, we see the view in the browser. This is Just-In-Time (JIT) Compilation. In other words, the compilation that happens at runtime.
This JIT compilation is perfectly fine when you’re developing the application on local machine. But it is very inefficient for a production environment. Because this compilation step is going to happen for every user of our application. So every time user lands on our application, the Angular compiler is going to walk down the tree of our components and compile all these components in their templates. Now you can imagine as the number of components increases or as our templates gets more complex. This compilation step is going to take longer. Due to this reason, we need to ship Angular compiler as part of the vendor bundle. That is why our vendor bundle is 2.6 MB even for the simpler application because almost half of its bundle is dedicated to the Angular compiler.
Now, what’s the solution? We can perform this compilation step Ahead-Of-Time before deploying the application then this compilation step doesn’t have to happen for every user. Our users will download the final precompiled application. And that’s mean, our application will
- Start Faster
Because browsers don’t have to wait for the Angular compiler to compile our application.
- Smaller bundle size
Also, we no longer have to ship an Angular compiler with our vendor bundle and this will reduce the size of this bundle significantly.
- Catch template errors earlier
Another benefit of AOT compilation is that we can catch all the errors in our templates earlier at compile time before deploying our application. And in contrast, with JIT compilation we see these errors at runtime. But if you have the complex application with lots of pages, we may not be aware of the errors of templates until we navigate to a particular page in our application. In contrast, AOT compilation we can catch all these errors at compile time before deploying our application.
- Better Security
And finally, with AOT compilation, we get better security because we compile HTML template and components into javascript files long before they’re served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are less opportunities for injection attacks.
So these are the benefits of AOT compilation.
Angular Compiler in Action
Now let’s see the Angular compiler in action. So if you open up package.json, under dev dependencies we have @angular/compiler-cli dependency.
- "devDependencies": {
- "@angular/cli": "1.1.0",
- "@angular/compiler-cli": "^4.0.0"
- }
This is the angular compiler package that takes the significant part of our vendor bundle. Now let’s see how to run the Angular compiler
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> node_modules/.bin/ngc
bin is the directory where binary files are located and ngc is used to runthe Angular compiler. And with the help of this command, angular compiler compile the components and their templates. Now back in VS Code again,
We can see we have 43 new files here. Here is an example. In the src/app folder, here we have a new file of css with suffix (.shim.ngstyle.ts). Let’s have a look,
So currently we have no css for app component template. So styles array of type any is empty. But if we did have any styles, the Angular compiler will export these styles using a const here.
Here we have another file app.module.ngfactory.ts. So for every component that you have a reference in our application. Angular compiler generate an ngfactory file,
Look at this code here. This is the combination of the component and its template. So we can see a little bit of the markup here like router-outlet, app-root. So this is the code that angular compiler generates at runtime. And of course this is typescript, so you can transpile it into javascript and then it will be executed. And in the result, we get rendered app component in the DOM. As you can see this code is so cryptic. So it is not designed for humans to read. I just wanted to show what happens under the hood when you load the application. So this is how compilation works. Each file ngfactory for each component is generated referenced in our application.
In the real world, we don’t any need to run the command of ngc. It was just because of the demonstration. We use Angular CLI to build our application for production and Angular CLI will internally run the Angular compiler.
Building Applications with Angular CLI
Now we’ll see how to use Angular CLI to build the application and get deployable packages for production. With this, you’ll get all the optimization techniques that we discussed earlier in this article. But first of all, we need to delete all the files that we generated when we run the compiler.
And discard all the files.
Now, back in terminal again, in order to build our application for production -
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng build --prod
And, this will create the deployable package that we simply copy paste to a different machine or use FTP or any other mechanism to deploy the production server. But before running this command, we run ng build (without --prod flag). So,
Don’t worry about the yellow warning. Look here we have vendor.bundle is 2.55 MB, which is still big. So we don’t have AOT compilation here. In other words, the Angular compiler is part of the vendor bundle. Now, back in VS Code, we have a folder dist stands for distributable.
And here we have favicon icons for our application, we got the glyph icon files which is part of the bootstrap. We got index.html and bundles.
First, take a look at index.html.
It is slightly different from our index.html which is in the src folder. So here in the body element after app-root, we have few script references and the first script bundle is inline.bundle.js and then reference to polyfills and other bundles in our application. And in contrast, index.html that we have in src folder doesn’t have any bundle script because during development these bundles are injected into the body element at runtime.
Now back again in dist folder, here every bundle has 2 files. First one is the actual bundle file and the 2nd file is the map or source map file. The purpose of this map file is to map a piece of javascript code in the bundle to its original src file. So when you’re debugging the application in chrome. This map file allows Chrome debugger to show you the actual code in the src file not in the bundle. Let’s take a look at one of these bundles,
We can see we don’t have any of the optimization technique which we discussed earlier. We have a lot of comments, a lot of whitespaces, long descriptive names. So we don’t have minification or uglification. We also have dead code. So if you have created components and services that we do not use in our application, we’ll end up in this bundle. Let’s see an example.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng g c courses
And I’m not going to use it anywhere in the application. Now build the application one more time.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng build
Now our bundles are again ready. Now let’s take a look at main.bundle.js and search for courses. Here we’ll see 27 results,
So all the code of our courses component is in the bundle. So we have the dead code here. Also, we don’t have AOT compilation because the angular compiler is included in the vendor bundle.
Now let’s see what happens when we build the application with prod flag.
Now you can see, our vendor bundle size is just 1.51 MB which is almost half the size. But, by the way, this is the initial size before applying any kind of minification and uglification. So if you look at the actual file size, it will be even more smaller.
Now back in the dist folder, we have a favicon and glyphicons like before. But when you open the index.html you’ll not see any whitespaces there. And then open the other bundles in dist folder one by one. All our html markup is represented as one long string. Here we have not any descriptive identifiers. And all the function names variables are all cryptic.
Look here we have dynamic numbers besides inline file name, we call it hash. And this hash is generated based on the content of the bundle and it is the technique to prevent caching. So everytime you modify your code and regenerate this bundle, this hash is going to change and this will prevents the client browser to cach the file with the exact same name because the name of the file is going to change in each build.
We can simply copy paste dist folder into non development machine, we can use FTP or in a most complex scenario, we can setup Continuous Deployment Workflow.
Environment
In the typical applications, we have the concept of Environment. So quite often in most organizations, we have 3 environements.
- Development (for Developers)
- Testing (for Testers)
- Production (to Deploy the application)
Earlier in our Angular series, we had the quick look at this environment folder.
This is exactly to implement the concept of environments of our application. So now let’s take a closer look of what we have here and how we can define additional custom environments. In this folder, we have 2 files environment.prod for production and environment.ts used for development. And in the environment.ts, we’re simply exporting the production one property.
- export const environment = {
- production: false
- };
Here we might have additional properties i.e. (You may wanna change the color of the navigation bar depending on their environment. This way testers know that they are looking at the actual testing website, now the production website. So they don’t accidentally modify some data in the production. Or you may wanna change the name of the application in the navigation bar. You may wanna add the word testing or perhaps you may wanna use different api endpoint in your testing environment. We can add all these properties in this object i.e.
- export const environment = {
- production: false,
- navBarBackgroundColor: 'blue'
- };
So here we have added the property in the development environment (means environment.ts) now we need to add this property in the production environment as well. So let’s go to environment.prod.ts,
And here we have changed the color of navBarBackgroundColor in production. Now back in the environment.ts file and read the by default comment. It is telling that when you build your application using Angular CLI and supply the environment flag, Angular CLI will pick one of these environment files and put it into the bundle. So we don’t have to write any code to work with the specific environment object.
Let me show you what I mean. So let’s go to navbar.component.ts and here we define the field called backgroundColor and we set it to the navbarBackgroundColor of our environment object
- import { environment } from './../../environments/environment';
- import { Component, OnInit } from '@angular/core';
-
- @Component({
- selector: 'navbar',
- templateUrl: './navbar.component.html',
- styleUrls: ['./navbar.component.css']
- })
- export class NavbarComponent implements OnInit {
- backgroundColor = environment.navBarBackgroundColor;
-
- constructor() { }
-
- ngOnInit() {
- }
- }
Now let’s go back to the navbar.component.html and here we apply style binding on the nav element
- <nav
- [style.backgroundColor]="backgroundColor"
- class="navbar navbar-default">
- ...
- </nav>
And now if you wanna see this in action, you don’t necessarily build your application. You can still serve your application with ng serve but additionally we need to specify the target environment which is by default is development.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve
And if you wanna load your environment into a production environment, we can add --prod
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve --prod
This is the short form of
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve --environment=prod
Now run the application in the production environment. And open the browser, our navbar is white here.
Now, run it again in the development scenario. But for running it in the development mode, we need to kill the port. Because 4200 port is already in use. Here is the link to kill 4200 port.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve
And now it is serving in the development environment. So the result is,
Adding Custom Environments
So we have seen how to work with development and production environment objects. Now, what if you wanna add an additional environment like the testing environment or staging environment. These are common setups of a lot of organizations. So we copy and paste one of the file and rename it in the environment folder.
And look the changes here we have applied in the project. We made production property false because it is the testing environment. And now we have the new environment file, and we need to register this with Angular CLI. So back in the root of the project, here we have .angular-cli.json. it is the configuration of angular cli and here we have the property called environments and in this property, we can register all our environments. So,
- "environments": {
- "dev": "environments/environment.ts",
- "test": "environments/environment.test.ts",
- "prod": "environments/environment.prod.ts"
- }
Now back in the terminal and we can run the application with test environment flag.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng serve --environment=test
And we can also run with ng build as well
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng build --environment=test
Now let’s see the testing environment in action. And now back in the browser and here our navigation bar is purple.
And it indicates the testing environment. And we’re sure that we can work now in the testing environment.
There is something you need to be aware of when you’re working with the non-development environment, here is not hot module replacement. So if you make any changes in your code or in your environment object, the changes are not visible immediately. We need to go back to the terminal, stop the webserver and run ng serve again i.e. let’s change something
- export const environment = {
- production: false,
- navBarBackgroundColor: 'green'
- };
Now save and back in the browser, it is still showing a purple navigation bar. Which means our changes are not reflected because we don’t have hot module replacement. Its only available when you’re running your application in the development environment. So we need to go back to the terminal, stop the web server,
and run ng serve again. Back in the browser and refresh it again manually this time. Webpack will not be executed its own.
So if you wanna add custom environments, add the new file in the environments folder and make sure all the environment files, the environment object you’re exporting has the exact same property in all the versions (dev, test, prod). And also don’t forget it to register it in the .angular-cli.json and here register a new environment.
Linting with Angular CLI
The good practice that you should use to make sure that your code is a high degree of readability and maintainability, is using a Linter. It is basically a program that can be configured with various rules and then it performs a static analysis of your code to see if you have violated any of these rules. This way we can ensure that your code is clean and consistent.
This is specially important when you’re working in a team because quite often a people have different styles of writing code i.e.
- var x = “abc”;
- var y = ‘abc’;
some developers use a single quote for the string and some use double quotes. And when you mix up the single quote and double quote in the same file that looks very ugly. Some people terminate their javascript statements with a semi-colon and some don’t care about them.
So in the Typescript world, a popular tool we use for linting is tslint and if you want to study more about tslint, you can explore it from here. Now the good news is, the project we create with Angular CLI automatically have the support of linting. So, if you go to the package.json, under dev-dependencies we have the reference of ts-lint.
- "devDependencies": {
- "@angular/cli": "1.2.4",
- "@angular/compiler-cli": "^4.0.0",
- "@angular/language-service": "^4.0.0",
- "tslint": "~5.3.2",
- "typescript": "~2.3.3"
- }
Here, tslint is installed by default. And if you see in the root of the project, here we have tslint.json configuration file as well.
This is where we define all the rules. Here is an example, we have a rule of quotemark which is set to single which means everyone in the code should use single quotes for the string. And if you don’t like single quotes and prefere double quotes, you can change this to double.
- "quotemark": [
- true,
- "double"
- ]
And if you want to entirely disable it. So,
- "quotemark": [
- false,
- "double"
- ]
Now let’s see linting in action. One simple way to run tslint is via Angular CLI. So,
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng lint
Now, this goes through all the files in our project and finds all the errors and reports them in one go.
Obviously, it is not so much interactive. It is really a little bit hard to go through these errors but it is the good option for before committing your code to the repository. So, we can quickly run ng lint to see all the linting issues in your code. Now let’s take a look at the few examples
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng lint
And on line 11, we have trailing whitespaces. So let’s go to the github.service.ts and here we’ll see on 11 a trailing minor whitespace. And these tslint rules are configured by default. If this rule is annoys you, simply go to tslint and search for trailing-whitespace. So this rule is set to true and we can set it to false.
"no-trailing-whitespace": true
This is how we read the Errors one by one. And we can fix them one by one or you can use Angular CLI to fix them automatically for you. So,
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng lint --fix
And still, Errors are showing there. So ts-lint will fix the errors that are easier to fix and it leaves others for us. So currently it fix most of the errors, they’re only 2 errors left that we need to manually fix. For example, it is saying “the selector” of the component GitHubFollowersComponent should have prefix app. And this is based on the same principal that we generate a component using Angular CLI. Your component selector is prefix with the app. I personally don’t like that, you may like it, you may love it. So we can configure tslint to apply that rule or not.
So,
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng lint (to find all the linting issues in the code)
And if we supply the fix flag, we can have tslint fix most of the easy issues for us.
PS C:\Users\Ami Jan\deploy-demo\deploy-demo> ng lint --fix
So this is the good technique to find and fix most of the linting issues in your code before committing it to the repository.
Linting in VS Code
Now let’s see how to lint the code in VS Code directly.
Install the extension and then press on Reload to make it proper in VS Code environment. And then open github-followers.service.ts place one of the import statement in double quotes instead of single quote.
Look it is showing a red squiggle line. And if you click on the yellow light button, you’ll see the options on how to fix this problem. And it is also helps to remove the white trailing spaces.
So this extension is very useful when you’re coding. You can find the linting issues and fix them as you code. It is the good practice to run ng lint before committing your code to the repository.
Other Deployment Options
So we have seen how to build a deployable package for your app using Angular CLI. We can simply copy and paste the content of the dist folder into the Web Server or you may use FTP. But let’s see a few other deployment options.
- GitHub Pages
It is basically super simple web host or static content that is html, css and javascript. So we can push our code to the GitHub repository and then using some basic setup. And we can see our web application on github.io.
This option is suitable if you and your team only building front end of your application because you can’t use Github.io to host your apis. Backend will be managed and deployed separately, this is the great option. Your app may use 3rd party library i.e. you may build an awesome front end for an existing api out there like apis for browsing movies, news, events and so on or your app may consume an api built within your company but managed by a different team. So that api is developed, version and deployed independently of this front end you’re building. Perhaps it is also used as the backend of the mobile app within your company. So this is the first, simplest deployment option.
- Firebase
Firebase is the cloud platform provided by Google that we used to build the backend of our web and mobile applications quickly. So with Firebase, we get the fast scalable and real time database and the library to work with this database. So we don’t have to build APIs from scratch. And this increases our productivity significantly.
And honestly speaking if you’re working on a project and using Firebase, it would take less time and effort. And if you are working with ASP.NET Core to build the Web API for the same project, it will take double time and effort.
So we should really go ahead with Firebase. It’s the great time saver and very fast and scalable.
- Heroku
If you don’t want to use Firebase and want to build the backend of your application from scratch, you may consider Heroku. It is the cloud platform that let’s you build, deploy, monitor and scale your applications. It has the support of various languages and frameworks. It is super clean and elegant as great documentation.
Also, in this category, if you want to build and deploy the application yourself, you may use Azure provided Microsoft. Azure may give you more sophisticated features but is for larger organizations with complex needs.
It is the most recommended option.