@froko/ng-essentials: Version 4.0 released

Hint: This is an updated version of my previous post “@froko/ng-essentials: Version 3.1.1 released“.

ng-essentials is an Angular schematic aimed to add better defaults to a newly created application. I’ve been working with Angular2+ since the early days, and I’ve always found myself tweaking and configuring the same settings over and over again with every new project I’ve started. Then I’ve heard about the custom schematics that have been introduced in Angular 7 and started playing around with them. The result was the born of ng-essentials back in fall 2018.

Installation

To install the ng-essentials schematic, run the following command in the root directory of your newly created Angular app:

$> ng add @froko/ng-essentials

As the npm site states, ng-essentials includes many of the ideas of a blog post, written by Martin Hochel: Use React tools for better Angular apps. The schematic improves a new Angular project in the following ways:

  • Update of the npm packages to their latest stable version, while keeping specific version dependencies (e.g. Angular vs. Typescript)
  • Removal of all automatic update signifiers (e.g. ^ or ~) in package.json, inclusive the save-exact=true setting in .npmrc. I’ve seen too many projects failed to build after some time since not all dependent projects seem to follow the semantic versioning.
  • Introduction of npm-force-resolutions as a pre-install script. This will ensure that sub-dependencies are installed with security-patched versions defined in the resolutions array of package.json.
  • Improvement of TsLint settings. One special case is the import statement ordering with different blocks. TsLint is now able to find and fix such issues so that you don’t have to worry about them anymore.
  • Installation and configuration of prettier for advanced code formatting: Just run npm run format to bring your codebase in a consistent shape.
  • Creation of a settings file in the .vscode folder. It will configure Visual Studio Code to format and fix-lint your file every time you save it.
  • Creation of a launch file in the .vscode folder to support debug capabilities while serving or testing your code.
  • Creation of an extensions file in the .vscode folder. It contains recommended plugins for Angular, Prettier and TsLint
  • Introduction of an ENV_PROVIDERS injection token in environment.ts and environment.prod.ts. This makes your code less dependent on the actual environment file. ENV_PROVIDERS gets registered in the providers array of the AppModule. So it’s possible to define your services like this:
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MyDataService {
  constructor(
    private http: HttpClient,
    @Inject('baseUrl') private baseUrl: string) {}

  getAll(): Observable<MyData[]> {
    const url = `${this.baseUrl}/data`;
    return this.http.get<MyData[]>(url);
  }
}
  • Removal of the e2e testing functionality with protractor. There are some reasons why I made this a non-optional operation:
    • Protractor is outdated. It once had its benefits compared to cypress (see below), especially when it comes to multi-browser support. But with the most recent major release of cypress, this is no longer the case. See this blog post for 5 reasons you should not use Protractor in 2020. Spoiler: They don’t recommend cypress as a first-class replacement…
    • Protractor has a dependency to jasmine – at least with the default Angular CLI stack. My goal was to remove karma/jasmine entirely when you opt-in for jest (see below). This is only possible if I remove Protractor as well.
    • Maybe your project doesn’t need e2e tests at all…

The following items are new to version 4.0 since I’ve finally found out how to invoke npm scripts with the Angular schematics (This might be a topic for another post…):

  • Formatting or your current code base according to the newly added prettier settings
  • Linting and fixing of lint issues of your current code base according to the new TsLint rules

Configuration Options

ng-essentials comes with 3 additional configuration options:

  • --jest
    Removes karma/jasmine entirely and replaces it with jest using @angular-builders/jest. ng test will automatically use jest as a test runner. ng-test --coverage will display an additional test coverage report, while ng-test --watch starts jest in a continuous mode waiting for file changes. If you have a wallaby license, you can use it as well – just use the automatic configuration. ng-essentials will store the chosen configuration options in angular.json and add itself as default collection. This will allow the creation of libraries and applications later on with jest enabled if ng-essentials has been added before with the --jest option.
  • --cypress
    Adds e2e testing with Cypress.io including the ability to write tests in TypeScript. Since there is no Angular builder yet, the ng e2e command has been removed and replaced by npm run cypress. In its default configuration, it will fire up ng serve and open a visual cypress instance where you can run your e2e tests.
  • --husky
    This option will install and configure husky as a pre-commit hook. It runs prettier to format your staged code and does linting of your existing codebase every time you commit to git. Since version 4.0 of ng-essentials, the installation of husky is now optional. If your git repo only includes your Angular project, this might be a valid option to maintain the quality of the committed code. If, on the other hand, your Angular project is just a part of a higher-order git repo, it’s now possible to entirely omit the husky installation, since the pre-commit hook will run on every commit, even if it has nothing to do with your Angular codebase.

Angular Workspace Support!

This is the most significant addition to ng-essentials and led to the new major version. It’s now possible to add ng-essentials to an empty Angular workspace, created with ng new [workspace-name] --createApplication=false. The idea for this feature is several months old, but I’ve never found time or inspiration to make it work. Big thanks to Pietro Sacco, who gave me the required motivation for the final implementation!

Here are some additional notes about the workspace feature:

  • If you choose the --cypress option, there will be only one cypress test folder in the root of the workspace, no matter how many applications you create in your workspace. This behavior is different from protractor, where every application gets its own e2e test folder.
  • If you choose the --jest option, you may get warnings during the test run, claiming that there are multiple targets. To fix this issue, configure the paths compiler option in the tsconfig.json file: Instead of pointing to two items in the dist folder, replace the items in the array with the path to the public-api.ts file in the src folder of the library.