Angular “Tour of Heroes” Unit Tests For 100% Code Coverage

After learning all the ways an Angular web app can perform HTTP communication, I have a better understanding more of Angular’s “Tour of Heroes” tutorial app. And even better, I have a better idea of how I could write unit tests for it! That wasn’t something covered by the tutorial itself, so writing tests for the tutorial app is my self-assigned extracurricular activity. This follows my previous self-assigned homework, an aesthetic overhaul using Angular Material component library.

An Angular project created via “ng new” command sets up a unit testing pipeline and a few boilerplate tests. “Tour of Heroes” was created this way but it was never touched in the tutorial. Every time we call “ng create” to add a component, that boilerplate also added a simple test to verify that component could be created in the test framework. By the end of the tutorial, we have a handful of these simple creation tests. Most of which would fail, because those components have become more complex than the original boilerplate and the test hasn’t been updated to match.

Import Dependencies

First step was to import all the missing dependencies so a component can even be created in the test harness. I first did this mostly by searching for error messages and copying the answers, but it was an unsatisfying approach because I didn’t understand what I was doing. To address this, I paused my mindless copy/paste and started studying. I started with Angular Developer Guide to Testing which led to my reactive programming tangent with RxJS. Now I’m back, and I understand how to use import section of TestBed.configureTestingModule to bring in dependencies needed by component under test.

HttpClientModule to HttpClientTestingModule

Once components could be created, I was faced with a long list of HTTP failures. They all had the same cause: components that need to perform HTTP communication imported HttpClientModule, which tried to make actual HTTP calls to a server that isn’t online. For unit tests, we need to use HttpClientTestingModule to redirect component HTTP activity to behavior controlled by unit test infrastructure.

Mock Services and overrideComponent

Once tests were in place for services that used HTTP directly, errors came from components that indirectly used HTTP via those services. To keep tests small (the whole point of unit tests) I stubbed out those services with mockups that had just enough behavior to support specific unit tests and no more. Hooking them into the system required using overrideComponent to switch out real services for their simpler mockups.

For my first pass, I wrote mockups directly as TypeScript classes. This is a simpler and more direct first pass, but I think I’m supposed to use “Spy” mechanism provided by Jasmine testing framework for such mockups. Learning to use Spy is still on the to-do list.

Code Coverage Report

Running “ng test –code-coverage” activates code coverage report courtesy of Istanbul. A brief coverage summary is printed to console every time the test suite is executed, but I wanted more details to see where I need to focus my effort. The detailed report is in HTML format under the /coverage/ subdirectory. I’m supposed to go double-click on that file to bring it up in a web browser, but I’m running Angular inside a VSCode Dev Container and I can’t “just” go and double-click that file as it is not accessible to my local web browser.

Solution: quickly whip up a static file web server with the serve-static package, letting my local web browser access the report via a port opened on my dev container. I added that file along with a shortcut to my packages.json file so I can bring it up by running “npm run coverage.”

100% Is Not 100%

=============================== Coverage summary ===============================
Statements   : 100% ( 82/82 )
Branches     : 100% ( 7/7 )
Functions    : 100% ( 47/47 )
Lines        : 100% ( 75/75 )
================================================================================

These mechanisms helped me to write unit tests that exercised all code paths: 100% code coverage! But this metric is misleading, because there’s much more to an Angular app than its TypeScript code.

Many important pieces of functionality live within HTML templates and are not covered by code coverage statistics. That requires accessing ComponentFixture.nativeElement. From there we can navigate the DOM tree, query for elements, and verify they are expected.

There’s much more to Angular testing. I haven’t even gotten into other things like verifying Angular router functionality but I am getting tired of Tour of Heroes. Time for a change of pace.

Notes on Angular “HTTP Client” Guide

A working understanding of reactive programming with RxJS Observables for Angular was listed as a prerequisite to Angular guide for HTTP client. After my long and convoluted tangent to learn RxJS, I felt I was finally ready to dive in and learn how to apply RxJS to handle HTTP transactions in an Angular web application.

One of the most powerful aspects of RxJS is the declaration of an Observable pipeline is a template. It means we can set one up independently of using them. To use them we call subscribe(), and it is a template that we can reuse by calling subscribe() again. An unexpected downside of this power is that nothing actually happens until we call subscribe(), which can be counterintuitive when we use the Angular HTTP client for operations like DELETE. Outside of Angular/RxJS, such things are fire-and-forget but here we have to subscribe() to start things in motion even if we don’t really care about the results of that subscription. This is apparently a common mistake because it is called out multiple times on this page. I also remember seeing this in the “Tour of Heroes” tutorial, which was absolutely wild when I first saw it. I now understand why it behaves that way, but I still think it is weird.

Unrelated to RxJS, I thought “Requesting a typed response” section was interesting. It enables TypeScript compile-time checking, which helps keep our code straight, but we have to remember we’re still on the hook for runtime checking. Sanitizing data is important for security! This also explains why the example code would copy elements from the result and not blindly copy the whole object. Blind copy would leave our code vulnerable to a maliciously written object that comes with its own toString() or something that is likely to get called in the context (and authority!) of our application code.

With my current basic understanding of RxJS and HTTP, the first half of this page was fairly straightforward. Then things got weird with “interceptors”. I understand it is a very powerful concept that allows separation of concerns across different chunks of code, each handling an aspect of HTTP activity. But getting them to all play nicely together seems to be a challenging task with lots of room for error. A very powerful gun aimed at our feet, it seems.

Even just loading them up has pitfalls. There’s a recommendation to load them with a “barrel” but I haven’t understood the tradeoffs to use/not use them. I also understood that load order mattered, but it didn’t cover symptoms of getting the order wrong. There’s even a back channel for application code to control interceptors (passing metadata) via HttpContextToken object.

An application of interceptor that looked very impressive was the ability to return a cached value immediately while also issuing the HTTP request. Then the real updated live value from the server is given, all on the same Observable! This is something that would have been really complicated to do with plain JavaScript Promise (async/await) and the first real “A-ha” for me to see power of RxJS in action.

Interceptors are also how Angular performs client-side work to protect against cross-site request forgery (XSRF) adding an XSRF-TOKEN in the header. It’s only part of the solution, though. It needs to mesh with server-side code to set the token and verify the token. It is on my “To-Do” list to find an implementation example, probably with Express.

And finally, there’s a section on using HTTP client in unit tests. This is the section I can put to work immediately.

Notes on Angular “Observables & RxJS” Guide

I went on a reactive programming tangent thinking it would help me become an effective user of Angular web application framework. Because some very important parts of Angular made extensive use of a JavaScript reactive programming library called RxJS. I found a lot of general information about reactive programming out there, but I need to stay focused on Angular. Returning to Angular documentation, I picked another developer guide section to start reading: “HTTP client“. This page has a “Prerequisites” section at the top which linked to an “Observables & RxJS Guide“.

It was an introduction to reactive programming with the RxJS library, with examples that are relevant to Angular apps. I didn’t know this guide existed. If I had, I would have started here first! If I had, I still wouldn’t have understood RxJS immediately, but I would at least have a better focus as I ventured to other RxJS guides. Mostly thanks to Observables in Angular which showed the most common RxJS usage patterns.

I was mildly disappointed the Practical Usage page had only two examples, and one of them was the type-ahead autocomplete mechanism already covered in Tour of Heroes. At least that one had a breakdown of how the asynchronous processing pipeline worked to accomplish its goal. The other example “Exponential backoff” had no such explanation. Just an overly optimistic claim “With observables, it is very easy” before we were tossed a chunk of code with no comments nor a breakdown of what it did. Definitely room for improvement here.

RxJS Observables were compared & contrasted against JavaScript Promises in the “Observables compared to other techniques” section. I saw some unavoidable overlap with similar topics on other resources I recently read but still, it was a great way to help my brain think about how to make use of RxJS aligned with its strengths. But I know the best way to get comfortable with RxJS is to start working on code that use it.

Tiny Step on RxJS Learning Curve

I learned a lot from reading Angular’s Developer Guide to Testing, one of which is that I have a significant weak spot in my Angular understanding: how and when to use RxJS for asynchronous operations. Not just for testing, but also for writing Angular application code. On my first run through “Tour of Heroes” tutorial, RxJS was a black box I didn’t understand at all. On my second run, I understood the tutorial enough to understand specific uses of RxJS from context, but my understanding did not extend to the rest of that library. I certainly don’t know how to employ RxJS for my own tasks. It’s time to buckle down and read official RxJS documentation.

This was quite a chore. It appears RxJS official documentation was written by its development team for an audience that already knows what it does and why they would want it. It started with “RxJS is a library for composing asynchronous and event-based programs by using observable sequences” and jargon gets thicker from there. (Interspersed with words like “just” and “simply” which this beginner found ridiculous.) There was no “Getting Started” section. The next-best candidate section “Installation” is full of material telling existing users how to migrate breaking changes, not an introduction to new users.

The good news is that, as of this writing, RxJS is still under active development. Today’s stable release 7.8.0 has a timestamp only a few weeks old. (December 15th, 2022.) I was concerned about that, because RxJS was a solution for JavaScript asynchronous programming before JavaScript evolved to have its own asynchronous constructs like async/await. It doesn’t map cleanly to Promises and conversion is a bit of a mess. But RxJS still does things that standard JavaScript doesn’t do, so there are still scenarios where RxJS would be the right tool for the job. It’ll take more learning before I recognize those scenarios.


Observable: RxJS foundation class. One thing that demystified a lot was rewriting an analogy using plain JavaScript. Seeing something familiar and understandable (with my very recent JavaScript education) gave me a starting point to try understanding the rest of the page. Unhelpfully this was at the bottom of the page.

Observer: It took a while for me to understand observer where my code fits into the system and I can use as little or as much of it as I need for a scenario. It can be a single callback for receiving data (“next”) but I can also register optional callbacks to be notified of problems (“error”) or when there’s no more data (“complete”).

Operator: Documentation said this is the powerful part of RxJS, but didn’t really explain why or how we would leverage that power. This is also where marble diagrams were explained, something that bewildered me when Angular testing discussed marble testing. The overview of available operators is a disappointing list of just names. Each name is a link to their reference page without any additional context. I’d have to click the link and read each one. I would love a reference where each link has an 1-2 sentence summary, but no luck here.

Subject: These are Observable that multicasts to more than one Observer. Up until this point I hadn’t known a basic Observable only broadcast to a single Observer! This critical information should have been covered earlier.

Scheduler: No usage examples or scenarios were given so I have no idea when I should care about choosing a different RxJS scheduler. I see the “How to do X”, but not “Why you want to do X.”


I’m sure everything in official RxJS documentation is technically correct but the information lacks context. Or more precisely, I don’t think they were even trying to provide context for readers who are unaware. Perhaps there are resources to help RxJS beginners elsewhere on the internet?

Notes on Angular Developer Guide to Testing

Once my Angular development container could run tests in Chrome using headless mode, I could see actual test failures. Since “Tour of Heroes” tutorial did not touch test files at all, these failing tests were untouched boilerplate tests. For the most part they just test to see if a component instance could be created within the test harness, there were no further updates to test “Tour of Heroes” functionality. Components that couldn’t be created in a test harness obviously led to abysmal code coverage numbers.

=============================== Coverage summary ===============================
Statements   : 18.75% ( 15/80 )
Branches     : 0% ( 0/8 )
Functions    : 6.38% ( 3/47 )
Lines        : 16.21% ( 12/74 )
================================================================================

Since I am just getting started, there were a lot of (1) copy error message (2) search on that message (3) read hits on StackOverflow (4) repeat. Component creation failure mainly revolved around fixing up “imports” or declarations” sections to calling TestBed.configureTestingModule(). After I got component startup sorted out, code coverage numbers looked a lot better.

=============================== Coverage summary ===============================
Statements   : 61.25% ( 49/80 )
Branches     : 0% ( 0/8 )
Functions    : 53.19% ( 25/47 )
Lines        : 62.16% ( 46/74 )
================================================================================

But that was a lot of copy/pasting from StackOverflow with little understanding of what happened. And even though tests registered as passing, there were still error messages shown on console output. I need to learn more, so I started reading the “Testing” section of Angular Developer guides. It seems to assume I know Jasmine and Karma, which I don’t. I plan to skim the first pass for a partial understanding, then maybe dedicate some time to learning Jasmine/Karma, then come back again. Here are some notes from my first pass:

Valuable Live Examples

Just like the “Understanding Angular” section, pages in “Developer Guides” very frequently have a link to a project that we can load up and examine either by downloading code for our own machine or fire it up within our browser connected to a StackBlitz virtual machine. Having functional code is always great and mitigates many documentation issues. One code snippet in “Testing Services” documentation called a function I couldn’t find any information about, looking at the live code I figured out it was something strictly within the demo project. (async-observable-helpers.ts)

Scattered Older Content

I see occasional signs of outdated content. Some examples: (1) API TestBed.get() was deprecated from Angular 9 but still pops up here and there. (2) Occasional mentions of “Tour of Heroes” that doesn’t match the tutorial I just completed a second time. Either they were snippets from an older version of the tutorial, or the example was modified for illustration purposes. (3) Standard boilerplate code listed in “Basics of Testing Components” do not match what today’s tools generate.

Having illustrative code examples fall out of date reminded us to keep in mind that some of their associated information might be out of date as well.

Component Testing Scenarios

The longest page (by far) in this section is “Component Testing Scenarios.” I think it is the goldmine. A list of how we might want to test our Angular components and tools to go about them. It puts a lot of Angular testing tools (which have their own section) in context of problems they were created to solve. As a beginner I don’t quite understand why I might want to do these things, but here’s the reference if I want to do them.

Almost a quarter of this very long page is dedicated to “Component with async service”. (Which makes this one section longer than most other pages in “Angular Developer Guides – Testing”) RxJS is used by Angular a lot in the realm of asynchronous behavior, so I need to learn more about that. Not just to test, but to build Angular in general. I expect things will make sense after getting a better grasp of RxJS terminology like “marble testing“. I thought the best place to start would be RxJS official documentation. (I was wrong.)

Running Angular Unit Tests (ng test) in VSCode Dev Container

I knew web development frameworks like Angular proclaim to offer a full package, but it’s always enlightening to find out what “full” does and doesn’t mean in each context. I had expected Angular to have its own layout engine and was mildly surprised (but also delighted) to learn the official recommendation is to use standard CSS, migrating off Angular-specific interim solutions.

Another area I knew Angular offered is a packaged set of testing tools: a combination of generic JavaScript testing tools and Angular-specific components already set up to work together as a part of Angular application boilerplate. We can kick off a test pass by running “ng test” and when I did so, I saw the following error message:

✔ Browser application bundle generation complete.
28 02 2023 09:17:22.259:WARN [karma]: No captured browser, open http://localhost:9876/
28 02 2023 09:17:22.271:INFO [karma-server]: Karma v6.4.1 server started at http://localhost:9876/
28 02 2023 09:17:22.272:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
28 02 2023 09:17:22.277:INFO [launcher]: Starting browser Chrome
28 02 2023 09:17:22.279:ERROR [launcher]: No binary for Chrome browser on your platform.
  Please, set "CHROME_BIN" env variable.

Test runner Karma looked for Chrome browser and didn’t find it. This is because I’m running my Angular development environment inside a VSCode Dev Container, and this isolated environment couldn’t access the Chrome browser on my Windows 11 development desktop. It needs its own installation of Chrome browser and be configured to run in headless mode. (Which is itself undergoing an update but that’s not important right now.)

From these directions I installed Chrome in the container via command line.

sudo apt update
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

Then Karma needs to be configured to run Chrome in headless mode. However, default Angular app boilerplate did not include karma.conf.js file which we need to edit. We need to tell Angular to create one:

ng generate config karma

Now we can edit the newly created file karma.conf.js following directions from here. Inside the call to config.set(), we need to define a custom launcher called “ChromeHeadless” then use that launcher in the browsers array. The results will look something like the following:

module.exports = function (config) {
  config.set({
    customLaunchers: {
      ChromeHeadless: {
        base: 'Chrome',
        flags: [
          '--no-sandbox',
          '--disable-gpu',
          '--headless',
          '--remote-debugging-port=9222'
        ]
      }
    },
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
@@ -33,7 +44,7 @@ module.exports = function (config) {
      ]
    },
    reporters: ['progress', 'kjhtml'],
    browsers: ['ChromeHeadless'],
    restartOnFileChange: true
  });
};

With these changes I can run “ng test” inside my dev container without any errors about running Chrome browser. Now I have an entirely different set of errors about object creation!


Appendix: Error Messages

Here are error messages I saw during this process, in order to help people to find these instructions by searching for the error message they saw.

Immediately after installing Chrome, running “ng test” will try launching Chrome but not in headless mode which will show these errors:

✔ Browser application bundle generation complete.
28 02 2023 17:50:43.190:WARN [karma]: No captured browser, open http://localhost:9876/
28 02 2023 17:50:43.202:INFO [karma-server]: Karma v6.4.1 server started at http://localhost:9876/
28 02 2023 17:50:43.202:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
28 02 2023 17:50:43.205:INFO [launcher]: Starting browser Chrome
28 02 2023 17:50:43.271:ERROR [launcher]: Cannot start Chrome
        Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
[0228/175043.258978:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq: No such file or directory (2)
[0228/175043.259031:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq: No such file or directory (2)

28 02 2023 17:50:43.271:ERROR [launcher]: Chrome stdout: 
28 02 2023 17:50:43.272:ERROR [launcher]: Chrome stderr: Failed to move to new namespace: PID namespaces supported, Network namespace supported, 
but failed: errno = Operation not permitted                                                                                                      [0228/175043.258978:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq: No such file or directory (2)
[0228/175043.259031:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq: No such file or directory (2)

This has nothing to do with Karma because if I run Chrome directly from the command line, I see the same errors:

$ google-chrome
Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
[0228/175538.625191:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq: No such file or directory (2)
[0228/175538.625244:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq: No such file or directory (2)
Trace/breakpoint trap

Running Chrome with just the “headless” flag is not enough.

$ google-chrome --headless
Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
[0228/175545.785551:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq: No such file or directory (2)
[0228/175545.785607:ERROR:file_io_posix.cc(144)] open /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq: No such file or directory (2)
[0228/175545.787163:ERROR:directory_reader_posix.cc(42)] opendir /tmp/Crashpad/attachments/9114d20a-6c9e-451e-be47-353fb54f28be: No such file or 
directory (2)                                                                                                                                    Trace/breakpoint trap

We have to disable sandbox to get further, though that’s not the full solution yet either.

$ google-chrome --headless --no-sandbox
[0228/175551.357814:ERROR:bus.cc(399)] Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or dir
ectory                                                                                                                                           [0228/175551.361002:ERROR:bus.cc(399)] Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or dir
ectory                                                                                                                                           [0228/175551.361035:ERROR:bus.cc(399)] Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or dir
ectory                                                                                                                                           [0228/175551.365695:WARNING:bluez_dbus_manager.cc(247)] Floss manager not present, cannot set Floss enable/disable.

We also have to disable the GPU. Once done as per Karma configuration above, things will finally run inside a Dev Container.

Hello Angular Layout

Using the Angular Material component library gave me some great looking controls, but adding the library into my app increased its size by more than I had anticipated. It’s a good thing Angular Material is an optional component, so I don’t have to use it for space-constrained projects. Something else not core to Angular framework is page layout. I thought it might be part of Angular Material, but I found nothing there, either.

Looking around online for some kind of page layout component for Angular apps, I found something called “Angular Flex Layout” which, like Angular Material, is an optional component. It sounds like the component had always provided a bridge across the gap between the potential capabilities of CSS and the actual capabilities of CSS in shipping browsers. Several years ago, that gap was quite large! But now it appears the gap is small enough for Angular Flex Layout to ride off into the sunset.

I found more details on Angular team blog post “Modern CSS in Angular: Layouts, which confirmed they intend for modern CSS (flexbox and grid got specific callouts) to handle most of what people formerly needed “Angular Flex layout” for. This blog post claimed to be the first in a series of helping people adopt modern standardized CSS for layout instead of using libraries like Angular Flex Layout, but I haven’t seen any additional installments posted. I’ll stay tuned hoping to learn more in the future.

For needs beyond modern CSS, that blog post pointed to layout-related features within Angular’s Component Development Kit (CDK). I read over some introductory pages and didn’t comprehend very much. I hope that after I become more familiar with CSS and Angular, I can articulate the gap CDK Layout fulfills.

And finally, that blog post also mentions using Tailwind CSS in Angular apps, but without further information. I know nothing about Tailwind and very little about Angular and CSS. At the moment I have no idea what tradeoffs are involved in using that library. I’ll stick that on my “To Do” list at the bottom. Right now I have a higher priority item on my list: get a handle on Angular unit testing.

Angular Material Impact on Download Size

I was interested in using Angular Material component library because I thought it would help me build web apps that look better than my usual efforts. My introductory experience with it was very promising and I think it’ll deliver on design aesthetics. The project was also an experiment to see other parts of Angular in action. On the topic of download size, the result was not as good.

One aspect of using Angular that sounded appealing was that it came with an already-configured build pipeline so I didn’t have to build my own. Starting from tools like TypeScript compiler, through to tools like Webpack. It is a multi-stage process to go from source code to a compact package delivered by our web server. It performs optimizations like “tree-shaking” for removing unused code, and “minification” which removed comments, whitespaces, everything nonessential. Ideally this meant the final package would have only what we absolutely need and no more. In practice, I’m not so sure.

After finishing the “Tour of Heroes” tutorial and playing with a bit of CSS, but before I converted over to using Angular Material, my application’s raw download size was a little over 309 kilobytes.

✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files           | Names         |  Raw Size | Estimated Transfer Size
main.e962da6362f99387.js      | main          | 274.74 kB |                71.19 kB
polyfills.716cc9a230a87077.js | polyfills     |  33.11 kB |                10.70 kB
runtime.6e50dac17b84e715.js   | runtime       | 922 bytes |               517 bytes
styles.19b697cb6d7ac4c1.css   | styles        | 477 bytes |               172 bytes

                              | Initial Total | 309.22 kB |                82.56 kB

After I installed Angular Material with “ng add @angular/material” but before I actually explicitly imported any components, the final bundle size grew by over 50% to 479 kilobytes:

✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files           | Names         |  Raw Size | Estimated Transfer Size
main.7c4c0522a82c6f83.js      | main          | 338.94 kB |                87.07 kB
styles.4aae9080591fb05a.css   | styles        | 106.13 kB |                 9.64 kB
polyfills.716cc9a230a87077.js | polyfills     |  33.11 kB |                10.70 kB
runtime.6e50dac17b84e715.js   | runtime       | 922 bytes |               517 bytes

                              | Initial Total | 479.08 kB |               107.92 kB

This was disappointing. As far as I know I haven’t actually used anything of Angular Material, yet I had already picked up 170 kilobytes of stuff that the automated optimization tools could not avoid. And even worse, this was completely opaque to me. I don’t know of any way to break down where those 170kB came from, nor what I could try to optimize them.

As I started actually importing and using components from Angular Material, my bundle size grew as expected. I had hoped maybe those 170 kilobytes were majority of core shared code and each additional module would add only minimal size, but this was definitely not the case. My freshman effort at Angular Material conversion added the following modules.

import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatToolbarModule } from '@angular/material/toolbar';

And by doing so, I picked up almost 300 additional kilobytes for a total of 776 kilobytes.

✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files           | Names         |  Raw Size | Estimated Transfer Size
main.dc2316f7fe149792.js      | main          | 636.43 kB |               134.91 kB
styles.7a21ac1018e81662.css   | styles        | 105.66 kB |                 9.52 kB
polyfills.716cc9a230a87077.js | polyfills     |  33.11 kB |                10.70 kB
runtime.6e50dac17b84e715.js   | runtime       | 922 bytes |               517 bytes

                              | Initial Total | 776.11 kB |               155.63 kB

Warning: bundle initial exceeded maximum budget. Budget 500.00 kB was not met by 276.11 kB with a total of 776.11 kB.

Final line of this output is a warning from Angular’s build-time bundle size budget watcher, which is half of a good feature. It’s great that it informed me I exceeded size budget, but I don’t understand what exactly contributed to that total and I certainly don’t know what I could do about it. Well, I guess there’s “Don’t use Angular Material” but I hope for something finer-grained than that.

Does this matter? It depends on the context. If I’m writing an app for my own use on my home network, a few hundred kilobytes are insignificant. If I’m writing something to run on my phone via mobile data, such data usage would be notable but not necessarily a deal breaker. If I’m creating a browser app from ESP32, there’s only 4MB of flash memory to serve such files and a few hundred kilobytes could sink the entire project.

It’s just like any other tool: there are right places to use it, and there are wrong places to use it. This applies to Angular itself, to Angular Material component library, and whatever I use for layout. Because for both good and ill, layout is not an intrinsic part of Angular framework.

Hello Angular Material

I made some small layout and styling changes to Angular Framework’s “Tour of Heroes” tutorial app. It looked a little better to me, but those changes didn’t stick around for long. They were merely a HTML/CSS warmup exercise and quickly replaced by the next activity: converting the app to use Angular Material component library.

While I don’t necessarily agree with everything in Google’s Material Design, for better or worse Google’s reach meant most users would already be familiar with them. The option to utilize Angular Material component library was, in fact, the main motivation for me to learn Angular. Now that I’m finally at this point, I eagerly opened up their Getting Started page and got to work. The instructions were fine and putting the library to use was about as easy as I can reasonably ask for. There were two items of note:

Import

This was taught right up front on “Displaying a component” section of Getting Started page, but I didn’t grasp its significance at first. Each Angular Material component is packaged in a module that we have to import before use, making every component (and associated overhead) an opt-in decision. This is not illustrated by their live examples on Stackblitz, because those examples imported everything. I wasted time trying to sort out exactly what was important until I figured out that they tell you in the “API” section of each component’s documentation. Example: the first line of Material Button API page is:

import {MatButtonModule} from '@angular/material/button';

And Reload

After importing the module as per API documentation, I could use that component, but it didn’t look right. Most of the behaviors were there, but appearance-wise it didn’t look quite right. Style bits were missing here and there, the most visible aspect was that I didn’t see any theme colors. We’re supposed to be able to select from “Primary”, “Accent” or “Warn” colors but the control looked plain despite setting color to one of those options.

Hunting on answers from Stack Overflow found a lot of information about defining and using custom themes, which I don’t care about (yet). But buried among custom theming information was my answer: after importing a component, the development server launched by the “ng serve” command would only pick up partial functionality. There was nothing wrong with my code. To pick up everything, including theme colors, I had to stop the running instance of “ng serve” and launch it again.

Looks Great! But…

Getting this far meant I could fold several Angular Material controls into my “Tour of Heroes” app. Using Angular Material controls meant I could delete a lot of CSS associated with custom styling of the tutorial. Utilizing this component library in my own projects should mean less fussing with CSS for styling. This is a great benefit as I don’t consider myself any good at user interface design. But this ease has a tradeoff in larger download size.


Code for this project is publicly available on GitHub

First CSS Exercise with Angular “Tour of Heroes” Tutorial

Running through Angular framework’s “Tour of Heroes” tutorial a second time was good for me. I learned a lot of web development between my first and second runs, helping me understand and retain a lot more information this time around. I’m still short of what I’d call “proficient”, though. In the interest of getting more practice, I will continue my personal Angular learning plan. The main focus of “Tour of Heros” was Angular framework, so it had only minimal attention paid to styling. So my next step is to play with styling this tutorial app.

The main objective is to exercise “think in CSS” portions of my brain. As a computer user it’s not hard for me to think of web interfaces that I enjoyed and didn’t enjoy using. Now I want to develop an ability to articulate my experience in terms of how I can implement them in CSS. This will start out very slow and rough, with many visits to MDN documentation for reference. I expect to get faster at it with practice and practice starts small. This first round will make only minor changes to CSS and almost no changes to HTML at all.

It’s not necessary for results of this first round to be good in an objective sense, but it’s important for the layout to be mine. Pick out small things I didn’t like and verify I can fix it to my liking.

  • Tutorial CSS used Cambria (a serif font) mixed in with majority of non-serif fonts. I felt those styles clashed for no good reason and that was the easiest place to start.
  • I thought the diagnostics message section at the bottom took up too much space and wasn’t distinct enough from the rest of the app. My change packed the “Clear Messages” button on the same horizontal line as the header, removing a lot of whitespace around both. I also changed the diagnostic message text themselves to a monospaced font. This may sound hypocritical because I just removed some serif font usage because they clashed, but in this case a style clash is a feature and not a bug. I always mentally associate monospaced typefaces with technical data, and I wanted it to stand out.
  • Dashboard component had a search box for hero names, and I thought that was not distinct enough from the rest of the dashboard. I gave it a subtly darker background to visually differentiate it from the rest of the dashboard, and I centered the component horizontally because Yahoo, Google, etc. all taught me to expect a search text box to be centered on screen.
  • Similar to how I packed “Clear messages” into the same horizontal space as the message display area header, I packed “Dashboard” and “Heroes” navigation buttons into the same topmost horizontal space as the application header at the top of the screen.
  • In the “Dashboard” view, we have a text box for search at the bottom. In the “Heroes” view, we have a text box for adding a new hero at the top. I didn’t like that ordering because I want to review existing data before I add a hero. I moved “add hero” control to the bottom, which also made it consistent with dashboard search.
  • And finally, in the individual hero view, I again added a CSS flexbox to pack buttons together for a more compact layout.

I preferred how the resulting app looked, and I thought it was a good simple warmup round before I dip my toes into more serious UI styling.


Code for this project is publicly available on GitHub.

Angular “Tour of Heroes” Tutorial Round 2

I’m glad I skimmed through “Understanding Angular” documentation section before going through “Tour of Heroes” tutorial for the second time. Combined with my improved understanding of web development, this time I actually understood everything covered in the tutorial. The best example are Angular directives, which were mysterious black boxes the first time around. I copied them straight from tutorial text without much comprehension of what they did. This time around, I mostly understood how they dictated Angular behavior. I also understood that some of what I see are shorthand versions and, if I get too lost, I can go look for their expanded-out full versions which are more explicit in their actions.

I Know Where Things Go Now

One memory I had of my first run of “Tour of Heroes” were a few steps where the instruction was to copy a snippet of code into a specific file. However, they didn’t say where in the file. The first time as a beginner, I didn’t even understand enough to know where a code snippet should fit. This time around, I never felt that way. When a code snippet is presented, I understood the context where it should be inserted. This was a very satisfying feeling! Once I completed “Tour of Heroes” for the second time (which also went much faster) I had a selection of topics to explore outside the scope of the tutorial.

Need to Revisit Angular Tests

One candidate is testing. At the moment I’m completely ignorant about automated testing of web apps. I know such tools exist, but so far, my web app projects were tested manually when I played around with what I wrote. As my project size grows (and I have ambitions of bigger projects) this approach would not scale well. Angular has provisions for testing frameworks, which we can kick off with “ng test”. Angular boilerplate includes a bare-bones test (filename ending with spec.ts) that went with the corresponding code (filename ending with just .ts.) Since the tutorial only changed code file without updating its corresponding test file, I ran “ng test” expecting to see test failures. But it appears I have some work to do before I even get that far, because I’m running Angular inside a VSCode dev container, and it doesn’t have Chrome installed.

node ➜ /workspaces/angular-tour-of-heroes (main) $ ng test
✔ Browser application bundle generation complete.
11 02 2023 09:44:34.255:WARN [karma]: No captured browser, open http://localhost:9876/
11 02 2023 09:44:34.268:INFO [karma-server]: Karma v6.4.1 server started at http://localhost:9876/
11 02 2023 09:44:34.268:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
11 02 2023 09:44:34.272:INFO [launcher]: Starting browser Chrome
11 02 2023 09:44:34.273:ERROR [launcher]: No binary for Chrome browser on your platform.
  Please, set "CHROME_BIN" env variable.

I know it is possible to run Chrome in an automated test where it runs without any user interaction or even a visible interface. I’ll need to figure out this “headless mode” before I can run “ng test”.

After a few minutes of looking around online, it appears running headless Chrome inside a container requires more knowledge than I have at the moment. Instead of tackling another new thing, I decided to practice what I’ve already learned. I will resume my tentative learning plan, which calls for me to turn my Tour of Heroes into a CSS exercise.

Notes on “Understanding Angular”

My first time through Angular framework’s documentation section had focused on “Getting started” and “Tutorial” sections, just to get a toehold on things. Due to a firehose of information about this large framework, I didn’t retain very much. Now I’m taking a second pass through documentation, armed with more knowledge and experience to understand more of it. I drew up a tentative plan earlier, but I’ve already decided to deviate from that plan. After I read through the StackBlitz tutorial, but before I started hands-on with “Tour of Heroes” tutorial again, I decided to read the documentation section “Understanding Angular” whose overview page started with this:

To understand the capabilities of the Angular framework, you need to learn about the following:

  • Components
  • Templates
  • Directives
  • Dependency injection
    The topics in this section explain these features and concepts, and how you can use them.

I admire this goal, but the reality was I lacked prerequisite knowledge to understand all of it. This is fine! Every time I understand a little more. At a rough guess, I would say I understood and retained about 5% of this information after my first effort, and this second effort had roughly 30% retention.

Live Code Everywhere

The length and quality of documents in this section vary greatly, probably reflecting different authors contributing from their own perspectives. But at the end of the day, developers want to see code and we have them. Most (all?) of the topics included links to sample code in both live-running form (running on StackBlitz) as well as downloadable source code example. Some go much further, for example “component interaction” goes as far as including test code. And in several cases, sample code covered concepts that were not covered on written pages, so it’s always worth checking out that link.

Nonlinear Organization

Sometimes my confusion is not from missing prerequisite knowledge, but counterintuitive organization of information. For example: Under the binding section, Property binding is the next-to-last item on the list yet it is listed as prerequisite by the second (attribute binding) and third (class and style binding) documents. To make sense of everything I have to jump around this page.

Attributes vs. Properties

Several documents in the binding section emphasized that we bind to properties and not attributes. But they didn’t explain what that difference meant! Looking outside this site, I found this StackOverflow thread which included a gem of an explanation: “When writing HTML source code, you can define attributes on your HTML elements. Then, once the browser parses your code, a corresponding DOM node will be created. This node is an object, and therefore it has properties.

Angular Directive Long Form

As an Angular beginner I can see Angular directives as a very powerful mechanism, but the syntax can be tough for me to decipher. Eventually I learned this was because we frequently see shorthands for using directives, and the structure is easier to comprehend when we see the “long form”. This snippet was shown as a *ngFor “long form”, and it was quite illuminating!

<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>
  </h3>
</div>

It was not as concise as the shorthand, but much easier for me to decipher what’s going on. Compare the above to another example of ngFor directive:

<ul>
  <ng-template ngFor let-hero [ngForOf]="heroes">
    <li>{{hero.name}}
  </ng-template>
</ul>

(Note that these are two different examples of ngFor and they do different things, because I copy/pasted them from different sections of Angular documentation. I’m only using them to compare syntax.)

Ready for Round 2

After reading through “Understanding Angular” I can’t say I totally understand Angular yet, but I have a much better understand of how it goes about its business. I expect some of this information to be reinforced as I go through their “Tour of Heroes” tutorial again, because I think I’ll recognize them the next time around and have a better idea of their usage context.

A Quick Look at Angular 15

In the interest of improving the odds that I’ll actually learn something I can put to use, I’ve devised a plan for how I intend to learn and apply Angular application framework. My skills have evolved since the last time I ran through Angular tutorial, and it’s no surprise that Angular has evolved itself. Web technologies move fast! My previous effort worked with Angular 11, and as of about two weeks ago, we’re now up to Angular 15. I looked through the changes to see how much I understood and how much would actually affect the kind of projects I intend to build. It appears that I picked a good time to review Angular — v15 looks to be quite a consequential step forward.

From the “Angular v15 is now available” (2022/11/16) page:

  • Standalone components: I got excited about this item because I didn’t understand Angular terminology. I thought “standalone” meant I could use Angular components piecemeal independent of the Angular framework, I was wrong. Reading more, I’ve learned some people felt Angular components are too dependent on a specific Angular mechanism “NgModule”. Architecturally that meant a NgModule was the smallest unit of reusability, and not Component as intended. This “standalone” feature makes it easier for an Angular Component to run without NgModule.
  • NgOptimizedImage: Sounds like the Angular framework can now handle resizing image files. So large screen desktops don’t get blurry images and small mobile devices don’t waste bandwidth downloading high resolution images.
  • Stack traces are more helpful: Sounds promising. Getting an informative stack trace has always been a problem with debugging asynchronous code.
  • MDC-based components: Angular Material was why I started looking at Angular framework to begin with! At the time it was an Angular-focused set of web controls that are implemented differently from those intended for non-Angular web sites. (The non-Google affiliated Materialize-CSS project was something I’ve tried along similar veins.) Now it seems like the two worlds are converging, nice.

From the “Angular v14 is now available” (2022/6/2) page:

  • Strictly typed forms: Reading the description, it’s the kind of thing that surprised in the “Wait, you meant it wasn’t like that already?” category. Angular uses TypeScript and leverages its compile time type checking to catch bugs. Given this fact I was surprised that forms (a major way to interact with user data) aren’t strictly typed. Perhaps there’s subtlety here I don’t understand but better type checking is almost always a good thing.

From the “Angular v13 is now available” (2021/11/3) page:

  • End of IE11 support: This only impacts me because I have a bunch of old Windows Phones that I had intended to reuse in other projects via its integrated web browser, which is a mobile build of Internet Explorer. Angular 11 didn’t officially support IE but it was possible to build for IE with a few project settings. The results… mostly worked. As of Angular v13 that is no longer an option. If I still want to put those old Windows Phones to work via web apps, I’d have to do it with older versions of Angular or without Angular at all.

From the “Angular v12 is now available” (2021/5/12) page:

  • Sass: I had forgotten about Sass until I read Angular v12 increased support for Sass. I learned about Sass quite some time ago, before my recent efforts to relearn CSS. I’ve forgotten much of Sass and how it addresses challenges of plain CSS. I’m going to refresh my knowledge of Sass before I proceed.

Learning Plan for Angular Round 2

Reviewing the TypeScript Handbook was very educational, even if I didn’t understand all of it. It was enough to make me feel confident I have what I need to get more out of revisiting Angular web framework. When I tried to learn Angular the first time, I only had a basic grasp of HTML, CSS, and JavaScript. Because of this weak foundation with weak supports, I didn’t really know enough to put Angular to work. I just ran through the tutorial and didn’t do much with it. Over the past few weeks, I’ve been patching up holes in my knowledge of web development, and I hope to have better results if I visit Angular again. It’s no guarantee of success, and there’s a good chance I’d only learn enough to realize I need to revisit the other topics like CSS and JavaScript again. But even in that case I’d learn more than I know today, and that is itself a win.

So given what I’ve learned recently, here is how I intend to tackle my second round of learning Angular:

  1. Read through Angular introduction again.
  2. Just skim instructions for the StackBlitz-based shopping cart demo without repeating hands-on activity. I like the idea of StackBlitz but its web-based development environment was different enough from a local development environment that I’ve decided I prefer to skip it in favor of practicing local development.
  3. Hands-on follow through the “Tour of Heroes” tutorial for the second time.

After finishing “Tour of Heroes” again, put my recent learning to work enhancing it:

  1. The “Tour of Heroes” tutorial was focused on Angular application framework mechanics, so the visual HTML and CSS is very plain. Put my recent HTML and CSS learning to work and spiff up that site. Including a mobile-friendly layout via media queries.
  2. The “Tour of Heroes” tutorial used a small class as a local proxy substitution for server-side database backend, storing its data in memory using JavaScript collection classes. Remove that proxy and migrate it to run on a Node.js server.
  3. Upgrade backend interface code to a more robust web API implemented using Express.
  4. Upgrade backend store to a MongoDB instance instead of in-memory JavaScript objects.

If I get this far, I would have practiced the entire MEAN stack. However, the MongoDB side would be quite lightweight given the limited demands of “Tour of Heroes”. Fortunately, in the MongoDB University course, we were given several practice databases of nontrivial size. I could build an Angular web app on top of one of those databases.

And if I’m successful with that, I would then have enough skill to tackle a MEAN stack project from scratch.

Tha’s quite a plan with many steps! I’ll likely deviate from this plan as I hit various roadblocks and work to resolve them, and it’ll take at least several weeks. But it feels exciting to have a longer-term plan. But first, a look at the Angular framework to see how it has changed since my first visit.

Circling Back to Angular for Another Look

After spending some time on MongoDB University to learn the basics of the MongoDB NoSQL database, then how to connect to one from Node.js code, I think I have enough of a basic understanding to tackle simple projects. It also completes my basic exposure to the entire “MEAN Stack” for bulding web applications: MongoDB, Express.js, Angular, and Node.js. Emphasis, however, on the “basic”. Going through a bunch of tutorials isn’t the same as being to put tools to work. I went through Angular some months ago, but there were too many unfamiliar topics for me to absorb everything the first time around. But I’ve learned a lot since then. I had a HTML refresher where I learned about semantic HTML, followed by learning more CSS I never learned (or never absorbed) before, and then enough JavaScript courses that the language is actually starting to make sense. I felt missing this knowledge earlier prevented me from usefully deploy Angular.

Part of the problem was that Angular is a big package which is highly prescriptive or “opinionated” on how each part would work with the others. This has advantages for a beginner because I don’t have to think about evaluating and picking from multiple alternatives, but it has the disadvantage that a beginner has to learn it all. With so many tightly integrated components, as my learning started falling behind, my understanding also started to fall apart.

Would I be better off learning another platform now? I contemplated learning React, which has a lot of coverage on Codecademy. I haven’t taken any of those courses yet, but I’ve read React is more modular than Angular. For some components we can start with something simple while we learn why we might want to substitute with more complex and powerful alternatives later. Further on this scale of flexibility is Vue.js, which advertised itself as something tailored for incremental development. It’s not just we can substitute components in Vue.js, we can go without them entirely if the project doesn’t use it.

As tempting as it might be to go after something new and shiny, I feel I will get a lot more out of Angular if I take another look. Or at least, have a better understanding of its tradeoffs before I go after something new and shiny. Reading my notes from earlier, I can tell I already understand some problems better than I used to. Example: Angular’s Tour of Heroes tutorial introduced me to the RxJS library which is Angular’s opinion on asynchronous JavaScript. Initially, I had no idea what I was looking at. But as the tutorial went on, I started seeing its benefits. Now, with my latest JavaScript courses, I understand RxJS was a solution to make asynchronous JavaScript things like Promises easier to work with. Unfortunately, it was a solution that predated official JavaScript adoption of async/await. So RxJS “Observable” mechanism doesn’t quite line up with async/await. This might be one example where Angular’s architecture holds it back: it is tied to pre-async/await RxJS and other platforms (React/Vue/etc.) may have an easier time adapting async/await. Is that important? That I don’t know yet, but at least I’m starting to understand more of the picture.

Before I dive back into Angular again, I have one more hole I thought I should fill: it uses TypeScript to tame some of the wildness of JavaScript. And now with a better understanding of JavaScript, I think I can get a lot more out of TypeScript.

Angular on Window Phone 8.1

One of the reasons learning CSS was on my to-do list was because I didn’t know enough to bring an earlier investigation to conclusion. Two years ago, I ran through tutorials for Angular web application framework. The experience taught me I needed to learn more about JavaScript before using Angular, which uses TypeScript which is a derivative(?) of JavaScript. I also needed to learn more about CSS in order to productively utilize the Material style component libraries that I had wanted to use.

One side experiment of my Angular adventure was to test the backwards compatibility claims for the framework. By default, Angular does not build support for older browsers, but it could be configured to do so. Looking through the referenced browserlist project, I see an option of “ie_mob” for Microsoft Internet Explorer on “Other Mobile” devices a.k.a. the stock web browser for Windows Phone.

I added ie_mob 11 to the list of browser targets in an Angular project. This backwards compatibility mode is not handled by the Angular development server (ng serve) so I had to run a full build (ng build) and spin up an nginx container to serve the entire /dist project subdirectory.

Well now, it appeared to work! Or at least, more of this test app showed up on screen than if I hadn’t listed ie_mob on the list of browser targets.

However, scrolling down unveiled some problems with elements that did not get rendered, below the “Next Steps” section. Examing the generated HTML, it didn’t look very different from the rest of the page. However, these elements did use different CSS rules not used by the rest of the page.

Hypothesis: The HTML is fine, the TypeScript has been transpiled to Windows Phone friendly dialects, but the page used CSS rules that were not supported by Windows Phone. Lacking CSS knowledge, that’s where my investigation had to stop. Microsoft has long since removed debugging tools for Windows Phone so I couldn’t diagnose it further except by code review or trial and error.

Another interesting observation on this backwards-compatible build is vendor-es5.js. This polyfill performing JavaScript compatibility magic is over 2.5 MB all by itself (2,679,414 bytes) and it has to sit parallel with the newer and slightly smaller vendor-es2015.js (2,202,719 bytes). While a few megabytes are fairly trivial for modern computers, this combination of the two would not fit in the 4MB flash on an ESP32.


Initial Chunk Files | Names                |      Size
vendor-es5.js       | vendor               |   2.56 MB
vendor-es2015.js    | vendor               |   2.10 MB
polyfills-es5.js    | polyfills-es5        | 632.14 kB
polyfills-es2015.js | polyfills            | 128.75 kB
main-es5.js         | main                 |  57.17 kB
main-es2015.js      | main                 |  53.70 kB
runtime-es2015.js   | runtime              |   6.16 kB
runtime-es5.js      | runtime              |   6.16 kB
styles.css          | styles               | 116 bytes

                    | Initial ES5 Total    |   3.23 MB
                    | Initial ES2015 Total |   2.28 MB

For such limited scenarios, we have to run the production build. After doing so (ng build --prod) we see much smaller file sizes:

node ➜ /workspaces/pie11/pie11test (master ✗) $ ng build --prod
✔ Browser application bundle generation complete.
✔ ES5 bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files                      | Names                |      Size
main-es5.19cb3571e14c54f33bbf.js         | main                 | 152.89 kB
main-es2015.19cb3571e14c54f33bbf.js      | main                 | 134.28 kB
polyfills-es5.ea28eaaa5a4162f498ba.js    | polyfills-es5        | 131.97 kB
polyfills-es2015.1ca0a42e128600892efa.js | polyfills            |  36.11 kB
runtime-es2015.a4dadbc03350107420a4.js   | runtime              |   1.45 kB
runtime-es5.a4dadbc03350107420a4.js      | runtime              |   1.45 kB
styles.163db93c04f59a1ed41f.css          | styles               |   0 bytes

                                         | Initial ES5 Total    | 286.31 kB
                                         | Initial ES2015 Total | 171.84 kB

Angular CLI as WSL 2.0 Test Case

I’ve been fascinated by the existence of Windows Subsystem for Linux (WSL) ever since its introduction. I’ve played with it occasionally, such as trying to run ROS on it. And this time I thought I’d try installing the Angular CLI on a WSL instance. But this time with a twist: this is now WSL 2.0, a big revamp of the concept. Architecturally, there’s now much more of an actual Linux distribution running inside the environment, which promises even better Linux compatibility and performance in Linux-native scenarios. The tradeoff is a reduction in performance of Windows-Linux interoperations, but apparently the team decided it was worthwhile.

But first, I have to run through the installation instructions which, on my 2004 build, encountered the error that required a Linux kernel update.

WSL 2 requires an update to its kernel component. For information please visit https://aka.ms/wsl2kernel

Then I can install it from Microsoft store followed by an installation of Ubuntu. Then I installed Node.JS for Ubuntu followed by Angular CLI tools. The last step ran into the same permissions issue I saw on MacOS X with node-modules ownership. Once I took ownership, I got an entirely new error:

Error: EACCES: permission denied, symlink '../lib/node_modules/@angular/cli/bin/ng' -> '/usr/bin/ng'

The only resolution I found for this was “Run as root”. Unsatisfying, and I would be very hesitant if this was a full machine but I’m willing to tolerate it for a small virtual machine.

Once I installed Angular CLI, I cloned by “Tour of Heroes” tutorial repository into this WSL instance and tried ng serve. This triggered the error:

Cannot find module '@angular-devkit/build-angular/package.json'

Which turned out to be a Node.JS beginner mistake. Looking up the error I found this StackOverflow thread where I learned that cloning the repository was not enough. I also need to run “npm install” in that directory to set up Node dependencies.

Once those issues were resolved, I was able to run the application where I found two oddities. (1) I somehow didn’t completely remove the mock HEROES reference on my Mac? And (2) package.json and package-lock.json had lots of changes I did not understand.

But neither of those issues were as important as my hopes for more transparent networking support in WSL 2. Networking code running in WSL was not visible from elsewhere in my local network unless I jumped through some hoops with Windows Firewall, which was what made ROS largely uninteresting earlier for multi-node robots. WSL 2 claimed to have better networking support, but alas my Angular application’s “ng serve” was similarly unreachable from another computer on my local network.

Even though this test was a failure, judging by the evolution of WSL to WSL2 I’m hopeful that work will continue to make this more seamless in the future. At the very least I hope I wouldn’t have to use the “run as root” last resort.

Until the next experiment!

Notes on Angular Architecture Guide

After completing two beginner tutorials, I returned for another pass through the Angular Architecture Guide. These words now make a lot more sense when backed by the hands-on experience of the two tutorials. There are still a few open question marks, though, the long standing top of my list are Angular Modules. I think each of the tutorial is contained into a single module? That would explain why I haven’t seen it in action yet. It doesn’t help that JavaScript also has a “Module” concept, makes things confusing to a beginner like myself. And as if that’s not confusing enough, there are also “Libraries” which are different from modules… how? I expect these concepts won’t become concrete until I tackle larger projects that incorporate code from multiple different sources.

In contrast, Angular Components have become very concrete and these pages even use excerpts from the “Tour of Heroes” tutorial to illustrate its concepts. I feel I have a basic grasp of components now, but I’m also aware I still need to read up on a few things:

  • Component metadata so far has been a copy-and-paste affair with limited explanation. It’ll be a challenge to strike out on my own and get the metadata correct. Not just because I don’t know what I should do, but also I haven’t seen what the error messages are like.
  • Data binding with the chart of four types of binding looks handy, I hope it’s repeated and expanded in more detail elsewhere in documentation so I can get some questions answered. One example: I read “Angular processes all data bindings once for each JavaScript event cycle” but I have to ask… what’s a JavaScript event cycle? The answer lies elsewhere.
  • Pipes feel like something super useful and powerful, looking forward to playing more with the concept and maybe even create a few of my own.
  • Directives seem to be a generic concept whose umbrella is fuzzy, but I’ve been using task-specific directives in the tutorial. *ngFor and *ngIf are structural directives. Attribute directive was used in two-way data binding. Both types have their own specific guide pages.

Reading the broad definition of services I started thinking “Feels like my UWP Logger, maybe I can implement a logger service as exercise.” Only to find out they’re way ahead of me – the example is a logger (to console) service! I had hoped this section would help clear up the concept of service providers, but it is still fuzzy in my head. I understand the default is root, which is a single instance for everything, and this is what was used in the tutorials. I will need to go find examples of providers at other granularities, which apparently can be as specific as per component where each instance of component gets its own instance of that service. When would that be useful? I have yet to learn the answer. But at least I’ve written these questions down so I’m less likely to forget.

Fixing Warnings of TypeScript Strict Mode Violation After “Tour of Heroes” Tutorial

Once I’ve reached the end of the Angular “Tour of Heroes” tutorial, I went back to address something from the beginning. When I created my Angular project, I added the --strict flag for the optional “Strict Mode“. My motivation was the belief that, since I’m starting from scratch, I might as well learn it under enforcement of best practices. I soon realized this was also adding an extra burden on myself for following the tutorial, because the example code does not always follow strict mode. This means when something goes wrong, I might have copied the tutorial code incorrectly, but it’s also possible I copied correctly but it’s just doesn’t conform to strict mode.

As a beginner, I really didn’t need this extra work, since I had enough problems with basics on my own. But I decided to forge onward and figure it out as I went. During the tutorial, I fixed strict mode errors in two categories:

  1. Something so trivial that I could fix quickly and move on.
  2. Something so serious that compilation failed and I had to fix it before I could move on.

In between those two extremes were errors that were not trivial, but only resulted in compilation warnings that I could ignore and address later. They are visible in this GitHub commit:

I first had to understand what the code was doing, which was why I imported MessageService to gain access to logging. The compiler warnings were both about uninitialized variables, but the correct solution was different for the two cases.

For the hero input field, the tutorial code logic treats undefined as a valid case. It is in fact dependent on undefined hero to know when not to display the detail panel. Once I understood this behavior, I felt declaring the variable type as a Hero OR undefined was the correct path forward.

For the Observable collection of Heroes, the correct answer is different. The code never counts on undefined being a valid value, so I did not need to do the if/else checks to handle it as an “OR undefined” value. What I needed instead was an initial value of a degenerate Observable that does nothing until we can get a real Observable. Combing through RxJS documentation I saw this was recognized as a need and was actually done in a few different ways that have since been deprecated. The current recommendation is to use the constant defined as EMPTY, which is what I used to resolve the strict mode errors.

Notes on “Tour of Heroes” Tutorial: Other Web Server Interactions

The Angular “Tour of Heroes” tutorial section 6 “Get Data From Server” covered the standard interactions: Create, Read, Update, and Delete commonly referred to as CRUD. But it didn’t stop there and covered a few other server operations. I was intrigued the next section was titled “Search by name” because I was curious how a client side single page application could search data on a static web server.

It turns out the application does not actually perform the search, the “search by name” example is built around sending a GET URL with a “name=” query parameter and processing the results. So the example here isn’t actually specific to searching, it’s just a convenient example to demonstrate a general server query/response outside of the simplified CRUD mode. It can be argued that this fits under the umbrella of R of CRUD, but this is as far as I’ll pick that nit.

Lucky for us, the search query parameter appears to be part of the feature set of the in-memory web API we’re using to stand in for a web server. Like the rest of the tutorial CRUD operations, none of this will actually work on a static web server. But that’s fine, we get to see the magic of Observable used in a few different ways. Like a new convention of ending an observable name with the $ character and asynchronously piping into a *ngFor directive.

For me, the most interesting new concept introduced in this section is the rate-limiting functionality of debounceTime() filter from RxJS. Aside from being a piece of commonly needed (and thus commonly re-implemented) functionality, it shows the power of using RxJS for asynchronous operations where we can stick these kind of filters in the pipeline to accomplish goals. I don’t fully understand how it works or how I might reuse it in other contexts. I think I have to learn more about Subject<T> first? But anyway, what we’ve seen here is pretty cool and worth following up with more reading later.