17.04.2018 — Angular — 5 min read

The Angular CLI is a command line interface for Angular. Its primary purpose is to assist developers with building Angular applications. Angular CLI was introduced together with the second version of Angular. Angular CLI allows you to generate and serving an Angular project as well as generate the Angular files (e.g. components, services, directives, pipes, interfaces, etc).

Introduction

In order to start your work with Angular CLI you need to install it globally by running, npm install -g @angular/cli so you could be able to work with it within any folder.

There are certain pre-requirements which need to be installed first. Angular CLI is dependable on Node 6.9.0 or higher, as well as NPM version 3 or higher.

The simplest way to check which version of the Angular CLI is running on your machine, you can just simply run ng v command in the console. As an example output you should be able to see: 1 Angular CLI: 1.6.7 2 Node: 8.9.4 3 OS: darwin x64

ng new

Using the Angular CLI makes it easy to create a new Angular application which works, right out of the box. It's worth to mention, that just created project follows the Angular style guide.

Let's see how it works in action. In terminal run ng new recipe-book . In this case recipe-book is an example project name, you can replace with anything you like.

The application generation process takes few minutes, in order to create components and install node modules. When the project is created, you should see a success message.

1 $ ng new recipe-book 2 create recipe-book/README.md (1027 bytes) 3 create recipe-book/.angular-cli.json (1247 bytes) 4 create recipe-book/.editorconfig (245 bytes) 5 create recipe-book/.gitignore (529 bytes) 6 create recipe-book/src/assets/.gitkeep (0 bytes) 7 create recipe-book/src/environments/environment.prod.ts (51 bytes) 8 create recipe-book/src/environments/environment.ts (387 bytes) 9 create recipe-book/src/favicon.ico (5430 bytes) 10 create recipe-book/src/index.html (298 bytes) 11 create recipe-book/src/main.ts (370 bytes) 12 create recipe-book/src/polyfills.ts (2405 bytes) 13 create recipe-book/src/styles.css (80 bytes) 14 create recipe-book/src/test.ts (642 bytes) 15 create recipe-book/src/tsconfig.app.json (211 bytes) 16 create recipe-book/src/tsconfig.spec.json (283 bytes) 17 create recipe-book/src/typings.d.ts (104 bytes) 18 create recipe-book/e2e/app.e2e-spec.ts (294 bytes) 19 create recipe-book/e2e/app.po.ts (208 bytes) 20 create recipe-book/e2e/tsconfig.e2e.json (235 bytes) 21 create recipe-book/karma.conf.js (923 bytes) 22 create recipe-book/package.json (1296 bytes) 23 create recipe-book/protractor.conf.js (722 bytes) 24 create recipe-book/tsconfig.json (363 bytes) 25 create recipe-book/tslint.json (3012 bytes) 26 create recipe-book/src/app/app.module.ts (316 bytes) 27 create recipe-book/src/app/app.component.css (0 bytes) 28 create recipe-book/src/app/app.component.html (1141 bytes) 29 create recipe-book/src/app/app.component.spec.ts (986 bytes) 30 create recipe-book/src/app/app.component.ts (207 bytes) 31 Installing packages for tooling via yarn. 32 yarn install v1.3.2 33 info No lockfile found. 34 [1/4] 🔍 Resolving packages... 35 warning karma > log4js > nodemailer@2.7.2: All versions below 4.0.1 of Nodemailer are deprecated. See https://nodemailer.com/status/ 36 warning karma > log4js > loggly > request > node-uuid@1.4.8: Use uuid module instead 37 warning karma > log4js > nodemailer > mailcomposer@4.0.1: This project is unmaintained 38 warning karma > log4js > nodemailer > socks@1.1.9: If using 2.x branch, please upgrade to at least 2.1.6 to avoid a serious bug with socket data flow and an import issue introduced in 2.1.0 39 warning karma > log4js > nodemailer > mailcomposer > buildmail@4.0.1: This project is unmaintained 40 warning karma > log4js > mailgun-js > proxy-agent > socks-proxy-agent > socks@1.1.10: If using 2.x branch, please upgrade to at least 2.1.6 to avoid a serious bug with socket data flow and an import issue introduced in 2.1.0 41 [2/4] 🚚 Fetching packages... 42 [3/4] 🔗 Linking dependencies... 43 [4/4] 📃 Building fresh packages... 44 success Saved lockfile. 45 ✨ Done in 95.28s. 46 Installed packages for tooling via yarn. 47 Successfully initialized git. 48 Project 'recipe-book' successfully created.

Angular CLI creates a folder with the same name as the project name. In our case its recipe-book . Let's quickly go through the files and folders which were just created.

1 recipe-book 2 ├── README.md 3 ├── e2e 4 ├── karma.conf.js 5 ├── node_modules 6 ├── package.json 7 ├── protractor.conf.js 8 ├── src 9 ├── tsconfig.json 10 ├── tslint.json 11 └── yarn.lock

Starting at the top, there is a README.md which has a basic overview of Angular CLI and available commands you can use.

which has a basic overview of Angular CLI and available commands you can use. The e2e folder is responsible for end-to-end tests.

folder is responsible for end-to-end tests. The karma.conf.js is a config file for Karma which is used for unit testing.

is a config file for Karma which is used for unit testing. The node_modules folder as you might already guess it's a folder where all of the packages and libraries were installed which are defined in package.json .

folder as you might already guess it's a folder where all of the packages and libraries were installed which are defined in . The package.json is the main place for your project configuration like scripts and dependencies .

is the main place for your project configuration like and . The protractor.conf.js is a config file for Protractor which is used for end-to-end testing.

is a config file for Protractor which is used for end-to-end testing. The tsconfig.json is a config file for TypeScript.

is a config file for TypeScript. The tslint.json is a TypeScript linter which checks our code against style rules defined in this file.

is a TypeScript linter which checks our code against style rules defined in this file. The yarn.lock or package-lock.json are the lock files generated by yarn or npm depends which tool for installing packages you use.

or are the lock files generated by or depends which tool for installing packages you use. Finally, the src folder is the place where in the future you are going to add all new components , services , modules , and other files for your application.

1 src 2 ├── app 3 │ ├── app.component.css 4 │ ├── app.component.html 5 │ ├── app.component.spec.ts 6 │ ├── app.component.ts 7 │ └── app.module.ts 8 ├── assets 9 ├── environments 10 │ ├── environment.prod.ts 11 │ └── environment.ts 12 ├── favicon.ico 13 ├── index.html 14 ├── main.ts 15 ├── polyfills.ts 16 ├── styles.css 17 ├── test.ts 18 ├── tsconfig.app.json 19 ├── tsconfig.spec.json 20 └── typings.d.ts

Structure of the src folder is pretty much self-explanatory. But still, let's have a quick look at it.

By default, app folder is a starting point for our application.

folder is a starting point for our application. Angular CLI is smart enough to detect the environment you work on and serve appropriate files based on that. The environments is build environments. From a preview, you may notice, that it has two files - environment.prod.ts and environment.ts as you might already guess one file is responsible for development while the other one for production environment.

is build environments. From a preview, you may notice, that it has two files - and as you might already guess one file is responsible for while the other one for environment. Angular CLI generates a default favicon which is used as a placeholder and can be replaced later on.

which is used as a placeholder and can be replaced later on. The index.html is the first thing the user sees when accessing our application.

is the first thing the user sees when accessing our application. The main.ts is the core file which responsible for bootstrapping of our application.

is the core file which responsible for bootstrapping of our application. The polyfills.ts file incorporates the mandatory and many of the optional polyfills as JavaScript import statements.

file incorporates the mandatory and many of the optional polyfills as JavaScript statements. The styles.css and test.ts these files are related to applying styles and initialising the Angular testing environment.

and these files are related to applying styles and initialising the Angular testing environment. Both tsconfig.*.json files are for TypeScript configuration. tsconfig.app.json is used for compiling the code, while tsconfig.spec.json for compiling the tests.

files are for TypeScript configuration. is used for compiling the code, while for compiling the tests. The typings.d.ts file provides the required typings for TypeScript.

ng serve

Yay, we have just generated a new application, but what we need to do to run it? It's really simple, all you need to do is to run ng serve in your terminal.

The ng-serve command starts a development server which listens on port 4200 by default. In case where port 4200 is already in use or you want to run it on a different port number, use --port to specify a different port. Example: $ ng serve --port 1337 Now when the development server is running, open your browser on http://localhost:1337/ .

1 $ ng serve 2 ** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** 3 Date: 2018-04-13T09:59:15.362Z l Hash: b1af346cc725e7d9fcb5 4 Time: 7418ms 5 chunk {inline} inline.bundle.js (inline) 5.79 kB [entry] [rendered] 6 chunk {main} main.bundle.js (main) 25.8 kB [initial] [rendered] 7 chunk {polyfills} polyfills.bundle.js (polyfills) 562 kB [initial] [rendered] 8 chunk {styles} styles.bundle.js (styles) 34 kB [initial] [rendered] 9 chunk {vendor} vendor.bundle.js (vendor) 7.44 MB [initial] [rendered] 10 11 webpack: Compiled successfully.

ng generate

Whoa, your application is up and running and can be accessed through the browser. Now it's the time to expand it!

The Angular CLI has a truly awesome command to scaffold new blueprints - ng generate or ng g as an alias.

Here is a list of all possible blueprints you can scaffold using ng generate

component

directive

pipe

service

class

guard

interface

enum

module

All you need to do is to run ng g [blueprint-to-scaffold] [your-blueprint-name] . Let's imagine we need to create a new recipes component. Then we just run ng g component recipes .

1 $ ng g component recipes 2 create src/app/recipes/recipes.component.css (0 bytes) 3 create src/app/recipes/recipes.component.html (26 bytes) 4 create src/app/recipes/recipes.component.spec.ts (635 bytes) 5 create src/app/recipes/recipes.component.ts (273 bytes) 6 update src/app/app.module.ts (402 bytes)

The Angular CLI adds reference to components , directives and pipes automatically in the app.module.ts .

Additionally, it's worth to mention the fact that ng generate support relative path generation for components. Let's quickly go through the certain amount of options ng generate offers us. In the first example, we are located in src/app/recipes :

When we run ng g component recipe , new component is going to be generated in src/app/recipes/recipe . When we run ng g component ./recipe , new component is going to be generated in src/app/recipe .

In the second example, we are located in the src/app :

When we run ng g component recipes/recipe , new component is going to be generated in src/app/recipes/recipe .

ng test

Testing your application is a good practice, but often developers tend to ignore this step whenever it's a business or personal projects due to lack of the time or desire.

"Write your * * * * * * * tests, always" — Mattias Petter Johansson

The Angular CLI is doing a great job at simplifying the developer lives by auto-generating testing files for us. The Angular CLI offers you unit and end-to-end testing. To run unit tests, open the terminal and run ng test . This step builds the Angular application and runs the test runner. You should see two different outputs: output in a console and browsers which was launched by Karma test runner.

1 $ ng test 2 10% building modules 1/1 modules 0 active13 04 2018 09:18:54.509:WARN [karma]: No captured browser, open http://localhost:9876/ 3 13 04 2018 09:18:54.515:INFO [karma]: Front-end scripts not present. Compiling... 4 13 04 2018 09:19:00.730:WARN [karma]: No captured browser, open http://localhost:9876/ 5 13 04 2018 09:19:00.995:INFO [karma]: Karma v2.0.0 server started at http://0.0.0.0:9876/ 6 13 04 2018 09:19:00.995:INFO [launcher]: Launching browser Chrome with unlimited concurrency 7 13 04 2018 09:19:01.000:INFO [launcher]: Starting browser Chrome 8 13 04 2018 09:19:02.686:INFO [Chrome 65.0.3325 (Mac OS X 10.13.3)]: Connected on socket jISkDcWPkf6iDQRWAAAA with id 62575173 9 Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 0 of 4 SUCCESS (0 secs / 0 secChrome 65.0.3325 (Mac OS X 10.13.3): Executed 1 of 4 SUCCESS (0 secs / 0.151Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 2 of 4 SUCCESS (0 secs / 0.203Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 3 of 4 SUCCESS (0 secs / 0.238Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 4 of 4 SUCCESS (0 secs / 0.283Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 4 of 4 SUCCESS (0.328 secs / 0.283 secs)

The same procedure goes for running end-to-end tests using protractor. You just run the ng e2e in a terminal.

1 $ ng e2e 2 ** NG Live Development Server is listening on localhost:49152, open your browser on http://localhost:49152/ ** 3 Date: 2018-04-13T08:29:04.113Z l Hash: 8a08417e4497e11cece3 4 Time: 7613ms 5 chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered] 6 chunk {main} main.bundle.js, main.bundle.js.map (main) 11.1 kB [initial] [rendered] 7 chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 203 kB [initial] [rendered] 8 chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 11.4 kB [initial] [rendered] 9 chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.76 MB [initial] [rendered] 10 (node:30726) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead. 11 12 webpack: Compiled successfully. 13 [09:29:04] I/file_manager - creating folder /Users/edvinsantonovs/Documents/repos/recipe-book/node_modules/webdriver-manager/selenium 14 [09:29:05] I/update - chromedriver: unzipping chromedriver_2.37.zip 15 [09:29:05] I/update - chromedriver: setting permissions to 0755 for /Users/edvinsantonovs/Documents/repos/recipe-book/node_modules/webdriver-manager/selenium/chromedriver_2.37 16 [09:29:05] I/launcher - Running 1 instances of WebDriver 17 [09:29:05] I/direct - Using ChromeDriver directly... 18 Jasmine started 19 20 recipe-book App 21 ✓ should display welcome message 22 23 Executed 1 of 1 spec SUCCESS in 0.685 sec.

In this case, the browser pops up, executes the application and dismiss once again after a short moment.

ng lint

When you start a new project with ng new , Angular CLI automatically generates a tslint.json with the set of rules of best practices for Angular. You can change them to suit your needs.

1 { 2 "rulesDirectory": [ 3 "node_modules/codelyzer" 4 ], 5 "rules": { 6 "arrow-return-shorthand": true, 7 "callable-types": true, 8 "class-name": true, 9 "comment-format": [ 10 true, 11 "check-space" 12 ], 13 "curly": true, 14 "deprecation": { 15 "severity": "warn" 16 }, 17 "eofline": true, 18 "forin": true, 19 "import-blacklist": [ 20 true, 21 "rxjs", 22 "rxjs/Rx" 23 ], 24 "import-spacing": true, 25 "indent": [ 26 true, 27 "spaces" 28 ], 29 ... 30 } 31 }

To check if your project has any linting problems, just run ng lint in the terminal.

In the majority of the cases, you will either see that all files successfully passed linting 1 $ ng lint 2 3 All files pass linting. or you will have a list of the files with lint error and description 1 $ ng lint 2 3 ERROR: ../recipe-book/src/app/app.module.ts[1, 31]: " should be ' 4 ERROR: ../recipe-book/src/app/app.module.ts[2, 26]: " should be ' 5 ERROR: ../recipe-book/src/app/app.module.ts[4, 30]: " should be ' 6 ERROR: ../recipe-book/src/app/app.module.ts[5, 34]: " should be ' 7 8 Lint errors found in the listed files.

ng build

Last but not the least command of the Angular CLI — ng build .

The ng build command compiles the application into an output directory.

1 $ ng build 2 Date: 2018-04-13T09:25:33.673Z l Hash: d08ebffadf328ed32e55 3 Time: 7260ms 4 chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered] 5 chunk {main} main.bundle.js, main.bundle.js.map (main) 10.3 kB [initial] [rendered] 6 chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 203 kB [initial] [rendered] 7 chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 11.4 kB [initial] [rendered] 8 chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.44 MB [initial] [rendered]

When the building is finished, you can find your application in the /dist directory.

1 dist 2 ├── favicon.ico 3 ├── index.html 4 ├── inline.bundle.js 5 ├── inline.bundle.js.map 6 ├── main.bundle.js 7 ├── main.bundle.js.map 8 ├── polyfills.bundle.js 9 ├── polyfills.bundle.js.map 10 ├── styles.bundle.js 11 ├── styles.bundle.js.map 12 ├── vendor.bundle.js 13 └── vendor.bundle.js.map

We just built our project, and you already can see the difference between the build and source code. The built project which is located in /dist looks tiny compared to the source code. That's great isn't it, but hold on there is one more trick!

By default, the development build target and environment are used.

Luckily enough, ng build offers us an option to specify build target( --target=production or --target=development ) and environment file to be used with that build( --environment=dev or --environment=prod ). Let's run production build by typing ng build --prod in a terminal. Whoa! It made our /dist folder even smaller with only a few files are left there.

1 dist 2 ├── 3rdpartylicenses.txt 3 ├── favicon.ico 4 ├── index.html 5 ├── inline.ba64e9064e468420379a.bundle.js 6 ├── main.e41bc4358dddb8b53359.bundle.js 7 ├── polyfills.46af3f84a403e219371b.bundle.js 8 └── styles.9c0ad738f18adc3d19ed.bundle.css

You might notice, several things:

There are no more *.map generated files.

generated files. There are hashes in generated file names.

Hashes in the file names are used as a part of the cache-busting technique. Every time we do the changes to our application, we need to redeploy the application to the server. In order to prevent our files to be cached on the server we add hashes to the file names. On every run of ng build --prod command, compiler randomly changes the hashes, so the server would treat the changed files as new ones.

Tips

Here is a list of tips I came across which might simplify your work with Angular CLI.