The Angular CLI
The Angular CLI tool, ng, is an official Angular project to ensure that newly created Angular applications have a uniform architecture, following the best practices perfected by the community over time. This means that any Angular application you encounter going forward should have the same general shape.
Setting up your development directory
Setting up a dedicated dev
directory is a lifesaver. Since all the data under this directory is backed up using GitHub, you can safely configure your antivirus, cloud sync, or backup software to ignore it. This helps significantly reduce CPU, disk, and network utilization. As a full-stack developer, you're likely to be multitasking a lot, so avoiding unnecessary activity has a net positive impact on performance, power, and data consumption daily, especially if your development environment is a laptop that is resource-starved or you wish to squeeze as much battery life as possible when you're on the move.
Creating a dev
folder directly in the c:\
drive is very important on Windows. Earlier versions of Windows, or rather NTFS, can't handle file paths longer than 260 characters. This may seem adequate at first, but when you install npm packages in a folder structure that is already deep in the hierarchy, the node_modules
folder structure can get deep enough to hit this limit very easily. With npm 3+, a new, flatter package installation strategy was introduced, which helps with npm-related issues, but being as close to the root folder as possible helps tremendously with any tool.
Create your dev
folder using the following commands:
For Windows:
PS> mkdir c:\dev
PS> cd c:\dev
For macOS:
$ mkdir ~/dev
$ cd ~/dev
In Unix-based operating systems, ~
(pronounced tilde) is a shortcut to the current user's home directory, which resides under /Users/your-user-name
.
Now that your development directory is ready, let's start with generating your Angular application.
Generating your Angular application
The Angular CLI is an official Angular project to ensure that newly created Angular applications have a uniform architecture, following the best practices perfected by the community over time. This means that any Angular application you encounter going forward should have the same general shape. The Angular CLI goes beyond initial code generation; you'll use it frequently to create new components, directives, pipes, services, modules, and more. The Angular CLI also helps during development, with live-reloading features so that you can quickly see the results of your changes. The Angular CLI can also test, lint, and build optimized versions of your code for a production release. Furthermore, as new Angular versions are released, the Angular CLI helps you upgrade your code by automatically rewriting portions of it so that it remains compatible with potential breaking changes.
Installing the Angular CLI
The documentation at https://angular.io/guide/quickstart guides you on how to install @angular/cli
as a global npm package. Do not do this. Over time, as the Angular CLI is upgraded, it is a constant irritant to have to keep the global and the in-project version in sync. If you don't, the tool complains endlessly. Additionally, if you are working on multiple projects, you end up with varying versions of the Angular CLI over time. As a result, your commands may not return the results you expect or the results your team members get.
The strategy detailed in the next section makes the initial configuration of your Angular project a bit more complicated than it needs to be; however, you'll more than make up for this pain if you have to return to a project a few months or a year later. In that case, you could use the version of the tool that you last used on the project, instead of some future version that may require upgrades that you're not willing to perform. In the next section, you'll use this best practice to initialize your Angular app.
Initializing your Angular app
The main way to initialize your app is by using the Angular CLI. Let's initialize the application for development using npx
, which is already installed on your system from when you installed the latest version of Node LTS, from PowerShell/Terminal:
- Under your
dev
folder, executenpx @angular/cli new local-weather-app
- Select No, when asked Would you like to add Angular routing?
- Select CSS, when asked Which stylesheet format would you like to use?
- On your terminal, you should see a success message similar to this:
$ npx @angular/cli new local-weather-app ... CREATE local-weather-app/src/environments/environment.ts (662 bytes) CREATE local-weather-app/src/app/app-routing.module.ts (245 bytes) CREATE local-weather-app/src/app/app.module.ts (393 bytes) CREATE local-weather-app/src/app/app.component.html (1152 bytes) CREATE local-weather-app/src/app/app.component.spec.ts (1086 bytes) CREATE local-weather-app/src/app/app.component.ts (207 bytes) CREATE local-weather-app/src/app/app.component.css (0 bytes) CREATE local-weather-app/e2e/protractor.conf.js (752 bytes) CREATE local-weather-app/e2e/tsconfig.e2e.json (213 bytes) CREATE local-weather-app/e2e/src/app.e2e-spec.ts (632 bytes) CREATE local-weather-app/e2e/src/app.po.ts (251 bytes) added 1076 packages from 1026 contributors and audited 42608 packages in 62.832s found 0 vulnerabilities Successfully initialized git. Project 'local-weather-app' successfully created.
Your project folder—local-weather-app
—has been initialized as a Git repository and scaffolded with the initial file and folder structure, which should look like this:
local-weather-app
├── .editorconfig
├── .git
├── .gitignore
├── angular.json
├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.e2e.json
├── package.json
├── README.md
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ └── app.module.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── browserslist
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── karma.conf.js
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.css
│ ├── test.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.spec.json
│ └── tslint.json
├── tsconfig.json
└── tslint.json
The alias for @angular/cli
is ng
. If you were to install the Angular CLI globally, you would execute ng new local-weather-app
, but we didn't do this. So, it is essential to remember that, going forward, you execute the ng
command, but this time under the local-weather-app
directory. The latest version of the Angular CLI has been installed under the node_modules/.bin
directory so that you can run ng
commands such as npx ng generate component my-new-component
and continue working efficiently.
If you are on macOS, you can further improve your development experience by implementing shell auto-fallback, which removes the necessity of having to use the npx
command. If an unknown command is found, npx takes over the request. If the package already locally exists under node_modules/.bin
, npx passes along your request to the correct binary. So, you can run commands like ng g c my-new-component
as if they're globally installed. Refer to npx's readme on how to set this up, at npmjs.com/package/npx#shell-auto-fallback.
Publishing a Git repository using GitHub Desktop
GitHub Desktop allows you to create a new repository directly within the application:
- Open GitHub for Desktop
- File | Add local repository...
- Locate the
local-weather-app
folder by clicking on Choose... - Click on Add repository
- Note that the Angular CLI already created the first commit for you in the History tab
- Finally, click on Publish repository, marked in the following screenshot as 6:
Figure 2.4: GitHub Desktop
Inspecting and updating package.json
Package.json
is the single most important configuration file that you should be keenly aware of at all times. Your project's scripts, runtime, and development dependencies are stored in this file.
- Open
package.json
and locate the name and version properties:package.json { "name": "local-weather-app", "version": "0.0.0", "license": "MIT", ...
- Rename your app to whatever you wish; I used
localcast-weather
- Set your version number to
1.0.0
npm
uses semantic versioning (semver), where version number digits represent Major.Minor.Patch increments. Semver starts version numbers at1.0.0
for any published API, though it doesn't prevent0.x.x
versioning. As the author of a web application, the versioning of your app has no real impact on you, outside of internal tooling, team, or company communication purposes. However, the versioning of your dependencies is critical to the reliability of your application. In summary, patch versions should just be bug fixes. Minor versions add functionality without breaking the existing features, and major version increments are free to make incompatible API changes. However, any update is risky to the tested behavior of your application. Therefore, thepackage-lock.json
file stores the entire dependency tree of your application, so the exact state of your application can be replicated by other developers or CI servers. For more information, visit: https://semver.org/.In the following code block, observe that the
scripts
property contains a collection of helpful starter scripts that you can expand on. Thestart
andtest
commands are npm defaults, so they can just be executed bynpm start
ornpm test
. However, the other commands are custom commands that must be prepended with therun
keyword. For example, in order to build your application, you must usenpm run build
:package.json ... "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, ...
Before the introduction of npx, if you wanted to use the Angular CLI without a global install, you would have to run it with
npm run ng -- g c my-new-component
. The double-dashes are needed to let npm know where the command-line tool name ends and the options begin. For example, in order to start your Angular application on a port other than the default4200
, you need to runnpm start -- --port 5000
. - Update your
package.json
file to run your development version of the app from a little-used port like5000
as the new default behavior:package.json ... "start": "ng serve --port 5000", ...
Under the dependencies property, you can observe your runtime dependencies. These are libraries that get packaged up alongside your code and shipped to the client browser. It's essential to keep this list to a minimum:
package.json ... "dependencies": { "@angular/animations": "~9.0.0", "@angular/common": "~9.0.0", "@angular/compiler": "~9.0.0", "@angular/core": "~9.0.0", "@angular/forms": "~9.0.0", "@angular/platform-browser": "~9.0.0", "@angular/platform-browser-dynamic": "~9.0.0", "@angular/router": "~9.0.0", "rxjs": "~6.5.3", "tslib": "^1.10.0", "zone.js": "~0.10.2" }, ...
In the preceding example, all Angular components are on the same version. As you install additional Angular components or upgrade individual ones, it is advisable to keep all Angular packages on the same version. This is especially easy to do since npm doesn't require the --save
option anymore to permanently update the package version. For example, just executing npm install @angular/router
is sufficient to update the version in package.json
. This is a positive change overall, since what you see in package.json
matches what is actually installed. However, you must be careful, because npm also automatically updates package-lock.json
, which propagates your, potentially unintended, changes to your team members.
Your development dependencies are stored under the devDependencies
property. When installing new tools for your project, you must take care to append the command with --save-dev
so that your dependency is correctly categorized. Dev dependencies are only used during development and not shipped to the client browser. You should familiarize yourself with every single one of these packages and their specific purpose. If you are unfamiliar with a package shown as we move on, your best resource to learn more about them is https://www.npmjs.com/:
package.json
...
"devDependencies": {
"@angular-devkit/build-angular": "~0.900.0",
"@angular/cli": "~9.0.0",
"@angular/compiler-cli": "~9.0.0",
"@angular/language-service": "~9.0.0",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.4.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.1.2",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.2",
"protractor": "~5.4.2",
"ts-node": "~8.3.0",
"tslint": "~5.18.0",
"typescript": "~3.6.4"
}
...
The characters in front of the version numbers have specific meanings in semver:
- The tilde,
~
, enables tilde ranges when all three digits of the version number are defined, allowing patch version upgrades to be automatically applied - The up-caret character,
^
, enables caret ranges, allowing minor version upgrades to be automatically applied - A lack of any character signals npm to install that exact version of the library on your machine
You may notice that major version upgrades aren't allowed to happen automatically. In general, updating packages can be risky. In order to ensure no package is updating without your explicit knowledge, you may install exact version packages by using npm's --save-exact
option. Let's experiment with this behavior by installing an npm package that I published called dev-norms
, a CLI tool that generates a markdown file with sensible default norms for your team to have a conversation about, as shown here:
- Under the
local-weather-app
directory, executenpm install dev-norms --save-dev --save-exact
. Note that "dev-norms
": "1.7.0
" or similar has been added topackage.json
withpackage-lock.json
automatically updated to reflect the changes accordingly. - After the tool is installed, execute
npx dev-norms create
. A file nameddev-norms.md
has been created containing the developer norms mentioned previously.
- Save your changes to
package.json
.
Working with stale packages comes with its risks. With npm 6, the npm audit
command has been introduced to make you aware of any vulnerabilities discovered in packages you're using. During npm install
, if you receive any vulnerability notices, you may execute npm audit
to find out details about any potential risk.
In the next section, you'll commit the changes you have made to Git.
Committing code using VS Code
To commit your changes to Git and then synchronize your commits to GitHub, you can use VS Code:
- Switch over to the Source Control pane, marked as 1 here:
Figure 2.5: Visual Studio Code Source Control pane
- Enter a commit message in the box marked as 2
- Click on the check-mark icon, marked as 3, to commit your changes
- Finally, synchronize your changes with your GitHub repository by clicking on the refresh icon, marked as 4
If you have two-factor authentication enabled, as you should, GitHub may ask for your credentials. In this case, you need to create a personal access token. Follow the instructions below to get this done:
- Go to the page https://github.com/settings/tokens
- Generate a new token and copy it
- Attempt to re-sync your change within VS Code
- Ignore the GitHub authentication window, which presents you with VS Code's credential input bar
- Enter your GitHub username, not your email
- Paste in the token as your password
- The sync should succeed, and subsequent syncs shouldn't prompt for a password
See the Git and Github Desktop section earlier in this chapter for a wider discussion of the various methods you can use to connect your Git client to GitHub.
Going forward, you can do most Git operations from within VS Code.
Running your Angular app
Run your Angular app to check whether it works. During development, you can execute npm start
through the ng serve
command; this action transpiles, packages, and serves the code on localhost with live-reloading enabled:
- Execute
npm start
- Navigate to
http://localhost:5000
- You should see a rendered page similar to this:
Figure 2.6: Default Angular CLI landing page
- Stop your application by pressing Ctrl + C in the integrated terminal
Congrats! You're ready to start developing your web application. If you ran into any trouble during your setup, see the next section on how you can verify your code against the sample project on GitHub.
Verifying your code
The most up-to-date versions of the sample code for the book are on GitHub at the repository linked following. The repository contains the final and completed state of the code. You can verify your progress at the end of a chapter by looking for the end-of-chapter snapshot of code under the projects
folder.
For Chapter 2:
- Clone the repo https://github.com/duluca/local-weather-app
- Execute
npm install
on the root folder to install dependencies - The code sample for this chapter is under the sub-folder:
projects/ch2
- To run the Angular app for this chapter, execute:
npx ng serve ch2
- To run Angular Unit Tests for this chapter, execute:
npx ng test ch2 --watch=false
Beware that the source code in the book or on GitHub may not always match the code generated by Angular CLI. There may also be slight differences in implementation between the code in the book and what's on GitHub because the ecosystem is ever evolving. It is natural for the sample code to change over time. Also on GitHub, expect to find corrections, fixes to support newer versions of libraries, or side-by-side implementations of multiple techniques for the reader to observe. The reader is only expected to implement the ideal solution recommended in the book. If you find errors or have questions, please create an issue or submit a pull request on GitHub for the benefit of all readers.
In the next section, I'll cover how you can optimize VS Code for Angular for the best possible development experience.