Whether you are into web development or not, you probably have heard some rumors about Angular JS. Let’s go through most common of them and see if they are true.
Never heard of it before
Ok, first things first. The basic building block of Angular application is component. This is a plain class annotated with some metadata making it an Angular component. Here’s an example from angular documentation:
Components must at least define a template (or templateUrl), that is HTML that tells Angular how to render the component, and a selector, which is html tag name used to specify component in templates.
In case you don’t need a template, there are directives. Directives are components without a template and they use @Directive decorator. Directives can be structural and attribute. Structural directives alter layout by adding, removing, and replacing elements in DOM. Attribute directives alter the appearance or behavior of an existing element.
To organise components into logical cohesive blocks Angular uses modules. Just like a component or directive, an Angular module is a class with a decorator. This time it’s @NgModule.
Angular supports data binding, a mechanism for coordinating parts of a template with parts of a component. Values can be passed from component to template (interpolation and property binding), from template to component (event binding) and both ways (two-way binding).
In order to fetch data there are special entities called services. But they are not limited to fetching data. As stated in angular documentation:
Almost anything can be a service. A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
And what is really peculiar about services, is that Angular takes care of creating and ensuring there is only 1 service instance present as well as injecting them into components using dependency injection mechanism.
What it actually means is when creating a component Angular looks at the types of constructor arguments and tries to supply it with needed object. For example having saw this in a component class:
Angular will try to find service by type Logger, that was declared in module providers earlier:
This approach not only makes code more readable, it also makes components and services loosely coupled making testing much easier.
Is it Angular JS, or just Angular, or Angular 2...wait, 4 ?
The short answer is - just Angular.
The world first knew it as Angular JS, which was the name of the first version of framework. Starting from version 2 it is called just Angular. Why not Angular 2 ? Because starting from that version Angular team adopted semantic versioning and fixed release schedule.
It says to release:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
It was decided to do:
- patch releases every week,
- 3 monthly minor release after each major release and
- a major release with easy-to-migrate-over breaking changes every 6 months.
What that means is, in order to ease migration, there will be new major version twice a year. That means that version number will increase pretty fast and to avoid confusion, it is not mentioned in the title.
Okay, there’s version 4 already, where’s version 3 then ? No number magic here – that’s because of the router package. It was version 3 while all the other packages were version 2, so version 3 was skipped to align package versions.
I used Angular JS and I didn’t like it
And Angular 2 is the same old Angular JS, with all its problems, but packed with fancy new features, right ? Wrong ! Angular 2 was re-written from the ground up, with new APIs and new patterns. Just take a glimpse at the size of upgrade to Angular 2 guide to get the idea of how much have been changed !
Main differences with version 1 are:
- Angular 2 is written in Typescript
- Say farewell to $scope and controllers, Angular 2 uses components
- It uses modules to organize components
- Makes heavy use of dependency injection, what makes testing a breeze
- No more $digest, zone.js is used to detect changes (more here )
- Uses observables instead of promises (more here)
Why do I need another Hypescript ?
Let’s look at the typical typescript class:
Looks much neater in Typescript, huh ?
I don’t want to configure anything, I just want to code
Good news, everyone! Angular command line interface has been officially released and this is exactly where you should start. Not only it will configure everything for you, it will even help you to move faster and more error proof with code linting and generation.
First, make sure that you your node.js version is at least 6.9 and npm version is 3.3 and up.
Then, install angular-cli globally with the following command
Now you can use angular-cli. Let’s generate a skeleton app by running
This will produce a lot of files inside my-app folder. Among them are typescript compiler configuration, karma test runner configuration, protractor e2e tests configuration, tslint linter configuration, it’s very own angular-cli configuration file, app module and a sample component file. Full list of generated files and their description is available here.
To see the app in action, navigate to project folder and type following command
And voila! Your first angular application is available at localhost:4200
But that is just a tiny bit of angular-cli possibilities. Other commands include:
- Generation of application skeleton
- Generation of components, modules, directives, services, guards, pipes and virtually every angular entity and adding it to module declaration
- Running e2e and unit tests
- Linting source files
- Setting / getting configuration values
- Extracting i18n messages from source code
- Building the application
- Ejecting your application and outputting the proper webpack configuration and scripts.
Full list of available commands is always available by typing
It’s enormously huge
Well, hello world application generated by angular-cli loads 2610 KB when you open it in browser just to show you that “App works!”. 2423 KB of that is Angular framework alone. It may be negligible small comparing to the size of the universe, but it is pretty hefty in terms of web development. Let’s find out if it can do better!
Angular-cli has 2 environments configured: development and production. By default all angular-cli commands use development environment. But we can switch them as we please, so let’s try building the app for production.
Which is alias for
Believe it or not, total page payload dropped to 135 KB with angular sources taking just 111KB, which is 20 times smaller than it was before ! What happened under the hood was 2 things: tree-shaking and uglifying.
It is applying uglifying after tree-shaking, what brings most noticeable changes. Along with mangling and minifying the code, it removes unused entries from the output, reducing the overall size of the bundle.
It takes a lifetime for the app to load
An Angular application consists largely of components and their HTML templates. Before the browser can render the application, templates must be compiled by Angular compiler.
By default angular compiles the app at runtime in the browser using the just-in-time (JIT) approach.
Views take longer to render because of the in-browser compilation step. The application is bigger because it includes the Angular compiler and a lot of library code that the application won't actually need. Template compilation errors are discovered only at runtime.
Alternatively one can use ahead-of-time (AOT) compilation.
With AOT, the browser downloads and renders pre-compiled version of the application, without waiting to compile the app first. According to angular documentation the compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload. Due to template compilation made during build, errors are discovered early.
There’s also server side rendering, which is a variant of aot compilation that renders the page completely on server but we’ll cover that later.
Although not particularly useful for this hello world application, bigger apps can further benefit from adopting lazy module loading.
Thanks to Angular modules we are able to group related pieces of functionality of our application and load those pieces on demand, saving precious load time. With lazy loading only the bare minimum needed to display the page is loaded initially. Lazily loaded modules are not loaded unless user navigates to their routes.
It’s not progressive web app compatible
You may have heard that angular-cli used to have --mobile flag while in beta, that was responsible for generating some PWA features. Well, it was decided to drop it for now after migrating to webpack build system.
But that doesn’t mean that Angular apps cease to be progressive ! All it means is angular-cli is not generating PWA features (namely service worker and manifest file) any more and this is to be done by you now.
This is easily done by using Google’s SW Precache library for example. It’s a build time tool that looks through static resources (JS, CSS and HTML) and generates a service worker file for you.
We have a series of articles about PWA in case you want to dive deeper.
It’s not search engines friendly
Single page applications, like the ones written with Angular, are great. They handle all user interaction on the client, maintain application state and eliminate the need of page reloads, but there’s one hickup - search engines don’t see content of your application.
Search engine crawlers expect plain html and not all of them are able to wait until your app has started. Thus, they usually ‘see’ something like this:
Not exactly what we would like them to see, eh ? Same thing happens when user tries to share a page with SPA.
But what if we could supply them with a pre-rendered page ? And this is exactly what server-side rendering does.
In essence it manages the state of the app on server to be able to render the page upon request, same as it would’ve been done on the client.
Server-side rendering for Angular is called Universal. Angular Universal works by compiling the app to make it capable of running on the server, a form of ahead-of-time compilation. And most importantly it brings us following features:
- Makes application SEO friendly by rendering page on the server and serving it as string, completely eliminating the need of client-side compilation.
- Further reduces starup time (even compared to AOT). And the slower is the network, the bigger is advantage of having page pre-rendered by Universal.
- Makes application more PWA friendly by gracefully degrading to server-generated application on slow connections and/or incompatible browsers.
NOTE: The resulting Universal app does not handle browser events such as mouse or keyboard inputs, nor send AJAX requests!
But don’t worry -- Angular app is still going to be loaded and there’s a tool called Preboot that will record browser events until full Angular app is loaded and play them back.
It doesn’t use shadow dom
No, it does not use it by default, to correctly work in all browsers. But that can be changed by specifying encapsulation property on the component decorator (more here). Possible variants are:
- ViewEncapsulation.None - No Shadow DOM and style encapsulation.
- ViewEncapsulation.Emulated - No Shadow DOM but style encapsulation emulation (default value).
- ViewEncapsulation.Native - Native Shadow DOM.
Data binding slows my app
For the data binding to work Angular uses change detection. Let’s see how it works.
Every Angular component gets a change detector responsible for checking the bindings defined in its template. It can perform hundreds of thousands of checks within a couple of milliseconds. This is mainly due to the fact that Angular generates VM friendly code and contrary to Angular 1, change detection graph is a directed tree and cannot have cycles (more here).
Using immutables means that we cannot change object property without creating new object, so whenever there’s a change, we get a new reference.
Let’s assume we have created an immutable object
Now changing any Billy’s property will result in a new object, so we can tell Angular to skip Billy’s properties change detection and do it only when it sees a new object reference with ChangeDetectionStrategy.OnPush:
And this way we can skip entire component subtrees checking !
Unlike immutable objects, they don’t give new references when a change is made, but fire events that we can subscribe to.
Ok, so we set the ChangeDetectionStrategy.OnPush again, but the reference to the observable property is never going to change, so how do we let Angular know that the change has happened ?
We make use of ChangeDetectorRef class, to mark this component as changed. This is a reference to angular’s change detector attached to every component.
Now component is marked for change detection after person was changed only.
At the end of the day Angular is not so black as it is painted !
It is packed with loads of features and can be pretty lightweight, fast, progressive and SEO-friendly !
Yes, it can be used right out of the box without any previous experience, but, as it is with every complex framework, to be able to exploit its full potential and use it effectively I recommend spending some time to understand its principles and common techniques.
Of course there are shortcomings, but they are no real deal-breakers and Angular team works tirelessly on making it better. One of such things is documentation, that could be a little more thorough, but there is huge community around it that is a great help in development.
Based on my experience I would advise to:
- To have server-side rendering because of Universal
- To use Test-driven development (TDD) or simply to have 100% test coverage because Angular is made with testing in mind
- To have static typing and ES6 features (like classes, generics, inheritance) because it has full Typescript support
- To make a medium-to-large application that is possibly going to expand because it has modular architecture, lazy loading and dependency injection
- To keep your dependencies down to one framework instead of having multiple third-party libraries
- If you don’t need a Single-page application (SPA) or need a simple one without features like routing, data-binding and dependency injection
- If your team is familiar with other framework, and time is of the essence
- Angular documentation
- Angular CLI documentation
- Webpack bundler documentation
- Universal server-side rendering
- Thoughtram - a blog by Angular contributor Pascal Precht with massive collection of in-depth articles
- Rangle.io - has an online version of the Angular 2 book, covering all aspects of the framework
- Nrwl blog - a blog by Angular team members and former Googlers Jeff Cross and Victor Savkin
Feel free to contact me at [email protected] if you have any questions or suggestions regarding this article, the Life, the Universe, and Everything.