What do you want to learn?
Skip to main content
by John Papa
Learn how to create, generate, lint, debug, test, build, and serve high quality apps that follow the Angular Style Guide using the Angular CLI.
Resume CourseBookmarkAdd to Channel
Table of contents
(Music) It can be challenging to create modern web applications that follow best practices and that are optimized for development. The Angular CLI takes care of these efficiently and effectively. Hi, I'm John Papa. Welcome to my course on the Angular CLI here on Pluralsight. I'm a web architect, Angular developer expert, and the author of the official Angular Style Guide. I'm very excited to share this course with you. The course gently introduces how to install the CLI, and then how to use it to create apps, generate new features, lint, test, and build apps. By the end of this course, you'll have learned how to build Angular applications faster and with great consistency. Before beginning this course, you should be familiar with Angular, but you don't have to be an expert by any means. If you'd like to get a primer on Angular, you can check out my course, Angular First Look, here on Pluralsight. Please join me on this journey to learn the Angular CLI. We hope you enjoy it.
Coding is fun, but creating applications that consistently follow best practices, are test hardened, and are optimized for deployment can be challenging. The Angular CLI takes care of these so we can focus on our code. Hi, I'm John Papa. Welcome to my course on the Angular CLI. What is the Angular CLI? Well, it's a command line interface that makes it easy to create an application that works and follows best practices right out of the box. In this course, we'll learn how to install the CLI, create an app, generate components and other Angular features, lint our code, compile an optimized build that we can deploy, and exercise our unit and end-to-end tests. We'll start by learning about the CLI, including what motivated its creation. Why did the Angular team create the CLI in the first place? What problems was it trying to solve and what are the benefits of using the CLI? And then, let's take it for a test drive and see how it works. Test driving the Angular CLI is a great way to get a feel for what it can do and how it can benefit us. Well, let's begin.
Let's kick things off by understanding why the CLI was created, what's the motivation behind it, and why should we use it. When it comes time to create a new application, there are just so many ways to create an app, and when we start looking out on the web to see how many different seed projects there are and generators, it just becomes overwhelming, not to mention how different they can all be. And are we following best practices? When consistency gets out of whack, maintainability becomes difficult too. We can use conventions and style guides, they certainly help, but how do they get enforced? How do we make sure that if we have a lot of different applications, that they're all following the same practices? How do we make sure that our applications are testable? How do we make sure that our applications are consistent and easy to maintain in following those best practices? Well let's dive a little bit deeper and we'll talk about what makes starting a new application difficult. Sometimes, just starting from a blank slate can be confounding. We look at the project and there's no folder structure, no files, no nothing yet, and a lot of that stuff can be boilerplate and it would be nice to have some of that out of the box, especially to help us organize the project structure. And how do we make sure our team of 1 to 2 to 10 to 100 people are following the style guide for Angular? Who's going to decide how to optimize our build? Will the build be the same across multiple projects? How do we make sure that our code across these projects is following our team conventions? And how do we make sure that all of our testing is set up for both unit and end-to-end tests? Notice so far, we're not even talk about writing the code, we're just talking about getting set up and establishing conventions and process. The key idea behind the Angular CLI is that when the tooling handles the process, developers like us can focus on the user's needs. This is where the Angular team had an idea. With the opportunity to reimagine Angular, they wanted to bake in a tool to help create projects that follow their style guide and make generating, building, and testing easy and efficient. It has to handle creating new projects and generating components, services, and other features. It has to be able to lint our code, to exercise unit tests and end-to-end tests. And creating a build is hard, so the Angular CLI has to be able to create an optimized build that we can deploy and performs well. That's the motivation and the mission of the Angular CLI team. Next, let's take a look at what's inside the CLI.
Sneak Peek Inside the Angular CLI
Let's take a quick look at just what the Angular team created with the Angular CLI. First, how do we get started with it? Well, we simply install it using npm. Once we have it, then we can use it to generate new applications. And once we have an app, all those different things that we wanted to do with it, like generate code, lint it, build it, serve it, test it, we can do all of these with the Angular CLI. And there's even a bunch of shortcuts that we can run. For example, we can type out ng build to build the application or just ng b as a shortcut. It's time to take this for a test drive and just see what the Angular CLI can do for us. So hop on in.
Test Driving the Angular CLI
Let's begin by taking it for a test drive. And we'll start out by installing the Angular CLI globally using npm install. Next, we'll use ng new to create a new application, and I'll call it my-dream-app. This will generate all the files and the project structure, and then run npm install to get all the packages that we'll need. Now that we have our application, we'll go into our folder and then we'll run ng serve. This will start our application running on port 4200 by default. This will build the application. Then we can go to a browser and browse the localhost:4200, and there's our application. But what else can we do? Well let's say we wanted to learn more on the documentation about components. We'd type ng doc and then the keyword, and this will launch up the Angular documentation and go and search for a component. When we need just a little bit of help remembering some of the commands we can type ng --help, and it will show us all the different commands for the different features. And if you want to learn more about the ng serve commands, we could just type ng serve, then help. But back to our code. What if we want to lint our code to make sure that it checks out okay? We can run ng lint. Want to run our unit test? Okay, let's just run ng test. And out of the box it'll build our application, and then it will exercise all of our unit tests and make sure they all pass. And by default, it'll set a file watcher on so it can detect any changes. What about end-to-end tests? Out of the box we get one of those too, and we can run ng e2e. Now this'll build our application again, and now it's going to actually launch a browser and serve the application so it can exercise our end-to-end tests. And if everything works, we're okay. And then when it comes time to deploy our application we can type ng build, and this will build our application and then put it in an output folder called dist by default. We can then take those files and deploy them to Azure or some other cloud service. We just saw how to create the beginning of an application, but what about an application that we've been working on for a while? Let's go take a look at a larger application. Now this app has a lot more files in it, and this time I'm going to serve it, but I'm going to tell it to serve using the production mode. Now this application's got routing inside of it, and it's got lazy loading built into it. So there's a lot of things going on with this application, and we want to make sure that it does the right things and that it serves it up in an optimized way. So once this builds and then it launches it in the browser, we can take a look at the different network traffic to see what does it do with those lazy loaded bundles. Now that it's served, we'll open up the browser and we'll look at the developer tools and network traffic, Let's clear out that traffic and let's go to a different section called Sessions and this should be lazy loaded. Notice we get a different bundle that came across the wire. That's exactly what we want. We don't even have to think about how to separate bundles with lazy loading because the Angular CLI does it for us. And if you want to take this application for a test drive, feel free. Just browse to github/johnpapa/angular-event-view-cli right here in the address bar.
We just experienced how easy and powerful the Angular CLI can be. We can simply generate a new application, go into the directory and serve our application with just a few commands. In this course, we're going to dive a lot deeper into all these different commands and how we can customize and use the CLI. Some of the topics that we'll be covering throughout this course are how to install the CLI, how to create a new application, how to generate components, services, and modules from blueprints. We'll take a closer look at how we can lint our code, and even perform some automatic fixing. We'll explore how to build and optimize the application and how we can unit and end-to-end test our app. By the end of this course you'll see how by using the Angular CLI we can become much more efficient with Angular.
Angular CLI Setup and Verification
Getting Started with the Angular CLI
In this module, we're going to learn how to set up the Angular CLI and how to make sure it all works right by verifying the installation. We'll start by making sure we have the right requirements that the CLI needs, things like the version of Node. Then we'll learn how to find the CLI and install it on our local machines. And then we'll learn how to verify that everything got installed properly. And we'll give it a quick test run to make sure everything's okay. Finally, we'll wrap up by looking at some really important resources that we're going to need while using the CLI. Well, let's get started.
Angular CLI Requirements
As we begin, we want to make sure that we have the proper requirements for the Angular CLI, and that begins by checking the version of Node. So, we'll type node -v at the command line, and you might see something like this: 8.11.1. Well, the Angular CLI currently supports any version of Node 8 or higher. We can also check the version of our package manager for Node, npm, by typing npm -v. I have 6.2.0. Any version of npm 5 or higher is currently supported by the Angular CLI. If you're wondering what the latest requirements are, the best thing to do is go check out the Angular.io website right here at this URL to check out the most up-to-date requirements.
Installing and Verifying the Angular CLI
Next, we're going to install the CLI itself. And to do that, we'll do it from a command prompt, and we're going to type npm install -g, for global, @angular/cli. This will install the CLI globally on our machine, which is want we want. The command is going to run up to the cloud, to the npm package manager, and pull down the Angular CLI and all of its dependencies locally. Now depending upon your connectivity at the time, it might take a moment or it might take a few minutes. Don't worry, we'll walk through it together in just a moment. After a successful installation, we'll want to run this command: ng -v. Ng is the Angular command line interface tool itself, and -v is the version of it. By doing this, we should see some kind of a response like this. Here's the Angular CLI using ASCII art, and then we'll see the version of the CLI, our version of Node, and our operating system. You can use this information to verify your operating system, Node, and all the Angular CLI versions. Now that we have an idea of how to install and verify the CLI is there, let's go walk through it together.
Angular CLI Installation
Let's begin. We'll open up a terminal or a command prompt, and the first thing we want to do is pull down the CLI. So we can type in npm install, or just npm i for short, which is what I like to do, we do -g for global, and then @angular/cli. So go ahead and type this along with me. Now when you hit Enter, it's going to go out and install everything that we need to use the Angular CLI. Now as you can see, it's running through the npm registry and it's doing a bunch of verifications, and then it's going to pull down the actual assets to your local machine. This could take anywhere from a few seconds to a few minutes based upon your connectivity to the internet, and the speed of your hard drive and computer, and how busy npm is at the time. As you can see here, I already had the Angular CLI in my machine, and it showed me at the end it updated the one package in 8 seconds. Once we have it all here, we can verify with another command. Now, let's go ahead and type in the command here for npm list. So we'll type npm list, -g, because we want to list the global packages, and we want to name this one angular/cli. So we're going to say list out any global packages that match this name. Now we're also going to give it one more flag: --depth=0. Without this flag we'd see all the dependencies there, but we just want to see just the Angular CLI. So we'll hit Enter here. Once we run that, it's going to look locally on our machine to say, do I have this thing called the Angular CLI, and it's going to use npm to verify this. Now as we can see, it did install properly. So now that once we have it, and npm has verified that, we want to make sure that we run the ng -v command that we saw previously. So ng -v, this is the actual Angular CLI, and -v means version, this is the command to say do we have the Angular CLI running? Notice the versions match when I ran npm list and right here when I ran ng -v. And that's all we need to do to install the CLI on our machines.
Generating and Exploring a New App
Now that we have the CLI, let's make sure that we can generate an application. Inside the terminal, let's go to a folder that we can create an app in. I have a folder called play on my machine. You can put it anywhere you'd like. While we haven't learned all the Angular CLI commands yet, we're going to skip ahead for just a moment just to make sure we can create an application, and we're going to run ng, for the CLI, the command new, to create a new app, and we're going to call it ngtest, just like that. And then I'm going to give it a flag of --skip-install. Make sure you get all the dashes in there. This flag is going to tell the CLI not to run out to npm install everything to your local machine. It will give us the quickest and fastest installation of a new app. So we can run that and you can see how quickly all the files get created. Now you can see the actual files created right here in this list. Let's go into that folder. We'll do cd ngtest, and then we can list out the files with the ls command, or dir for Windows, or we can open up our favorite editor. You can use any editor you like. I'm going to open up in Visual Studio Code because I happen to love that, and I have a shortcut on my machine called c where I open up in VS Code in the current folder. Once we have that, we can see over here on the left-hand side all the files. We'll get rid of that welcome message here. I'll use the Command+plus twice to make it a little bit bigger so we can look at it. Now you can see there's a bunch of files in the root. Here we have the Angular CLI's configuration file. That's the JSON file right there. We'll look more at this file in depth a little bit later in this course. Then there's an .editorconfig, so we can set up our spacing right here, like indent_size of 2. Anything you happen to like you can put in there. And then there's a .gitignore file, so it's ready for Git. And all this stuff is ready out of the box for us. And then we have the package.json file, which shows us all the information about the dependencies and the scripts for our application. Then rounding things out down here, we have a README file, pretty standard for open source; we have a TypeScript configuration file, which is all set up and ready to go for Angular; and a tslint file to help lint our TypeScript. Now let's go inside of the src folder. In here there's a couple of files we really want to pay attention to. First, we have an index.html. This is going to be the basic file that we browse to or that we serve up. And then we have a main.ts file. This is the file that kicks off all of Angular. If we go inside the app folder, we can see we've got some components and some modules, and we're going to learn a whole lot more about what all these files do and how the files get generated, but I recommend this is a great starting point just to make sure that you can actually generate an app. Notice there's no node_modules folder yet. That's because we didn't run the npm install command. If we go back to the package.json file down here, we can see all these dependencies for angular/animations, and so on. And those versions of those packages will change based upon the version of Angular that you're using. If you want to run the npm install after the fact, we can go back to Terminal and we could type in npm install, or just simply npm i for short, either way, i is just an alias of install, and then it will actually install all those packages for us. Now we're not going to run npm install right now. We'll do that a little bit later. And now we've proved out that the CLI is installed and ready to roll.
Angular Extensions for VS Code
Having the right tools makes a world of difference when you're working with any programming language or framework or tools. That's no different here with VS Code and the Angular CLI. We're going to go ahead and install an extension for VS Code by clicking on this square over here on the left, and then we're going to type in angular essentials up in this text box. Now you notice that I'm the author of this extension. It's actually an extension pack. If we click on it, over here on the right we can see at the bottom, it shows us what's installed with it: Angular Snippets that will basically allow you to create code by typing a couple characters, we don't have to remember any pesky syntax then, and the most important extension that it includes is the Angular Language Service. This basically makes VS Code light up with Angular. It really makes it a lot easier and I definitely recommend this. I would not code Angular without it. Then there's a couple others in here, which I've included for helping out the Editor Config or tslint or debugging. And then at the bottom there's an Icon Theme, we'll take a look what that does, and Node npm, we'll take a look at that one as well. But first, let's install these, and you'll notice that it'll start saying Install, and when each one's ready it will say Reload. When the whole thing's ready you'll click Angular Essentials says Reload. It will then reload VS Code. I'll click back up here on the upper left-hand icon called Explorer. The first thing we'll notice is the icons next to the files. Notice that the README has an i inside of a blue circle. We have the Node.js symbol next to the package.json, and then a red Angular shield for angular.json. Opening up the src file, we can now see the different symbols next to those files as well. Then inside of app, we get different icons for modules, components, specs or tests, HTML, and CSS. That's coming from that icon theme in the extension pack. Another nice thing in here, if we go down to the package.json, you'll notice that all of these are green. It's because we're getting warnings that none of these things are installed yet. Well, if we click in there, the npm Node extension that we installed will now show us a little light bulb, and we can Show Fixes. We can install just animations or run npm install for everything, which we can do manually in the next section, but it's nice now that we can do this right from VS Code without having thing to go to the terminal if we don't want to. This is just the tip of the iceberg in what's inside of all these extensions. We'll check out these and many, many more tips in the upcoming sections.
Angular CLI Resources
We just learned how to generate an application, skipping the npm install by running this command right here, and it does a super-fast installation of the Angular app, just so we can explore what we get. And once we get that code, we can open up it in our favorite editor like Sublime or Atom, WebStorm or Visual Studio Code. In this module, we learned how to run node -v and npm -v to verify that we meet the Node requirements of the Angular CLI. And then we learned how to install the Angular CLI with npm and verify that everything is in working order by doing ng -v. And then together we created a quick application, skipping the npm install to verify that the CLI gives us a project. I used VS Code as my editor and the Angular Essentials Extension Pack. Now these are optional, but I highly recommend them. You can feel free to grab them from here at these links if you like. Finally, I really encourage that you look at these main Angular CLI websites. First, there's the main CLI website, and then there's the docs at Angular.io, and then the GitHub repository for the Angular CLI. Now that we've learned how to install the CLI and make sure it's in good working order, we're going to spend the rest of the course generating applications, building them, learning how to test them, and using all the different features of the CLI to build Angular applications. Let's go.
Generating a New Angular Application
Very likely, the first thing most of us will do with the Angular CLI is to create a new application. In this module, we'll learn how to do that, because that's what the CLI is all about, it's for building applications, and the first step is to generate one. So in this module, we'll talk about how we generate an application and the different options that we can do right out of the gate. And then we'll get into learning about all of the little flags that we can add onto the Angular CLI when we're generating the application and the effect that they have. Then we'll learn how we can configure the CLI based upon our own preferences, and some of these things will work right on the generation of the application. For example, maybe we want our apps to all use Sass instead of CSS. And there's some nice features in the CLI that we can use that will help us check our code, which is called linting. And not only can we lint them, but we can also fix the code automatically if we want to. And by the end of this module, we'll see how easy it is and how fast we can generate applications with Angular.
Commands for Generating a New App
Well let's take the CLI for a spin by generating a new application. First, we'll learn the commands. Ng is the CLI itself, new is the action that we're going to take, create a new application, and then we give it the name. By doing this we'll generate an application called my-app, and it'll put it in the folder called my-app by default. Don't forget to cd into that folder after you generate it. Another option is this --dry-run flag. So, the --dry-run flag is really cool because this'll tell it to go ahead and tell you and report out all the files that it's going to create, but not actually create them. This is nicer when you're learning about setting some of the flags to say okay, what am I actually going to generate if I set these flags before I actually write them out? And then another option is to --skip-install. So, --skip-install means don't actually run the npm install. Because that's the longest part of generating any application, it's not writing the files, it's actually pulling down all the supporting files and dependencies. Obviously if you're going to run --skip-install, you'll have to run npm install later at a later point. But sometimes when you just want to see what files are going to be written out and look at the structure, --skip-install is super nice. As a side note, when you run --dry-run, it also skips the install, obviously, because it's not actually writing any files. And when we're running these, sometimes it helps to know what are all those other flags that we can get to. So we can run ng new --help. So the --help flag will report out all the different options, tell us the defaults, and tell us what those different flags do, such as the --dry-run or the --skip-install. Well now that we know how we can get started, let's go do this together.
Generating and Customizing a New App
Let's start by going into our folder called play, and we'll create a new project in here called my-app. So we'll say ng new my-app, like this. And first we're going to run it with the --dry-run flag. Now, how did you know what the --dry-run flag is? Well, we learned that earlier by showing --dry-run. And here we can see all the different files that it would create for us. Now, here's all the files that we're going to go look through in just a moment, but notice at the bottom it says run with "dry run", so no changes were made, which is super awesome because we get to look at what we're doing before we create it. Now, how would we know where those flags are and what they are for us? Let's go ahead and look at a different command we can run, --help. Now running --help you'll see all the latest commands that are supported. First thing you'll notice is one up here called --dryRun with a capital R. Actually, both of these will work. The one that we use, --dry-run, and the one with the capital R there. But the one with the dashes is more consistent. I also like to use just -d. Notice that a lot of these flags have a single letter that you can use to run them. And when you use the single letter, those shortcuts, or aliases, generally are applied to anything that's got a long name for a flag, and they use a single dash for the alias and double-dash for the full name. So we could run the same command up here that we did before, --dry-run, like this, or we could run the command like that. Notice again we'll get to look at the files. And this again is super helpful to be able to look at what's going to be output. Here we can see at the very top, we've got a README, our angular.json file, our package.json, and all the basic stuff that the Angular app needs to run out of the box. Now that we know that's the name of the project that we want to create called my-app, we can run it with --skip-install, that's another flag. What this is going to do, it's going to create the project, but it's not going to go out and run npm install. Why would you want to do this? Well sometimes I do this if I'm offline somewhere and I know I can't connect to the internet, and I don't want it to just sit there trying to install when I know it's not going to be able to, or if I really need to get started super quick, and then later on I'll run npm install. So right now, notice that took just no time at all, created our project. And then, we can cd into the folder, and we can open this up in our favorite code editor. For me, I'm going to use Visual Studio Code, and we can see the project here. We'll get rid of the Welcome screen, and we can see what's in our project. One of the first places I like to look is the package.json. Here's where you see the script files. Notice we can run some npm scripts, like ng, or we can run start, or build, or test. For example if we run npm start, it's going to run ng serve under the covers. And you can change these to customize any way you like. And then we have our dependencies. Notice that right away now we're using Angular with version 6.0.3. And two things should stand out to you. First is the version number and strategy, and the second one is that I've got a bunch of green underlines over here. The green underlines are coming from this npm extension that we installed. That's because we ran ng new with the --skip-install flag, so once we run npm install these should not be green anymore. And again, just to show how the extension works, you can go over and click on the light bulb and let it run npm install if you want to. On everything. This one will just install the animations, this one will install all the modules. The second thing here we talked about was the version and strategy. It's saying go get Angular 6.0.3. That's 6 is the major version, 0 is the minor, and 3 is the patch. And the caret means that we're always going to match up to version 6, but we can get new minors and new patches. And that just follows the semver standard. Notice that all the Angular libraries and dependencies match the same version, and then down in the devDependencies, we can see that there's a couple Angular devDependencies and TypeScript and some other things in here as well.
Angular CLI JSON File
Alright, now that we've looked at the package.json, let's go ahead and look at the angular.json file. This file is the key to how the Angular CLI works in our projects. It's where all our settings are stored. So let's kind of browse through here. First up top, we can see a couple of the configurations. There's a project in here called my-app. Now, the reason there's projects, because you could have multiple projects inside of one master, effectively, workspace inside of the Angular project itself. Right now we only have one project, though. So we have my-app, that's what we named it when we did the ng new. And the root of our project is right where we are. The sourceRoot is src, we can see that matches the src folder up here in the left. The projectType is an application, it might be building libraries or other things as well. The prefix for our app is app. Now that's the default. So, this is kind of important, I want to key in here for a moment. The prefix of app, we can change this if we want to, but what does it affect? If we go inside the app folder, we can look at a component like app.component, and notice that the selector for the app component is app-root. This is the prefix right here. Now we want a prefix because we want to make sure we don't name our component something that could have a name conflict later. For example, if we named our component something like div, probably not a great idea, that's actually the same name as an HTML tag. So we don't want to do that. So, by having app in here, we could actually name it app-div if we really wanted to, but by having a prefix, it allows us to separate the naming conventions. Also, the prefix should be something that you can recognize. So for example, maybe you're doing a sales application, you could do sales, or s, as a prefix. If you work at a large company, maybe you call it acme. So if you want to do that, you could go through your project and change all the prefixes like this, but when you generate the project, it's easier to do so if you use that --prefix flag, and we'll show that in a moment. So, we can manually change it here in this file and in every component, and then we generate new ones that'll use that, but there's a better way, as I said. So we'll put this back to app for now, and let's continue taking a quick look down at what else we get. Inside the build here, inside of architect, you can see a bunch of commands. One of the options is when I build, where do I put the code? It's going to go into a dist/my-app folder. We can see where our index file and our main files are designated, because you can change those names if you'd like to, where the polyfills are, these are the different polyfills for working in different browsers that we can configure. Our TypeScript configuration. Something I do end up changing quite a bit are the assets, right here, and the styles. So, assets is basically anything that you're going to be just copying and putting into the build folder when you're done. Into, in this case, the dist/my-app. These are things like your images, your fonts, or icons like here. The second one on line 23 says get everything that's inside the src/assets folder and just pull that over, that way you don't have to list all the files. And then if you have multiple different style CSS or SCSS for Sass files, or LESS files, you can list those here in the styles setting. You can scroll through here to see a bunch of different options that get set for us. Now, let's go back and pay attention to that prefix for a moment. Let's say we wanted to generate new components and have them use that prefix. Let's actually close Visual Studio Code here, we'll go back to our main folder, and we're going to back out into the play folder. We're going to generate a bunch of new projects here in this section. We're going to call this one my-app2, and for this one we're going to set the prefix equal to acme, just to show how this would work. Now, we'll still keep the --skip-install on there just so we can make a super-fast install, and that's --skip-install. So once we generate this, we'll cd into the new folder, into my-app2, we'll open up code, and we'll go look at two specific things here. First what we're going to look at is the angular.json file, right there. Notice the prefix on line 10 is now acme. And, we can go over and navigate into the app folder to look at the app.component, and notice the selector on line 4 is now also acme. Now what else do we get in here? Notice we get for every component, we're getting a .spec file. This is for our unit testing. Now if we like .spec files and we want it for testing our project, we can add all these in here pretty easily. But what if we wanted to omit the tests? Well we have a bunch of different options here. So let's back out of my-app2, and we'll run that same command that we just ran. Instead of my-app2, we'll call it my-app3, and this time we're going to put in a --skip-tests, like that. Now we generate this one. We'll see what it generates right here. Notice it put all our files down, and we can see, if we look through here, where the app.component is. Notice there's an app.component.ts, .html, and .css, but there's no test there. Let's go back into VS Code and we'll see what that looks like. So let's cd into the my-app3 folder, we'll open up VS Code, and then we can go back and look at the src files in the app, we don't see any spec files in this case. So how do you know what these different flags are? That's a great question. We did ng --help earlier, but let's look at ng new --help here. We have run a few of these commands already. For example, we did the --dry-run, and we just saw the prefix. And notice we have aliases for --prefix of -p, and for --dry-run, -d. Some of these other ones are quite interesting though. For example, if you wanted your components to also include the styles and the html template, we could use inline styles and inline templates, and we could set that as the default for our project by using these flags. If we want to skip setting up git, we do --skip-git. We saw the --skip-install and --skip-tests here as well. If we want to specify Sass, we can do that with the --style flag. There's a bunch of different things that we can set up right out of the get-go for our application. For example, I happen to like Sass, so let's back out of this folder and let's create a new project. We'll call this one my-app4, and we'll use the same flags we had earlier, and we'll add on the --style flag at the end, and we'll set this to scss. We'll generate that, we'll cd into my-app4, we'll open that up in code, and now if we go look at our components, we should see we've got a Sass file there, .scss. And our app.component is referencing that here in the styleUrls. Probably more importantly, if we go look at the angular.json file, we can see that we have a new thing up here called the style extension of scss in our schematics. So for app4, it's saying default all of our style extensions to be scss. And if we search through this file for that, you'll see that now it's referencing styles.scss inside the styles section, and that it's also doing the same thing when it compiles our test because of the configuration for that as well. And because it's using Sass in this case, when the Angular project builds it automatically knows to use the Sass compiler to build that in to generate our CSS for us. Alright, and one of my last settings that I really want to look at here, we'll go back to the ng help to look at this, is the --routing flag. The --routing flag helps us generate a routing module. Now if you've built any Angular projects, and you haven't used the CLI, you know that to set up routing there's a couple things you have to do. If you're not familiar with that, go check out my course, Angular First Look, and you can learn more about how routing works. But let's say you wanted to set routing up out of the box. Well, let's create a new project like that. We'll back out to our play folder, and this time we'll use the same command we've been using, and I'll change this to my-app5, and let's add in a new flag. And something that you may notice as well is it doesn't matter the order that these flags appear in in this case. So I'm using the same flags, but I'm adding routing. And let's generate this project once again. Now when we look through here, we're going to see something a little bit different. Down here on this line, you can see there's an app-routing.module. Well, let's go inside of VS Code where it's a little easier to see that. And now, I can open up the src folder under app, and you're going to see the new file up here. This is our app-routing.module, and this file sets up routing for us and it gives us a place to add the routing paths up here, and it imports the right modules, and everything just kind of works out of the box. And if you look at the app.module itself, notice it's importing AppRoutingModule here, and then again on line 13. Well, we just created a bunch of different projects, and really just to demonstrate how these different flags worked. Now, what if you wanted to combine some of these again? Let's go back and look at that command we just ran. That's a lot of different things to run and remember, right? Well, what if we don't want to do that. We've got --routing, --skip-tests, --prefix, --skip-install, and we've got --styles in there. Let's back out of this folder, and let's look at the command that we just ran. We have routing and skip-tests and prefix and acme, just a bunch of different settings. What if we didn't want to set all those up? Well, one way we can do this is by combining flags. So let's go open up a new tab real quick and we'll look at the ng --help on ng new. And here we can see a bunch of flags we've got. Now, notice we have aliases here like -d for --dryRun, and we've got --skip-tests is capital S, and it is case-sensitive here. We want to add inline styles and templates, you do lowercase s and t. So we could say something like ng new my-app6, and we'll add a few of these together. So, first we use a single dash to use the shortened aliases. We use s and t. And if you don't remember what those are, we can look over here. S is going to be inline styles, and inline templates is t. We'll add in the dry-run here just so we can try this out. I'd like to put that one first. The order is not important, though. Skip-test, let's do that too with a capital S. And now for style and for routing, we don't have an alias that's shortened, so we have to spell those out. So we'll do --routing like this, and then we'll also do --style. Now also with style, we want to make sure we can specify the value, so that would be kind of hard to do inline, but now we can do it right here. So it's a much shorter syntax, and let's see what happens. Now, notice it says Run with "dry run" no changes were made at the bottom. Down here we can see the app-routing.modules created, and notice there's only a single app.component file. Now let's take a look what happens if we remove the --dry-run flag, and we'll just put on --skip install for a moment, just because we want this to happen super fast. And we can see the files that got generated, such as the routing.module down here. But let's go into VS Code, it's much easier to see this. Now, if we open up the src folder and the app folder, notice there is just one app.component file. That's because the template is now embedded in the line up here, so we can see that on this line, and then you can all see the styles would be embedded right there. There's also no spec file. That's because we omitted that with the flag. And do we have our routing file? Yep, we absolutely do. So this is just a shortened way with the syntax here to use the aliases. And again, we can look at those by running ng new --help. So as you can see, there's various ways that we can use the ng new command to generate projects based upon our personal preferences, and then set it up so that all future things we generate in the project follow those conventions. And all of this is stored inside the angular.json file.
Common App Generation Flags
We just saw we can generate a new application by using some of the different flags like --style scss. We can set that to be scss, less, or css. We support all the major options here. And we also saw some other flags like the prefix where we can change the prefix for our components or our directives. And then there was --skip-git, which will initialize to the Git project, and we also did --skip-tests to remove the specs from the project when we generate our files. And one of my favorites is to add --routing to the project right from the get-go. So right from the start we'll add the routing modules and the other features and do the routing support right in the project. Obviously we can combine all these flags together, and it's quite common to do so. So in a single command with ng new, we can put all the flags together right at the app generation time. A lot of these flags are actually stored afterwards inside of the configuration file, angular.json. So how do I like to roll? Well, my biggest tip for you would be when you're generating one, to set up the things that you want to use most often. So when I run ng new, I of course specify the name of the application, and I like to add routing, that's pretty common. And I'll set my prefix up, and I don't choose ma as my prefix, obviously. I like to choose something relevant for my project, like if it's a sales app I use sales, or something short like that. And then I define my style scheme. Maybe I'll use Sass or CSS. And then I like to also start with the --dry-run flag. That's really important because I want to make sure before I generate the code that I'm getting what I want first. So --dry-run lets you preview what you're getting, it's a dry run, or practice. And then once I'm ready, I remove that --dry-run flag so it can actually generate the application. Now let's go generate an app using our custom settings and see if it serves up with the Angular CLI. Back inside of Terminal, we'll go back to the play folder and we'll run a new command for ng new my-app7. Yep, we're up to 7 now. And let's run this with some of the common features we'll want. Like I want routing to be there out of the box, so I'm going to add --routing. I want to use a prefix in here as well, I'll set mine up to be jp for my initials. Obviously we'll choose a more appropriate one for whatever project we'd normally create. And then I want to set up styles to be Sass, so I'd do that here. Now, because I want to make sure I'm getting what I'm asking for, I'm going to put the --dry-run flag at the end here. So first I'm going to run through that, I see it created a folder called my-app7. I can see that I've also got Sass files right here, scss, and I've got my routing.module. Great. So now, let's run that same command without the -d at the end, and I'm not going to run --skip-install here because I want it to go ahead and run npm install for me, which is what it's doing there at the bottom. It's running out to the internet, it's going to install all the dependencies for my project, and at the end we should have a node_modules folder. Now we can see that it's installed everything, and if I cd into my-app7, if we do an ls there we can see the node_modules folder exists down here. But let's open this up inside of VS Code and take a look at what we have. Alright, so over here we've got a node_modules folder, and then we've got our src. If we look inside the app, we've got our routing.module, that's great, we're using Sass right here, so everything's ready to go. Now, how do we make sure this actually runs and can serve? Well, there's a couple ways we can do this. If we remember back in the package.json file, to serve it's ng serve. We'll learn more about this command later, but we're going to do a little sneak peek ahead for now just to make sure things are working right. We could run npm start or ng serve. Now we can do that right from Terminal over here. We could say npm start, or we could just do ng serve, like this. But before we run it, let's run it with the --help command, just to see what's happening, because we haven't learned much about this one yet. Now in all these flags, there's a bunch of them, the one I always like to run is --open, or -o, because it will not only build the code and serve it in a browser, but it'll actually open the browser for you. So let's run ng serve -o for the shortcut. So now Angular behind the scenes is building our project, it's putting these together for us, it's going to then serve it in memory, and then open that in the browser on localhost:4200. Notice there's a couple things on this page like Welcome to jp!, an image, and some links to help you get going. Let's put this over on the right-hand side, and I'm going to put VS Code on the left. And then we're going to go into the file that generates this code. We're going to open up app.component.html to see what HTML is put out on the page. Notice there's a lot of it here. What if we just wanted to say Welcome to jp! with the image? We'll delete all these useful links at the bottom of the page, and then we'll press Save, and it automatically rebuilds and serves it on the right-hand side. Well, that's pretty cool. We can even get rid of the image if we want to. We can make any changes we like, and then if we go over to the app.component.ts, the title is jp, we can say Welcome to the Angular CLI Course!!, like that, and it'll also rebuild the TypeScript for us and then display it inside the browser. So we generated a new application, we then served it up, opened it in the browser, and as soon as we make changes to our files and save them, it's already building in memory and launches over here on the right-hand side inside of the browser. And, eureka, it all just works.
Configuring the Angular CLI
We've learned how we can configure and customize things with the CLI. There's a couple ways to do that. During the ng new process, we could add some flags there like we did in the examples, such as --style. Or we could go manually and edit the angular.json file, which is actually pretty cool in some editors because the schema is associated with it, so you get some IntelliSense and autocomplete. But there's another way too. We can do ng config, and then we can set the properties and the values inside the JSON file, right from our command line. Let's take a look at that. Here's an example of what might be inside of a CLI file, inside of angular.json. Here we can set the default like we did with ng new with style scss. Notice we have the project name right there is ngtest, and down here we can see that we're telling it to use the style extension of scss, which is for Sass. Now we'd have to know where to find these inside the file, so maybe there's an easier way. And you'd be right. Well we saw that we could set the Angular CLI's configuration inside that Angular.json file manually. But we can also use the command from this command line called ng config. Here we indicate the JSON path inside of the file, and then set the value for it. We can also set it for a global file, for angular.json, for a machine. Now what's the difference here? The global file is one that exists for your entire machine, and all products on your machine will then use those same defaults, so you don't have to continually set this up for every project, which is kind of cool. For example, if you like to use Sass all the time, you can set ng config with the scss setting, and set it to your global file on your machine. Or, you can leave the -g off and do it just for your project that you're working on. So what does this look like? We could set that Sass setting here by saying ng config, and then we go into schematics, because that's where it is inside of the JSON file, and how will we know this? We can go back and look at that JSON file to see where those are located. And then the property called schematics/angular. And then we're going to tell it we want component's style extension to be scss. And that's all we'd have to do there. And if you want to see some of the other options on ng config and how you can set them, remember you can always do ng config --help. The key to remember here is anytime you start manually setting these changes for a project, you might want to go back inside the CLI's file, angular.json, look at where it is in that schema, and then maybe run the ng config command in the future to make that easier to actually set it up.
The CLI comes with built-in linting as well, which helps us check and make sure our code is okay. We can simply run ng lint, and that will run across the project and make sure the TypeScript code is good to go. Now if you want to look at some of the options there, you can do ng lint, project name, --help, and this will show you all the different options for ng linting. That's super helpful because it shows us some cool things that we can do. Like, I like to run ng lint with the format of stylish. It'll actually color code the output so it makes it easier for me to read. Then we could also do ng lint with the project name with --fix, and this will correct any automatically fixable problems. So those are kind of cool things that we can do. Now, before I run the ng lint with our project name with --fix, I'd like to make sure that I've committed all my changes, or at least stashed them with my Git commands, so then I can run the fix and see what those fixes actually changed and made changes to my files. It's a great way to learn about how things work. Alright, so now that we've learned about the ng lint command, let's go use it together in our project. Going back to my-app7, we've got the code on the left-hand side and Terminal on the right. You can run ng lint on my-app7, like this, we can do --help to see what commands we have. Here we can see several of the options that we can use, including doing the automatic fixes or formatting out the output. Now let's run ng lint here on this project, and we'll see if we have any errors. Now, there shouldn't be any errors because we just generated this and we haven't made any code changes, so it should pass everything. That's a good thing. But let's say we started writing some code up here. And we'll put in here, let's say, let num = 7 up top, and then down inside of here, let's create a new function. We'll call the function sayHello. And inside of that function, we'll set let, actually, let's do var x = 10. And one more change. At the very top up here, let's get rid of the semicolon at the end of line 1. Now, you notice I'm having red underlines inside of my editor because my editor is smart enough to read that I'm using TypeScript, and it shows me not only TypeScript errors, but also tslint errors. But let's come back over here to the editor and we can look at these now inside of Terminal. Now, the Terminal is showing me all the errors, and it's kind of hard to read. So let's run this command with a new option called --format stylish. And when we run this with the stylish format, we should see the errors a little more color-coded and easier to read out here. So we can see the same errors are there. Now, we could go back to our editor and let the editor fix these changes, but that does like a file at a time. What if I wanted to make these fixes all at once? Now I can run with --fix. So when I do that, it's going to run through the project and it's going to try to fix the code for us, and it should change over in the editor as well. So now notice the editor changed to use a const instead of let. And, down here it is also used a const in our file. So now the file should pass linting. And to verify, we could just run it again without the --fix just to see what's going on there. And after we ran it with --fix, it will just tell us there's nothing to fix in the file.
We just learned how we can generate new applications using the different flags with the CLI. It helps us customize the things that we need. And we learned how we could lean on the help system for different commands or for just ng --help to see all the help commands. I like to use the --dry-run flag because that helps us practice things before we actually write the files out. It also avoids the npm installs. And finally, we looked at how we could use the linting tools that are built in to both check and fix code automatically. So, what's next? We're going to learn how to create other files and add them to the project to extend it.
Generating Code from Blueprints
Angular CLI Code Generation
Once we have an application, it's really helpful to be able to generate components and modules and services, and all sorts of other features of Angular. We can do that by using blueprints. Blueprints are the concept that Angular uses to generate code, and there's a bunch of them that come out of the box. So in this chapter, we're going to learn about those blueprints that we use for the most common features, things like components, services or NgModules. There's also some basic TypeScript blueprints too because we'll be using things like just a generic class when we need to or an interface. Many of the blueprints also have several options. For example, we may want to use inline styles with a component, and that can be an option that we add on to it. We'll learn about what those options are and how to learn more of them. I'm a big fan of the aliases as well because I like to move fast when I'm generating code. So we'll learn about those for both options and for our blueprints. And like we did earlier for generating a project with ng new, we can also set up some very commonly used features in the project configuration, that angular-cli.json file. We'll learn about how we can set up our preferences for our team in that file. By the end of this module, we'll have everything we need to generate a whole bunch of Angular features using these blueprints.
Throughout this chapter, we're going to be using the command ng generate, and then the name of the blueprint. That's the key to using blueprints with the Angular CLI. So, what's a blueprint? It's exactly what it sounds like. We're going to generate code using these blueprints. The Angular CLI needs to know how we actually want to create these files. What features are there? What does the syntax look like? These are defined by our blueprints. So the blueprints define what those files are and we can indicate a name and some options with them, and the options will help us customize them a little bit to our liking. For example, when we do this, we use the generate command first, and that's the syntax here for ng generate, name of blueprint, such as component or service. And then some options, which are optional, obviously, and we can also use the --dry-run option to practice these. So we don't write them out to the hard disk. Here we're generating a new component by saying okay, ng generate component named customer. Or we can generate a service named customer-data, and that'll create a file called customer-data.service.ts, or we can create just a plain old TypeScript class. These are three of the basic blueprints that we can use and the files that they'll generate. Now that we've learned about the blueprints, let's go learn how we can use those with component generation.
Component Blueprints and Options
Quite often we'll be generating components, so let's dive into how we can use these blueprints at the Angular CLI to generate components. I love things that help me code faster, and one of those things in the CLI are aliases. So we can use the generate command to generate code from a blueprint like this, ng generate component customer. But we can also use g as an alias for generate. And then we can also use c as an alias for a shortcut for a component blueprint. So we can rewrite this by simply saying ng g c customer, and well, that's just a heck of a lot easier to type and faster to move along. Not everything has an alias, but let's take a look at some of the common ones. For example, some of the options that we can put on to these blueprints are things like --flat. So a --flat will decide if we want to put a component in a folder or not. By default, it does go into its own folder, so if you want to turn that off, you can say --flat true. We can also define that we don't want to have a separate external file for the template by indicating --inline-template. Now that's kind of long to type. So the alias is a single dash, not two, and just t. Likewise, we can also define the styles to be inline, or we can say just -s. You can see all those aliases are really helpful, especially when the options are much longer. Do we want to create a separate spec file for every TypeScript file that we create? If you want to, it's on by default. But if we want to turn them off so it doesn't generate a spec for every TypeScript file, we can just say --spec, and then false. If you want to take advantage of things like view encapsulation inside the component, we can turn that on or off with --view-encapsulation, and then set the strategy. Or we can just do -v. Similarly, we can use change detection to set that up in the component. Here we have a -c as an alias. So we can add on to the component and say -v, set the view encapsulation strategy to something like emulated, and then -c for the change detection strategy to on push. And I really like to practice, so I like the --dry-run flag, and you can just use an alias of -d for that. In that case, we're going to report the files out before we actually write them. And as you can see here, most of the longer options have an alias, which makes it a lot easier to type and move along faster. Now let's take a look at how these aliases can really help us. Here are the two common ways we can generate components. Here's one where it's just a pet component, and then the other where it's a pet component without the HTML or CSS separate files. So the first one we're going to generate the HTML, the spec, the CSS, or Sass, if we're using that, and components for our files inside of its own folder. The second one, we're only going to create the spec and the TS file because the HTML and CSS are going to be inside of the component inline. That's a lot to type though. Now let's take a look at how that would look with an alias. Ng g c pet. I don't know about you, but I kind of like that a lot better. It's much faster to type and I like being more efficient. But we can also do this. Ng g c pet -t -s. In that case, we're setting up the inline template and style with the aliases, and when we have multiple single character aliases like -t and -s, we can combine those. So here we can say ng g c pet -ts, so we're stacking them just like this. Now let's take a look at some commands that are very commonly used. Here we're going to create a new component called pet and we may not want it to be in its own folder, so in this case it's not going to create a pet folder and it's not going to stick the pet component in some separate folder called pet. Instead, it'll create the same files, just not in their own folder. That's the flat option. Or we could add --inline-template. We discussed this one earlier. That's where we don't put the template in its own file, and instead we put them inline in the TypeScript. Same kind of thing with the --inline-styles. Here, we're going to create the CSS in the TypeScript file, not a separate file for CSS. If we want a separate prefix for all of our components, we can set that up in a component by component basis here using --prefix to maybe my. And then we can also combine a lot of these by saying ng g c pet, we can combine and stack the inline style and template by using the aliases with -st, and then we just use --flat and --prefix my to combine those. Now that we've learned about how we can generate components, let's go ahead and do some of these hands on, and we'll learn about a bunch of the blueprints along the way. We'll go to a new folder and we'll type in
ng new angular-hello. This will generate a new project for us with all the basic defaults, and we're going to let it run npm install this time because we want to run the project as well. Now let's go inside of the folder called angular-hello and we'll run ng serve -o. This will compile our application and open it up inside of a browser. So I'll pull a browser over. So when it's ready, it should open up right here. And there we go. And now let's open another tab in the terminal. I'm going to hit Command+T to make that happen so I can keep the application running for a moment. And then I'm going to run and open my Visual Studio Code instance. I have a shortcut called c that does that. And let's put it over here on the right-hand side. And first let's explore what we have. Inside the src folder we can see the app and then the app.components. We'll make this a bit larger. And we can see there is our HTML. So let's get rid of all the code down here below the div. Now we just have a basic div right here, and as we're changing this notice it's changing over here because it's still running and compiling. So I can stick the word, if I went up here to John Papa and get rid of Welcome to title if I want to, and it recompiles and just displays that right there. Let's put back the Welcome message. Great. Now let's move this over to the left-hand side and we'll go back to our terminal and we'll type in ng g c, we're going to generate a new component, I'll call this customer, and I'll put -d in there for --dry-run so we can see what it would be doing for us. Notice this is going to create the four files for our customer component, for our TypeScript file, our spec, our HTML, and our CSS inside of a customer folder. And it updates the module to reference that new component. Well that's what I want, so let's go ahead and do that removing the -d flag. When I do that, I can come back over here to the Explorer and we see a customer folder with our four files in it. Here we can see the component itself, referencing the HTML and the CSS right here. Now let's create another component. Ng g c, you should be getting familiar with that, and we'll call it orders. Now let's say we want a view encapsulation. We can type in --view-encapsulation, like this. Now we can say it's going to be Emulated. And then just in case I'm not sure I typed it right, we can say -d for --dry-run, and I'll show you a trick here. If we add in a couple extra d's on emulator and we hit Enter, with the --dry-run still, notice we're getting an error. It's telling us that viewEncapsulation of emulator is not working, right? It's saying viewEncapsulation should be equal to one of the allowed values, which we could go look up in the docs. Now we happen to know that emulated is right because it worked with this command right here. Now, who wants to type --view-encapsulation like that when they could type -v. That's what I prefer. So we'll do that here. And then we'll also put in change detection. So you type in --change-detection, or you could do -c OnPush. And once again, we'll do -d here for --dry-run, make sure it works. Finally we'll remove the --dry-run now that we see it works, and it should generate an order for us. We'll come back into VS Code, we'll make it full screen, we'll go look over here in the orders folder, and we can see we we've got a TypeScript file which has both of our encapsulation and change detection strategies set.
Declaring a Component in an NgModule
Now we not only created the components, but notice it also says here in Terminal that we updated the app.module. Let's take a look inside of Visual Studio Code to see what that means. Now let's go to the app.module. It said that it made a change to this file. We'd be able to see what that change was. Now we happen to know right here that with the customer component and the orders component, they were both imported right here on lines 5 and 6, and then also declared as part of the declarations down here on lines 11 and 12. We can also see the Git changes right here. By clicking on the green, we can see we added those two lines of code. And then down here, the blue recognizes that they are modifications. All three lines are modified because there's a comma that was had to be added to after the app.component. So that's pretty neat. Not only did it pull the components in, but with Angular, we have to declare the components somewhere in an NgModule. So it did that for us. In addition to using the --dry-run, another technique we can use to see what changed is to use source control. We just saw a glimpse of that here. If we go over to the Git control, right there, we can see the different files. We can, again, look at app.module, right here. Now we can see side by side the Git changes. I'll go full screen for a moment. Here we can see the changes to the files left and right. There's also an inline view. If we hit the three little dots up here on the right and Toggle Inline View and Visual Studio Code, we can see the deltas in the file. I like to use this also just to see what's happened before and after I generate code. So often, I'll actually commit my changes and then I'll run the generate commands and see what the differences are. So that's just another technique that you can use in addition to using the --dry-run flag. Now this technique's a little more advantageous in my opinion because dry-run will tell you what you changed or added, but it won't necessarily tell you what lines of code have actually been modified. Whereas this technique here, by using source control, will tell you just that. So that's just a little tip that I like to use when I'm trying to figure out what I want to generate and what the effect of those changes will be.
Now let's take a look at how we can generate some other blueprints. So we'll go to Visual Studio Code to see what those code changes are and we'll commit them all for now. Just like that. We'll do this so we can see all the changes that we're going to make as we continue to generate more code. Now we could continue to use the external terminal, right here. Nothing wrong with that. If that's how you like to roll, go for it. But to avoid some of the flipping back and forth, let's open a new integrated terminal inside of VS Code. This will allow us to stay in one tool. So I'm going to type Ctrl+Shift, and then the backtick, and you can see a new terminal. Or, we can hit Command+Shift+P, or Ctrl+Shift+P on windows, and then we can type at the top, integrated, and you can see there's Create New Terminal. And it'll show you the shortcut right up here in case those ever change or if you remap them. Now let's go ahead and use that new terminal at the bottom of the screen to generate a directive. We're going to type ng g, and then it's going to be d for directive. And let's say we've got a directive or some kind of a search box, so we'll call it search box. Now if we run that with the --dry-run flag, we can see which files will get created. Here we've got a spec and our TypeScript file. And it also updated the app.module. That's probably for our declaration, right? And that was --dry-run, so let's go ahead, we'll hit the up arrow to do the same command, and we'll backspace to get rid of the -d, and then we'll run that. Now we should see that over here on the left. So on the left now, we can see our search box directive and our spec. Now you notice the third file changed. That's right here, we can see there's the app.module. So we can see that we added an import and we have another declaration now, and the CLI did that for us. That's pretty cool. Notice that with our directive, it's flat. It's right in the same folder as our app.component, which is right in the root folder inside of our app. If we don't want that to be flat we can create a search box to folder. If we didn't want it to be flat, you have another option. With the up arrow again, I'll keep the d on there, and let us call this one 2 just to show once again what's going to get created by default. Here it's flat right in the app root, but we can also stick a flag in there called --flat, like this, and we can say false. And in this case, the directive will get put inside of a folder called search-box2. And it's still going to update the nearest NgModule that it can find. This is a really nice feature of the CLI because it allows us to decide how we want to structure our application.
Let's commit our changes one more time here. These are our directives. Now let's add a service. Maybe we need to get a service for getting sales information. So we can say ng, generate g, and we can type service, or just s, which is our alias. And we'll call our service sales-data. So down in the terminal, and we'll hit Command+K to clear it out, we'll type in ng g s sales-data, like that, with a -d for the --dry-run so we can see if it's creating the service, and we also see it's creating a spec. Then we can take our --dry-run flag off. Once we do that, we should see some Git changes over here on the left. When we learn Angular, we learn that services have to be provided somewhere in the application, and it's doing that for us right here on lines 3 through 5 with the injectable. One of the newer features in Angular 6 is it allows us to specify providedIn with root, so Angular will be able to provide this service for us. Well let's say we wanted to use the old style of providing, and it would look something like this. Now, we'd have to go and move over to our app.module over here, and we'd have to add it in as a provider. So down here we could type in SalesDataService, like that. And notice it automatically got rid of the red underline that was there for just a brief moment. That's because VS Code automatically imported the file right here on line 8. Now if you look at our Git changes, you can see that. It's another reason I really like the Git changes because it shows you, hey, you just added this line of code and this one down here. Pretty neat, but let's undo that change for a brief moment. We'll click on Discard Changes. So nobody is providing that service yet. And we'll go back to the service file. Now let's undo those changes with Git and we'll regenerate sales-data so we can see the original way it's going to generate for us. Now again we come back over here, and the sales-date service, again has the injectable and it will just automatically be provided. So there's a couple different options here for how we can handle providing services. The CLI will default doing it by providing in the root. Now before we continue, let's go ahead and commit both of these changes.
Generating Classes, Interfaces, and Enums
Let's say that we wanted to create a folder where we could put things like models. So we could do mkdir and then models if we wanted to. That's one way of going about doing it. Or we can use the CLI using the ng command. So we can say ng, and then generate for a class maybe, and class, we can use abbreviation of cl. Now we can specify models/customer. Now I'll stick -d in there for --dry-run so we can see what's going to happen. It's going to create this file called customer.ts in the models folder. Now let's remove that -d flag and actually see it created. Here we can see that the models are created and there's our Customer class. Our Customer class is quite simple, it's just a plain TypeScript class, and now we have a models folder to put it in. So that's pretty cool that we can create a folder and the file right into it. It can dive right down into the structure. This technique is also really good for creating things like interfaces. So you can type in ng g i for interface, right inside the models folder again. If you want to create a person interface right here, we can do this. So now we can see there's a second file over here on the left for an interface. That's awesome. What else can we do? Well, we can create enums. So we can say ng g enum, or just e for the alias, and we can type models again. If that's where we're going to put these, that's a great place, and maybe this is going to be something like gender. So we do that. And now we have our enum and created inside of the folder. So not only can we create the basic features of Angular like components, directives, and services, but we can also create regular old TypeScript features like enums, interfaces, and classes. This can be quite useful if you need to use these features inside your applications, especially for things like models.
We can also use blueprints for creating pipes. First, let's commit our changes over here, and then we'll come back to our terminal. So we can do ng g pipe, or we can just do p for short. And maybe we want an init-caps pipe that we want to create. So I'll type that in, and I'll use the -d again just to see what it looks like. Here we can see it creates a pipe and a spec right in the root, and it also updates the app.module. And that's for the declaration of our pipe. Now, I kind of like my pipes to go in their own separate folder, so let's create a folder here. We'll do ng g p again, and then we'll call this folder shared, and the name of our pipe again is init-caps, and we'll put the -d in there to see it one more time. So this time you can see it creates the same files but now the pipes are actually inside of the shared folder. And it still declares it to the closest module. like app.module. Well let's go ahead and remove the --dry-run flag here and we'll write this pipe out. We should see it appear over on the left inside of our folder called shared. And there it is. And we can also see that it's now in the app.module folder. Now with the Git change we can see that it added the import up top, and it also declared it down here. If we wanted it to go to another module, there's actually a flag that we can use. So if we do ng g p, or pipe, and then do --help, we can see a few of these options. One of the options is module, or -m. So if you want tell it where to put it, we could have gone back to our code here and instead said -m and then put the name of the module in place. Now this is going to do the same exact thing. So, it would go there by default. So there's no reason to type it. But if we had other modules, other NgModules, and we want it to declare in those, this is how we would do it. Okay, great. Now let's commit all of our changes to the pipes.
Let's close our windows that are open right here, the code ones in Visual Studio Code, and instead take a look at our folder structure. We're starting to get a lot of features here. Maybe we want to create our own module first in future features like logins. So maybe we have a login screen and components and services that go with it, and this login area might want to go into an NgModule. So we can do ng generate module, or just ng g m, like this, and then login for the name of it. Now let's first put the -d flag on here. Modules by default are going to get their own folders. So we can see that they're all put inside of a login/, and then we've got login.module.spec. and login.module. Once we create that, we can also decide if we want to have specs or not. So if I don't want specs, I can say --spec false. Here we can see the spec is removed. Once we create the login module, we want this to be imported into the app module so they're all linked together in a way that makes sense. So we also want to put in here - m for what module to put it in. In this case, I want to put it in the app.module. So now we run this, we'll see it's creating the login module, and then it's going to update app.module. And of course all this has been done with the --dry-run flag so we can just try it out. Once again helping us so we don't have to constantly write files and then delete them or use Git changes to remove them. So let's try that command without the -d, and now we're creating our login module over here in the login folder, and then we can see through the Git changes that it's also been added to our app.module, right down here. Well now let's say that we want to have something else in there like a component. We'll clear the screen and we'll try adding a component called login to the login.module. Ng g c login, like this, and we'll do -d. Let's see what would happen. It's going to put the login component inside the same folder as the login.module, which is pretty cool, in this case because they're named the same. So if I show that again, where if we used a different name for the component, like login123, you'll notice it would go into the login123 folder. So it's important to know where you're actually going to put things. So let's say we didn't actually want to call it login, we wanted to call it loggingin, like this, so it's a different name. In this case, it's going to go to loggingin folder. Well if I want that to be in the login module inside the same folder as that, I could do it like this where it's login/loggingin. So now, I've got my src/app/login, and then inside of there we're going inside of a sub folder called loggingin and we're creating our component with all of its various files. Now notice the cool statement down here, it's UPDATE login.module.ts. What's happening there is the component has to be declared. It's automatically finding the closest module to it. So in this case, we don't have to tell it which modules to declare it in because we wanted it to go to that login module. So now if I remove the -d right here, we could create it. We'll see there's our loggingin and there's the components, and then in the module itself we can see it's been declared right here on line 9. Let's see what happens if I try to create something in that folder, we'll just call it foo. And we'll tell it to go into the app.module root, and we'll do -d because you don't really want to create this. So now it created the foo component inside the login folder, but it updated the root module. Now I don't recommend declaring a component in a module that's several parents up. Generally the good rule of thumb is to declare your components in the closest module. But if you ever fall in a situation where you need to go outside those boundaries, you have that control.
Configuration and Resources for Out-of-the-Box Blueprints
We just learned a whole bunch about the out-of-the-box blueprints that we can use to create different files with the Angular CLI. Let's start with the directive here. We can write a search directive with ng d, or directive search. We can also create a service with ng service, or with the alias s. What if you want to create a pipe? No problem. Just use ng g pipe, or p as the alias and the name of the pipe. What about plain old TypeScript classes? No problem once again. We can say ng g class, or cl as the alias to do that. And with any of these, we can specify a folder or subfolder that we want to put them in. We can also create an interface with TypeScript using ng g i, or we can create an enum, like gender, with ng g e, or enum, just like this. What about creating Angular modules? We learned what we need to do to create a new module, so there's blueprints for that as well. Ng generate module, then followed by the name of the module, and then any options. We can also tell Angular that this module should contain a routing module as well. We'll see that very soon in this course. But what we showed was how we could do ng generate module, maybe sales. And we can use the alias here again, ng g m sales. Okay, that's a lot to remember, right? Well, if you do get a little bit stuck and need a little help remembering them, always lean on ng --help. The help flag is great and it shows you all sorts of commands. And you can use that --help command on any of the subcommands too. Now let's take a step back and look at what we've learned about generating code with blueprints. There's a whole bunch of out of the box blueprints that we used. We learned about the components and classes and interfaces and services and a bunch of the options that we can use on them all. We also learned about the --help flag and the docs, because frankly, they're going to help us navigate how Angular CLI works in case there are new flags introduced in the future. And you can see that I'm a huge fan of the aliases for both the blueprints and the options. If you're not sure what some of those are, you can always refer to the docs, or you can just use a full out name. You don't have to type ng g c like I did for generating a component. You can type ng g generate component. And it should be obvious by now that I'm a big fan of practicing with the --dry-run option, or -d. I find it super helpful for just taking a quick look to say, you know, I'm not sure what's going on or what's going to generate, but let me see real quick first, and then I can remove that --dry-run flag. Now in the next chapter, we'll learn a whole lot more about how we can generate modules with routing considerations, and we'll have a little fun with that.
Generating Routing Features
Generating Routing Features
We just learned how we can generate a lot of code using the out of the box blueprints that come with the Angular CLI. Now let's take that a step further and we'll learn about how we can add routing features to modules and create routing guards. First, it's good to understand that we can add routing features manually, but we can also do some of this with the CLI. Like in most things, it's good to consider what we're about to do. Before we create a module, do we want to have routing in this module, or don't we? We'll learn what the different outcomes will be in this module. We'll also add some routing paths to some components because we want to see the routing actually work, and we'll learn about how we can generate guards for those routes.
The NgModule Blueprint with Routing
Let's begin by revisiting the blueprint for modules and take a look at how we can add routing to it. We've already learned that we can use ng g module, and then specify the name to create a module, just like this. Here we're going to create an admin module, but we can also add the routing option. So what will this do? If we say ng g m, for generate a module, and call it sales, and we add this option for --routing, what we're going to get is going to be a sales module and a sales-routing module. So there's actually two modules that get created. The one on the right, the sales-routing module, will contain all the routing information, and we'll also get a sales module. So we get a sales routing module, and it happens to be imported into the sales module that we get as well. A demo right about now would really clarify this. Let's go ahead and do a little hands-on work where we generate some modules and routing modules and see what actually gets created.
Generating a New Routing App
Let's begin by going to a clean folder, mine's _play, and creating a new project using ng new, and we're going to call angular-routing, like this. Now I want to give it routing right out of the get-go, so we'll use the --routing flag. Now because I like to practice, we're going to use the -d. This shows us here where we can find the app-routing module, right there. And right below it, we're getting our app.module. Okay, now that we know that's what we want, let's go ahead and run that command, this time without the dry run, like that. Once it installs, let's go ahead and cd into the folder angular-routing, and then we'll open up inside of our favorite editor, mine is Visual Studio Code, and then I'm going to use the embedded terminal inside of here. And this time I'll use it by doing Command+Shift+P, looking for the integrated terminal. Then I'm going to type an ng serve -o. It's a great way to make sure that everything just works. And there we go! It opens up right inside the browser. Now I'll move that off to the right. And we'll keep this open and running. Now we're going to use a nice feature in VS Code to open up a second terminal. So now on the left-hand side we have the running instance of ng serve, and on the right-hand side we have another terminal, so we can run commands like this. So where do we start? Let's look at the package.json, make sure that what we have in here is our current version of Angular and everything got installed properly. That's all there. We've got our node_modules up here. And inside of our app, we have our app.module. That's our main module, and notice it's importing this thing called AppRoutingModule, right there. If I hover over that and hold my Command key down and click on it, or I can right-click and go to definition, we go right to the app-routing module. This is the new module we created for our routing. This follows a convention that we use in Angular where we set up the app-routing module to contain all of our routing information. It imports the router features, right here on line 2, and then we can set up our routes, which we'll do in just a moment, and then we export this entire module, which then contains everything we need to know and goes back and gets imported into the app.module right here on line 13. Now right now we don't have any routing happening in our application, so let's go look inside of the app-component.html. We've got a lot going on up there, so let's remove some of the code here. We really just want to have this div and remove all that ul and the router-outlet. That's basically the X marks the spot of where all the things that we route to will be displayed in our application. So if we go back and look inside of Chrome, we can see the application now just says Welcome to angular-routing. And if I put it side by side quick, we can also just say abc here, and as soon as it automatically saves, it'll automatically render on the right-hand side. Great! Now let's generate two different components, one called dashboard and one called customer. Do ng g c dashboard. Then we'll do the same thing for customer. Now we should see those files appear over here. There's our customer. Look at the HTML, it says customer works! Dashboard, dashboard works! Perfect. But how do we get to those? Well, we want to create routes for those too, so let's go inside of the app-routing module, and we're going to enter paths for both of these routes. We'll create a route that goes to dashboard that will display the dashboard component in the router outlet. We could type this by hand, but you might be guessing, if you know me well enough now, that I don't like to type a lot by hand. Instead, since we installed the Angular Essential extension from VS Code, it comes with the Angular snippets that I created for it. Some of these are going to help us creating route paths. So I'm going to open up the array here and I'm going to type a-path, and you're going to see a bunch of different kinds of paths. Now, in this case, we want to choose a path for eager, because we want an eagerly loaded path. And we will say we want it to go to dashboard, and when a user goes to dashboard, we'll tell it to open up the dashboard component, like this. Now we still have a red underline because it can't find the name dashboard. We can see the helpful error message down there. Inside of VS Code, we can see the light bulb, which we can click on and have it automatically imported for us, and therefore that one's set up properly for us. Now let's make another path here, we'll use the snippet again, a-path eager, and this one's going to be when you go to customer, I want you to load the customer component. This time I'm going to hit Command+dot to get the same quick fix instead of just hitting the light bulb. Now that's imported as well. And by default, if I go to slash, just the default route, I want it to go to the dashboard. So I'm going to tell it up top, a-path-default. And the default path is going to be blank, it's going to match the entire path, basically just an empty path, and if I see that, I want it to go to the dashboard, like this. So now I've got my three paths in place. Now it's all great to have these different places to route to, but we have to have something we can actually click on to get to those routes. So let's go back to our app.component.html, and we remember that the router outlet is basically the X marks the spot for where those different components are going to be shown. So let's create a little navigation menu right above it. So I want to create a nav, and inside there we're going to create a ul which has two lis, each of which has an anchor with a binding property of router link. Well again, we can type all that HTML, or we could use a built-in feature of VS Code, which is called Emmet. This is easier shown than explained, so let's just type this out. We type nav, and then the greater than, ul, so the nav has a ul, and on the right you can kind of see what it's going to look like, and that ul, I want it to have an li, actually two of them, times two, so now you can see that they're in the right, with the preview, and then greater than, a, each one of them will have an anchor. And now this gets a little tricky. I want it to have a router link that's using binding, and we know in Angular to do binding with properties, we put the square brackets around them. So normally you would just have two square brackets like this, and we want to say routerLink, but that's not generally what we want on the right. See how routerLink doesn't have the square brackets around it. So I'm going to double square bracket it like this, and now you can see in the right what it's going to look like. And then I just hit the Tab key, and voila, I've got my HTML. Now if that seems like too much, absolutely just type it out by hand. I kind of like Emmet because it makes it a little easier to get things moving. Now we're going to use that routerLink, and we're going to set that equal to going to the dashboard. So when somebody clicks on that, we want to say alright, go to dashboard. And then we want to put a word in there, so we'll put dashboard in for the menu. And then likewise, we want to do something similar for the customer. So now we have a URL for customer and one for dashboard, and we also have menu links for them. Now let's just take a look, make sure we everything right. We've got our router links here going to /dashboard and /customer. Let's make sure that those paths match what we have inside of the routing module. In the routing module, we have a path for /dashboard and customer, and actually, we just want these to be without the slashes, because in this case it is the root already. So now that those both match, dashboard and customer, to what's in the HTML, dashboard and customer, we should be able to flip over the Chrome, and we can see the application. By default, it went to dashboard. We can go to Customer, Dashboard, and if we remove that dashboard up there and go to the root, it's going to automatically redirect to dashboard for us. Now what's really cool about all this is the Angular CLI makes it a lot easier to add routing to your application. Remember when we created the routing module from scratch, it added this app-routing module, which put all the boilerplate in for using routing. And then all we had to do was add our own components and hook up the paths ourselves, and then put a little bit of logic in for the template to route back and forth. And then we're good to go. And things that I always forget, like making sure I actually have the routing module being imported, and making sure that I've got the router outlet in my component, those things kind of just get taken care of by the CLI. Those things just kind of get taken care of for us by the CLI. Now let's make sure we commit these changes. Go back into VS Code, do like this, and we'll go into source control, and then the next section, we'll learn how we can add other modules with routing too.
Generating a New Module with Routing
Before we continue, let's take a look at some examples that show how Angular routing works. We'll open a new tab, and let's go to this URL, angular2-first-look.azurewebsites.net. Now once you get there, there's a bunch of samples from my Angular First Look course here on Pluralsight. And we're going to search for the word routing. If you go down to sample numbers 25 through 28, that's all of our routing examples, let's take a look at number 25 right here, Angular: Router, and we'll click on the View Sample button. So the first one here shows we have characters and we have vehicles. If we click on these we see all the different characters, and then all the different vehicles. Let's take a look at the app-routing module under the app folder. Here we can see we have a bunch of routes set up for our characters and our vehicles, and we also have parameterized routes for the characters with IDs or vehicle IDs. But what happens if we want to have other modules? Notice that the vehicles here, these are just a bunch of components and services, same with characters, there are no sub-modules. So everything's inside the main module. Let's go back to the samples and we'll click on number 27, Angular: Eagerly Loading Routes. We'll click on the View Sample here. And this one, again, looks very similar. We've got characters and we've got vehicles. There's a big difference though. If we go over to app, we can see we've got app-routing module. And now this looks a little bit cleaner because there's less in it. The main app routing only has the default path, which goes to characters. And then it's got this path not found. If we go inside of characters, you're going to see a characters-routing module. So in this one, we have a characters-routing module, which segregates all the character's paths. So we go to a characters component, character list, and then character detail. And they all get pulled into a character module, right here. So the point here is that routing can get more complex as we add more and more modules to an application. Let's get out of here and go back into our application. We'll come back into the terminal, and I've got two of them open here, and the first one we're going to run ng serve -o. If it's already running for you, that's fine. And this is just going to build and show the application. And then on the right-hand side, I'm going to add a new module. We're going to add an area called admin. So we're going to do ng g, for generate, module, and it's going to be named admin. Now before we hit Enter, we want to think about what we want to add. We want it to have routing, so we want to say, okay, --routing here. And these things might be sensitive for only administrators, so we're going to segregate all the admin stuff inside of this module, and we'll let people route to it. So first let's add in the -d, right here for --dry-run to see what we're getting. Let's run it real quick. And notice we're going to get an admin folder, an admin module, and an admin-routing module. Okay, that's close to what we want. There's one key thing missing. We want to make sure that this admin-routing module gets pulled into the admin module, which then gets pulled into the main app.module ourselves. So down here, we also want to add -m app.module, and we'll do a -d here again. Now this time we should get the same three files created, plus it should update the app.module. That's what we want. Great. Now that we've got a good sense of what it's doing, let's remove the -d for the dry run and let it roll. Now it ran it, app re-compiled, and if we go look at what was changed, you can see that our app module now imports the admin module over here. Then we'll go back and look at the inline view just make it a little easier to look at. So you add the admin module here, and then we also put it down there as the imports. Great. Now we have this new admin-routing module and this new area to put our components in, we want to create a root component inside the admin module for things to kind of land on. So this is our admin area, could be a dashboard of some kind. So we want to ng generate a component, and we're going to call it admin. And that'll be the component we add right here. It's going inside of the admin folder, so now we've got the admin-routing and our admin component, right there. Inside the admin area, we may want to manage the list of users, and we may want to have another page or component that handles email blasts to our customers. We want it to be in the admin module. So what we can do is say ng g c admin, for the folder, /email-blast for the first one, and when that gets generated, notice it gets put right inside the admin module here, and it should be declared inside of our admin module right there. Perfect. Now we can do the same thing for our users. So both of those components are now declared in the proper place, right here on line 14 inside the admin module. Now let's go to the admin-routing module itself. Here, we have our routes, which we can define now to go to the email blast from the users. Inside of our route array, we'll create an object here and we'll set up these paths. The route's going to have child routes, and the syntax is a bit lengthy, so let's use a snippet here. So I'm going to type a-path, and we'll choose route-path-with-children. And the default path is going to be admin. If they go to admin, that's where they're coming here. And then we want it to go to the AdminComponent. And then our first child path, we have these two components we created, one for users, one for email blast. So we can set one of them for a default path, say when you come here to the default path of just admin, with nothing after it, we'll go to the UsersComponent. And then we can use another snippet in here for eager, and say when you come to blast, we'll go to the EmailBlastComponent. Now we have a lot of red underlines. Here we can use those quick fixes with the light bulbs, and we say import this from here, or we can say add all missing imports. Let's try that and see where it gets them from. Notice up here it was smart enough to get the admin, users, and email blast all from the correct places. That's pretty cool. So what do we do here? We're saying that if they go to admin in the route followed by nothing, go to users. So basically, /admin is going to go to users. And then if they go to admin/blast, it's going to go to the EmailBlastComponent, but where is this going to show up? This is all related to the admin component, so let's go look at the admin component's template. Right now it just shows admin works! We want to change that to have a router outlet. And perfect. The X marks the spot for where to put the email blast or the user component is going to be right here inside of the admin component's HTML. And we'll leave in the text up here just to show that it actually worked there. So if we go back and look what we did, we have a terminal over here still running the application, and if it's not, just go ahead and rerun ng serve -o. That should launch it back up in the browser once it builds. Our application seems to be running here, but we didn't add any menu links to click on it. We could do that with some navigation, but we know we have an admin area, so let's go back into our application, and let's go and type in admin in the URL. When we do that, notice we're seeing admin works because that's where the admin component got loaded, inside of the router outlet, inside of the main app component. So the main app component has a router outlet which loaded the admin works and the users works. And then inside of the admin component, it's got a router outlet that loaded users because that's the default. Now if I type in /blast up here, we have the only thing that changed is the email blast works because that got loaded down below as well. So now we have our nested routing set up, and we used the Angular CLI to do the grunt of the work for us. Let's take one last look at Visual Studio Code and show the Git changes that we've made in here. Now I'm going to hit Command+J, which just hides the bottom terminals. It doesn't make them close down, just hides them. And I'll show the get changes up here. We've got plenty of files that we actually changed. Notice we added an admin module up here, and admin components, we added our email blast and our user components, and we also modified this app module. So everything else was new, but the app module was modified. So just a little bit down at the root. And the CLI hooked all this up for us. So once again, we just knew what we wanted to accomplish. We wanted to make sure we had this admin area with users and email blast, and we took advantage of the Angular CLI to put in that boilerplate code for us. And then we just wrote in the custom code that we needed to make it all work.
Generating a Guard
We just walked through a demo of how we can add routing to the application using the CLI, and we did it a couple different ways. One way was to generate a new module right from the get-go using ng new, and then the app name with some options. So here, by saying --routing, we actually added a routing module right from the beginning. And this was really handy because it allowed us to start out with the routing features that we needed right from scratch. In the last sample we did, we showed eager loading of these other routes and these modules for the admin area. Now what if our admin area wanted to be protected so you couldn't get into it unless somebody had certain roles or permissions. Well in that case, we could use guards with Angular. Now we can generate guards by doing ng g, and then guard, and we can call like an auth guard if we want to, and that would generate off a file for us like auth.guard.ts, and we could use this to protect the routes if we want to.
In this module, we learned how we could take advantage of the different routing features in the Angular CLI to add those routing aspects to our app. For example, when we start a new app, if we know we're going to need routing, we could use --routing option, and that's going to generate the app, the module, and a routing module. Now if we want to create sub-modules in our application, other NgModules, we do that, we can use the ng m for generating a module, and we name it admin, and we use the routing option there. On this one we want to make sure that we're actually going to import this other admin module into the root app module as well. And to take it a step further, we can use the blueprint for generating a component to add a users component inside that admin area. And that'll declare that component in that admin module. The one thing I want to make sure we drive home in this module is that we need to consider if we want to have routing when we're generating an app or a module. If we do, we add that --routing option, which then the Angular CLI just takes care of kind of connecting all the dots for us. Then we just add our routing paths and our links, and we can also add guards using the CLI that we can use to evaluate our routes. We're going to touch on routing even more in the upcoming chapters as we get into building and serving our application too.
Building and Serving
Building and Serving
Writing code is, well, it's awesome, but at some point we have to build and serve our code too. So in this module, we'll learn how to build and serve Angular apps for various target environments such as local development or a production build. And we'll learn how the Angular CLI can help with that, as well as the development lifecycle. We'll cover a variety of different topics here. We'll start off with how do we build using the Angular CLI and explore all the options that we have. And then we'll look at the different build targets that we can do for both development and production, because they're quite different and we have different needs for those. And then we'll explore what builds we actually get. We'll take a look at the output because it's good to understand what the Angular CLI is doing when it's building the content for us. And we'll take a look at how we can serve the code and use that in our development lifecycle. We'll also learn the role that webpack plays in the Angular CLI and how we can eject the webpack configuration if we want to and how we can handle third-party libraries.
Well let's begin by learning how we build our Angular code. Well the Angular CLI uses builds to help us compile our application, and then we shove that into an output directory. There's a lot of things that go into making a build, so it's good that we have a lot of options, and we can use these build targets to determine how the output gets laid out. For example, we may want a dev build to look different than a production build because during development time, we're more focused on speed and debugging and efficiency, and when I mean speed, I mean speed of development cycles, whereas when we go to production, we want to make sure the code is rock solid and secure and fast as we can get it. And then all the builds that we're going to generate are going to use bundling. And for production builds we want some extra stuff to happen, and some of those things are uglification. Now you may have heard that called minification and mangling as well, and there's also a term called tree-shaking, which is going to basically shake out all the dead code that we're not actually using, or at least it's going to try to do as best possible job that it can. And that's a good thing because that's less code that gets transmitted to the client that doesn't have to be parsed there in the browser. Now a great place to start with ng build, because there are so many options, is the ng build --help. That's going to show us all the different kinds of things that the build can do. We'll start off by looking at how we do development builds, and for that we'll use ng build. And yes, we can specify a bunch of options here, and we'll take a look at some of these, but ng build out of the box is just ideal for development. We're not going to do any production builds right away. We want to make sure we're writing our code and it's working the way that we expect it to. And when we run ng build by default, it's going to go to the output folder that's specified in the angular.json file, which happens to be dist followed by the app's name. So that's where we're going to go look for the actual outputted files. And once we generate that, we're going to see a bunch of files. First, we're going to see a runtime bundle. That's currently the WebPack runtime. Our application's going to need that to basically load all of our modules and put everything together for us. Then there's our main bundle. This is, well, the core of our code and the root NgModule. And then we're going to see a polyfill bundle. That's going to help us polyfill for different browsers. We'll also see a styles bundle, which is where all the styles will be located, and a vendor bundle, which will contain Angular and any other third-party vendor files we pull into the packages. We'll be taking a look at these different files and we'll explore the source of these. There's a few tools that I like to use that allow us to look at the source code to draw a dependency map of what is actually in our bundles. Okay, so when these things get rolled up into bundles, it's kind of hard to tell, well, did my code get there, whose code is in which bundle, and did it just bring the files and code over that I'm actually using? So it's really nice to get a look at that. We install the tool's dev dependency here, and then we just run this line here, which'll go build it, and then we run this line, which will analyze our bundle, and we can see all the dependencies in a visualized map. This tool uses webpack stats to explore the bundles, and we can get that right here. There's a second tool that uses source maps to create a visualization. They're very similar tools, and I like to use both when I'm really trying to find out how I can reduce my bundle size. Again we'll just build it, and then we'll make sure that we run that code. You can get that one from this link. The first one uses the webpack stats file and the second one uses source maps. And source maps are enabled by default in the dev build, so we're good to go there. If you want to run the second one with a production build, you have to enable the source maps since production builds don't do that by default. Now it's time to go run ng build and we'll explore the output so we can get familiar with what's there. After that, we'll take a look at some of the other options that we have.
Exploring a Development Build and Its Bundles
Building Target and Environments
Back in our angular-routing app that we created, we can see here on the left how the app is about 3.3 MB. That was our dev build. Let's see what happens if we run a build with AOT turned on. And we'll still run it with the stats-json so we can examine the output, and I'll keep this tab open over here so we can compare the dev build versus the dev build with AOT. Now we can run that npm run stats because we created that in the package.json as a script. And this will analyze the output. Now I'll take this tab and I'll put this over on the right-hand side. So now we can see the entire build is about 2.19 MB. That went from 3.3 down to 2.19, so about two-thirds the total size. The vendor build alone went down to 1.9 MB from about 3 MB over here. So we're seeing things slowly get pulled out. So by running --aot, we're actually removing quite a bit of code in there that we didn't need. And part of this is the Angular compiler. Notice there's a compiler over here on the left, and if hover over it, that's about a meg, and it's missing completely over here on the right-hand side. That's because when AOT works, it does all the compilation on the server when you do the build, so it doesn't have to worry about sending the compiler over the wire to the browser. Now let's organize these a little bit so we can do a little more inspection. We're going to put this one in the upper left and this one in the lower left. So this is the old dev build, the current dev build, and let's Ctrl+C+break and we'll run a different build now. Now let's take a look at what we can do with some of the other flags. So ng build help, or -h. There's a whole bunch of things that we can do. We've seen a few of these already. We talked about watch down here in the bottom. Another one I like is verbose. Sometimes when things are going wrong, it's nice to see more of the output. Stats-json, super helpful, so we can do what we're doing right now with webpack-bundle-analyzer, and they even mention it here right inside the help file. And then next we're going to use this prod flag. So let's clear that out and we'll run ng build, or you can just do b --prod and we'll turn on stats-json again. And I want to emphasize, we don't want to run with stats-json all the time because it creates that big file, but that's really just what we're doing now so we can explore the output. So once it goes through this build, it's going to run through and do AOT uglification, it's also going to tree-shake some things out. Inside of our distribution folder, our dist folder, we can see what the total size would be. Now notice here, we've got a 1 K file that's our runtime, it's webpack, our styles are about 0 bytes, polyfills are 59 K, and then our code is only 261 K. That's pretty good. Let's take a look using the tool we just looked at a moment ago, npx. Now let's take a look at the visualization. And I'll put this one over here on the right. So over here on the left we had 3.3, and then when we turned on AOT it went down to 2.1, and then now we are down to 314 K total, and that's a significant reduction from where we started. And the polyfills are something that we can use to support some of the older browsers, and you can even tinker with that to make sure you're using just the polyfills that you need. So what is in the final output? Notice that our source code, including our main.ts and our modules, are all in here, as well as Angular and RxJS. So if we just look at some of the output, like let's turn off all and just look at main, you're still going to see our source code in here and Angular RxJS. They combined our code with the vendor code to get the best optimization that it could. That's why there's less files here, there's three of them, than what we started with if we come over here, there's five of them. So we just learned how we can use these different commands. It was ng build to do a dev build. And we can turn things on for the dev build like AOT when we want to, or we can say go ahead and run a prod build and even customize that a little bit by turning on things like the stats-json or source maps briefly, just to run it like we did here. And if we need to learn more about these commands, we can always do ng build --help or go look up the docs. And now we've learned how to customize our builds for both dev and production and how to explore them using this visualization tool, let's go ahead and take a closer look at the ng serve command that we keep using.
Throughout this course we've been running a command called ng serve, well, that serves Angular. Now let's take a closer look at how that actually works. Serving is really important with web apps because we need to be able to see it running. The compiled output is served from memory and the Angular CLI is going to lean on webpack, which will then serve up code inside memory, so it's not actually hitting that dist folder. This makes it super fast and really efficient for live reloads. Just like getting help with other features is a good thing to do, we can also get help using ng serve --help. So we'll do that when we get stuck on things or when we just need a little nudge on what to do with these different options. So what are some of the common ng serve options that we can run? Well the good news here is that even though there's a lot of those different options on ng build, all those same options can also run on ng serve, plus some of the other ones shown here. We've already seen how we can use -o. That's the alias for opening it up in the browser. By default, ng serve will run the server and then you can go to the browser and type in the URL to see it. If you'd like it to do that automatically, open it up in a tab, you can just type ng serve -o, and that's my preference. You can also change the port that it's listening to when serving. This is super helpful if you have multiple Angular projects that you're running or you're using other ports already. And by default, we're using live reload, but if you want to change that behavior, you can use the live-reload option. And if you're not familiar with live-reload, that's a behavior where you make changes to your code, and the server's watching those file changes and it will automatically rebuild it and show them in the browser. That way you don't have to stop the server and relaunch. There's a couple of different options for SSL that allow us to set up the SSL to run over HTTPS. We can even specify certificates too. And if you sit behind a firewall or you just need to configure a proxy, you can do that with the --proxy-config option. Now let's go take some of these options for a spin with ng serve.
Exploring Angular Serving Options
Back in our demo, we might still have the server running. If we do, let's kill it so that it's not running at this moment, and we can prove it over here by refreshing in the browser and nothing should work. Okay, now let's go ahead and just serve plain old ng serve. When we do that, it's going to go ahead and build in memory and it's going to get the server ready to go. Now where is the server going to be? We can go type that in, it's going to be at the default port right here. We'll just put in localhost:4200, hit Enter, and there it is. Notice the first line over here on the right. It says the live development server is running right here, localhost:4200, and notice they say it was a development server. This is not for running production code out on a real website. This is for us locally so that I can see that it just worked just great. Now what if we didn't want it to be on that port? Another option we could do is --port and we could type in a port number. So we can keep this one running and go to a new tab, and let's type ng serve --port, and we'll do another port like 8626. And now it's going to go ahead and do the build once again and we have to come up in the browser and open another tab. And this one will be localhost:8626, and that one should be running as well. So if we look at these side by side, we've got this one running over here, which is still running on 4200, and this one over here on 8626. Let's move this over to the left. Now if we kill this one here, 8626, and we can run it again, this time we run it with -o. It'll run on that port and it'll open it up in the browser for us. So right now it should be dead until it actually runs. Now it's looking for the server, and there we go. There's the new one that just came up and now both of them are actually working down here. We only need one of them. Now what about that live reload behavior? Just to remove some stuff here, let's go get rid of the terminal here that has 4200. That one's canceled, so this one should not be working. Great. And we'll combine that with the other one. Now 8626 should work. I'll refresh just to make sure it's there. And it's working over here. So to test live-reload behavior, we'll take a look at our application HTML and we'll put that side by side. So here it is in VS Code, and right below the title let's add a div. And inside of that div we'll put something like, oh, I don't know, how about John Papa, just like that. Now notice, it automatically appeared over here on the left. Now what if we don't want a live reload be happening each time, because that's going to refresh over on the browser every time we save a file, and I have auto save on so it's just happening all the time. So instead, let's go back to our terminal and I'll kill the process that's running. Now we're going to run on the same port, but this time we're going to run it with live-reload set to false. So it's going to build once again, serve it on port 8626, and this time there'll no live-reload. And it should open it up in the browser over here. Perfect. We still have John Papa, and now let's go back to VS Code, but now let's change the name for something like John Papa to something like Dan Wahlin, a good buddy of mine. When I do that, Dan isn't showing up over here on the left. How come Dan isn't getting any love? Because live reload is not on. But if I refresh the browser over here, it is appearing. There's Dan. So with just a little bit of tweaking that we can do, we can see different behaviors as a running live-reload. And one last setting with ng serve that's really good to look at is the prod setting. So let's go back to our terminal, we'll kill the process, run ng serve --prod with -o because I like to open it up. And this is going to go back to port 4200. Now it's going to run ng serve, but first it's going to do that prod build. It's going to do the full production build that we talked about earlier with AOT and minification and really trim down the size of everything. And now you'll notice that it's really making clear up top, in big red letters, that this means pay attention, this is a very simple development server, not for putting it out there on the web, but for local development. But the production build is now running over here in the browser. Let's go ahead and take a look inside the development tools on the browser. We'll go full screen for a moment. We'll pull over the tools so we can look at the network traffic. And I'll refresh. Notice that our main file is about 111 K. And you can also see that these bundles are using cache-busting hashes at the end of their file names, or fingerprints as some people like to call them. So ng serve --prod is a great way for you test out what it's going to be like to serve a production instead of bundles right here in your local development environment.
Adding New Capabilities
With the Angular CLI, there's a feature called ng add where we specify a package that will help us add new capabilities to our applications. Let's take a look at this. The syntax is ng add, and then the name of the package. And this'll add the new capabilities to our project. It'll download any dependencies that it might need from npm, run any install scripts, update a project configuration, and scaffold any package-specific setup code. Here are some of the packages that you can add using ng add. We might want to pull in Angular's pwa features for progressive web apps. Or possibly pull in Angular material for a lot of the theming and the components that it has. Or Angular elements, or pull in a third-party library like ng-bootstrap using schematics. This really opens up the doors to the Angular ecosystem, both for first-party and third-party applications to be able to pull in other kinds of libraries. And this is a brand-new feature that came with version 6. Now that we've learned about this new feature, ng add, let's take a closer look at it.
Adding Angular Material
The ng add feature of the CLI helps add capabilities to our application. It handles a lot of the plumbing that's required to add complex features. Let's add a few new capabilities from Angular material and take close look along the way and what changes are being made for us. First, we're inside the angular-routing app that we've been working with. And notice we've committed all the changes. And this is helpful because we want to be able to see the changes that we make over the next few minutes. So now let's add in Angular material by doing ng add @angular/material. Now this is going to go ahead and update our project for the configuration to set up Angular material. And we'll take a look at the Git changes over here. So here's the Git changes, angular.json, we've got this input in the styles of the indigo pink theme. We can change that them if you'd like. Package.json has two new dependencies for the cdk and material. We've got the package-lock. The index.html has a couple of the Google APIs for the icons and CSS. Our CSS got a little bit of style, and our app module pulled in the browser animations module, and then also imported it down here. Awesome. Next, let's add a navigation component to our application. We kind of made our own before, but let's get something a little bit nicer looking. We're going to do ng generate, or just g, and then we're going to tell it using Angular material, let's use one of the schematics that's built in. We're going to pick out the one called material-nav, and then I'm going to give it a name of nav. That's going to be the name of our component. So it's going to generate that and you can see it put a new component called nav out there. We'll take a look at the Git changes at the app.module.ts. Now notice right here, and I'll do a little formatting, we can see all the different things that were imported. We've material button, icon, list, sidenav, and toolbar. There's a bunch of things that were pulled in. So we can go ahead and import them into our application. We'll get out of Git changes so we can see that a little bit cleaner. If we go over to app module, now we can see all the changes that are there. These are all the material modules brought in for the navigation. So that component uses a couple of different things. All right, what else did it do? It pull in this nav component in the Git changes. So let's go over to the regular view, here's nav, and we'll close these ones, and we can see there is nav component. There's quite a bit going on in there. And it tells us where to put our content. We'll do that in a moment. And we can customize our links, we'll do that as well. And then here's a bunch of settings for how the nav component will work. To show that we can customize some of this, the nav component by default will close when we hit the Escape key. Let's change that behavior. We'll come inside of here and put another property in here called disableClose, and we'll set that equal to true. Now we have this component, and what's it called? So we go back to nav component and we see the selector is app-nav. We'll go put that inside of our app component. We'll put it above the existing nav right here. That's going to be app-nav, just like that. And we're going to remove the title up here. We don't need this title because we already have a title inside the sidebar that we just created, this new sidenav inside the nav component. Now I'm going to wrap this app-nav with that div that we have, and we need to remove the router-outlet as well. That router-outlet, we're going to take that out of here, go back to our nav component, and remember down at the bottom we had Add Content Here, well, we're going to add content here. That's our content, right? The router-outlet is at x marks the spot, so that's where we're going to put those things. We'll go back to the app.component.html and we no longer need this nav, we just need the links. So I'm going to copy just the links, go back to the nav, we'll find the links that were up here. I'm going to paste it above it, and do a little bit of surgery. So what I want to do is I want to go ahead and remove all these lis, so I'm just going to copy them out using my editor and delete those. And then inside of here, I want to type in mat-list-item, which is basically what the links say right below that too. So now I can get rid of those three links and add these ones here. We'll put it in proper indentation. So we move the links over to our nav. We put our router-outlet down here because that's where the content's going to be. And you can see right there's the title, angular-routing. And then we put our entire nav inside of our app component. Look how much cleaner that app component looks like now. A lot of what we just did there was us just moving our navigation around, which is just normal application development, but the hard part was just getting the components set up and hooked up in our application. So ngi did a lot of that for us, and then the schematics added it in. Let's take a look now to see what happens if we run this application. So now it's going to go out and build again, and it's building it locally here in memory. It's going to pull in all the different features that we just added in, including the nav component, and it should show us a different looking application. Notice now we've got the Dashboard, we've got our Customer, Users, and our Admin Blast. Awesome. We'll let's see how we can use more of these schematics inside of Angular material to help us out with our application. We're going to cancel the application there. Now let's replace the dashboard. So to do that, we have this component up here called dashboard, which if you look in the selector it's called app-dashboard. We're going to just delete that entire folder. And I know that we're --- it's okay, let it go ahead and do it, I know that we have other things that are pointing at it, but we're going to name the new one the same way. So we're going to do ng generate, or just g, and then @angular/material, and then the schematic's going to be material-dashboard with a dash in there. And this is going to have a name of dashboard. Now the name is important here because we want to name it the same as what we just had. Now normally you can name it anything you want, but this way we don't have to worry about any breaking changes. So now we have a component again and the selector is still app-dashboard. So on every place that was pointing at this dashboard component before, like right here on line 4 of the routing module, it still should work just fine. Great, let's go ahead and see if this runs again. We'll do ng serve -o. It should compile it and now our dashboard should look a little bit different for us. And there it is, there's our new dashboard using a dashboard component, which has a lot of built-in features for it. Great. Now when we go to customers, maybe we want to have a list of customers in there. So we're going to use ng generate again, with @angular/material, and this schematic is going to be called material-table. And we're going to give this one a name of customer-list. So now we have a customer-list and we're going to put that inside of this customer component over here. Now let's take a look inside of this customer-list. This table's a little different because it not only has a component, but it has data source. The data source has some sample data in it, and obviously we could go off and get our own data from an HTTP server if we wanted to. But for now, let's use the customer-list HTML and look at some of the properties that is has. We're going to default it to have page size of 5 just because we only have a little bit of data, and we'll put in a page size option of 5 and 10, just so we can see the data all in one page for right now. And obviously you can change these to whatever you want them to be. Now let's go over to the customer component in the HTML, and then right in here, we're going to remove all that and we're going to replace that with app.customer-list, and now let's run this application one more time. And this time it's going to build the application and it's going to show us our dashboard, our list, which is our table, and then also our nav. So here is our customer right over here, and you can see it's got built-in functionality to go to the different pages because we've changed it to page size of 5. Ah, we could go to 10 if we want to, or we could go back to 5. So what we saw in this section was how we can use ng add to pull in other libraries, and then use schematics inside those libraries that maybe are either first-party or third-party libraries to add different features and capabilities to our applications. Before we wrap up, let's go back to our code and let's look at the Git changes one last time. There's our new components, and all the other changes that we already reviewed, and we'll just save these as angular material.
Adding Scripts, Styles, and Assets
We just learned a couple of cool things that we can do with the Angular CLI when we want to build our applications or pull in external libraries. So we can pull in scripts or styles or even our own assets if we want to, or pull in other libraries that have NgModules like angular-material. Now we learned quite a bit about building and serving this module, so let's recap some of the most important things about running builds and serving up our code. First we get a really fast development cycle with this ng serve. I like to use that with the -o option, and remember, that's not running it off the disk, that's running our build in memory. When it's time to promote our code we want to check out a production build so we can run ng build with the prod flag. And that's great because it'll put all those production ready files over into the dist folder by default. There's quite a bit that the build and serve commands do. We looked at how we can build the output to the product files in the dist folder and we looked at how we can customize our builds and our serving process. It's very important to be able to have control over how you're building things and it's good that the CLI exposes so many different flags and options to do so. We also learned how we can use ng serve to launch the code in memory up in our browser, which is great for the development lifecycle. We took a look at how we can pull in external libraries like angular-material and that we can put our own custom scripts or styles inside the process to build those as well. Now that we've learned how to build our code, it'd be good to know how to use the CLI to test it. We'll learn about that next.
Running Unit and End to End Tests
Running Tests with the Angular CLI
We all want our applications to be stable and not break when we add new code. This is where testing really helps us, and the CLI makes it easy. In this chapter, we're going to talk about how we can execute unit tests using the Angular CLI, which under the covers uses Karma to do the test running. We'll talk about how we can watch file changes with it so it automatically reruns the tests, and we'll look at a whole bunch of other options that we can use when we're testing. While unit tests are great for testing discrete units of functionality, it's really good to have end-to-end tests in our apps too. The CLI also helps us run these using Protractor. We'll explore the different options that we can use while using Protractor, and learn how we can debug both unit and end-to-end tests. Well, let's dig in.
One of the great things about the CLI is that it automatically generates some of the tests for us. We've seen that already when we generate components and services, how it automatically creates those spec files. Now it's up to us to add mores tests to those specs. But once we have them, how do we run them? Well, those unit tests are going to be testing discrete functionality for us. We'll test little pieces of each component or each function inside of a service. We need to isolate all those features when we're running under tests, and this is super important when we're trying to build an application that's of high quality and doesn't have any regressions. Okay, but how does the CLI help us? Well first, we can fall back on our good old --help command. We just type in ng test --help, or -h for the shortcut, and it will show us all the options for testing. The good news is, out of the box we can just run ng test, and it does pretty much everything we need. So we run this, we're going to test all the specs that are inside of our project. It's going to locate all those files automatically that follow this pattern. And remember, when we generate files, we automatically get the file name in convention with .spec.ts, so we're good to go there. And out of the box, it's going to watch for file changes and then test again. So if we run this in a separate terminal process, and then we go ahead and we edit in our editor, it's automatically going to pick up on the file changes when we save, and then rerun those tests. That's it, there's no magic here. It's all inside of the CLI, but seeing is believing. So let's go get some hands-on experience and run some unit tests with the CLI.
Executing Unit Tests
It's time to go back into our Angular routing application, and we're going to learn how we can execute tests using the Angular CLI. So we'll type ng test and first with --help. Now I'm going to maximize this panel so we can see a little bit more in here. These are all the different options that we can run with ng test. And by default, if we run ng test without a project name, it'll run all the projects in our application because we can have multiple projects in our workspace. We only have one right now, really, as our main core. Now I'm going to go back and put the terminal back down where it was, and now we're going to run ng test, just plain old ng test, and let it rip. So it's going to build our application once again, and then it's going to show those tests after they've executed and the status of them: either failed or passed. Now I can see we have 8 failed out of 11 tests. Now where do we get those tests from? They're automatically generated by the CLI. So I'm going to put this panel on the right-hand side, and there is a browser that opened up. We can see all the specs over here and the failures. We're looking at the failures by default. Let's first get our application in working order and we'll see how when we're running ng test over here, it's still in Terminal, how things will automatically recompile. So just for some space, I'm going to hide this side bar, and that's Command+B just to hide it, and the first one we're seeing is in the AdminComponent it's saying that router-outlet is not a known element. So let's go take a look at the AdminComponent. We'll look for spec, right there. I'm going to hide the terminal, I'm not going to kill it, I'm just going to hide it with Command+J. Now we know the AdminComponent has a router-outlet in it. So let's go check that out just to remind ourselves. Right here, there's our router-outlet. So I come back to our spec, we know that we have to tell it that this thing exists. So how do we do that? So after declarations, we type in schemas, right here, and then after schemas, we're going to put in this array, this thing called NO_ERRORS_SCHEMA. And now I notice that I'm getting some IntelliSense, and it automatically imported up on line 4. So now we're down to seven failures. We have another router-outlet in our application too, so we're probably going to run into the same one again. Now I notice here, we have the AppComponent. We'll just go one by one; it's saying app-nav is not a known element in that component. So let's go over to app.component.html, and we can see there's app-nav right there. Now we'll go to the app.component, and that's going to be a spec, and we'll go to the top of that spec, right here, it's listing out that it has an AppComponent, but are other things in there? Yes, we know that it has to declare this other object. So now, we can put here NavComponent like that, and it automatically imported up on line 4. Now we've got a new error; we don't have less failures, same failures, but we have a new error. So now we're getting errors about can't bind to 'mode' since it's not a known property of mat-sidebar. That's our material sidebar, so all these material things that we're pulling in inside of the app module, we need to go pull those in to the AppComponent if we want to test those. So, let's grab all of these, right there, BrowserAnimations down through MatSortModule. We'll go back to our component.spec and underneath the routing module, we can go through and add all those. And now it's like, wow, lots of red underlines, but now I can hit the light bulb and choose Add all missing imports. And I'll give you a tip: when you're done, use prettier to format it. Mine is set up by default when I save to do that, but another great thing to do is make sure that the import up here actually matches angular/material. Sometimes it gets a little confused in the tooling and it might put something else in there, so make sure you're getting it from the right place. Now I notice once we did that, now you're seeing 11 specs with 5 failures. AppComponent should render a title in the h1 tag. So let's go to the bottom of the AppComponent. Remember, once upon a time we had a h1 tag in there, we no longer have that. So we go back to app.component.html it's just a div with an app-nav now. So let's change the specs, it should render a title in an h1 tag. Let's just say should render a app-nav in a div, like that. It's not great English, but you know what I mean here. So we've got a div which has app-nav, and we're not looking for textContent anymore, we want it to be something like toBeDefined. We want to make sure that one passes here. Cool. So that one passes, and we can also check this by doing something like a negative, we could say toBeUndefined and this should fail this time, and it does, see? So let's put that back to toBeDefined. It's a great thing with tests to make sure that we actually have pass and fail. So now we've got CustomerListComponent should compile. Now right here, we're seeing that it's saying Can't bind to 'dataSource' in the CustomerList. Let's go to the CustomerListComponent and check out what's inside of it. This is the real one. It's got some stuff in here like the dataSource. Now remember, this is where in our CustomerListComponent, if we look at the HTML, we can see there's our customer.component and then our customer.list.component has a mat-paginator and a bunch of other things. Remember all those different things we imported in AppModule, right there? Let's go grab those and put them into our CustomerListComponent spec. So we can see it right here, we'll go up to the top, and we don't have an imports list here, but we can just add one like this, with the array, and we'll paste those in, do a quick fix. Right here with the light bulb, do Add all missing imports. And then up there it's red because it's got way too long of a line, as we can see. It went all the way over to column 219. We'll save it, and now we're down to three failures. Okay. It says 'app-customer-list' is not a known element. So our customer.component.spec has our CustomerList. So we have to go to our app, to our customer.component with our .spec right there, and then up here, this one's going to have to pull in the CustomerListComponent as a declaration. And it'll also do the automatic imports. The automatic imports are so nice in this case. And now, this one also is looking for the dataSource. So, we're going to pull in from app.module, once again, all those, and we're going to put them up at top by doing imports, like that. Paste them, and then we're going to hit the light bulb. And then all the things that this module needs for this particular component are ready to go. So now we're down to two failures. In this case, we're looking at the Dashboard. The Dashboard uses the material table. So we're going to go over to the dashboard.component.spec, we're going to put the imports there as well. And we spelled imports wrong, and then we're going to go down into it, paste it, and click light bulb, imports. Save, that should solve the dashboard, and then we're down to one: the mat-toolbar is not known in the NavComponent. So now let's go take a look at our NavComponent. It's got a bunch of mat stuff in here. For this one, we can go back into the navspec. We can see that it's got the MatNav sidebar module in this declaration. We can remove just the sidebar module right there and put in all the other ones that we had. And we could limit out to just the ones that we need, and that's probably the better course of action in this case. We still have a failure, it's saying, it can't bind to 'routerLink'. So this is because it's actually using the routing, and if we go back over into the app.component.spec, I think we're going to see a hint at the top. RouterTestingModule, right there. If we pull that in to the nav spec, we'll just take that first because we're using routing features. And now we can import it from routing testing. Notice we have a lot of options there for the routing testing, and now we have all of our green specs over here. Now, is this the best way to fix your tests by pulling in all these different modules? Probably not, there's better ways to go about doing a full-on testing. This is not the point of this course, obviously, but you can go check out the Angular testing courses at the Angular Fundamentals or the Angular First Look to learn more about testing. But for here what we're trying to do is just make sure that we import the proper things that each component needs, either by importing the modules or by declaring the components where they're needed, and then also making sure that the specs actually have a pass/fail situation where they're needed. But notice all along we get this great little window over to the left to show us what specs are working, which ones are failing, and then if we open back up our terminal down here, we can see all the specs have re-executed each time, there's all the failures. As I scroll to the bottom, you'll see the successes on the latest run. So every time we change something, let's just change this spec real quick, and let it save, you'll automatically see it rebuild, execute, and show it over on the left. Now if you didn't want all these menu items to be showing in the sidebar nav, we could change our specs around so we don't actually load all these things up, and instead we could mock them. But again, we can look at the testing course to learn more about that. This is how easy it is to test with the Angular CLI.
CLI Testing Options
We just learned how easy it is to run tests using the Angular CLI. We just typed ng test, but what about all those other options that we could use? Let's take a look at some of the more popular ones. A pretty cool feature is being able to see the code coverage. Now by default, this is turned off because it takes a little bit longer because it has to generate which code is covered by the test and which ones aren't. When it's turned on it generates this report which is pretty cool to look at. And if we're looking for speed, though, we like to keep this off. This makes it ideal to turn on occasionally when we're looking to make sure we've covered the right code pass, and we think we've covered it with our tests. We'll take a closer look at this when we do a hands-on demo. By default, we can see the progress of the test as they're compiling and running to the execution in our console output. We saw that in the previous video, but again, if we're running in a CI server, maybe we're capturing all that output and we don't actually want to capture the progress, we can turn this off. When we wanted to debug our tests, we can enable sourcemaps with --sourcemaps flag, or we can disable it to give a slight speed increase to our tests. There's also a watch flag, so we can say something like watch is true or watch is false, and this helps us with the continuous testing versus a single test cycle. Tests are going to execute after a build is executed through Karma, but if you add the watch flag, you can control whether it's going to continue watching file changes or it's going to do a single run. So you can run the single test if you want by saying ng test --watch false. This could be ideal when we want to do a single pass and maybe for a CI build. So you can turn on the single run by doing --watch false, and under the covers this is using Karma as a test runner to watch those file changes. Okay, what about that test code coverage? That was that cool flag that we could use, the flag that was --code-coverage. We can run it with ng test just like this. It's going to put a report generated in a folder called /coverage. It's going to print out a report for all the code coverage, for branches, functions, statements, and lines. But like most things in Angular CLI, this is also configurable. Inside the karma.conf.js file, we can change where that report folder is going to. Now if we just want to run this command, again, we just say ng test --code-coverage, just like this. Now that we've learned about some of these other options, let's go get some hands-on experience with them using the Angular CLI.
Let's take a closer look at how we can run some test coverage here. Now we run ng test to do the test coverage, and then I'll turn on the test coverage like this. This will still go through the compilation process and build everything out, and then it will exercise the tests, but when it's done it's going to exit inside the console. Notice that the browser blinked quickly and then it shut itself down, but it also generated something in the code coverage folder. We can see that over in Terminal by looking at the coverage, or we can see it also over here inside of Visual Studio Code. Now you notice there's an index.html there. What I'd like to do is just open that in the browser, but let's reveal that inside the finder, and then we'll just double-click on it. Here we can see our code coverage is, right now, 100%. That's because we don't really have a whole lot of code running and our tests are basically just exercising that the app is there. Well let's make a change so we can see how this works. Back inside of our code, we'll go into the user.component itself, and we'll add some logic. Now I'll make this full screen and blow it up a little bit. Let's first assume that we have a list of users that we want to track. And for now, we'll just type them as any array. We'll also make sure that we've got permission to do something. So we can set that up as a boolean, and by default let's set that to = false. And let's assume that when we're starting out, if we have permission, we're going to do something. I'll use the tooling features there to add the this. Now if we have permission, we're going to go get some users. If we don't, we're going to initialize the users to, something like an empty array. Okay. Now what are we going to do inside of here? Let's say we're calling some kind of an asynchronous function called getUsers, and that will have a then clause, which will get the users, it'll pass it back to the lambda, and we'll set this.users = users. It will also have some kind of error handling as well. Assume that our error has a kind of an e.message. We'll do a console.log e.message. Not very fancy, but just something to kind of get the point here. Now we don't have a getUsers yet. Notice that it's red right there. If we take a look, we can say add a declaration. We don't really want to do that, it's not a property. But we can come down here and say getUsers, like this, and we can take advantage of the async keyword and most recent versions of TypeScript, and we can say return an array, and for now we'll just create an object. We'll do the first name of john, and let's say we're going to send emails because you have an email blast as well that we could do in this application. We'll say email@example.com, and we'll just make a second object here, just so that we have more than one thing in our array, and we'll do colleen. Okay. So now that we have that object, it's going to come through here. Now notice our normal logic is going to run through the if path by default to say okay, we don't have this, it's false, it's going to run through this line 19. Well, what can we do here? Well first we can get rid of that boolean because we don't need that, right? It's trivial because it can implicitly figure it out. So now that we have our objects here, let's see what our code coverage looks like when we go back to the terminal, and let's run our same test again, and it will generate the code coverage. This time we should be seeing that we don't actually have full code coverage. So, coming back over in here, let's take a look at that code. Here with our code, we should be running through the path that goes through line 19. Everything from line 15 through 17 should never run, nor should the function between 24 and 27. Okay, now that it's run, let's go back into our browser. We should be able to just refresh here, and notice our users actually went down in coverage. We have statements at 73%, 11 of the 15 ran. Branches, 1 of 2. That makes sense because we had an if statement. So the else ran, but not the if. Functions 3 out of 6. And then lines, 8 out of 12. Well we can dive into there and take a look at what's going on inside that component, and again, we can see exactly what happened. Well let's make it actually run through this async command. So now let's change permission to be something like true. Now when we changed that, notice what happens over in our tests. This time it's going to run through the getUsers, so things should go up, right, because it's going to execute the getUsers and run the return statement down here. But it's not going to run line 19 now, of course, and we didn't have an error, so it's not going to exercise line 17. Let's take a look at that coverage again. This time you're going to refresh, and we notice that it did the catch here, like it registered that it was there, but it did not exercise the code inside of it. So what's cool about this is by looking at the coverage, it's not that it's great to have a 100% coverage, it's that we can exercise different branches. So we should be writing tests in this case that exercise: okay, what happens if I have permissions? What happens if I don't? And what happens if I have permissions and I cause an error? Does that line of code run? So you can see that using the code coverage can help us take a look at what lines of code are we actually exercising in our tests. And I think that it's super helpful that the CLI includes these features out of the box for our testing.
Debugging Unit Tests
Often it's really helpful to be able to run our tests and debug them on the fly. Well to do this, we can run ng test and then it will open up inside the browser, and because sourcemaps are included by default, it will make it super easy for us to debug those. Let's take a look at what happens here. It will build everything up, run the tests, execute them, and then right in the browser we can debug. So I'll go full screen with the browser here, and we can click on Debug, open a new tab. We can open our Developer Tools, and then I'll make a little bit of room here. And if we click over on Sources, and then up here we can hit Command+P, or we can just navigate down there. I'll do Command+P, and now I can type in the name of one of our components. Well, what if I can't remember them? I can do component. like this, but I happen to know that it was a users.component. So now I can go down into the code itself. So we could actually put debug points here or we could put breakpoints inside of the users.spec. Now what's cool is let's say I just put in partial names like this. Notice it's finding that there's a file that begins and ends with users.spec, so, that's helpful as well. So inside of here, we have some kind of silly tests. Right now they're not doing a whole lot. But we can exercise these there. So how do you rerun them? Well, we go back up here and refresh, and when the browser hits that line of code, it's going to debug through it, and we can run through these. We can put our breakpoint down here if we want and see what these values are going to be. And we can run right through them, we'll just hit Run. There we go. And then when it hits that other test, we can actually break on top of these. We can explore the values in the component. We can highlight this whole value, and we can do evaluate inside the console. It'll open up down here, and we can explore the whole object, and of course, we can change values as well. So if for some reason we wanted to take the component and set it = undefined, then we could then execute this and it should fail this test when we run through. Therefore, it failed. What's powerful about this when we have failing tests, we can go into here and we can actually debug and evaluate things on the fly, which will help us understand why our tests are either passing or failing.
End to End Tests
The main purpose for building our applications is usually because, well, somebody is using the application. So that's where it makes sense to have end-to-end tests. What are end-to-end tests? Good question. Well that's when we test out the application's behavior like the users would be through user interaction. It's a great way to prove out that the app is going to behave the way that user wants it to. And under the covers, the CLI is going to use Protractor with Angular. The way we learn about these different flags at the command line is to type ng e2e, and then --help. So how do I like to run with this? Well, when I run it, I usually just run ng e2e. That's going to exercise the end-to-end test. It's going to compile it, it's going to serve it, and it's going to run my test and tell me all the output. Now let's take a closer look together at how we can run end-to-end tests.
Executing End to End Tests
When we generate an application with the Angular CLI, we get a bunch of features for end-to-end testing out of the box. For example, we get this protractor.conf file, right here inside the e2e folder. And notice that it's already configured to run everything that's got an e2e-spec.ts as an extension. Now notice that all of our specs are inside of the e2e folder for our end-to-end tests, right here inside the src folder. So let's think about that. Unit tests are usually associated with testing a discrete piece of functionality. For example here, in the user.component.spec down in our src folder, under app, admin, users, this spec is side by side with our users.component because it is testing all the things inside the user.component right here. So it makes sense that they go side by side. An end-to-end test might test a whole set of features, for example, going to the application, logging in, navigating to the user screen, and then clicking a few different buttons and maybe going back to a different page. This would be a whole sequence of user interactions. Well that doesn't really associate with any particular feature, so generally end-to-end tests will sit outside the src folder, and in this case going inside of an e2e folder. Of course all that is configurable again, and we can change it if we want to. But this is how it runs out of the box, and it's really by convention. Now there's also a tsconfig file here inside of the src folder for e2e tests, and then we've got our spec and our page object right here. The test that gets generated for us goes to the page and then makes sure that the paragraph text says Welcome to angular-routing! Because that's what was generated when we created the app. Now the page object, which is the other file, that's the page and it's going to help us by basically abstracting some of the functionality like this getParagraphText here, which I can hover over and it'll jump into the page object, like this. You don't necessarily need the page object, but some people feel that it helps abstract some of the functionality out when you're running end-to-end tests. You can technically just grab the code right here, we can flip back over, and then we can replace the text here and just do it right in line. But if we did that then we'd have to come over and import all the stuff from the other page, and it's just another way to abstract things. So how you design your tests are really up to you. This is a pretty conventional practice, though. So let's go back to page object. It's looking for some CSS here, looking for an app-root, and then h1 to get that text. And then that text should equal what? Let's go back to the other page. It's going to equal Welcome to angular-routing! So let's go take a look at our app component because that's the first thing that loads. It's coming back to our source code. There's our app.component.html. Do we have an h1 that says Welcome to angular-routing? Well, there is no h1 in here. Remember, we changed our app a little bit because we're going to do that, we're developers. But we do have the navigation component that loads up. And our navigation component automatically will go and load the dashboard component by default because that's our default route when we set up routing. So let's go take a look at the dashboard component. This is what's going to load by default. And notice line number 2. There's an h1 that says Dashboard. So, if we run our end-to-end test, it should not find Welcome to angular-routing, it should fail. So let's go back under the terminal, and I'll use the embedded one. We'll type ng e2e, just like this. Now we only have this one end-to-end test right now, and generally we'll have far fewer end-to-end tests than we will unit tests because it's testing basically the whole interaction of the app. And then we can take a look at the results. Notice we had a failure, right here. Expected 'Dashboard' to equal 'Welcome to angular-routing!' We kind of expected that because we walked through it there. But let's go fix our end-to-end test to work. Now we don't want to change the code from Dashboard to something else, we want to change the spec to accommodate this. So first, here's our spec, it's getting the paragraph text, is the navigation correct? Getting paragraph text should be able to go into app-root and then h1, that's not very specific. We could say app-root and then it loads the dashboard, and then it loads an h1, but we're going to keep it like this. It should still work; it just means there's a child h1 somewhere under there. Instead, we should take out this text and put in Dashboard. Now we want to make sure it's exactly the same word, so let's put it side by side here in VS Code. I'll open up a second pane over here. We'll look at it side by side. This is Dashboard, let's go into the dashboard HTML, and there is the word Dashboard on line 2 on the right, and line 12 on the left. So now if you rerun, we should see a passing situation. So once again it'll build up the scenario, and then it'll exercise the interaction and make sure that it actually shows the word Dashboard. And here you can see that our test did indeed pass. Now if you're looking for more information about how to run end-to-end tests, there's some excellent Angular courses on testing in the Pluralsight library. But when it comes time to run your tests, the Angular CLI is right here waiting for you to make it easy.
In this chapter we learned quite a bit how we can run the tests and debug them, both unit tests and end-to-end tests with the Angular CLI. We explored how the ng test command helps us execute the unit tests, and then we can debug those tests in the browser. Then we can debug into the code, step right through it using Chrome or our favorite browser. When it comes time to run our end-to-end tests, we can execute that with the command of ng e2e, a that will exercise Protractor to run through things, and of course we can debug those as well using the different tools like the Element Explorer.
With great tooling comes great power to all of us with the Angular CLI. There's a lot of new features that were introduced in version 6 of the Angular CLI. In this module, we're going to go over a few of these features, including how you can update your version of Angular using the CLI. We'll tackle workspaces that contain multiple Angular projects, and also how to generate your own Angular libraries using the CLI tooling. Then we'll tackle how you can add libraries to Angular with ease. And we'll take a look at a new tool called the Angular console which gives us a visual representation of the CLI and more.
Perhaps one of the most important things we can do while maintaining our applications is to keep our project versions up to date. This helps us not only with maintainability, but also performance and patching for security issues. But keeping a project current with important updates isn't always easy, but it should be. With ng update we can take our existing Angular application and we can update it with new versions and new dependency versions as well. So we run this ng update command and it adopts the current versions of Angular. It also updates the third-party libraries using the schematics built into it. So we can transform a project from working with a version like Angular 5 to version 6. Now of course we can always start out with the help flag. So we can run ng update --help, and we'll see a bunch of options that we can use. When updating our Angular app we simply start out with this command, ng update. Now ng update by itself will just tell you what options there are. So we can list those options if we want to. Where are they? We can just run ng update and do --help as well. And we can update a project with ng update, the name of our package that we want to update, and then the options. Some of the common options that we can run here are --dryRun, we still get that. It lets us do a run through without making changes. I highly recommend using this option before you do any ng update. In fact, before you run it without --dryRun, I would always commit all of your Git changes or make a new branch. The --all option basically tells Angular CLI to update all the packages in package.json. Sometimes there might be dependency mismatches, they might be incompatible with each other, and then the CLI will tell you that when you run ng update. If you know that you want to do it anyway, you can use --force and it will force all the updates. And again, always use a fresh branch or commit all your changes first so you can try these things out before upgrading your project. Now let's try it ourselves.
Running ng update
There's a great Angular update guide that the Angular team created at update.angular.io. Here we can punch in the Angular version we are on, like 5.2, and then the one we want to get to, like 6.0, and then we can choose our package manager and say show me how to update. Come down here and we can then follow the steps, and some of these are manual changes you want to make to your code. But then down here we can see the ng update command, and they can walk us through what we want to do. First, we want to make sure we're on the latest version of the global version of Angular CLI. So let's go back to our terminal, and I'm in a folder that has no Angular project, and I'm going to type ng -v to see what version of the CLI I have right now. Here I have version 1.7.2, that's an older version that would generate a project with 5.2 of Angular. And let's go into a folder called ng5 and we'll run the same command, and now we can see an Angular 5 project, right here it says Angular 5.2.11, and it's using Angular CLI 1.7.4 locally. So we can see we're using older stuff all around. Now the first step over here says let's go ahead and upgrade our global version of Angular. Let's do that right now. So we're updating our global version to the most recent version of the Angular CLI. After that, it's recommending that we update our local version here in this package to the most recent version as well. So we'll run that command here inside this folder. And then after that we're then going to use those newer versions of the Angular CLI to update. So we're going to run ng update @angular/cli. We'll copy this command. And now we'll run this inside of our project. And it's telling us your global version is greater than your local. So in this case the local version is going to be used. All right. We had a bunch of messages here, but let's go open up our code and see what actually happened. So our ng5 project had a bunch of dependencies in here that were a version 5 before, and the Angular CLI was also like 1.7. something. Now let's go over and look at the Git changes. Notice the Git changes here, and I'll turn off the inline view and go over to side-by-side so we can see it a little bit better this way. Everything was 5.2 and moved over to 6.14. Even RxJS and zone.js got upgraded. And, very importantly, the Angular CLI got upgraded from 1.73 to 6.1. So everything seems to have gotten taken care of for us, which is really nice, and even TypeScript down at the bottom. This is a huge advantage of using ng update. It helps us go through our projects and make sure that we have the right dependencies in our project. Now that we have a proper version of Angular CLI there, let's go run ng update by itself. We're going to deviate a little from the instructions and just see what it has to say. When we run ng update by itself, it tells you what's going on with your project. It says it's in good working order. Now we do ng -v, and we can see it's running a modern version of the Angular CLI and of Angular. We're going to run ng update @angular/cli one more time, and the reason for this is we still have the older version of the angular.json file. The one that was .angular-clijson, right there. Notice it's removing that and creating a new one. It's going to read all the configuration and translate it to the new schema format. Now this isn't in the instructions over in the update guide. I'm telling it here because it doesn't happen the first time you run through this. Notice we didn't get that file updated the first time. The first time we ran through this it updated using the older version of the Angular CLI, so that way we had to run this command twice. The first time we ran ng update @angular/cli it upgraded the CLI locally to version 6.something, and the second time it fixed our angular.json file. Let's take a look at that file. Now we've got a bunch of other changes. Notice this file is gone, and now this file replaces it. We also got other files like the karma.conf, that got updated. So did our tsconfig, our tslint, and our spec.json file. So let's take a look at the rest of the changes here. They also want you to update your version of the Angular framework package to 6 with RxJS. Now these ones specifically, we don't have to do it anymore because everything else has been updated, but we can run through this if you wanted to, and then you could also update Angular material if you were using it, this project is not. And then when you're done the way you know if it's all good is you run ng update, and then you also run your application, right, and you run your unit tests and your end-to-end tests. If you happen to be using old versions of RxJS, there's a way for you to upgrade and migrate those too, and that's really nice. And you can run these commands at the bottom of your page, and it'll also take care of those for you. So let's see if our application runs. We'll go back into this terminal this time, and we'll run ng serve -o. And it should build our project, and it's no longer Angular 5, you know the folder and the name of it is ng5, but it should be working, and there we go.
Updating Our Demo
Now let's go back to our Angular routing project and open it up inside of our editor. And we'll take a look at the package.json to see we have Angular version 6.1 and the CLI 6.1.2. Now let's open up our terminal. I'm going to use the embedded one here. You could also use the external terminal, just we can see things as they are happening. I'm going to run the command ng update without any parameters. Now we know we're running the most current version of the Angular CLI that's available at this time. But notice that it's telling us that some of these versions need to be upgraded. Now we could try to run ng update all, that's what this command at the bottom is telling us to do them all at the same time. And normally that's what I would do. But let's take it one at a time. First, let's run ng update cli, and we'll make this a little bit bigger. And we'll also show the CLI in line 32. Now let's run this command. Now we notice that the version changed up here. If we go to the Git changes we can see package.json, that version changed and that was the only change in that file. Now if we go back to the top, we can see the commands here, we'll run ng update @angular/core, and then @angular/material. So let's go back to the bottom, we'll run that command for core. We should see further changes happening. In this case notice it's changing all the versions to 6.1.4 from 6.1.2 pretty consistently. It also changed our version of TypeScript. So let's take a look at the package.json once again, and this time I'll hide the terminal and I'll go back to side-by-side for comparison. Notice all of our versions changed to 6.1.4 for Angular, and then TypeScript bumped up as well. Now there's one other command that we wanted to run. And if we don't want to scroll we can just run ng update once again, it'll tell us what that command is. We have to remember that it was the @angular/material one, and it also shows us that. So now we can run @angular/material, and it will update the versions for that as well. What it's doing is it's looking at the schematics for these different packages, in this case material, to see what would I have to do to go from this version to that version. So now go back to our package.json. We can take a look in here side by side and @angular/material and the SDK also bumped up their version. And now to make sure there's nothing else to change, we can run ng update one more time just to say is Angular going to tell us is anything else out of order. Nope, everything is in good order here. Now that we've upgraded, we can run ng serve -o, or just ng s o, and let's take a look and see if our application runs. And there it is. So this time we upgraded our current project from a 6.1.2, I believe, or 6.1.0, up to 6.1.5, which means you can not only update in between major versions, but also you can do minors or patches in some cases.
Starting with version 6 of the CLI, we now support for workspaces containing multiple projects. You could have multiple applications or libraries in there. So we can have multiple projects in one workspace. If you want to visualize this you can open up the angular.json file. That schema now supports this multiple projects inside the one workspace. That's why we saw so many different changes when we did ng update. So now we have a project, which is really a workspace, which contains multiple sub-projects. This is great for keeping separation, and you can build test, serve, many or just one of these. So how does it work? Well, you target your workspace. So when we run ng build, by default that's going to build all the projects in the workspace. We've been running that all along in this course because we only really had one project. The most recent was the Angular routing project. Now if we had multiple projects in our workspace, we could say ng build, then the project name. So if we added other libraries and projects to our workspace, we could just build the Angular routing project by saying ng build angular-routing. There's other commands too that support this syntax. So ng build, ng serve, ng tests, ng e2e, we can all run these with a project target. For example, I could say ng build my-app and it's only going to build a project in my workspace that matches my-app. Let's take this for a spin.
Let's go to a new folder and we'll generate a new project, and we'll call this our home project. And we'll let it run through its normal install. Now once it's done we'll go into that folder, we'll open it up inside of VS Code, and we can see our project here. There's our app and there's our app component, and there is our home project. Now notice all the Git changes are already committed because that's a brand-new project. If we look inside of our angular.json file, we should see a structure here which says projects. So right here on line 5 there's all of our projects, the default project is home. We only have one right now, and then notice there's a node underneath projects called home, right there. There's also a home-e2e because that's a project to itself that matches this home project. So now let's go back to our terminal over here and now run ng generate --help. Notice there's a bunch of things we can generate, one of which is application. So you say ng generate, or just g, application. And let's say we want to have a second project inside of this project. So home is like our home app, but maybe we have a sub app that we want to run other places too. Maybe it's like a help area. So we'll run this application, and notice it was a lot quicker. That's because it's updating and then creating the files, but it's already got all the package.json stuff that it needs. So let's take a look at the Git changes that it caused, there were 24 of them. And the key one to look at is going to be angular.json. Now instead of watching in the Git changes, let's just go look at it here. Notice you have projects once again, there's home, home-e2e, and then there's help-area now, and help-area-e2e. The default is still home. So it defined these in this schema. Now let's look outside of our File Explorer. Notice the src folder here and projects. Src has our home app in it, and projects has the help area inside of it. So it's got its own src folder. Now what if we want to build one or the other? Let's go ahead and just close that down, and we'll use the terminal inside of VS Code we can see what's happening. Pay special attention to the folder structure over here as I do an ng build command. This time we're going to build, and we're going to say build just the help area. And when we run this we should see a dist folder open up over on the left once it's built and pull all files in there, we learned that previously in this course, but what will be inside of there? Notice there's a subfolder called help-area with its built files, but there is nothing for the home project. So now we could run ng build home for the root project as well, just like this, and it will build that project and put all the contents inside of dist home. And there we have it. And if you run the command without a project it will default to the default project for you. We can also run other commands like ng lint with a project. Notice we've got this project here. If you're curious which ones have this, you can always run the command --help to find them. Just run ng serve to see the same syntax. Now while this is helpful for multiple projects in a workspace, it's even more helpful for creating your own libraries. We'll take a look at that next.
One of the most exciting new features in the Angular CLI starting with version 6 is that we can generate libraries for our project workspaces. So we can create and build our own libraries with Angular. To see what options we have, we can use the good old --help once again. So we can type in ng generate library --help to see the options; we'll do that in just a moment. And when we generate our own Angular library, we can then type in ng generate, or g, library, and then the name of your library, like my-lib. We can also pass in some options. The CLI is going to go ahead and update our tsconfig to look for our library reference. This is really important. Without that we wouldn't be able to build it. And then every time we change any code in our library, because our application should be referencing it, we must build the library first before the app can see it. So we go ahead and build the library saying ng build, then the name of the project, my-lib, and that will build the library for us. We can run this with --prod if we need to. Some of the most common options here are --dryRun. We can see what's going to happen when we generate a library. We can change the entry file if we want to to create the library's public API file. By default that's going to be the public_api.ts. We can tell it to skip creating package.json dependencies, don't add them to that, or skip the tsconfig if we have something a little bit more involved that we want to do ourselves. So how do we use a library once we create this? That's a great question, and it's really important to follow these steps. The way that the Angular CLI will find libraries is first when you do an import statement it's going to look inside the tsconfig paths, and then the node_modules folder, which means if you don't build it, it's not going to find it. So we have to say ng build, the name of our library, and then probably --prod if we want to get a production build to test it out. If not, we can use a dev build like this. And then in our app we would say import, for example, logger from my-lib, and logger could be some kind of thing that we're using inside of there, it could be a class, it could be a service, it could be a component. So the big tips here are always rebuild our libraries after we make changes, and we also have to keep our public API file current. We'll take a look at that when we do some hands-on here a moment. Once we have completed our library, we might want to package it up and send it to npm. To do that, first we'd want to build our library with the production flag, absolutely production if we're going to push it up to a package manager. And then we're going to go into the folder where we built the library. In this case by default would be cd dist/, name of your lib. Then we'll run npm publish. If you're not familiar with publishing to npm, or even if you are, check it out here at this link and you can learn more about how to do that. So remember, always build your library for production and then you publish it to npm. Now let's go walk through doing this ourselves.
Creating a Logger Library
Let's go into our Angular routing project, make sure everything's committed, and we're going to add a library of our own called my-lib that has a logging service. Now in here first we're going to write ng generate, and then library --help. Of course spelling these words right helps. Now notice we have a bunch of options that we can run, but we're going to pay attention to how it says the usage appears ng generate library, then the name of the library. So we're going to do that. Ng, g for short, library, my-lib, just like this. And we're going to let it create that. Now a bunch of Git changes are going to happen up here on the left. Let's make the terminal a little smaller so we can see some of our code. If you come over here we can see that we've got a tsconfig change. This is important because it's adding the paths for my lib so we can see it in our main project. And in angular.json we have a new my-lib project. Pretty much what we expected. And then under projects we have my-lib right here. Now by default we've got these different files. We've got a component, a module, and a service. We'll take a quick look at those. Here's the module, which is declaring our component, there's our component, which is just a basic one, and then service, which doesn't have any features yet. We also see our public API is exporting all three of those files. Now let's say that we wanted to add a logging service. We can now use our ng generate again, but this time it's not going to be library, we're going to generate a service, which is ng gs, or ng generate service, we'll call this our logger. Now we want to tell it where we're going to put it. So if we do --help and kind of get an idea how it's going to work. So looking at this again, and I'll maximize the panel so we can see it all, here we can see one of the options is project name. So, instead of doing --help we'll do --project my-lib. So we're telling it to generate a service called logger in the project called my-lib. Everything worked, it generated both. And if we're not sure we could always put -d at the end for --dryRun. Now I'm going to get rid of that maximize panel, we'll come back up into my-lib, under the lib, and there it is. And here's our logger service. Let's give it a method. Looking for a log method. And we'll go to parameter of message, which will be a string. And we'll simply just do a console.log message. Obviously we'd probably want to do something a little bit more complex or involved here, but we're just going to try to test this out. Now let's go ahead and try to use this. And let's say we'll just put it inside of our app component. We want it to use that service that we created that logger service. So a common mistake that we might make is we open the constructor and we try to inject this and we say logger, and it's going to be LoggerService, just like that, and it's trying to automatically import it here, that's not where we want it from actually. Because you don't want to have a hard reference. When it's done we want to reference it from my-lib. Now that's the mistake we made right here. My-lib, it can't find it. Why? Because we have not built it. So it's let's do ng build my-lib. And we're going to do it with --prod, because when it's actually up in npm, which is probably where we're going to put this, it will be built for production. So when we did, that under dist we can see my-lib is now up here with all different kinds of bundles that we'll need. Now notice my-lib now works. Now LoggerService is not working. So we have problem number two, it has no exported member logger service. Remember up in the projects, we have this public API. This file here needs to have another export, and this one should be logger.service, just like that. So let's rebuild it one more time, and before we do let's go to app component, so we'll rebuild with production. Remember any time we make a change to our library we need to rebuild. So now we rebuild it and notice the little red lines are coming and going and there's my-lib. There's LoggerService, and it says it has no export member. And sometimes when this happens you just kind of go off and on you press Save. Now it still telling us that it's right over here. One way to fix that is to close the file and then go back into the app components, and our red line goes away. So now when we serve our application, it's going to build our project, and it's already referencing through my-lib on line 2 here the built project for my lib. So our main project here, the Angular routing, is going to crank up and I think the way we've got it configured here is app component when it kicks off is just kind of log a console message, not too exciting. Let's take a look. Now over in the console we can see hello angular. If I refresh just to show you that it's happening, there's our message. If we want to change this, we could say instead of hello angular we could say hello world. Let it rebuild, when it comes back over there is hello world. So the big key is to make sure that not only do we generate the files in the right place in my-lib, like right here, we give some kind of a public API, in this case logger.service log, but we also update the public API to yes. Now I expect that the CLI commands will change a little bit in how it generates this. It may generate different code in the future where it's not giving you a default service component like this, or maybe it's automatically going to add the logger service. So keep an eye on these, but the components here of what we're trying to do, pun intended, is still the same. We want to make sure that we have the public API file that we're using all set up and exporting everything, and we want to make sure that we have the files in the right place. And most importantly, we want to make sure that we build the library before we try to import it, and make sure you import it like this. Do not try to use a straight up path because then you're not using the build files. Now when we npm publish this my-lib, the code here in your app doesn't change at all. And that's how we create a library.
Adding to Angular
Sometimes we just want to add other features to our application, other capabilities that may be third-party libraries have created, or someone else's library in our own team. We can do that through ng add, and then the name of the package. This will add all the new capabilities that are in that package to your application. It'll also add the dependencies using different schematics that that package had set up for us. And then it configures any changes for the new capabilities that we need, maybe transforming some of our code. If you want to see an example of this, we went through this in the module called Building and Serving where we added Angular material to our application. And the ng add feature was introduced with Angular CLI version 6.
There's a tool called the Angular console that was created to help give a visual interface and add a few extra features to what the Angular CLI does. This Angular console is a nice UI written with Electron and it does everything the CLI can do, but it gives it a visual experience and allows you to do things like discover and install extensions. It also has integrated terminal output. This tool is in collaboration with the Angular team and a company who created it called Narwhal. You can download the Angular console right here from this link. Let's go take a look at it. Let's go to angularconsole.com, and here we can see that we can download it by clicking this button. I'm going to choose Download for Mac, and here you can see it's downloading. If you scroll through what they're showing you here, this is what the visual interface will look like. It's not meant to replace the CLI, but to augment it. It's very powerful to use the CLI, but sometimes we want a visual interface, and this could be a great entryway for people to use the CLI who maybe aren't as comfortable or used to, or just don't like using the terminal. Plus, it's going to add extra features like discovering other extensions. Now that it's there, you can install it. I've installed mine already, so let's go take a look. Here's our Angular routing project. Let's take a look at what it would look like inside of the Angular console. So in the Angular console when you open it up, we can look at recent projects, create a new one or import an existing one. Here I've navigated to my folder where I put angular-routing. When I click on that I can then import it. Now I notice it sees the application, the end-to-end tests, and my library. So I could then build my library if I wanted to, right here, and you can see the output of that is running. You can tell it to run it for production if we want to, and click on Run. Now it's building the package, and down below you can see my other project was still running in the background. We're going to cancel that for just a moment because we have two things running. But it built my Angular package and everything should be good right here. Now notice there's other fields we could click on. We can expand this and we can see the project name, tsconfig, other options that we could set if we wanted to. Let's go back, and now we can see for angular-routing we've got our projects, code generation if you have any schematics, and then here we've got our tasks that we can run. And then if there's any extensions that we can run we can look through here. For example, we can see that @angular-material detected that it was installed already. If you wanted to make this a PWA we could install that as well. And some of these things are first party, meaning they come from Angular, and others are third party. So you can imagine that this list will only grow. So going back to our project, we could test it, run it, build it, and we can open it up right inside of VS Code or Finder right from here. Now let's say we wanted to go look at our recent projects. So we can click on Recent or we can create a new project with Create. So here first we'll create a parent directory, and I chose play, set name for my workspace, we're going to call this my-console, and then the schematic we're going to choose, it's going to be the default Angular CLI workspace schematic. Narwhal's also given us their own schematic in here, and we could probably add others in the future. So now we can hit Create and it's going to run ng new my-console. And this is the default schematic right there that it's showing us, and it's going to generate and create this new project for us. Now we can cancel it if we want to, and I'm going to maximize this to full screen so we can see everything that's happening. It's running out to npm and grabbing everything and building our project. And once it completes, now we have my console application here. And then we can click on Serve if we wanted to. And we can set any fields you want like watch, we could turn that on or off. We can turn aot on or off and any other optional fields. And they broke it up as important and optional in here. I expect the UI may change a little bit, but this is the idea behind it. And if you don't want to look at the commands you can hide it or you can show it. And to get back we can come out of here and go back to our main page. So the Angular console is just another way we can interact with the CLI and do a couple additional things like look for other kinds of libraries that we can add in.
This module we learned about the different tooling features that the Angular CLI provides. We first took a walk down how we can update Angular from major versions or minor or patches. This is great for keeping our code up to date and current, especially since we don't have to do a whole lot, Angular does all the heavy lifting for us. We learned how the workspaces work so we can have multiple projects inside of the same Angular workspace. And the CLI helps us generate these and keep them up to date. We took a look at how we can generate an Angular library when we created the logging service that we used. And of course, remembering the tips to always build your libraries that you're importing into your main application, and updating the public API file to make sure that we're actually being able to use those and import them. We explored how we can add libraries to Angular, and we took a look at a tool called Angular console, which builds on top of the CLI and adds some additional features in a visual interface. There's a tremendous amount of power and flexibility and ease of use in the Angular CLI. And now you know how to use it. I hope you enjoyed this course. I'm John Papa. Thanks for watching.
John Papa is a Principal Developer Advocate with Microsoft and an alumnus of the Google Developer Expert, Microsoft Regional Director, and MVP programs.
Updated31 Aug 2018