Category: Angular CLI

In this article, I’ll share with you my experience of upgrading more than a dozen of Anguar 5 projects to Angular 6. These projects were small to medium in size, but they used lots of various Angular features because these are the projects from the second edition of our Angular book. Many of these projects had multiple apps configured in the file .angular-cli.json, and they were automatically migrated into the new project structure as defined in the new configuration file angular.json.

First of all, there’s the site https://update.angular.io that gives you an idea of how to do the upgrade from version X to version Y, and you certainly need to read the instructions there first. But the devil is in the detail, right?

Theoretically, the upgrade should be a 1-2-3 process that consists of the following three steps:

1. npm install @angular/cli@latest –save-dev
Run this command in your project’s dir, to upgrade (and install) the latest Angular CLI version in the devDependencies section of package.json. This command shouldn’t need @latest, but it does.

2. ng update @angular/cli
Run this command to convert the project configuration file .angular-cli.json into angular.json introduced by Angular 6.It also will update testing and tslint config files.

3. ng update @angular/core
Run this command to upgrade all Angular dependencies in the package.json file (except Angular Material and Angular Flex Layout, if used).

What else is needed

On my computer, I had Angular CLI 6 install globally, and my typical project had the line “typescript”: “~2.4.2” in devDependency section of package.json.

Before running and upgrade steps, bump up the TypeScript compiler version in your project or you’ll get an error “@angular/compiler-cli” has an incompatible peer dependency to “typescript” during the step 3. Start any project upgrade with manually changing this dependency to “typescript”: “~2.7.2”. If you still see that error, delete the node_module directory and re-run step 3.

If you use the Angular Material library, run ng update @angular/material to update its dependencies in package.json.

If you use the Flex Layout library, modify its version to 6.0.0-beta15 or later prior to running ng update @angular/core.

Your project’s .angular-cli.json might include the file favicon.ico in the asset’s property that’s not used in your app. Angular 5 would still launch your app even if this file was missing. In Angular 6, you need to explicitly remove all occurrences of favicon.ico in the newly generated angular.json.

After migration, I noticed some strange behavior in the UI rendering, which seems like a bug. In some of my apps, I had the following HTML in the component templates:

In Angular 5, it rendered just fine, but after migration to Angular 6, the browser rendered both links without the space between them: HomeProduct. Adding &nbsp; after the first anchor tag helped. I thought it might be related to the Angular compiler’s option preserveWhitespaces, but it didn’t.

Starting from TypeScript 2.7, you may need to take care of the error TS2564: Property ‘SoAndSo’ has no initializer and is not definitely assigned in the constructor. For example, the following class variable declaration won’t compile:

product: Product[];

Either set the TypeScript compiler’s option strictPropertyInitialization to false or explicitly initialize class variables, e.g.

product: Product[] = [];

Upgrading your app to RxJS 6

During the upgrade, I spent the most time updating the code related to breaking changes in RxJS 6.

Your updated package.json will include the dependency “rxjs-compat”: “^6.0.0-rc.0” after step 3. At the time of this writing, the current version of rxjs-compat is 6.1.0, so if you decide to keep rxjs-compat, update its version in package.json and reinstall dependencies. Theoretically, having the rxjs-compat package should allow you to run your app without making any changes in the app code that uses RxJS API. In practice, this may not be the case and the app may fail either during the build- or runtime.

So I decided to remove the rxjs-compat dependency and modify my code to conform to RxJS 6 structure. Remove rxjs-compat from your package.json file to avoid unnecessary increase of your app bundle size. Then run ng serve and fix the RxJS errors (if any) one by one. Then load your app in the browser and keep the browser console wide open so you won’t miss the RxJS-related runtime errors, if any.

The internal structure of RxJS 6 has changed, and you need to change the import statements to get the classes and operators from the proper places. You may start with reading this upgrade guide. Disclaimer: I didn’t follow my own advice and started learning by doing.

In the past, the golden rule was “Don’t import Observable from rxjs, import it from rxjs/observable otherwise the entire RxJS library will be included in your app bundle”. No more. The new golden rule is import { Observable } from “rxjs”; The same applies to Subject, Subscription, interval(), of(), and many other RxJS thingies.

You need to stop using the dot-chainable operators (they simply won’t work without rxjs-compat package). Now you have to use the RxJS pipeable operators, and your imports should look like this:
import { debounceTime, map } from ‘rxjs/operators’;

The ng update command added the rxjs-compat package to your project, and if you’re lucky, your app might run as before without changing the code. But some of my apps gave me build errors, while others crashed at runtime.

It also gave me the error TS2339. This time the fix included replacing the deprecated function empty() with the constant EMPTY:

import {EMPTY} from 'rxjs';
...
return EMPTY;

Another app had this:

numbers$ = Observable.interval(1000)...

This code sneaked through the build phase, but crashed my app during runtime. Here’s the fix:

import {interval} from "rxjs";
numbers$ = interval(1000)...

Don’t bet too heavily on rxjs-compat. This package may help you to quickly get your app running in Angular 6, but until you remove rxjs-compat from your project, don’t report to your boss that migration is done. Find the time and fix the code in your Angular 5 app to conform to RxJS 6. After this is done, migrate your app to Angular 6.

The next one is for those two people who also use RxJS WebSocketSubject. The API has changed in RxJS 6. In the past, you’d do this:

The release of Angular 6 is around the corner, and in this blog, I’d like to highlight some of its new features announced by the Angular Team.

I started working with Angular when it was in its early alpha versions. Every new Alpha, Beta, and Release Candidate was full of breaking changes, and the announcement of each new release was giving me goosebumps.

After the official release of Angular 2 in September of 2016, the Angular Team started to care about us the developers from the trenches; new major releases come twice a year and switching from one release to another is an easy task. Angular is gaining popularity in the enterprise world leaps and bounds, and the Angular team continues improving this framework. To the best of my knowledge, these are the new and upcoming features:

Angular Elements. While Angular is a great choice for developing Single-Page Applications, creating a widget that can be added to any existing web page was not a simple task. The package called Angular Elements will allow you to create an Angular component and publish it as a Web Component, which can be used in any HTML page. Say there is an existing non-SPA app built using JavaScript and jQuery. The developers of this app will be able to use Web Components built in Angular in the pages of such an app. In our opinion, this killer feature will open many enterprise doors to the Angular framework.

Ivy renderer. This is a code name of a new renderer that will make the size of the app smaller and the compilation faster. The size of the Hello World app is only 3KB gzipped. The Angular Team promises that switching to Ivy rendered will be smooth, and I’ll take my hat off if they’ll be able to make it a non-breaking change.

Bazel and Closure Compiler. Bazel is a build system used for nearly all software built at Google, including their 300+ apps written in Angular. Closure Compiler is the bundling optimizer used to create JavaScript artifacts for nearly all Google web applications. The Closure Compiler consistently generates smaller bundles and does a better job in dead code elimination compared to Webpack and Rollup bundlers. In the upcoming releases of the Angular framework, you’ll be able to use this toolchain for building your apps as well.

Component Dev Kit (CDK). This package is already used by the Angular Material library, which offers 30+ UI components. What if you don’t want to use Angular Material but want to build your own library of UI components and control page layouts? CDK allows you to do this. It also supports Responsive Web Design layouts eliminating the need for using libraries like Flex Layout or learning CSS Grid. CDK was released in December of 2017, but the Angular Team keeps improving it.

Schematics and ng update. Angular CLI generates Angular artifacts using the technology called Schematics. If you decide to create your own templates and have Angular CLI use it, Schematics will help you with this. Staring from Angular CLI 1.7, you can use the ng update that automatically updates your project dependencies and makes automated version fixes. With Schematics, you’ll be able to create your own code transformations like ng update.

I’ looking forward to these features that will make Angular even better, but what else could be improved, that’s not on the roadmap yet? Angular CLI is a great tool, but it has lots and lots of dependencies on the third-party software. Over the last year, several times I’ve experienced broken builds in the latest releases of Angular CLI that were caused by some erroneous release of a third-party package.

The Angular CLI folks are pretty good at releasing patches when errors are reported, but the process of regression testing should be improved, so these errors wouldn’t even sneak in. I stopped using the ^ sign for the version of @angular/clip in package.json. I use the exact version that works for me unless I have a compelling reason for upgrade.

I use the Yarn package manager for all my Angular projects. Besides being faster than npm, yarn creates a file yarn.lock that stores the exact versions of installed dependencies. Last year, I wrote about a specific use case that caused a breaking change during one of my Angular workshops.

Yesterday, I had to create a new project using Angular CLI. The project was successfully generated and started with ng serve. Then, I wanted to create a production build with ng build –prod, but the build failed with the error Cannot find module ‘uglifyjs-webpack-plugin’. I know that Webpack uses UglifyJS for optimizing sizes of the bundles, which is great, but my production build fails, which is not great at all.

The generated package.json file located in the root of my project has no direct dependency on uglifyjs-webpack-plugin, but there is one deep inside node_modules in one of the thousand (literally) dependencies used in Angular CLI projects.

To make the long story short, the WebPack team pushed to npmjs.org the new version 1.1.7 this plugin, which was empty. The Angular team got in touch with them, and an hour later, the fixed version 1.1.8 of the Webpack UglifyJS plugin was pushed to the npm central repo.

My project already had the yarn.lock file with an erroneous version of this plugin. I deleted it and ran yarn install again. This time it picked up the fixed 1.1.8 version and the ng build –prod command started working again. Thank you, the Webpack team for the quick turnaround! Happy end!

This was a specific issue with the newly generated project created at the “wrong time”. But imagine a team working on a project for some time, and their github repo didn’t include the yarn.lock file that stored the reference to the working version 1.1.6 of that plugin, and Mary (the QA engineer) decided to make a production build. A minute later, the entire team got an email titled “Who broke the build?”

The bottom line: Push the yarn.lock of the project that works and builds correctly into your version control system to ensure that the entire team has a reproducible and working build. This way, your project won’t depend on someone from across the globe submitting erroneous packages to the npmjs.org.

P.S. While npm 5 also creates the file package-lock.json with the registry of all installed dependencies, it doesn’t guarantee that each npm install will install exact versions of the packages listed there.

With Angular CLI, generating a new app and installing dependencies takes 30 seconds. Creating a production build takes another 15 seconds. And the best part is that the size of the deployed app can be as small as 55KB gzipped. Let’s do it.

1. Generate a minimalistic app with the inline template and styles with the following Angular CLI command:

ng new hello-world --minimal

2. If you’re not creating custom decorators and perform the AoT build, you don’t need to import the reflect polyfill, so comment out the following line in the generated file polyfills.ts:

import 'core-js/es7/reflect';

3. In the generated file app.component.ts remove most of the HTML markup from the component template so it looks as follows:

template: `Welcome to {{title}}!`

4. Make a production build (it performs the AoT compilation by default):

ng build -prod

5. The npm package serve is a small web server that can gzip static files on the fly. Install it globally:

npm install serve -g

6. Change to the dist directory where the application bundles were generated and serve the app (it’ll run on port 5000 by default):

There are situations when an ability to generate new Angular CLI projects from the locally installed packages is quite useful, for example:

You’re running a live workshop at a conference in a hotel and the students have to install project dependencies multiple times. When 20-30 people are installing Angular dependencies at the same time on a hotel’s connection, it can take three minutes or more.

You’re on a long flight and want to try something new with Angular.

In this post, I’ll show you how to generate Angular CLI projects in a disconnected mode.

Yarn creates a file yarn.lock that keeps track of the exact version of packages installed.

For example, if package.json has a dependency “@angular/core”: “^5.0.0”, running yarn install today would include the version of 5.1.0 of this package. If you want to make sure that all devs in your team use this version even after 5.2.0 is available, push yarn.lock in the source control repo, and everyone who pulls the code will get 5.1.0. Reproducible builds are guaranteed. While npm 5 also creates a file package-lock.json, it doesn’t guarantee the same versions for all developers.

To configure Yarn as a default package manager for Angular CLI, run the following command:

ng set --global packageManager=yarn

Now let’s see how to create a local directory (a.k.a yarn offline mirror) with cached packages so Yarn can use it without the need to connect to the Internet.

Perform the following steps before boarding the plane while the Internet connection is still available.

1. Configure a directory for locally cached packages by running this command:

yarn config set yarn-offline-mirror ~/npm-packages-offline-cache

This will create a file .yarnrc in the user’s directory on your computer. In my case (I use MAC OS), this command creates the file .yarnrc with the following content

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
lastUpdateCheck 1512857190418
yarn-offline-mirror "/Users/yfain11/npm-packages-offline-cache"

2. Generate a new project with Angular CLI without installing dependencies:

ng new hello-cli --skip-install

3. Copy the file .yarnrc into the newly generated directory hello-cli

4. Change directory to hello-cli:

cd hello-cli

5. Install the project dependencies using Yarn:

yarn install

Important: Make sure that there is no file yarn.lock in hello-cli when you run this command for the first time.

This command not only will install dependencies in the node_modules directory but will also create a directory npm-packages-offline-cache in your user’s directory. This directory will contain about a thousand of compressed package files required for the offline installation. These are gzipped files with extension .tgz. This is your Yarn offline mirror with npm packages.

6. Just in case, clear the existing yarn cache to make sure we’ll be using only the files from the mirror:

yarn cache clean

Now let’s board the plane. Turn off the wi-fi or unplug the network wire. Our aircraft is airborne.

In the hello-cli directory, run the following command:

yarn install --offline

Yarn will install all the dependencies from the offline mirror. Now you can create as many Angular CLI projects as you need without being connected:

1. Generate a new project:

ng new hello-cli2 --skip-install

2. Copy the file .yarnrc into the hello-cli2 directory

3. Change to the project directory

cd hello-cli2

4. Run the offline installation of the project dependencies

yarn install --offline

Have a safe flight!

P.S. If you’re running a workshop, have a flash drive with the yarn offline miror directory and ask the participants to copy it into their user’s directories. Then they’d just need to run a command to create the .yarnrc file as explained in step 1.

I’m happy to announce that my colleague Anton and I started working on the second edition of our Angular book published by Manning. The new TOC is here. The major changes in the second edition are:

– Get rid of any mention of SystemJS – use Angular CLI only
– Replace the chapter on Webpack with the chapter on ngrx
– Add more code samples illustrating various features and techniques

I just finished re-writing the first chapter and would like to offer you a fragment that illustrates the use of Angular CLI for creating dev and prod builds. Your feedback is appreciated.

To make this article more practical, generate a new project Hello CLI using Angular CLi:

ng new hello-cli

Then build the bundles, start the dev server and open the browser on port 4200 by running a single command:

ng serve -o

Now goes the chapter fragment.

Production Builds

The ng serve command bundled the app files but didn’t optimize our Hello CLI application. Open the Network tab in the dev tools of your browser and you’ll see that the browser had to load 2.4MB to render this simple app. In dev mode, the size of the app is not a concern because you run the server locally and it takes the browser only 802 milliseconds to load this 2.4MB of code as shown below.

Now visualize a user with a mobile device browsing the Internet over a regular 3G connection. It’ll take 10 seconds to load the same Hello CLI app. Many people can’t tolerate waiting for 10 seconds for any app except Facebook (30% of the Earth population just lives on Facebook). We need to reduce the size of the bundles before going live.

Applying the -prod option while building the bundles will produce much smaller bundles by optimizing your code, i.e. it’ll rename your variables into single-letter ones, will remove comments and empty lines, and will remove the majority of the unused code. There is another piece of code that can be removed from the app bundles – the Angular compiler. Yes, the ng serve command included such compiler into the vendor.bundle.js. In the next section will talk about production builds and how to remove the Angular compiler from your deployed app.

For the most part, it consists of standard HTML tags, but there is one line that browsers won’t understand:

Welcome to {{title}}!

These double curly braces represent binding a value into a string in Angular, but this line has to be compiled by the Angular compiler (it’s called ngc) to replace the binding with something that browser would understand. A component template can include another Angular-specific syntax (e.g. structural directive *ngIf and *ngFor) that need to be compiled before asking the browser to render the template.

When you run the ng serve command, the template compilation is performed inside the browser. After the browser loads your app bundles, the Angular compiler (packaged inside vendor.bundle.js)performs the compilation of the templates from main.bundle.js. This is called Just-in-Time (JiT) compilation. This term means that the compilation happens in time of the arrival of the bundles to the browser.

The drawbacks of the JIT compilation are:

1. There is a time gap between the loading bundles and rendering the UI. This time is spent on JiT compilation. On a small app like Hello CLI this time is minimal, but in real world apps, the JiT compilation can take a couple of seconds, so the user needs to wait longer for just seeing your app.

2. The Angular compiler has to be included in the vendor.bundle.js, which adds to the size of your app.

Using the JiT compilation in the prod is discouraged, and we want the templates to be pre-compiled into JavaScript before the bundles are created. This is what Ahead-of-Time (AoT) compilation is about.

The advantages of the AoT compilation are:

1. The browser can render the UI as soon as you app is loaded. There is no need to wait for code compilation.

2. The ngc compiler is not included in the vendor.bundle.js and the resulting size of your app might be smaller.

Why use the word “might” and not “will”? The removing of ngc compiler from the bundles should always result in smaller app size? Not always. The reason being that the compiled templates are larger than those that use a concise Angular syntax. The size of the Hello CLI will definitely be smaller as there is only one line to compile. But in larger apps with lots of views, the compiled templates may increase the size your app so it’s even larger than the JIT-compiled app with ngc included in the bundle. But you should use the AoT mode anyway because the user will see initial landing page of your app sooner.

Creating bundles with the -prod option

When you build the bundles with the -prod option, Angular CLI performs code optimization and AoT compilation. Let’s see it in action by running the following command in our Hello CLI project:

ng serve -prod

Open the app in your browser and check the Network tab as shown in the next image. Now the size of the same app is only 120KB (compare to 2.4MB) and the load time is 573 milliseconds (compare to 802 milliseconds).

What a great result! Google home page weighs more than 200KB. As a matter of fact, the size of the app could be reduced even more after applying the gzip compression to the bundles. Note that the file names of the bundles now include a hash code of each bundle. Angular CLI calculates a new hash code on each prod build to prevent browsers from using the cached version if a new app version is deployed in prod.

Recently released Angular CLI 1.3.0 offers a new option –build-optimizer, which does a better job in eliminating unused code. Even in our simple app it reduced the size of this app to 111Kb. On larger apps the effect of this option can be even bigger. In one of our apps that uses Angular Material it reduced the app size from 290KB to 200KB (lots of dead code there?). The option –build-optimizer works with both ng serve and ng build commands.

ng serve -prod --build-optimizer

Shouldn’t we always use AoT? Ideally, you should unless you use some third-party JavaScript libraries which produce errors during the AoT compilation. If you run into this problem, turn the AoT compilation off by building the bundles with the following command:

ng serve -prod -aot=false

The next screen shot shows that both the size and the load time increased compared to the AoT compiled app.

We were using the ng serve -prod command, which was building the bundles in memory. If you’re ready to generate prod files, use the ng build -prod command instead. We’ll go over the process of building production bundles and deploying the app on the server in chapter 8.

The goal of this section was to get you started with Angular CLI, and we’ll continue its coverage in chapter 2.

You may need to have an Angular project that has multiple apps so you can run the build of a particular app, say depending on the customer you’re preparing the build for. In my case, I wanted to create a project with multiple apps that I use in my Angular workshops. Having a single project with multiple apps allows you to run a time-consuming npm or yarn install once and just modify the name of the app you want to run.

For example, you may have multiple versions of the main bootstrap file that load different root modules. The file .angular-cli.json has the apps section with the property main, and to run a particular app, I’d instruct the students to modify .angular-cli.json to point at a particular app, e.g. "main": "main1.ts". To run another app, I’d instruct them to change this line to "main": "main2.ts".

But then I figured out that you can configure multiple apps in the same .angular-cli.json and run the build for a particular app by name. The apps property is an array, and you just need to configure each app there. For example, the following fragment shows how I configured two applications – app1 and app2 in the same .angular-cli.json:

Now to bootstrap the app main-resolver.ts I run the following command:

ng serve --app app1

To bootstrap the main-luxury.ts, I run this:

ng serve --app app2

You can also refer to each app by its index in the apps array:

ng serve --app 0
orng serve --app 1

The option –app is available for the ng build command as well. The following screenshot shows my project after I built the app1 into dist and app 2 into dist2.

This is a pretty useful Angular CLI feature and I wanted to share my findings with you.

Update. The angular team is working on the Angular Elements module that will allow you to create Angular widgets that you’ll be able to embed into any HTML app. This should allow you to have multiple apps on the same HTML page as well. This feature should be available in the upcoming Angular 6 releases.
Also, Angular CLI 6 makes it easier to configure multiple apps in the same project in their new configuration file angular.json (a replacement for .angular-cli.json).