How to upgrade your Angular CLI project to Angular v7 (or v6) without too much manual pain

I recently upgraded a relatively big project to Angular and Angular CLI v7.
The instructions were the same as upgrading to v6. Except, for both versions there were missing pieces that I didn’t see fully documented in one place, and the most comprehensive docs I saw on how to do it involved more manual work than I liked, so, I decided to share my findings here for the next person.

Let’s upgrade…

Prerequisites

NPM

Before we continue, make sure to have latest NPM (at least 6.2). You can upgrade your NPM by running:

We’ll use the npx tool from NPM to run binaries from local and global packages as needed.
I don’t like installing the CLI globally, that’s why you’ll see me often run npx ng instead of just ng.

Angular v7 Or Angular v6

If for some reason you really want to upgrade to v6 first, replace latest below with something like ^6.0.0 and add a --to argument to ng update, but in my experience, going to v7 from v5 didn’t require this step.

ng update

This is the tool that takes care of upgrading all dependencies in package.json, and some breaking code changes between Angular versions.

It’s awesome, but it doesn’t do everything as we’ll see below.

Installing Latest Angular CLI

First, you need to install the latest Angular CLI locally before running ng update.
We cannot just run it with npx without install, because the global CLI always passes commands to the project specific version if applicable, so, to run the command, it needs to be locally installed.

There’s another missing dependency which might break the upgrade, and you’ll have to install it as well.

Later below you’ll run npx ng build to make sure everything else is alright. If it or ng update itself complain about missing packages, just add them. For example, my project required me to add date-fns for some reason to build.

Running The Update Command

The minimum you need is something like:

The --force is required to ignore peer dependency warning.
The --from must be the previous Angular CLI version you had before. Angular CLI can be confused without it.

If you have other libraries that support upgrading, and you probably do, the more generic form of above becomes:

See below for more about libraries.

Manual File Changes

Unfortunately the following files will have to be updated and merged by hand:

  • angular.json, from an existing .angular-cli.json or similar
  • tsline.json
  • src/polyfills.ts

Create a new project using the CLI, copy the files from that project, and then look in git diff or something to restore any customizations you might have, like styles / scripts / assets in angular.json, or uncommenting/restoring some import statements in src/polyfills.ts.

Remember to go to a different directory outside your project to create a new project to copy the files from.
The command for creating new project without installing the CLI is:

RxJS Automatic Upgrade

That’s another one where order of steps is important.

First, you need to install these 2 packages:

Then import the compatibility package in your code, so that the app still compiles, as it’ll be broken with RxJS upgraded to v6+. Add the following line at the end of src/main.ts.

Then, automatically convert all files to the new RxJS syntax:

Note that this command might take LONG time if you have a big project.
Give it time. Don’t panic!
Also note that I used tsconfig.json here, the one intended for the editor, not the project specific tsconfig.app.json. It’s because it might be better to upgrade any code in tests too.

The reason I used tslint directly is that the -c flag didn’t work for me on Windows, not from rxjs-5-to-6-migrate directly (it is a CLI), and not from npx ng lint.
After you finish. You can also copy the contents of node_modules/rxjs-tslint/rxjs-5-to-6-migrate.json and merge them into your project’s tslint.json file, and do the whole thing using just npx ng lint --fix.

After that, run npx ng build and see if there are any few left over errors, and correct them manually.

Then you can try removing the import in main.ts, and npx ng serve to see if everything is good, and no other library breaks.

Manual RXJS Upgrades

After the RxJS automatic upgrade, npx ng build will probably still give you RxJS related errors.

Don’t worry about cannot find module ... errors. These are fake and caused by other errors above them.

The one manual change I had to do after running the above command was to go in VS Code, and Find & Replace all ObservableOf to just of. I didn’t need to fix the import statements.

You may also get a few duplicate import errors. This is rare. In my project it was caused by some file importing delay from lodash, and using the RxJS delay operator instead. They should be few enough to be not too bad to fix manually.

If you get too many errors for too many operators, make sure you did install and import rxjs-compat BEFORE running the RxJS upgrade.

Manual Library Upgrades

Some libraries might require manual upgrade.

For example, The Telerik (now Progress) Kendo UI library can be upgraded by running:

Some libraries will be upgraded automatically for you, but have some code left behind.
You’ll just have to run ng build, and fix errors manually by checking the libraries’ docs and searching.

In my experience on a relatively big project, that wasn’t too much work.

That’s It

Hopefully no pain from libraries etc.

If you are able to get the site running in the browser, and all functionality seems to be working as before, create a pull request for your team, and apologize to them for the massive size of changes due to RxJS upgrade!

Cheers,

Try latest Angular CLI Beta / RC, with Angular v7 and the new Ivy compiler, no install required thanks to npm and npx

There are some pretty nice features in Angular CLI 7, like user prompts offering multiple options when creating new projects. Also it comes with Angular 7 support, which itself has some nice features like performance and routing improvements, the new Ivy compiler, and support for latest TypeScript.

In this post I’ll show how to try out the new combo easily.

TL;DR

Prerequisites

Make sure you have Node 8.x or higher (run node -v to check). Then that you have NPM 6.2 or higher (run npm -v to check).

I highly recommend upgrading NPM at least to latest, by running npm install --global npm, or npm i -g npm for short.

Using the CLI Without Install

Recent versions of NPM come with a nice utility called npx. It allows us to run any CLI package without installing it. If we are inside a Node project already (we have package.json), it allows us to call any CLI tool from inside our project’s node_modules/.bin folder.

For Angular CLI, the NPM package name is @angular/cli, and it gives you the CLI command ng.
So, this is how I’d create a new project using the current version of the CLI, and run it in the browser, using ng serve -o (-o opens it in the browser).

In the first line, we downloaded @angular/cli from the NPM registry, that’s why we needed the full package name. In the last line we just used the command ng that we knew was available in sample-project/node_modules/.bin.

Note that we didn’t need to escape the -o flag in the last command.
The Angular CLI usually sets the npm start script to ng serve, so the line npx ng serve -o is the same as:

Except we didn’t need the -- bit, that makes npm send the argument to the actual CLI command instead of NPM itself.

Managing The Correct Version

If we already have the Angular CLI globally installed (via npm i -g @angular/cli), npx will use the version that’s installed by default. We can force a download of the current version by adding -p to the first line, and specifying that we want the ng command manually, like:

Another way is to include the version in the command, like:

I added ^ to ensure I get the latest 6.x.x, but it’s optional.

Instead of a version, we can use a tag (a named version), let’s see what tags are available for Angular CLI by running npm info @angular/cli dist-tags. The output might look like:

You can run npm info @angular/cli, without appending dist-tags, to learn so much more about the package, like all versions, description, license, dependencies, and more.

Now, to make sure we get the latest version of the CLI, we can use the tag instead of the version, like:

You do NOT need to do this if you never install the package globally (or if you globally remove it).
I usually do NOT install it myself.
But there’s benefit in learning about the gotchas, and about tags.

Using Prerelease Version (No Ivy Yet)

As you saw above, we don’t have many tags really. The only tag other than latest, is next.
So, to create a new Angular project using the latest beta/RC version of the Angular CLI, we can simply run:

You’ll see the fancy new project prompts, and after that, you can confirm the version that was installed by running:

npm ls shows the locally installed version of the package, and you should then see the latest beta or RC being used.

Go ahead and play with it!

Enabling Ivy compiler

There’s another flag you have to add when creating projects in order to use the Ivy compiler, which is --experimental-ivy. The command to create a new project becomes:

Some Ivy compiler guides suggest that you need to activate Ivy compilation by adding angularCompilerOptions object to your tsconfig.json file, with a enableIvy property set to true or "ngtsc" or "tsc" , but I didn’t seem to need to do any that.

To be impressed by Ivy, run:

And notice how the main .js file is only 32KB!

Upgrading Existing Projects

If you already have an Angular CLI project, using the latest stable version of Angular CLI and Angular itself, you can use ng update to try out the upcoming bits.

It would look something like:

And if you use Angular material, also add:

Note that these commands are pure Angular CLI schematics magic not NPM as most of the other stuff mentioned here.

Conclusion

That’s all you need to start playing with the newest bits, so go on and hack along!

Cheers,

Little Known Angular XSRF Protection Support In Http & HttpClient APIs (v2.0+ vs 4.3+)

This post is about a new feature / code restructure in Angular v4.3+ that is pretty well documented, yet, hardly talked about in posts, and worth drawing special attention to.

The feature we are talking about here is Angular helpers for guarding against XSRF attacks in its old and new HTTP modules.

What Is XSRF? (Cross Site Request Forgery)

XSRF (Also knwon as CSRF) is a form of web security attack that can allow others to impersonate your identify and perform some actions on websites that you are already logged in to. Let’s start with an over simplified version of how the attack and protection work (as I understand them).

XSRF Attack

  • You login to website A and get a session cookie, maybe use it a bit
  • You open website B in a new tab or even the same tab, you are still logged into website A
  • The owner of website B (or someone who hacked it) happens to be a user of website A too, and knows what calls it sends to the server to perform different tasks
  • Website B loads a hidden form with the submit URL going to website A
    . It could be sending an email on your behalf, deleting many important items, whatever that is you can perform in website A
  • Website A takes the request and performs it, because you are still logged in

XSRF Protection

There are many ways to protect against this attack. Mainly you’d use server-generated token stored in somewhere that’s not a cookie.

A classic server side application with a single form each page that submits back to the server can generate a token as a hidden field in the form, and then validate it on submit, and generate a new token for the next page etc. Website B will not have a way to generate a valid token when trying to simulate the server form.

A client side application (SPA) could do the same with headers, sending the token in a header when making any API request (A.K.A AJAX call), and getting the new token in the response of that API / AJAX call.

The initial token may be obtained via a call to a known API, or in a cookie that’s downloaded when the HTML page is loaded. Since the other site can only do only put a form on its own page, it cannot modify headers to inject the token, or call the API directly due to CORS (Cross Original Resource Sharing) policy.

Angular HTTP APIs & XSRF Protection

By default the Angular v2+ Http service (from angular/http HttpModule) had builtin support for the Cookies To Headers XSRF protection technique we just mentioned.
If it detects a cookie with the name XSRF-TOKEN, it adds an HTTP header named X-XSRF-TOKEN with the same value to the next HTTP request you make.

Since the support is so transparent, I have seen developers who did not even realise it’s there. If you are a front end developer who had someone else on the backend implement the server issuing and validation of the tokens, you may not even realise it’s there.

But things changed slightly in Angular v4.3, that you probably need to be aware of.

HttpClient

In Angular v4.3, a new library for creating HTTP (AJAX) requests was added to Angular.

Instead of injecting an Http object from @angular/http as you did since v2.0, you inject an HttpClient from @angular/common/http. The new HttpClient has several new features but most notably:

  • Automatically maps responses to JSON by default (configurable)
  • Added a pipeline for injecting middleware to requests/responses (called interceptors, like those of AngularJS v1.x)
  • Has some really cool testing utilities that are much simpler than the old v2.0 Http module

Whether you like it or not, you’ll probably end up using the new HttpClient in your Angular applications. This is because starting Angular v5.0, the old Http will be deprecated (so it may be removed entirely in v6).

For the record, the relatively quiet introduction of the new module in v4.3 and the deprecation of the old in v5 still makes me feel anxious regardless of how good the new one is. The old one generally just worked, and the way it’s replaced reminds me of the 3 router versions that were written during Angular v2.0 pre-releases.

XSRF Interceptors

Since the new HttpClient came with proper support for request and response interceptors, it made total sense for the XSRF support in it to be implemented as interceptors as wel, not as part of HttpClient itself.

This is all cool and good design, but there is a catch, which although is well documented, it’s not having enough people talking about on Medium and Twitter etc.

The XSRF in HttpClient is an opt-in feature. It’s NOT enabled by default, unlike the Http service. This means that you could easily migrate your code from Http to HttpClient and not realise that your builtin XSRF support has been lost, until you test the application and you start getting 403 Unauthorized errors from your API of course.

Luckily, all you need to do to get the support back is just import another module, like:

// import { HttpModule } from '@angular/http';
import {
  HttpClientModule, HttpClientXsrfModule
} from '@angular/common/http';
// ...

@NgModule({
  declarations: [
    AppComponent,
    // ...
  ],
  imports: [
    // Now this one is gone:
    // HttpModule,

    // New replacement
    HttpClientModule,
    // Restore Xsrf support
    HttpClientXsrfModule,
    // ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Gotcha

The old HttpModule supported sending the XSRF-TOKEN header for all HTTP requests. While the new HttpClientXsrfModule made sure it doesn’t send the header for GET or HEAD requests.

GET requests don’t make much sense for XSRF attacks anyway because the attack is about changing data while impersonating you (the attacker cannot get the result anyway because of CORS rules). GET requests by definition should not change data.

However, if your API relies on this, your app might break when you move to HttpClient. In that case you might want to look at this Github issue I created and apply the workaround github.com/angular/angular/issues/19885

More Goodies

The HttpClientXsrfModule also makes it easy to change the cookie & HTTP header keys separately if you require that.

Of course you have to remember that both XSRF protection and JSONP require server support as well from the API server you are calling for them to function.

Finally, the same support is also included as opt-in for JSONP requests as well, by adding HttpClientJsonpModule (also from @angular/common/http) to your imports. This utilizes the power of interceptors that allows them to avoid sending an HTTP request completely and do something completely different instead.

As I said, the usage of HttpClient in general, as well XSRF support (and what is XSRF in general) is well documented by the Angular team.
Check it out at https://angular.io/guide/http.
I still noticed that not enough people are talking about this feature and the actual change, so, hopefully this post can bring some awareness to it.

My Experience Running Jest In A Real Angular CLI Project On Windows

Jest is an alternative test runner by Facebook. It’s popular in React world. I was wondering how it’ll be like in an Angular CLI app. I knew a new semi-empty app won’t be a good enough test, so, I checked it in a real private project I’m working on, so see if it has any benefits for the project and the team.

While I cannot share the project codes, I can still share how the experiment went, as I talked about it yesterday at the ng-sydney Angular usergroup April gathering, also, as I logged it in a related Angular CLI github issue by a friend ng-sydney attendee.

Introduction

For the record, I tried Jest with instructions from @thymikee‘s post (which uses jest-preset-angular), and it worked just fine.

Let me share my findings:

Result Summary

  • It works!
  • It took some small changes.
  • It seemed slower in my case.
  • It caught more errors than Webpack/Karma/Jasmine, which I was very grateful for.
  • The experience is quite different though that I won’t make it the default my team yet.

Required Changes

  • I started with all the steps in the post above.

  • For some libraries I had to follow this github guidance, which made the jest property in my package.json look like:

    The transformIgnorePatterns is the most interesting here. I used \\ because I’m on Windows, and I used ^<rootDir>\\ to try to speed things, although it didn’t make a big difference. There’s also "allowJs": true in "compilerOptions" in src/tsconfig.spec.json.

  • I also had to change the tests. The post mentions all the changes needed (mostly only changing jasmine. to expect. in a few places).

    But there’s another change I had to do, which is removing any expectationFailOutput, which is when you give a custom error message for when a matcher fails to match. Seems Jest does not support that.

Gains

  • Jest seems to run tests in more isolation than the current Webpack/Karma/Jasmine combo, which showed me some errors in my tests that somehow didn’t show before.

  • Jest is reporting which tests are taking too long, the slowness warnings were useful smells to identify not-greatly-written tests.

  • The watch mode is very nice, even though it seems to work off git changes not file watching, which can be confusing at first when you see slightly more files than expected, but it’s still very useful.

Issues

  • As mentioned in Required Changes above, now I cannot use custom error messages in my test matchers (that said, it’s true that default matcher errors are very beautiful and obvious, but still).

  • At the moment, it seems the jest-preset-angular initialization code needs optimization. It doesn’t call polyfills.ts and instead calls its own set, even though it’s optimized for Angular CLI (for example, it uses src/tsconfig.spec.json).

    More importantly, it imports the entire rxjs library, which might hide errors when you forget to import some operators.

  • It’s surprisingly slower than the Webpack/Karma/Jasmine combo!

    For my 196 tests, the Angular CLI v1.0.0 default test runner (with Angular 4) takes ~ 55 seconds, while Jest takes ~100 seconds.

    Update: That conclusion might not be accurate. The time I quoted for each test runner is what the test runner reported. This might for example not include Webpack compilation and browser opening in Karma and might be total time in Jest. If so, then the total time would be the same.
    Thanks @hugoccampos for bringing this to my attention.

  • No browser tests debugging apparently (It might be my ignorance here). A bit harder maybe for those starting testing.

    The Angular CLI does a great job at making testing easy for those not used to it.

  • When Jest itself fails to run, for example if I put a badly formatted regex for transformIgnorePatterns shown above, or mess up something in my src/tsconfig.spec.json file, the errors it shows are very cryptic and tell you nothing that can lead to the real issue (unlike matching errors in tests, which are very nice).

Angular 4.0 Final Is … Here! And Angular CLI 1.0 Is Final Too!!

Update (March 24)

Angular 4 Final Is Out Already

Check out the official announcement, and github changelog.
After that, check the updated documentation for Angular 4 at angular.io.
If you need access to Angular 2 docs, check the black-and-white official docs archive at v2.angular.io.

Update 2

And, on the same day, just as mentioned earlier in the post below…

Angular CLI 1.0 Final IS Out Too

Checkout the changelog, README / Docs.
And if you ever used Angular CLI before v1.0 final, check the official upgrade guide.

Hello, This is Meligy from GuruStop.NET.
Good news, we are expecting Angular 4 final any hour now!

How Do We Know?

During the ng-sydney Angular meetup gathering last Wednesday, Stephen Fluin from the Angular team repeated a couple of times that Angular 4 final is expected this week.

A quick look into the latest Angular team meeting notes also confirms that Angular 4 is due on Thursday, March 22 (although they mentioned there are a couple blocking issues, so, it might be on Friday or so).

Angular CLI, the best tool to create, develop, and test Angular applications, is also going to be released as 1.0.0 final alongside Angular 4.

P.S.
If you prefer to add server-side rendering, you might check Angular Universal fork of the CLI fork for Node, and `dotnet new Angular` for ASP .NET Core. If you need to build an Ionic app, check Ionic CLI 3 beta. They all would come with Angular 2 support by default only though, while the official Angular CLI supports generating Angular 4 projects by running `ng new app-name –ng4`.

[Video] Angular 4 And The Angular CLI

If you want to learn more about Angular 4 and the Angular CLI, see Stephen Fluin`s video here:

[Video Playlist] More Recent Talks, NG-NL

If you are interested in more free up-to-date Angular videos, the NG-NL Angular Netherlands conference also took place last week, and many session videos are available now in this YouTube playlist:

https://www.youtube.com/playlist?list=PLQi8NNYCH8TDFnOhjrIsjZGMD6Ks8SQid

Angular 4? (Not 3!!)

Just for those who don’t know, the reason there is no Angular 3 is that the Angular router for Angular 2 has been rewritten 3 times, and the NPM package for Angular router is now 3.x, while all other Angular packages are 2.x.

To make all the packages the same version again, the Angular team skipped version 3 entirely, and jumped directly to version 4.

It’s worth reminding though that Angular 4 is mostly backwards compatible with Angular 2. You should expect most if not all your applications to continue to work with it.

And a final reminder, it’s “Angular”, for Angular 2+, and “AngularJS” for Angular 1.x. These are the names that the Angular team prefers, and that’s what you’ll see me use more often going forward.

What’s Next?

Once Angular 4 final is out, I’ll send you a follow up email, with a very customized writeup of what I personally find most exciting about Angular 4, and can’t wait to use in all my production projects.

I’ll also share some awesome resources for RxJS and TypeScript.

Stay tuned!

Cheers,

– –

Meligy

ng-sydney | Usergroup Founder & Organizer

Shared Modules In Angular Apps: Providers Best Practices And What Does `forRoot()` Do?

When you write a shared module for your application, that contains stuff you use in other modules in the same app, you typically want all the services in that module shared only once.

If you just put the services in the providers property of the shared module’s NgModule() decorators, you might get weird cases, especially with lazy loading, when it feels like there’s more than one instance of the service. This is bad if you want to have shared state.

So, there is a better way to write your shared modules:

import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
// ... other imports

export const providers = [
    // ... your shared services here
];

@NgModule({
    declarations: [...],
    imports: [
        CommonModule, 
        SomeLibraryModule,
        ...],
    exports: [
        SomeLibraryModule.forRoot()
        ...
    ]
})
export class SharedModule {
    static forRoot() : ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [...providers]
        };
    }
}

The forRoot() pattern / convention is very common in libraries, and you’ll see it in things like ng-bootstrap and others. The name isn’t special for the compiler / framework, but it’s a common pattern.

When using these, in the imports section you can just import the module itself (which gives you any declarations needed like directives etc), and in the exports use the forRoot() version of the module so that it’s available for consumers of your shared module.

Then in your other application modules you can add SharedModule to their NgModule‘s imports normally, except for the AppModule.

The AppModule will be the only place where you add SharedModule.forRoot(), like:

Then in your AppModule, import it as:

@NgModule({
    declarations: [...],
    imports: [BrowserModule, SharedModule.forRoot(), ...],
    ...
})
export class AppModule {

}

There is one exception to this though. Your tests.

If you are writing any unit tests where you are importing the SharedModule, you will probably need to import the module with its providers, because there is no AppModule in the test.

Something like:

TestBed.configureTestingModule({
    imports: [ SharedModule.forRoot(), ... ]
})
...

If you haven’t already, have a look at the NgModule official documentation. There’s a main guide, and an FAQ page.

And of course let me know if you have any questions / problems.

Successfully Upgrade Your angular-cli App (Beta 28 & Below) To The Latest @angular/cli Beta


Have you had issues moving from angular-cli beta 28.3 or earlier to the newer versions of the CLI?

Try these steps then!

Global Dependency

This one is as easy as:

npm rm -g angular-cli @angular/cli
npm cache clear
npm i -g @angular/cli

Specific Project

Note: You do NOT need to have the CLI installed globally for this (although it’s a good idea).

First, ensure you have an npm script in your package.json file that looks like:

"scripts": {
    "ng": "ng"
    // ....
}

In this tutorial I’ll replace ng calls with npm run ng -- (note final space ) for those people who may not be able to upgrade their global package.

Now, let’s get to real work.

Commit everything you have in git, then:

npm rm angular-cli @angular/cli
npm cache clear
rm -rf node_modules
npm i -D @angular/cli
npm run ng -- update

Accept all files from update (which used to be called init) other than app module and component, especially (but not limited to) angular-cli.json, polyfills.ts, package.json and main.ts.

Then go to git undo any unwanted change (deleted packages from package.json, missing scripts or files from angular-cli.json, etc). Undo entire app module and component files if you accepted them by accident.

Then

npm install
npm run ng -- build

And you can go roll with npm start / npm run ng -- serve.

All good!