Opinionated Angular Setup
Tags: angular, javascript, typescript, webdev
Published: 2021-01-24 15:24:20

---
title: Opinionated Angular Setup
published: true
description: This is my opinionated guide on how to set up a new Angular Project.
tags: Angular, JavaScript, TypeScript, Webdev
//cover_image: https://direct_url_to_image.jpg
---

# Introduction

This is my opinionated guide on how to set up a new Angular Project. Below, I described all of the steps that I usually take whenever I set-up a new Angular Project. This was originally meant to be a checklist for myself, but then I decided to write it down in the format of an article. I hope someone can benefit from this. If you are a newbie and just want to learn Angular, you should not care much about this setup. But if you want to set up a serious project and need to make some decision on e.g. testing, formatting, or ChangeDetection then this guide may be useful for you. I additionally tried to add some context and explain my decisions. If you are in a hurry just read the bullet points or jump right to the section you are interested in.

At the time of writing this post, the latest [`@angular-cli`](https://www.npmjs.com/package/@angular/cli) version was `11.0.4`. I used this version to generate the project. Since the project structure changes sometimes, the below steps may vary a little bit depending on your CLI version. You can use your favorite editor and follow along with the steps. I used VS-Code with the plugins [Angular Language Service](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template), [TSLint](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin), [Prettier](https://marketplace.visualstudio.com/items?itemName=SimonSiefke.prettier-vscode), and [SCSS Formatter](https://marketplace.visualstudio.com/items?itemName=sibiraj-s.vscode-scss-formatter). They are all optional and just a recommendation.

You can find the final result on my [GitHub](https://github.com/kaisnb/opinionated-angular-setup). Take a look at the [commit history](https://github.com/kaisnb/opinionated-angular-setup/commits/master) to see every single step as a granular commit.

## Index

- [1. Generate a new Angular project](#1-generate-a-new-angular-project)
- [2. Change Detection Default](#2-change-detection-default)
- [3. Think of a Component and Directive Prefix](#3-think-of-a-component-and-directive-prefix)
- [4. Setup Prettier](#4-setup-prettier)
- [5. Replace Karma/Jasmine with Jest](#5-replace-karmajasmine-with-jest)
- [6. Replace Protractor with Cypress](#6-replace-protractor-with-cypress)
- [7. Add PWA Features](#7-add-pwa-features)
- [8. Add Angular Material (Optional)](#8-add-angular-material-optional)
- [9. Use a System Font Stack (Optional)](#9-use-a-system-font-stack-optional)
- [10. More Ideas](#10-more-ideas)

## 1. Generate a new Angular project

The first step we must take is to generate a new Angular project. This is usually done by using the CLI. If you haven’t done it yet, go to https://nodejs.org/en/ and install the LTS version. After doing this you should have the package manager NPM available. Open your favorite terminal and type `npm i -g @angular/cli`. This will install the Angular CLI globally so that you can use the `ng` command everywhere. Run `ng --version` to check if everything went well. If it was already installed, you can use the same command to update to the newest version. Using the `ng` tool, we can now generate a new project. Navigate to the folder where you want to create the project. Type `ng new my-angular-project` to generate a new project called `my-angular-project`. The CLI will now ask you a few questions. These are my preferred answers:

- Strict type checking and stricter bundle budgets? -> Yes
- Routing? -> Yes
- Stylesheet format? -> SCSS

Everything can be changed later. Strict type checking is always a good idea to prevent any errors that may result from loose typing - like Null-Pointer and many others. It's out of the scope of this post to discuss this topic. Routing is needed in almost every bigger SPA. You have to decide on your own if your SPA needs it or not. The last question is about the format of your Stylesheets. I prefer to write Scss since it is a superset of CSS, which is not the case for Sass. Choosing Scss over Less is just a personal preference. Choose whatever you are the most familiar with.

## 2. Change Detection Default

The following section is a bit more complicated to understand as a beginner. Basically, there are two [Change Detection Strategies](ChangeDetectionStrategy) in Angular. One is called `Default` and the other is called `OnPush`. The default applies if you do not override the Change Detection at the Component level. If you take a look into an already generated Component e.g. `app.component.ts`, you see that there is no `changeDetection` property inside the configuration of the [Component Decorator](https://angular.io/api/core/Component).

Default Change Detection is a little bit easier to implement but is less performant. What this means is that every time Angular runs its Change Detection, all bindings are checked. This is costly and can become a bottleneck in more complex applications. What I prefer is always switching to On-Push. It is more performant since a Change Detection Cycle does only check the Bindings of Components that are marked as dirty. A Component will be marked as dirty when (a) an Input of the Component changes, (b) an event is emitted from this Component, (c) you use the `async` Pipe inside the template or (d) you manually mark it as dirty. There are plenty of good posts about this topic out there. I really recommend you to conduct a quick Google Search and dive deeper into this topic if you are interested.

You can enable the [Angular Debug Tools](https://angular.io/api/platform-browser/enableDebugTools) to profile how fast Angular runs a Change Detection Cycle with each of the strategies. You will see that there is a huge difference. The tradeoff is that you may have to write a little bit more code sometimes to run the Change Detection at the right moment. If you structure your code well in reactive style and leverage tools like [RxJS](https://rxjs.dev/) and the [AsyncPipe](https://angular.io/api/common/AsyncPipe) then your application will automatically be compatible with the OnPush strategy.

What we do now is set the OnPush strategy as default for the schematics. Every time you generate a new Component using `ng g c` the Change Detection will be set correctly.

- Open the `angular.json` and add a property `changeDetection` inside `projects > my-angular-project > schematics > @schematics/angular:component` with the value `OnPush`
- Refactor your `AppComponent` to use the correct strategy.

## 3. Think of a Component and Directive Prefix

It’s suggested to use a prefix for all your components and directives. You can read more about the reasons inside the Angular coding style guide. There is a section about [Component Prefix](https://angular.io/guide/styleguide#component-custom-prefix) and [Directive Prefix](https://angular.io/guide/styleguide#directive-custom-prefix). The default prefix in our newly generated project is `app`. Angular picks up this prefix when generating new components. To enforce this style there exists a custom tslint rule which comes with the [`codelyzer` package](https://www.npmjs.com/package/codelyzer).

- Open the `angular.json` and change the property `projects > my-angular-project > prefix` to your own prefix.
- Open the `ts-lint.json` and replace `app` with your own prefix inside the `directive-selector` and `component-selector` rule configuration.
- Refactor your `AppComponent` to use the correct prefix. Don’t forget about the `index.html`.

As TSLint is [officially deprecated](https://github.com/palantir/tslint/blob/master/README.md) I assume that this section will change slightly in the future and [TSLint](https://palantir.github.io/tslint/) will be replaced with [ESLint](https://eslint.org/).

## 4. Setup Prettier

TSLint already does a lot for us but it is not meant to be a full-fledged formatter. For that reason, it’s a good idea to add a formatter to enforce a consistent code style across all developers. Since the line between linting and formatting seems to be a little bit blurry, there are areas where the tools overlap. For example, both tools care about the maximum line length or quotes. This means that we need consistency in our configuration, otherwise the linter will complain if run after the formatter and vice-versa. I decided to use Prettier for formatting since it is widely adopted (12.148.717 weekly downloads on npm at the time of writing this post) and opinionated. Opinionated means that we do not have much to configure, which is great. I like the defaults and do not care much about how the formatting looks. My main goal is consistency. There are many different ways to [configure Prettier](https://prettier.io/docs/en/configuration.html). My preferred way is to put the configuration inside the `package.json`.

- Install the NPM package `npm i --save-dev prettier`
- Open the `package.json` and add a key `”prettier”`. Use the following config object: `{ "printWidth": 140, "singleQuote": true }`
- For convenience add a script in your `package.json` to apply the formatting: `"prettier": "prettier --write \"**/*.{ts,js,css,html,scss}\"",`
- And one to check the formatting: `"prettier:check": "prettier --check \"**/*.{ts,js,css,html,scss}\"",` which is useful for the CI Pipeline.
- To run it from your Editor, download the appropriate Editor Integration https://prettier.io/docs/en/editors.html

## 5. Replace Karma/Jasmine with Jest

Angular comes with a default framework for Unit-Testing. They use Karma as a Test Runner and Jasmine is the JavaScript Testing Framework they use for other things like assertions. Both are good tools that work well. However, I ultimately decided to use Jest. There are tons of good articles out there where you can read about Jest vs Karma. I made my decision because of two key reasons. First, Jest has a much bigger community around it. Since it comes from the React ecosystem, it is widely used and loved by millions. At the time of writing it has about ten million weekly downloads on NPM compared to less than two million for Karma. This is a huge benefit in my opinion especially when you browse the web for solutions to tricky problems. The other reason is its architecture. The architecture is fundamentally different compared to Karma. Jest uses jsdom to simulate the DOM instead of running a Browser like Karma. This improves performance and is in my opinion the right way to go. Jest is built on top of Jasmine, its API is mostly compatible. After following the below steps you can run the `app.component.spec.ts` test we already have and it will work without any changes to the code.

- Run `npm uninstall jasmine-core jasmine-spec-reporter @types/jasmine karma-chrome-launcher karma-coverage karma-jasmine-html-reporter karma-jasmine karma` to remove all Karma and Jasmine dependencies
- Delete `src/test.ts` and `karam.conf.js`
- Open `angular.json` and remove the whole `projects > my-angular-project > architect > test` block.
- Run `npm i jest @types/jest jest-preset-angular --save-dev` to add all dependencies we need for Jest
- Open `tsconfig.spec.json` and replace the types `[jasmine]` with `[jest, node]`
- Add a file called `setup-jest.ts` in the project root directory with the following content `import 'jest-preset-angular';`
- Add a file called `jest.config.js` in the project root directory and put the following code inside: `module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], };`
- Inside the `package.json` replace the old `test` script with `"test": "jest", "test:coverage": "jest --coverage",`
- Update the documentation inside the `README.md`

If you want more details regarding what happened here, check out this excellent [Blogpost](https://www.xfive.co/blog/testing-angular-faster-jest/) for more information and useful tips.

## 6. Replace Protractor with Cypress

Angular’s default solution for End-to-End-Testing is Protractor. It is developed by the Angular Team. I am going to remove Protractor and replace it with Cypress. I suggest you search the web if you are looking for more information about the comparison of Protractor with Cypress. But again there are two main reasons why I prefer Cypress over Protractor. First, it has a big community and is very well maintained. They are pushing new releases and the Changelog is always huge, full of improvements, bug fixes, and new features. I started using it with version 3.3.0 and it has since then constantly getting better and more stable. The second reason is that the architecture is fundamentally different from Protractor. Cypress is executed in the same event loop as the application tested and that allows it to be much more stable and not as flaky as traditional E2E testing frameworks. To set up Cypress and remove Protractor we will use an awesome [Schematics](https://www.npmjs.com/package/@briebug/cypress-schematic) made available by [Briebug](https://briebug.com/).

- Run `ng add @briebug/cypress-schematic --addCypressTestScripts` and choose yes to remove Protractor.
- Add `/cypress/videos` and `/cypress/screenshots` to your `.gitignore`
- Update the documentation inside the `README.md` and
- Run `npm run e2e` to verify that everything's working correctly

## 7. Add PWA Features

In Angular, there is this really nice [Schematics](https://angular.io/guide/service-worker-getting-started) to turn your application into a PWA with just one command. It creates a `manifest.webmanifest` file, adds the necessary configuration to use Service Workers, and adds some dummy icons. Almost every application can benefit from Service Worker support. Your application does load faster now and you can use features like [A2HS](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Add_to_home_screen) and show a Splash Screen.

- Run `ng add @angular/pwa`

## 8. Add Angular Material (Optional)

In the next step, I want to add a component library. This step is totally optional, but in almost any project you choose some sort of UI library to speed up the development of your application. There are a lot of very good libraries out there like [NG-ZORRO](https://ng.ant.design/), [PRIMENG](https://www.primefaces.org/primeng/), or [ng-bootstrap](https://ng-bootstrap.github.io/). A more comprehensive list can be found [in the official Angular Docs](https://angular.io/resources?category=development). Whenever possible I choose [Angular Material Components](https://material.angular.io/). It's a set of components for Angular that follows Google's [Material Design](https://material.io/) specification. The assortment of components is not the largest but they are all really high quality. I have personally used them a lot and have never experienced any issues. The following steps will be specific to this library. See the [installation guide](https://material.angular.io/guide/getting-started#install-angular-material).

- Run `ng add @angular/material` in the root of your project.
- Q: Choosing a Theme -> Custom
- Q: Setup global typography? -> Yes
- Q: Setup browser animations? -> Yes

Of course, you can answer the question depending on your needs. I only wanted to give you the options I typically pick.

**PERF TIP:** Below I want to show two optimizations I typically apply to improve the application performance a bit. They may be considered to be "premature optimizations" so avoid them if you do not know that you need them.

- Instead of including the whole theme `@include angular-material-theme($theme);`, we can customize and only include the CSS for components that we want to use e.g.

```scss
@include mat-core-theme($theme);
@include mat-button-theme($theme);
@include mat-icon-theme($theme);
```

- Instead of loading the whole icon font, I prefer to manually include the SVG's of Icons that I use and embed them in the code. Remove the icon font include from the `index.html` and register the SVG's in your `AppModule`. Take a look at the [MatIconRegistry docs](https://material.angular.io/components/icon/overview#icon-sets) for more details.

```typescript
export class AppModule {
  constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
    iconRegistry.addSvgIconSetLiteralInNamespace(
      "mdi",
      sanitizer.bypassSecurityTrustHtml(`
        <svg xmlns="http://www.w3.org/2000/svg">
            <def>
                <svg id="close" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
                <svg id="menu" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
            </def>
        </svg>`)
    );
  }
}
```

## 9. Use a System Font Stack (Optional)

If the design of your UI allows it, I prefer to use a [System Font Stack](https://css-tricks.com/snippets/css/system-font-stack/). The main reason why I do this is that I avoid loading a font file and save a lot of bytes. Below, I will use the System Font Stack which is used by [GitHub.com](https://github.com/). The following steps are specific to Angular Material. If you have chosen a different component library there may be other ways to do it.

Define your custom typography and pass it as an argument to the `mat-core` include. That's it.

```scss
$custom-typography: mat-typography-config(
  $font-family: "-apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji"
);

@include mat-core($custom-typography);
```

In the Angular Material docs, you can find more about [typography customization](https://material.angular.io/guide/typography#customization).

## 10. More Ideas

These were the key steps I usually take when setting up a serious Angular project. Of course, you can also code right away and do any of these steps at a later point in time. Before I leave you alone to start coding, I want to give you a quick list of a few more things that came to my mind. These were topics I first wanted to include but then left out since I think they make less sense to set up right at the beginning of a project.

- Add [Compodoc](https://compodoc.app/) to generate a documentation
- Create a `.dockerfile` to containerize your application 
- Add [ngx-translate](http://www.ngx-translate.com/) for internationalization
- Use [Husky](https://www.npmjs.com/package/husky) to set up Git hooks e.g. to run the formatter or linter on `pre-commit` event
- Add tools like [commitlint](https://github.com/conventional-changelog/commitlint) to keep a clean commit history
- Set up CI/CD with tools like [GitLab CI/CD](https://docs.gitlab.com/ee/ci/), [GitHub Actions](https://github.com/features/actions), [Travis CI](https://travis-ci.org/), [CircleCI](https://circleci.com/)
- Deploy your application to one of my favorite platforms [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/).
- Many others... 

# Thanks for Reading

I hope this post was at least a little bit useful for you. Please feel free to reach out with any questions, comments, or feedback.

Kai Schönberger, 2021/01/24