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.
Start CourseBookmarkAdd to Channel
Table of contents
It can be challenging to create modern web applications that follow best practices and that are optimized for deployment. 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 author of the Official Angular Style Guide, and I'm very excited to share this course with you. This course gently introduces how to install the CLI and then 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 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 and 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 when you 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 talking 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 re-imagine 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 perform as 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 did 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 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 in the documentation about components. We can 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 in ng ---help, and it will show us all the different commands for the different features. And if we want to learn more about the ng serve commands, we can 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, that'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 has 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 the network traffic, and we'll browse the localhost 4200, and on the right-hand side we can see a bunch of different files that came across. 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 of 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 an optimized 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 is 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 do node -v at the command line, and you might see something like this 6.9.1. Well, the Angular CLI supports any version of Node 6.9 or higher currently. To be sure, always check the Angular CLI website.
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 what we want. This 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 the successful installation, we'll want to run this command, ng -v. Ng is the command line tool itself and -v is the version of it. By doing this, we should see some kind of a response, like here's the Angular CLI using ASCII art, and then we'll see the version of the CLI, and our version of node, and our operating system. 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
Well, let's begin, and we'll open up a terminal or command prompt, and the first thing we want to do is pull down the CLI. So we can type in npm install, or for short just npm i, and we do -g for global, @angular/cli. And 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 may take anywhere from a few seconds to a few minutes, based upon the Wi-Fi connection, the speed of your hard drive and computer, and how busy npm is at the time. Once we have that there, we can verify it with another command. Let's go ahead and type in the command here for npm list -g @angular/cli. We're going to list all of the global packages named angular/cli on our machine, and we're going to use ---depth=0, because we just want to see the name of it. If you don't put that depth flag in there, it's going to show us every dependency, kind of what we listed above. So we're going to run that, and it's going to look locally on our machine to see, do I have this thing called the Angular CLI, and it's using npm to verify this. And as we can see, it did install properly. So now that once we have that, we wanted to make sure that we ran ng -v. That is the command to see do we have the Angular CLI running. Ng is the CLI itself, so we're running that, with -v to verify the version. 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 machine.
Generating and Exploring a New App
Now that we have the CLI, let's make sure we can generate an application. Inside the terminal, let's make sure that we 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. We're going to run ng, that's the CLI, the command new, to create a new app, and we're going to call it ngtest, and then I'm going to give it a flag of ---skip-install. This flag is going to tell the CLI not to run out to npm and install everything to your local machine. It'll give us the quickest and fastest installation of a new app. So we can run that, and you can see how quickly it created all the files. Now you can see the actual files it created right here. Now let's go into that folder, we'll cd into it by doing cd ngtest, and then we can list the files out with ls, 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 like that, and I have a shortcut on my machine called c, which will open up Visual Studio Code and the current folder. Once I have that, we can see over here on the left-hand side all the files. We'll get rid of the welcome message, and we're going to use the command plus to make that 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 a json file, we'll learn all about these. There's an editorconfig so we can set up our spacing, like 2 for indent_size or 4, whatever you happen to like. There's a gitignore file so it's ready for Git. We also have a karma.conf file for unit testing. Then there's our package.json which shows us everything we need to do for npm to go get the packages. There's an end-to-end protractor.conf file, we have a README, we have our TypeScript configuration file which is ready to go out of the gate, and we have a TypeScript linting file ready to go. And then here's our source code, which has got our basic files getting ready. We have our index.html, that's what we're going to launch. The main.ts is the entry point to the application. And then inside the app folder we can see the other files, and I'll make it slightly smaller so we can see a little bit more here. 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 as a great starting point just to make sure that you can actually generate an app. Notice there is no node modules folder yet. That's because we didn't run the npm install. In the package.json there are some package dependencies right here, and those will change based on the version that you're using. And if you want to run the npm install after the fact, if you ran the skip-install, you could go back to your terminal and run npm i, or npm install, either way, i is just an alias of install, and then it will actually install all of those packages for you. We're not going to run npm install 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 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 an app, just so we can explore what we get. And once we get that code, we can open it up in our favorite editor, like Sublime, or Atom, WebStorm, or even Visual Studio Code. In this module, we learned how to run node -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 globally on the machine, 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 the CLI gives us a project. Finally, I really encourage that you look at these two main Angular CLI websites. First there's the main CLI website, that's cli.angular.io, and there's also a jumping off point from that website to 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.
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, and 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. Now there are some nice features in the CLI that we can use that will help us check out 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. And 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 of the files that it's going to create, but not actually create them. This is nice for 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 those other flags that we can get to. So we can run ng new ---help. so the ---help flag will report out all 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 to our root and we'll create a new folder. I can make a directory here called angular-play. Now angular-play is going to be a place that we're going to create a bunch of projects and try some things out, so it's nice to kind of get it off of the root, and then don't forget to cd into that folder, and then there's nothing in there, awesome. Now we're going to run ng new, and we can start out with my-app, like we did in the slides just previously and we can see what happens, but first let's run it with the dry-run flag. Now when you're running flags like this, spelled out, the convention is two dashes that will prefix the flag. So you'll see two dashes, and then dry-run is the flag. Now when I run that, it'll show us all the filenames that it's going to create. Notice there's a warning up top first saying, okay, you specified the dry-run flag, so none of these will actually be written, and it's going to give us a couple of files, like an editorconfig and a README, and you can see the structure of the basic things that are in there. We get a single Angular component and its associated files right here. We also get an application module, and then we get some environmental files as well for using it in prod or dev builds, and we get some basic stuff like a favicon and a main.ts file which will kick things off, a style.css, that _____ for the whole application, and then there's a couple other files here at the bottom. We'll learn more about a lot of these as we move forward, like the tsconfig.app.json, which is for the TypeScript project for our application, and then there's a different TypeScript configuration for all of our tests. And then there's a bunch of other files that we're going to take a closer look at. But now that it looks pretty good, like I know what I'm going to get there, let's run this without the dry-run flag, but instead with the skip-install. I want to generate the files, this is one step further, but I don't actually want to run npm install yet. So now we're going to generate the app with skip-install. Same speed basically, now we'll open up the files inside of my favorite editor, that's Visual Studio Code, and then over here in my-app we can start exploring. First let's look at the package.json. It's always good to start here, because this kind of tells you what are you getting. So out-of-the-box, we've got a couple of scripts that we can run, notice we can run "start". The convention here is a script in a package.json, and you can run npm followed by "start", and it will run this command, "ng serve", which as you might imagine, is going to serve the application. Same thing with npm "test" or other commands here. And then we have our "dependencies". Notice that right now we're using Angular with 2.4, and that's the carrot, which means that it'll get anything larger than 2.4.0, including 2.4.0, all the up until, and stopping before, 3. So basically that carrot says, get me anything that changes in these last two numbers. And then there's "devDependencies" down here as well. You'll notice the CLI itself is one of the devDependencies, so it can be used to help generate other files, and serve the project, and do builds, and other cool things. Now let's say we didn't want to use 2.4. Let's close Visual Studio Code here, and I'm going to go here now and look at the my-app folder, and I'm going to remove the entire folder. You can do that through the command line or you can do that through Finder or Windows Explorer. So I just got rid of that folder and it's completely gone. Now, let's run that same command again, ng new my-app ---skip-install, but this time let's run it with ---ng4. Now at the time of recording this, Angular 4.0 is in release candidate, so they're putting a flag in the CLI to say if you want to generate with the version 4, use this flag. Once it's been released, you won't need this flag anymore, but this will be the convention that they use as new versions come out, like Angular version 5. So now we're generating this, let's go back into the folder and then we'll open it back up and let's look at the package manager. Now let's notice the dependencies are slightly different. They're looking at anything that's 4.0 beta, all the way up through, but not including 5. So this is a great way that we can get different versions of Angular by cranking up a new project.
Angular CLI JSON File
Alright, now that we looked at the package json, let's go ahead and look at another file in here which might have caught your eye, .angular-cli.json. This is the Angular CLI's JSON file, it's a configuration file. Notice up top it already set the project name to "my-app". We told it to do that when we generated the project. Now there's a bunch of defaults that the CLI will use. Like, where's your code stored, in the "src" folder, what is your output directory going to be when you build it, "dist", what are the assets that you want to get included and served, those are going to be these assets in the assets folder and this favicon.ico file. So we get that icon, and we get anything in the assets folders, which by default, is nothing. Where's your index.html going to be? What's the first file at the entry point of the application? That's main.ts. Are there any polyfills for you BroadcastReceiver? They're located here. And then there's some testing information, there's your TypeScript configuration file. Now here's a really interesting one, your "prefix". Let's say I'm going to create an application, and that application is going to be a customer app or a sales app. This prefix is what's used to prefix all of your components and directives. So, for example, if we look over at the app component that was created here, you'll notice the selector is called 'app-root'. We may not want it to be app for all these prefixes, we might want it to be sales, for example, or our company name, like acme, So something we could do is go inside of the angular.json file, and we can just edit this and call it something like acme, and that would be the prefix of any newly-generated files. Now that doesn't help with the ones that were already generated, so how do you do that? How do you make sure it's automatically creating the selector that you want? Well, one way is you can go over here and we can change this over to acme, but another way is we can set it with a command line flag. For example, if we go back to the terminal here, and let's go back out one level, and we'll create a new project here. Let's run a command here, we'll call it my-app2, and not only are we going to skip the install, but we're also going to say set the prefix, and that prefix is going to be, we'll call it acme. Now we're going to generate that, and we'll go into that folder, and I told you we're going to create a couple of different folders here, and we'll look at that in Visual Studio code, and now if we look in the JSON file we're going to see down here for the prefix it's "acme" on line 20. And if we go look at the app.component, now we can see that the selector is acme, so that's a great way at the beginning of the application when you're generating it to set that prefix right out of the gate, and that's a common thing that you'll do. You may notice, as well, that we're getting a spec over here. What if we don't want specs in our project, well, there's flags for that too. Let's close these down, and let's go ahead and go back and generate another project. This time, we're going to call this one my-app3, we'll keep the prefix in there, and we'll make this my-app3, we'll do a prefix, and we'll put in here ---skip-tests. So we know that it's going to be dash-dash, and then it's skip-tests. So this time when it generates things there will be no spec files. Now we can go in and say, alright, go into my-app3, we'll open it back up in an editor, and if we look over here, we can see we've got the app.component and the html and the css, but there is no spec file. Now I recommend having tests, because everything is ready to go out of the gate, but this is one way you can do that. So there's other settings we can do too. Now we mentioned that there was an ng ---help, let's take a look at that. There's quite a bit in here. I'm going to go full-screen with the terminal so we can read through them all and scroll back up. There's things like ng build and stuff, but we're looking at ng new, so what if _____ we search for was ng new. We can just search for that in the terminal and find it, and now we can see things like the dry run. You're also seeing the ng4 flag, which exists now, skip-install we've learned about. You can also skip-git. So this tells us that by default it's false, meaning that if you don't specify this you're going to have git in the project, which means it's going to set and initialize a git repo, locally on your machine, of course. You can skip the tests, you can change the directory that it's created in, by default it puts it in the name of the project. And you can also specify things like the style, or maybe you don't want styles to be created in our own file or templates, which is my preference, I like to do that, where they are in separate files, but if you want to change that to do that in line, you can actually set this as well. So let's change another setting and generate another project. Right now we're in app3. Let's go back out again, and now let's take that command that we had, and we'll do app4. We're generating quite a few here, aren't we? So we're going to do the prefix of acme, and we'll come through and we'll do style, this time we want sass. Let's give it a shot, we'll go back into my-app4, we'll open it up inside a code, and now if we look at the source code in here, we can see that we're getting sass files. And not only are the files given the sass extension, but the Webpack build system that's being used under the covers is ready to go, knowing that we're using sass, so it's going to compile it for us, and that's pretty cool. Even like the overall styles are going to be sass down here, and if we look inside the CLI for json, we're going to find there's the style sass, and then at the bottom the defaults that we're going to be using. So by setting this up at the project level, and putting this in the CLI's json file, now when I generate new files, I don't have to keep telling it I'm using sass every single time. This way everything across the project will just default to sass. That's pretty cool. One last setting I want to share, because I think it's pretty awesome, is one called routing. Now sometimes we want to generate a project, and it's going to take advantage of routing features. so to do that we'll create my-app5, and routing usually has a lot of little stuff that goes along with it. so what does that mean? It means you've got a routing module, you've got to add the routing modules and import them in from Angular, you've got to set some things up in your app. What if you don't really remember what all the steps are? well, one thing you can do is go check out one of my other courses and learn how to do that. Or, you could use the CLI and say, you know what, I want it to do it for me. So let's do that. My-app5, we'll go in and we'll go into my-app5 here, we'll open that up inside of an editor. Now let's take a look at some of the differences. Right out of the gate, we notice we've got an extra file here called app-routing.module. We'll take a look at that, and it gives us the basic routing file here. It's got some empty routes up here because it doesn't know which routes we want to add yet. And then it pulls in the different imports and exports. It also went to the app module, and it pulled in the appRoutingModule that we created on line 6, and it added it to the import statements on line 17. So it's connecting the dots for us, and when it comes time to add components and route to those, there's actually commands for those as well. So one thing that's really kind of nice to do right up front is, when you're creating your project, to make sure you know what settings you want to use in your project before you generate all of these, so you can use the proper commands. And I like to tell people, you'll notice that we used commands like the dry-run here, or the skip-install because that'll help you kind of see, what are you going to get when you start going down this road before you actually start committing and pushing everything up into your git repo. It's a great way to check things out. Don't worry, hard drive space is pretty cheap here. We can check things out, go back, and we created five different aps here, and it was a great way to play it, and then we can delete those if we want, and then generate a new one.
Common App Generation Flags
We just saw how we can generate a new application by using some of the different flags like style sass. We could set that to be css, sass, less, this supports all the major options. We also saw some other flags, like the prefix where we can change the prefix for our components or directives. And then there was skip-git, which will not initialize the to git project. And we also did skip-test to remove the specs from the project when we generate files. Now one of my favorites is to add routing to the project, which will add the routing modules and other features to do routing and support that in the project. Obviously we can combine many of these flags together, and it's quite common to do so. And if you do this at app generation time, with the ng new command, and set all these different flags, a lot of these are stored inside the configuration file, .angular-cli.json. So how do I like to do it? Well, my biggest tip for you would be when you're generating one to set up the things that you want to use. So I like to add routing, that's pretty common. I set my prefix up, and I don't choose ma, but I choose something that's really relevant for my project, like if it's a sales app I use sales or s, something short. And then I define my style scheme, maybe I'll use sass or css. And then I use the dry-run flag as well, and that's really important because I want to make sure I'm getting what I want first, and then once I'm ready I remove that dry-run flag so I can actually generate the application. Now let's generate an app using our custom settings, and see if it serves. We're back inside of our Angular-play folder, and we're going to generate another application. We'll do ng new, and this time we'll call it my-app7, just because we like to skip around. And then we'll do routing, we're going to add that to the app. I want to tell it to use sass, so we'll do that. And then I want to set my prefix up, so let's say I'm going to use the prefix of jp for John Papa. Now I'm going to add the dry-run first, take in my own tip, and we can see here what gets created. And we'll notice that the files being generated are sass files. We also can see the app-routing module. Great, so next step is let's go ahead and take off the dry-run, and we're not going to run the skip-install either, we're going to let it generate the project, the files, and it's going to run through and run npm install as well. So now it's going out to the internet, and it's going to find everything that it needs for Angular, and it's going to install it. Let's give it a moment to do that. Great, now that it's generated that, let's go into the my-app folder with my-app7, and let's list out the files. The first thing we should notice is because you ran the npm install there's a node_modules folder right there. Now let's open it up, take a look at the project inside of our favorite editor. Right over here, we can see there's our node_modules. There's Angular and all the different pieces of Angular, and we can see we've got our routing module inside the app folder. But does it run? Let's find out. Alright, so if I come up here we can type in ng serve, and I like to do -o. I'm only doing one dash here, because this is an alias for open. Now I want to serve the project and open it inside of a browser. So it's doing a build in memory, and we'll learn about how this works later, and then once that build is up and running, it'll actually launch it in the browser. And here it is in the browser, it says jp works. Let's actually look over here on the console and make sure there's no error message as well, and let's refresh it just to make sure everybody knows that it's here, it's running through. And one of the cool things is, if I go back over here, and let's go inside of the app.component.html, and we'll put it side by side, and we can see a lot of things on our screen at once now. Here we've got the dev tools open in case there's any errors so we can see those, we'll clear that out. It says jp works. Let's go inside the AppComponent file, and we'll look inside the ts, and notice this 'jp works', and we'll write of course at the end of it. And then as soon as we save that file it's already building in memory and launches on the right-hand side. Eureka! It all works.
Configuring the Angular CLI
We've learned how we can configure and customize things with 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 edit the .angular-cli.json file, which is actually pretty cool in some editors, because the schema is associated with it, so you get some intellisense and automcomplete. But there's another way to. We can do ng set and then the property and its value. So from the command line we can change the values of the CLI right form the command line. So here's an example of what might be inside of a CLI file. Here we can set the prefix by doing ng new prefix ma, and we could set the default like we did with ng new with style sass, or we can combine those in one line and change both of those. But what about the ng set technique? Here we can use ng set and indicate the property where it is in the json file. And if we want, we can set this inside a global file. There is a .angular-cli.json file for your entire machine for you. In my mac it's been in my user's home folder. Now it doesn't exist until we actually add something to it, but we could do that for things like saying, I always want to use sass, I'm just a sass kind of person. So I could say ng set defaults.styleExt sass, and then add the -g on there to make it global if I want to. So if you want everybody in your project, on your team, in your company, to use the same settings, you can actually create a file like this, set all these defaults, and then distribute this JSON file. Now remember, it doesn't go inside your project folder, this one goes inside your home folder. And just by adding a global flag, it'll get put inside to that file which is more global. Without the -g, it gets put in the angular-cli.json file that's in your project.
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 ---help. This will give us help specifically on that command, and that's super helpful because it shows us some cool things that we can do. Like I like to run ng lint with a format of stylish. It actually color codes the output so it makes it easier for me to read. And then we can also do ng lint ---fix to automatically correct any automatically fixable problems. So those are kind of cool things to do too. Before I run the ng lint ---fix, though, which also works in some editors by just doing automatically fix with TypeScript, I like to make sure I've committed all of my changes or at least stashed them, so then I can run the fix and then see what those fixes actually were. It's kind of a great way to learn about how things can work. Let's take a quick look at a demo on how to do that. We'll flip back over to our code and to our terminal, and inside that terminal, we can see we're still in my-app7, we stop the project, let's first run ng lint on the project, and that should tell us if there's any problems. Well out of the gate it would be kind of weird if the CLI generated a problem for us, so there's none there right now, but let's go ahead and make some problems. We're going to remove a semi-colon up here, and notice my editor is already telling me I've got an issue, it's missing a semi-colon, and let's go ahead and create something like letnum = 7, and we'll make sure that we've got a semi-colon there. And this time it's telling us, hey, 'num' is never actually reassigned, use 'const' instead. So now let's rerun ng lint, and by doing that we should see these issues appear. And you can see them right there, 'num' is never reassigned and a missing semicolon. Now something else we could do is run that _____ the format of stylish. Now when we run this, we can see it's a little bit color coded, it makes it a little bit easier to read. Now what if we also wanted to do the ng lint with the fix? So first, let's go ahead over here, and let's just commit these changes, and let's go back, and we'll do ng lint ---fix. And now it's going to tell us what those errors were, and that it tried to fix them. So it shows the output again, and now if we come back over here we can see that the semi-colon is there, and it put const up here. If we look at that inside of a git change, now we can see what those changes actually were. So that's kind of a cool feature right built into the CLI.
We just learned how we can generate applications using the difficult flags with the CLI. It helps us customize the things that we need. And we learned how we can 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 file 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. And 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 onto 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. At 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 the 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 those blueprints with the Angular CLI to generate components. I love things that help me code faster, and one of those things with 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 we can also use c as an alias or shortcut for a component blueprint. So we could rewrite this simply by 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 common ones. For example, some of the options that we can put onto these blueprints are things like flat. So a ---flat will decide do we put the 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 html 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 it. Likewise, we can also define the styles to be inline, or we can say -is. You can see those aliases are really helpful, especially when the options are much longer. Do we want to create test files or the spec files? If we 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 we'd like to take advantage of things like view encapsulation inside of the component, we can turn that on with ---view-encapsulation, and then set the strategy, or we can do -ve. Similarly, we can use change-detection and set that up in the component too, and there we have an alias of -cd for there. So we could add on to the component, say -ve, and then set the view-encapsulation strategy to something like emulated, and then -cd 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 do an alias of -d. 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 easier to type and move faster. Let's take a look at how these aliases can really help us. Here are two common ways that we can generate components. Here is one where it's just a pet component, and then the other where it's a pet component without the html and css files. So the first one, we're going to generate the html, the spec, the css, or sass for using that, and a component for our files, inside of its own folder. The second one, we're only going to create the spec in the ts file, because the html and the css are going to be inside of the component. That's a lot to type though. Now let's take a look at how that would work with an alias. And, well, 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. Let's take a look at some commands that are very commonly used too. So here we're creating 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 stick the pet component and all of its associated files in it. Instead, it'll still create the same files, just not in their own pet folder, that's the flat option. Or, we could also add in inline-templates. We discussed this earlier, that's where we don't put the template in its own file, instead we put it inline in the TypeScript file. Same thing with inline-styles. We can put the styles right inside the component's ts file. We can change the prefix if we want to from the default, just for this component. And another option is to turn off the specs. So if we combined all of these here, we would actually only create one file, the TypeScript file, because the spec would not be created, and both the templates and the styles would be inline. Some people choose this as their main option. I happen to like all those files being separate. So it's really up to you, and what's great about this is you get to choose based upon your team's preferences. 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 other blueprints along the way.
Let's go ahead and generate a couple of these blueprints, starting with one of the components. First, we'll have to generate a new project. We'll do ng new, and this time we'll do angular-hello. This is going to be our new project, and we're going to ng4 so we can make sure we get the latest version, and we're going to let install the npm packages as well, so this might take a moment. As it's doing this, let's think about what we want to generate once we have this project. The first thing I'd like to do is make sure it actually runs and serves, so we'll try that. But after that, we'd also like to make sure our project can generate components, and some services, and some other features, and then also serve those up and make sure we can lint them and everything is A-Okay. Now that we have our project, we'll make sure we go into that folder and go to hello. And I'll clear my screen up there, and we can come up and look and see what's there. We can see we've got all of our files in the node_modules folder. I like to make sure it can serve, so we do ng serve -o, that's an alias to open it inside of a browser. And let's take a look at what that looks like. Here's the application running in the browser, we'll put it side by side here. And we can see we've got the app works, and on the right-hand side we've got our terminal running with it. Now if we let it keep running, we can go ahead and open this up inside of one of our tools like Visual Studio Code, and then we can take a look at the files that are in here. So, for example, we can go into the app.component.html, just to make sure this works, and we can type in something like John at the top. It should save, and we should automatically see john app works, right there. Great, we'll get rid of John, not for reals. Okay, so now we're back over here and we want to generate some more components. How might we do that? Well, let's go ahead and back to our terminal, and in here we're going to say ng g, again I'm in a second terminal pane, c for component, and we'll name this thing customer, and we'll just let it run with the dry-run flag first. So this is what it would generate for us. So it didn't actually write them out, but we've got our customer component with the module. Now let's go ahead and do that, say we want to have one here, and we'll call it customer, and by default, that's going to create our component for us, and it's recompiling the application on the left, and you might have just seen it blink for a minute. Nothing visually change, but we were able to add that in there. Now if we go back to our Visual Studio Code, inside of app we should have a customer folder with those four files. Let's see what it gives us. So looking at it here, the command on the right generated those four files, and you can see we've got our template file and our styles, which would be linked over into the css file here, and then also our html for our template, and we also get a spec out-of-the-box. We'll look at how testing works in a future chapter. Let's assume that we want to create another component here, and this time instead of calling it customer it's going to be an orders component. And maybe on that orders component we want to use a couple of the other options that we have. Now I still want it to be in its own folder, and I don't want inline templates or style, so I'll leave those alone, but maybe I want to have view-encapsulation. So I can type in view-encapsulation, make sure you spell that right, and then we can put our strategy there, like Emulated, and that would define the view-encapsulation for us. Alternatively, if you're like me, you like the aliases, and we can type in -ve Emulated, and then maybe we might change the detection strategy to be OnPush. So now when we generate that, we should see another component appear over here, this time in the orders folder. Now we take a look at that orders.component, and we can see in here that we indeed have the same stuff, except it has also imported the proper symbols for ChangeDetection and ViewEncapsulation, and it set them up to use the strategies of Emulated and OnPush for us, which is pretty cool.
Declaring a Component in an NgModule
Now we not only created the components, but notice it also said that we updated the app module. Let's take a look inside of Visual Studio Code to see what that means. If we go to app.module, because it said it made a change to that file, we would be able to see what that change was. Now we happen to know right here that with the CustomerComponent and the OrdersComponent were both imported in on line 7 and 8, and then also declared as part of lines 13 and 14. 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 dry-run, another technique we can use to see what changed is to use SOURCE CONTROL. Here we can notice that, we can see if we look on there, right, using the git control up here, and we can see that line 10 had changed to add in these lines, AppComponent, CustomerComponent, and OrdersComponent, as opposed to just the AppComponent. 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 were. So that's just another technique that you can use in addition to using the dry-run. Now, this technique is a little more advantageous sometimes because dry-run will tell you what change, as far as files whether they were created or updated, but it won't necessarily tell you what lines of code, whereas this technique, by using source control, will tell you 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.
Now let's take a look at how we can generate some other blueprints as well. So we'll flip back over to the Visual Studio Code just to see what those code changes are, and I'm going to commit these for now, there are my new components, and I like to commit them just so I can see what those changes will be as I continue generating more code. Now let's go ahead and generate a directive, ng g, and then it's going to be d for directive, and let's say we've got a directive for some kind of a search box, so we'll call it search-box. Now if we run that right out of the box, with dry-run we can see the files that will get created, there is a spec and a directive, and we'll update the app.module as probably the declaration. Let's go ahead and do that, and then we should see over here on the left what those changes were. There's two new files, there's our spec and our directive, and then we also get the app.module, which, once again, we can see the change it declared that new directive for us, pretty cool. Now notice that the directive, if we go back into Visual Studio Code, and let's close the windows and just look at the file view right here, we can see that there's customers and orders, but our directive is flat, it's in its root folder right inside the app. If we didn't want that to be flat, we can create search-box2 briefly here, and we say --flat, and we say false, then we're going to get it in a folder. Now just because I don't want to generate this, I'm going to put d for dry-run there. We should see the output on the right, and notice we're getting a folder called search-box2, and then the search-box directives are inside there, but it's still updating the root app.module. And, again, this is a nice feature of the dry-run. We didn't necessarily want to generate this, but it shows us kind of where that file is going to go and what it's going to be named, which ones will be created, and which files will be updated.
We'll commit our changes one more time here, and that was for our directive, and now let's add a service. Maybe we need to get a service for getting sales information. So we can say ng g, and we can type service or just s, which is our alias, and let's call this our sales-data service. We'll do -d to see the dry-run, and here we can see it's creating the service and a spec. Now we can take the dry-run flag off of there, and what's nice is it's creating those two services, and it's warning us that the service has been created but not provided. Now, when we learn Angular, we learn that services have to be provided somewhere in the application, so it's giving us a hint about that. So back over in our project, even though we have the new service here, our sales-data service, we're probably going to need to go and import that somewhere and provide it. One place to do that could be the app.module down here in providers, which once we do that we can use our tooling to say, okay, what do we do with that information. We can either type in the import at the top, or in some tools, like Visual Studio Code, we get these quick fixes where it can automatically import for us, and it's going up into the sales-data.service. Now if you happen to be using single or double quotes there, we can also quick-fix right there, and we get our single quotes. So sometimes the tool cannot tell us exactly where we need to provide things, and in those cases you're going to see warnings here, whereas with components it actually put them in the declaration, as it did with directives, but with the provider we might want to provide it in a component or we might want to provide it in a module, and it's really up to us and our implementation. What if you know exactly where you want to put this? Well, in that case, let's try creating another service here called sales-data2, and on this one we can choose the option for module to tell it which module to go into. Now, we can say please provide it in app.module, so we can type in app.module, and now we can pull this out. And notice now that it's actually going to pull in and update the app.module.ts, and it provided it down there for us, so we have a couple of different options here for how we handle providing services. Before we continue, let's go ahead and commit both of these services for now, and then we'll move on.
Generating Classes, Interfaces, and Enums
Let's say we wanted to create a folder where we could put things like models. We can do mkdir models, that's one way of going about it, or we could use ng, and then generate, and then a class, maybe this is where the classes are going to go, and we can say models, and then the name of this class, let's just say it's going to be customer. Now by doing that, we can do -d just to make sure it's going to do what we think, notice it's going to create a file called customer.ts inside of a models folder which doesn't exist yet, but we want it to exist, so now it's able to go ahead and create the folder for us. Now here's our customer class, which is very simple, it's just a plain TypeScript class, and now we have a models folder. So that's pretty cool, it can dive right down into the structure. This is also great for creating interfaces to, so we can do ng g i, and then we can go right inside the models folder again if we want and create a person interface right there. So now we can see that there's a second file in there, one for customer and now one for a person, awesome. Now what if we want to create an enumeration as well? We can do ng g e, or enum, enum is not too much to type, and then we can type in models again, if that's where we want to put those, and maybe this is going to be something like gender. So we do that, and now we've got our enum created inside of this 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.
We can also use a blueprint for creating a pipe, so we can do ng g pipe, or just p, and maybe we want an init-caps pipe that we want to create. I'll use the -d again just to see what that looks like, it creates a pipe, a spec, right in the root, and then we can update and declare that in the app.module. Now I kind of like my pipes to go in their own folder, so let's create a folder in here, maybe we've got a shared folder, that's fine, and now if we do that we can see it puts it in a shared folder, and it still declares it in the closest module. Well let's go ahead and remove the dry-run, and we'll write this pipe, and we should see it appear over here in shared folder. And there it is, there's our pipe, and there's our spec for it. Now, it should also have updated the app.module, so let's go down to app.module, and we can see it in the declaration section on line 20, and up here in line 12. If we wanted it to go to another module, we can also use the -m flag again to specify which module to put it in.
Now let's take all the changes we've made and let's commit those, so we have some pipes and models, and now let's close the windows 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 its own module for something called the login area. So we can do ng generate, and then module, or just m for short, and we can create a login module. Now one of the options here is to do dry-run again so we can see what file we created. Modules, by default, get their own folder. Now once we create that module, we can also do other things like tell it, do you want a spec or not. Now unlike components and services which automatically get specs by default, modules don't, so if you want a spec for that one you're going to have to do spec true. So if I do that with a -d, you're going to see down here the spec will get created. Now I don't usually create specs for my modules, but you can if you want to. But let's say we wanted to create this module, so let's go ahead and write it this time. So we've got ng generate the module called login, and now we can see that it's right here. And there is an ng module, and it's pulling in the common module for imports by default, and you can add or change or remove anything you want from here. Now let's say that we wanted to have something else in there, like a component. Well, let's clear the screen and try adding a component called login into that login module. Now, we can type in component login, and just do a dry-run real quick to see what it would do. It's going to put it in the right folder, but notice that it's going to update app.module. Well, if I want to declare login in the login module, what I need to do is do -m, for that alias for module, and this is where it's going to be put, and I just say login/login.module, because it's in that subfolder. Now I'm using dry-run again here just to see the difference. Now notice the two update statements. The first one was going to put it declared inside the app.module file. Th second one is going to put it declared in the login/login. module. That's where I want it. So I'm going to remove the dry-run now, and then I'll go ahead and install this, and notice on the left that login module was open, and it did indeed import it on line 3 and declare it on line 9, and we can see that our component exists right here. Now once we create a module, we have to decide on how they're all going to be linked together as well. So back in the app.module, you'll notice down here the module is not being imported, so we're in app.module and maybe we want to import the login module right here. It's not doing that automatically, so we could go type that code in ourselves. So we could type that in right here. We could just go down and we can import, and we know that that's going to be located in the login folder, and it's called login.module, and then we're going to import the LoginModule like that, and then we're also going to change this using the auto-fix, which we can click on our little light-bulb over here to use single quotes. Now we've imported that module, and then we can pull it down in here inside the import statements, and voila, there we go.
Configuration and Resources for Out-of-the-Box Blueprints
We just learned a whole bunch of the out-of-the-box blueprints that we can create different files with using the Angular CLI. Let's start with the directive. We can write a search directive, ng d, or directive. We can also create a service with ng service, or 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. And when you create the directives or the components of the pipes, it'll automatically declare them in the closest ng module it can find. And for services it'll warn us that we have to provide it somewhere, unless we use that -m flag to tell it which module to put it in. What about a plain old TypeScript class? No problem. 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 a subfolder we want to put them in. We can also create an interface with TypeScripts, maybe use ng g i, or we can create an enum like gender, ng g e, or enum. And then we learned about what we need to do when we create a new module. So there's blueprints for that as well. Use ng generate module, then put the options on there. Now by default you're not going to get a spec with modules, and we can direct the Angular CLI that this module should contain a routing module as well. We'll see that very soon. But what we showed was how we could do ng generate module, maybe sales, and we can use the aliases here, again, ng g m, then sales. And if we do want the spec, we have to tell it in this particular case. Of course, we could always set up configuration to do that too. So all these options allow us to customize how the module is created. Okay, so a lot of times we're creating a lot of flags, and maybe we don't always want to put those flags in for all these generation commands, so here's another tip. Set these project wide settings that we've been talking about. For example, if you always want your components to be in a flat folder, not to go in a subfolder, you can set ng set defaults.component.flat true. You can also do the same thing for directives if you want to. You can set either flat true or flat false, and then you're good to go so you don't have to keep specifying those flags. Also, if you want to use sass again, we could set something like this up where we set the styleExt to sass. The key here is to use whatever your team is most comfortable with. Why is this important? Well, maybe you disagree with what the defaults are out-of-the-box with the Angular CLI. This is how the Angular CLI lets us customize these things, and it stores them in that .angular-cli.json file. And if you ever just need a little bit of help with what these flags are, always lean on that ng ---help flag. It really comes in handy. Now let's take a step back and look at what we learned about generating code with blueprints. There's a whole bunch of out-of-the-box blueprints that we used. We learned about components, and classes, and interfaces, and services, and a bunch of the options that we can use on them all. We also mentioned how we should always lean on that ng ---help, and the docs, because they'll help us navigate as flags are 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 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 generate component. And I'm also a big fan of practicing with the dry-run option, or -d. It's super helpful for just taking a quick look to say, you know, I'm not sure what this is going to generate, let me just see real quick first, and then I can remove that dry-run flag. And finally, check with your team and figure out what are our standards and practices going to be, and then customize those project-wide settings and distribute them with your project. In the next chapter, we'll learn a whole lot more about how we can generate modules with routing considerations as well.
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 you 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 back to our angular-play folder and generate a new project that's going to be an ng4 project, and it's going to contain routing right out of the gate. so first we'll use ng new, which we learned about previously, and we'll name this project angular-routing, and I want this to contain Angular 4, which once Angular 4 is officially released you won't need this flag, and I want to specify the option for routing. I want to make sure that routing module is there right from the get-go. Now because I like to practice, we're going to use the -d. So this shows us here on the third line of the create that we're getting an app-routing module. We're also getting our regular app.module a couple of lines further down. Okay, now that we know that's what we want to get, let's go ahead and run that command again, but this time without the dry run. Once it installs, let's go ahead and cd into the folder, angular-routing, and let's open up inside of our favorite editor. I happen to like Visual Studio Code here. And I always like to take a look at the package.json to make sure I got the right versions of Angular, which I do in this case. And now let's also take a look at the source folder, because we wanted to see the routing module. So inside of app we've got this app.module, that's our main module, and notice on line 6 it's importing app-routing.module from this other file. So we can go ahead and we can get a preview of what it looks like right here, and we can click right on it to go into that file, and here we can see that we've got a routing module file which contains an empty route by default. Now also notice back in the previous file, not only did it pull in the AppRoutingModule, but the AppRoutingModule also contains routing information. Notice that we've got the Forms and the Browser and the HttpModule that's being imported here in our main ng module. If we go in the app-routing.module we're importing the RouterModule up top, and then into this NgModule right here. So all the routing module feature are pulled into this AppRoutingModule, which is then imported into our main module, thus giving us routing in the application. But don't believe me, let's make sure it actually works. Let's do ng serve -o, and our application should launch, and open up in the browser, and not have any problems. And here we can see the app works. I also like to make sure that I check the dev tools and look to make sure there's no console warning issues, and I'll just refresh and make sure, and we're good to go. Now our app is running, but we're not actually taking advantage of the routing because we don't have any place to route to yet, really. So let's go ahead and open a second tab up here in the terminal, and we'll go back into code, and we can see we've got this routing.module and our main app.component, right here. Now all the routing is going to go into this router outlet. It's nice that it created that for us as well, because we told it we wanted routing features. Now let's generate two different components, one called a dashboard and one called customer. So we're going to do ng g component, like that, and the first one is going to be dashboard, and we'll also run the same command, but this time we'll run it for customer. So now we've got two other components that we can get to. And just for now, let's go inside the dashboard and we'll take a look at the html file. There's our template, it shows the dashboard works, and the same thing over here for customer, customer works. But how do we get to those? Well, we can create routes for them. Let's go inside the app-routing.module, we'll go full-screen there, and we can enter the path for these different routes. Now I like to put all these on the same line, so we're going to do that here. We'll leave the default route there for a moment, and we're going to create another route down here, and we're going to tell it, okay, when you see the path of, let's say, dashboard, I want you to load the component that's going to be the dashboard component. And some of the tools, like Visual Studio Code, with modern typescript, if we just command dot, we can import the dashboard component from this other file. Now that's exactly what we could have typed ourselves up here, and then we can switch over to just single quotes, but this time we're just taking advantage of the tooling. When we see dashboard as a route, it's going to load the DashboardComponent inside of the router outlet that we saw over inside app.component.html. Now by default I wanted to load the dashboard too, so when we see this empty path, I don't really want it to go to children, instead I'm going to tell it, hey, let's make the pathMatch equal 'full', and I want it to redirect to where? Dashboard. Now let's make one more path here, and that's the CustomerComponent. So here we can say CustomerComponent, and we can take advantage of the quick-fix again, if we'd like, right here, which we'll do, and then I can fix those single quotes up top, or if you like you can type that out yourselves. So now we've made our app-routing.module aware of our different paths and which components should be loaded. But we made a very important assumption here as well, and that's when we have the DashboardComponent and the CustomerComponent, somebody has to declare them in an Angular app. Notice they're not declared here in the routing module. Are they declared down in our app.module? Why, yes they are. That's because when we did the generation of these component earlier, it put them in the nearest non-routing module to declare them. So that's pretty cool, very helpful for us so we don't forget to do that. Now it's all great to have these different places to route to, but we have to have something we can click on to actually get there. So let's go back to our app.component.html, and right above the router outlet, which is basically the X marks the spot for where those different components are going to load, let's create a little navigation menu. So I'll create a nav, and inside there we'll create a ul, which has got two li's. Now if we do that with the _____ syntax tax in Visual Studio Code and hit tab, and we actually get two of these. Now inside of here I want to create an anchor and that anchor is going to have an href of space, and I'm going to use the routerLink, and we're going to set that equal to the path of dashboard. And, of course, we want to make sure that we put something in that menu, so we're going to call it Dashboard here, just like that. So now we have an anchor, and we click on it and it's going to use the routerLink syntax to go to the dashboard path, and it's going to say Dashboard. Now I'm going to repeat that line, and this time I'm going to copy and paste and I'm going to go to the Customer. Now these have to match what those paths are, the Dashboard or the Customer, so let's go make sure that's the case. And we can see these side by side, here you get Dashboard, that's that path, and the Customer for the other path. Now, if everything has worked okay, and I have auto-save on inside my Visual Studio Code so all the files are saved, I should be able to go back here, this thing is still running, and if I look inside my tool I can see Dashboard and Customer, and by default it's already on Dashboard. I can go to Customer, and that works too, and back to dashboard. What happens if I go to just slash? We're back on Dashboard again. Now what's really cool about this is that the Angular CLI makes it a lot easier to add routing to your application. Remember when we created that routing module from scratch it added this app-routing.module file, which put all the boilerplate in for using routing. And then all we had to do was go and add our components, hook up the paths, and then put a little bit of the logic in for the template to route back and forth, and we were good to go. And things that I always forget, like making sure I actually have the AppRoutingModule being imported in, and then also making sure I've got a router-outlet inside my component, those things kind of just get taken care of for us. Now let's make sure that we commit these changes. We'll go into the source control here, because we want to make sure we saved off this project. In 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 up a new tab, and let's go to this URL, angular2-first-look.azurewebsites.net. Now when we go there there's a bunch of samples there, and I'm going to search for the word routing. If you go down to sample number 25, 26, 27, 28, that's all of our routing examples. Now if we take a look at VIEW SAMPLE on sample number 25, and these are the examples from my course on Angular2 First Look, they'll show us how we can route between Characters and Vehicles, right there. And you notice some similarities. Here is our app-routing.module, we just got different paths in it, and then we have an app.module which imports the app-routing.module, and then here's our components for vehicle and characters. Okay, but what happens if we want to have other modules as well? Well, if we go down to example 27, we can see eagerly loaded routes. Here we have a very similar example, at least from all appearances it seems to work the same, Characters and Vehicles, but now the app-routing.module doesn't have as many routs in it, and the reason for this is that the vehicles don't actually just contain components, it contains an entire module. It's got a vehicles.module here, and a vehicles module contains routing for the vehicles list and the vehicle, by the id, the point here being that routing can get more complex as we add more modules to the application. So how can we use the Angular CLI to help us get to a point like this. Alright, let's close those examples down, and we'll come back into our terminal. One side may be running, and if not, just take ngserve -o, and let's add a new module for an admin area of our application. So we're going to say ng generate, a module, we're going to call it admin. Now we want it to have routing, so we want this admin area to have things in it that may be very sensitive only for administrators. So first we're going to make sure that we have routing that we can get to these different pages in here. So let's do that with a -d first just to make sure we know what we're getting. We're going to get an admin folder with an admin module and an admin routing module, that sounds perfect. Let's go ahead and take off the dry run and we'll let it run through here. Now we should see the application over here still functioning, we can still get the dashboard and customer, and if we open up Visual Studio Code we should see a few new files, right there. In our source control we can see the admin.module and then the admin-routing.module, perfect. Now inside of there we want to create an admin component, and we'll add a new component here, ng g c and then it's going to be admin. So that'll be the main component that we route to, and then inside of there we're going to have two other components. Inside the admin area we may want to manage a list of users, and we may want to have another page or component that handles email-blasts out to our customers. So we'll say ng g c, and then we can do email-blast, and that can be one component that we create. Now where's that going to be placed? Well, first of all we can tell it to go inside the admin module just by doing a folder, like this. And if we do that, because it's in the admin module, we'll actually place it inside that folder, and notice that it's actually going to put the email-blast declared in the admin-module.ts file. Right there it updated it. We can verify that by doing it right here. Now we can do the same thing for our users list. So both of those components are now declared in the proper place. We'll take a quick look, here's our admin module, and it's got its own routing module, which we'll set the routes up for, and this admin module right here needs to get pulled back into our main app module. So that's one thing we have to do ourselves right now. So we're going to go back to the app.module, and down in the imports, right above the AppRoutingModule that we have that's in the root, we're going to add in our AdminModule. And we haven't imported it yet, but again, we can use our quick-fix here to help it import that line of code, and we'll use it again over here to make it single quotes. So now that admin module, which if we click on that is going to dive into here, that sets up our routing, it declares our different components. We can go to our AdminRoutingModule and we can set up our routes to get there. So inside of our route array we'll create an object here, and we'll set the path up. When somebody tries to go to admin that's where they should come, and by default when they go to a component that should go to our AdminComponent. Now, again, we haven't imported that so we use the quick-fix to import it automatically. I'll come up here, and I like to use single quotes, but we don't want to stop _____ the AdminComponent. Inside the AdminComponent, which really is just another router-outlet, we want to stick in the users or the email-blasts. We'll take a quick look at that AdminComponent to see it, and we can see it's going to the admin.component.html for its template, it just shows admin works! right now. We want to change that to have a router-outlet, perfect. Back inside of our admin-routing.module, we told it we want it to go to the AdminComponent, but it's going to have children. Yep, congratulate it, these children here are going to go to our two sub-routes, one for users and one for email-blast. Now we can define what those paths will look like. So, by default, if we want, we can have it go right to the users path and the component we'll tell it to go to is the UserComponent. And we'll take advantage of our quick-fix _____ the import up top, and then we'll duplicate this line real quick, and then the other path is going to go to email-blast. We'll just make it go 'blast', and that'll be EmailBlast. And we'll use the quick-fix once again, and then up top here we'll change both of these to use single quotes. You can do Fix all. Now notice, all we've had to really do is add our own components, which we're using the generator for, and then we just define our paths ourselves. So now, if we go back and look at what we did, we have terminal over here still running our application. If you're not, you can actually stop it here and rerun ng serve -o and that should launch it back up inside of our browser once it builds. So our application seems to be running, but we didn't add any menus links to click on. Now we know we have an admin area, and if we go to admin/blast, we should see our email-blast, and we can see that works right there. If we also just type in admin, that should also work. And we could add links right here for the nav too. Let's take one last look at Visual Studio Code and show the get changes that we've made in here. Now it seems like there's a lot of them, and there are because we added a couple of different components, and every time we add a component, which we added three, we added four different files. So down here we had the user component, which we just generated that, and pretty much left it alone. It's got a test, it's got a simple template, and some css. Same thing with email-blast. The real magic happened when we generated the module, because that module got generated and it created this AdminRoutingModule as well. So we pulled that in, we just defined our paths, and our components pulled them in. And when we generated the components, remember, it declared those for us inside of the module that was closest to it. So which one was closest to these guys? If we look back in the Explorer, we can see users and email-blast are both closest to admin.module, so that's where they got declared. And now how does that get pulled back into the main app? This AdminModule is something we had to import back in the app.module. 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 CLI to put in that boilerplate code for us, and then we just wrote in the custom code that we needed to make it 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 of 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 in 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 could call an auth guard if we wanted 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 wanted 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 just use ---routing option, and that's going to generate the app, the module, and a routing module. And if we want to create sub-modules in our application, other ng modules, when we do that we can use the ng m for generating a module, here we name an 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 user's 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 connecting all the dots for us. Then we just add our routing paths and or 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 Lifecyle. 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 as fast as we can get it. And then all the builds that we're going to generate are going to use bundling, so we'll put them into bundles or WebPack likes to call them chunks. And for production builds we want some extra stuff to happen, and some of those things are uglification, 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, and that's a good thing, because that's less code that gets transmitted to the client and it doesn't have to be parsed there. Now a great place to start with ng build, because there's so many options, is the ng build ---help. That's going to show us all the different kind of things that the build can do. We'll start off by looking at how we do development build, 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 those, 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 specified in the angular-cli.json file, which happens to be dist in our case, so that's where we'll go look for the actual outputted files. And once we generate that, we're going to see a bunch of files in that output folder, the dist folder. First, we'll see an inline bundle, that's the WebPack runtime, and our application is going to need that to basically load off our modules and put everything together for us. Then there will be our main.bundle. The main.bundle is, well, our code, it's all the code that we write. 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 that we pull in the packages. And we'll take a look at these different files, and we'll also explore the source of these. There's a tool that I like to use that allows us to look at the source maps 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, who's code is in which bundle, and did it just bring the files and the code over that I'm actually using. So it would be nice to get a look at that, and this tool here called the source-map-explorer is easy to use. We just run these commands. The top one we do first to install the tool and then after we install that tool we just run this line right here, which will go ahead and run the source-map-explorer on our bundle, and we can then see all the dependencies. 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
Let's go back into our angular-routing application that we made, and we'll add a couple more of those links to the other menus that we needed to get to. For example, we know if we went to admin, we want it to go right to Admin Users, we'll just kind of make the menu very, very obvious, and the other one was Admin and then it was an email-blast, so we'll go ahead and set that route up to be Admin Blast, like that. Now let's go ahead and run the application with ng serve -o, and we should be able to use those menu items to get to those other places too, like Admin and Admin Blast. There is the Users, and there is our Blast, great. and the Dashboard still works, and so does the Customer. So it's not an exciting application, but it's one that we can use to try to build some things out with. Alright, now we're going to open up a second tab again, and I'm going to leave the project running for now. But what if we wanted to build this? I mean, right now, if we do an ls, we can see there is no dist folder. Now why am I talking about the dist folder? If we go back over into the project and we open up the angular-cli.json file, which is right there, we can see all these different settings, and one of these is the outDir on line 9, it shows the "dist" folder. That's where it's actually going to build things. So let's go ahead and just run ng build, and this should fill up a build inside of that dist folder. So we'll go over here, and we'll kind of watch things happen a little bit. I'll close down the files and we'll just look, and eventually we should see a dist folder up here, and we do. And it also tells us over on the right-hand side that the time took almost 7 seconds. Now we talked about what those different files and those bundles are that the build created. Let's take a look at those. There's a favicon, and there's our index.html. If I format this, you'll see a couple things in here. It put in five different scripts. Those are the five scripts we can see over on the left. The inline bundle is the WebPack code, and then the main.bundle, well, that's our code. Notice here on line 213 we can see our EmailBlastComponent. That's not the way we wrote the code, but this code has been built, and it's going to be working with WebPack to load it. Then there's our polyfills, our styles, and then our vendor.bundle, which is where angular is at this time. So let's close those down a little bit, and now let's run the application, and we'll do this and we'll do this full screen for a moment. Now we're serving, remember, in the other terminal, so let's take a look at the Network tab. When we're serving this, we can see the different files that are coming across. Notice we've got our inline.bundle, our polyfills, styles, vendor, and main, those are the different files that came through. Now a couple things might jump out at you right away. First of all, that vendor.bundle is pretty big, that's 2.5MB. Remember, this is a dev build, it's completely unoptimized at this point, it's just the first thing we've tried to run. Now our code isn't too big, right? It's 23KB, but we can get that down too. And you might be wondering something else. We didn't have anything in the dist folder, so how is this being served? Remember, when I first ran the serve over here, there was nothing in that dist folder. That's because what's happened in here is WebPack is serving everything in memory. It did an in-memory build and serves it in the browser so you can run it. So then what's going on with this dist folder, like all the files that are in there, what is going on with them? They're not being used for this serve process yet, right? Well, it's just showing us what those files are so we can go explore those too. Let's step back for a moment, because this is important. We ran the ng build, and it put everything into the dist folder, but we know that we can serve in-memory, so we don't actually need to build to do the serve, because the serving will do that in memory for us, and we can see in the browser. But, what we're seeing out of the ng build isn't optimized, and we definitely need to get that sized down. So first, let's go ahead and take a look at what's in that folder. We're going to install another package here. We're on npm install, or i, and it's called source-map-explorer with dashes in between those words. So we're going to run source-map-explorer and we're going to do save-dev. This is going to go out and pull out this exploring tool into our local developer dependencies inside of our package. Now once we have this tool, we can run it and run it against one of our bundles. Now the easiest way to run this right now is to use a long typing cycle, we're going to run node_modules. Inside of there, there is a .bin folder which has a source-map-explorer executable, and we're going to say space, run that against the dist, and then I want to see the main bundle that's in there. Now when I do that, it's going to open up a picture in the browser. Now here we can see all the different files in our app. In that particular file, we can see we've got 9.42 KB for that file, and then what's inside of it, what's making up the meat of it? Notice we've got 12% of that is this app.module.ts, and that makes sense because we have a lot of things in that module. And then we created a bunch of very small components, like the user component and the email component, so we can see those in here. There's not a whole lot to optimize in this particular file yet, but let's say we wanted to take a look at that big 2.5MB file. Well, let's go do that. Inside of dist, there's a vendor.bundle. Let's open that up. It'll take a moment to parse it, and then once it's ready it brings it up. Now here we can see 2.19MB, and inside of that we can see the compiler is pretty big, and that's 40% of the code here, and then we've got some core files and we've got the router, we have forms, we have the platform for the _____ browser, we have some common files which are shared, and http. Wouldn't it be nice to get some of this down? I mean, I'm sure we're not using all of this, right? Well, the good news is, there is a way to do that, and we're going to learn more about it, but right now it's just good that we take an understanding of what's in the build, but we've learned now how we can do a basic development build, we can serve without even doing a build, and we can use the Network tab in the Chrome tools to see where our files are getting large, and then we can actually dive into those files using the source-map-explorer.
Building Target and Environments
Back in our Angular routing app that we created, we can see here on the left in Finder how the vendor.bundle is 2.3 MB, and we look up here and we can see that our main.bundle is 24 KB. Let's see what happens if we run the ng build with a different flag like --aot. That's the ahead-of-time compilation that's actually going to be added into the dev build now. Now first it deleted the dist folder so it could do a new build for us, and then once it's done with that build we can go back into the dist folder. And now, notice the vendor.bundle is quite a bit smaller. It's still not great, but it's much smaller now, we're down to 1.4 MB. So by running --aot we're actually removing quite a bit of code in there that we didn't need, and part of that is the Angular compiler. So if we come back over to this view right here, notice that compiler was there before, that's 900 KB. Now, if we go back and run that tool again, we should be able to take a look at what's inside of that folder. So go ahead back to vendor.bundle, let's run it again, we'll inspect what's in there, open a new tab, notice there's no compiler at this time. So looking at these, and we can put these side by side, we can see the one on the right is after aot, and the one on the left is before aot. Now that's kind of cool. Alright, so we'll put that back over here, and actually we'll close those two down. Now let's take a look what we can do if we add a bunch of other flags in. Now what flags are there? We could do ng build ---help to see all these different flags. And you can see there's a lot of them in here. There's things like locale and i18n, there's also verbose flag, which is helpful when you get more details to output out with the logs, and we can see here the aot one that we ran previously. But let's run the prod one with the environments. So let's go ahead and do ng build ---prod. Now, once again, it's going to delete the dist folder on us, but it's going to do a full prod build. So we'll watch over here in Finder just to see kind of what happens there, and we'll take a look at the final output. So once it goes through this build it's going to run through and do aot and uglification, and it's also going to tree-shake some things out. And inside of our dist, now look at the vendor bundle, 387 KB, that's pretty good. We got way down from 2.5 MB to about 400 KB. We also have all our polyfills shrunk quite a bit, that's down to 58 KB, and our main code is even down to 21 KB. And then what's the overhead of running WebPack in this case, it's 1 KB file, this inline bundle, so that's not too bad. Now, if we wanted to, we could actually run that same command again, but this time we can't just run it on vendor.bundle. Why? Because vendor.bundle isn't the file either. We also got a little bit of cache-busting, we got this long filename. So over here, I'm going to use a little auto-complete help, and we're going to use that same tool to try to do it. But, uh-oh, there's no source map. So we could generate the prod with sourcemap, just to explore and see kind of what's in there at this point. So it deletes the dist folder, it's going to regenerate those files, and it's going to pull the source maps in, which will take a little bit longer because we need those source files, and then once that's there we'll be able to explore what's in those files. Now in a normal prod build you're not going to want a sourcemap to be there, but we're just doing this so we can kind of understand what's actually being put in place. Notice the bundle is still 387, but we have this big sourcemap right there. Okay, so now let's go back and run against dist, and then vendor, and I want it to automatically fill in the name of the file, that's the cache-busting that we like to see, and now we can see what's actually in the file. Notice we're using a little bit of rxjs down here. It's got a router, it's got common things, it's got forms, and it's got the core features of Angular. So we just learned how we can use these different commands. It was ng build to do a dev build, we can turn on things 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 sourcemaps briefly or just run it like this here. And if we need to learn more about them, we can always do ng build with ---help, or go look up at the docs. Now that we've learned how to customize our builds for both dev and production, let's go ahead and take a closer look at that ng serve command 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 we run ng serve is served from memory. The Angular CLI is going to lean on WebPack, which will then serve up the code inside of 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, 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 do these different options do. So what are some of the common ng serve options that we can run? Well, the good news here is, even though there's a lot of those different options on ng build, all those same options can also run on serve, plus some of these other ones here. We've already seen how we can use -o, and 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 to do that automatically, you can just type ng serve -o. That's my preference. You can also change the port that it's listening to when serving. And, by default, it's 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 is watching those file changes and then it will automatically rebuild it and show them in the browser. That way you don't have to stop the server and then relaunch. There's a couple 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 -pc alias. 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 that so it's not running at this moment, and we can prove it by refreshing and nothing should work over here. Okay, now, let's go ahead and serve just 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 that server going to be? We can go type that in, and it's going to be at, by default, this port right here. Now notice the first line, the Live Development Server is running right here, localhost 4200. And notice they said it was a Development Server. This is not for running production code out on a real website, this is for us locally, and we can see that that works just great. Now what if we didn't want it to be on that port. Another option we could do is p, and we could type in a port. Maybe we want it to run on something like 8626. So when we do that, and we go ahead and we rebuild this, it's going to do the same thing, but now notice the port is going to be 8626. So we have to come up in here to the browser, and we can type 8626, and once it's ready to go, there we are. Now if we kill that again, we can combine those two with -p and -o, and it'll run on that port, and it should launch a new browser showing us the application running on 8626. What about that live-reload behavior? Well let's take a look at our application and we'll put that side by side. When we make a change here, and maybe we'll just stick something else in here like a div that happens to have, I don't know, let's just put John Papa in there so we can see the words John Papa right there. Now what if we don't want live-reload to be happening each time, because that's going to refresh over on the browser every time we save a file? So instead of that, let's go back to our terminal, we'll kill this right here, and now we can use live-reload set to false. and that's the shortcut alias for live-reload. So it's still going to run on that same port, it's going to open up in the browser, and it's not going to do live-reload. So once it's launched, we still have our application, but now over here let's say I change that name from John Papa to something like Dan Wahlin, a good buddy of mine. When I do that Dan isn't showing up over here. How come Dan is not getting any love? Because live-reload isn't on. But if I refresh the browser over here, it is appearing now. So with just a little bit of tweaking that we can do, and see different behaviors as we're running live-reload. And one last setting with ng serve that's really good to look at is the prod setting. Now, this is going to run ng serve, it's going to open a browser against a prod build. It's not looking in the dist folder still, it's actually doing the full build process in memory, and then it's going to launch inside the browser. Once again, notice that there's a red message up top. Red means pay attention. This is a very simple development server, it's not for putting out there on the web. Again, we're using this server so we can test our prod build. Now that it's launched, let's go ahead and take a look at what's in the browser. We'll refresh this again so we can get all the traffic, and now you can see all those bundles are there with those cache-busting hashes at the end of them, or fingerprints, as some people like to call them. And here you can see the different file sizes that we're getting. Again, our vendor bundle is down to 129KB, and our code, which is in main, is 4KB, not too bad.
The Angular CLI uses WebPack under the covers, and there is a configuration file, but where is it? We don't see it. What if we wanted to customize our WebPack configuration and we decided we didn't want to use the CLI anymore. Well, there's a cool option called ng eject. Now I'm going to run this command on our project, just to show you what this does. This is a way that we can eject our application and put the proper WebPack configuration so we can run things on our own. And the warnings here in yellow tell us that we're not going to be able to run ng serve or ng build anymore, but we'll have to run these scripts instead, and those scripts are going to be located in our package.json. Let's take a look at using the git commands here, of what changed. First, our angular-cli.json file changed a little bit. We have identified it as being ejected, and the rest of these are really minor white space changes. The package.json file changed quite a bit. Here, we used to run ng serve, build, and test. Now we're actually going to run webpack directly, and karma directly, and protractor directly, so you can see what CLI and webpack were doing for us before. If we scroll down a little, we're also going to see a whole bunch of development dependencies that were added to our project. These are things that were dependencies inside of the CLI before, but those were ejected out. Now why would we want to do this? If we want to use the CLI we don't need to do this, but the nice thing here is it gives us the option of ejecting out all these features so we can have much more fine-tuned control if we want to. It's like an exit strategy. And there's one new file here, the webpack.config itself. So this is what was being basically masked from us by the CLI, and now the CLI can eject all that out, and you can see there's quite a bit of configuration in here. So for those of you who want to do the WebPack configuration yourselves or change how it's actually working, we have that control. And now, if we want to run things, instead of running ng serve we could run npm start. And just to show what that's going to do, let's go back over and take a look at the package.json, and we can see that npm start is now running "webpack-dev-server". So if we run that here, it's going to crank up the dev-server and do the same kind of build, and some of this output looks very familiar because this is some of the same things we saw earlier, and then it will launch it up and be ready on a server for us to go browse to. Now let's say we didn't actually want to eject here because I use git commands, now we can just undo all of those changes, discard the files. Now if I come back over, I can do ng serve -o, and now it'll actually do the build again, and it's going to launch it inside our browser. While I love the CLI, it's nice to know that if I need to do something a little more customized I can eject the configuration if I want to.
Adding Angular Material
Let's take a closer look at how we can pull in an angular-friendly library like Angular Material, and how this would work with the build process. First, let's go get Angular Material. So we'll type in npm install, and that's going to be angular/material, and we'll save that. And that's going to pull down Angular Material for us. And now while that's working, let's go into our code and we're going to need to hook up Angular Material to our application. We're going to go to our app.module. In our app.module, we need to import the material module. So down here in the imports, we're going to put in material. Let's put it in right here. It happens to be called MaterialModule. Now we have to import that up top here. We'll type this one in, it's going to be the materialModule. And that's going to come from where? Angular/material. Great, now we're pulling in angular/material into our main.app module. Next we want to take advantage of all the different kind of styles that we get with Angular Material, so inside of source styles, let's plug in these two import statements here. The first one is going to go out and get a specific theme with Angular Material for us, and then it's going to get the icons. Finally, let's just make sure we're actually using Angular Material. So let's go back into the app component.html, and right below the nav, but above the router-outlet, so we can see all of this, let's create a button here, and let's make that button be md-raised-button, and we'll put the word ok in there, and then we'll create an md-icon, and we'll put the done icon there. Now, if we go serve our application with ng serve -o, let's take a look at what comes up. And it launched in the browser, and it shows us here we've got this angular material button, which we get the nice little animations that they use, and everything worked out great. And that's how easy it is to add in an angular-ready module like Angular Material. Now let's take a look at the browser in full screen, and we'll go look at the Network tab, and we'll refresh, and we can see we've got our same old bundles. The vendor.bundle is there, it's actually slightly larger now, only 3.4 MB, again, this is a dev build because we pulled in all the things we wanted for material as well, and we got our icons down here too. So everything worked great with that particular build by pulling in Angular module.
Adding Scripts, Styles, and Assets
We just learned a couple of cool things we could do with the Angular CLI when we want to build in external libraries. So we can pull in scripts or styles or even our own assets if we want to, and we can pull in other libraries that have NgModules like Angular Material. And if we wanted to just back away from the CLI into our own WebPack configuration, we can eject at any point we want. Now we learned quite a bit about building and serving in 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, and remember that's not running it off the disk, that's running our build in memory so it's super fast. Now when it's time to promote our code, we want to check out a production build so we can run ng build with a 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 can do. We looked at how we can build the output out to those production files in the dist folder, 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. And we 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 a couple of different external libraries like Angular Material and how we can put our own custom scripts or styles inside of the process to build those as well. And if we'd like to see what life is outside of using the Angular CLI to do our building and serving, we can actually eject and use WebPack directly. Now that we have learned how to build our code, it would be good to know how to use the CLI to test our code. 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. Well, 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 more 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 of those features when we're running under test, 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 when 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 naming 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 open up our code once again. We'll go back to our good old, angular-routing app that we generated previously, and on the left-hand side we'll put it inside our Visual Studio Code editor, because we're going to make some changes to it, and then on the right-hand side we'll open up terminal. And first we'll start with running ng test -h, and that'll show us all the help commands that we could use. We can also refer back to the docs as well. Okay, we'll clear that out. Now let's run ng test, and as this is executing, what's happening is it's building our application, and then it's going to execute the test, and then finally it'll wait for any file changes that we make. Now on the left-hand side we can see our html reporter, and it shows us that we have 8 specs with 4 failures, not so good, right? On the right-hand side, we also see the same report, but it's not nearly as easy to read. This is one of the reasons that I like this html reporter that opens up. Now if we click up here we can see that there's a Spec List, and some of the specs work and some did not. Notice that the AdminComponent and the AppComponent specs didn't work, but click on the AdminComponent should create, we'll see that the 'router-outlet' is not a known element. Okay, so what happened here is there's a router-outlet inside of that component, and it doesn't know what that thing is, because remember, we're isolating those tests to just that particular component, so it has no idea what a router is. Whenever we're trying to isolate tests, it's really important that we make sure we set it up so it can run without any dependencies. Now let's go back to our Visual Studio Code editor, and we'll go inside the admin.component and take a look at it. So here is the admin.component, there is our TypeScript, there's really not much in there, and let's go take a look at the template. Inside of there we can see the router-outlet. Well, when we run it in its own isolation it doesn't know what that router-outlet is. That's because the admin.module is the one setting it up. Alright, so how do we take care of this and isolate it? We go back into the admin.component, but its spec file, and in that spec file there's an option that we can do when we're setting up our tests. After our declarations, we can see there's a bunch of other options here. One of them is called schemas. Inside those schemas there's one called NO_ERRORS_SCHEMA, and it's all uppercase, like that. Now it's red-underlined because it hasn't been imported yet up top. Now we could hit our little quick-fix, which is command dot on my keyboard, like this, or I can hit the little light bulb over here. While it may be located in these, what we really want to do is just go to "angular/core" just once. It's not appropriate for us to dive down deep inside the source code, so we'll just do angular/core, and I'll move that up just so we have all of our Angular stuff up top and then our imports are below that. Now you'll notice the tests are re-running over on the right, you might have seen the terminal change quite a bit. So now if we go back over here and look at our Spec List, now the AdminComponent is happy. Okay, so I don't really like looking at the terminal, I like looking at those tests. Let's go into the AppComponent and try the same thing. Once again, we'll grab the schemas, we'll go into the app.component, because that html also has a router-outlet right on line 17. And let's go to the AppComponent spec, and then right after the declarations here we'll add the schemas. Once again, we'll add the import statement, I'll pick the one that has least amount of problems with it there, and it's just angular/core, and then we'll move that one up. It re-ran the tests on the right-hand side, and everything is good. Now you may be wondering why it's re-running the tests so quickly. Well, it's waiting 1 second, by default, to rerun them after a file has been saved, and over here I didn't press File Save, what I have is Auto Save turned on for Visual Studio Code, which I really like because it makes my life easy as I'm coding along, and not to worry about, did I press Save or not. Now some other things you can do inside this reporter is you can click on the individual tests. We can click on the green there to go in and see the test, and now it just reran that one spec, but not the others. If we go back and run the top, it'll run them all. And if there were any failures, which we can cause, once again, by just coming down here, and let's just comment out that line, it should rerun those tests, and then we can see we can go back to the Spec List by clicking on that, or just click on the failures on the right-hand side, right there. Now let's fix our tests, we'll uncomment out that line, we should see it pick up File change. And once it picks up the file change it reruns them, everything is good. Now we can close this window, but what really stops the test is coming back to our terminal and hitting Ctrl+C and getting back to our command prompt. And that's how easy it is to run tests inside of the 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 can use? Let's take a look at some of them. A pretty cool feature is running 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, and when turned on, it generates this report which is pretty cool to look at. 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 paths that we think we've covered with our tests. We'll take a closer look at this when we do a hands-on demo. We can also enable coloring, which by default is on, but we can turn that off too. This changes the colors in the terminal output. Sometimes we just want to do a single pass of the test, like when we go through a CI build. For that, we can turn on single-run by doing -sr. By default, this is turned off, so it can continuously watch the files, and by default, we can see the progress of the tests as they're compiling and running through the execution in our console output. 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, so we can turn this off. And when we want to debug our tests, we can enable the sourcemaps with the -sm flag, or we could disable it to give a slight speed increase to our tests. And then finally there's a watch as well, so we can say -w and true or false to either enable watching or disable it. Under the covers, this works the same way as the single-run, where a single-run of false and watch of true are effectively the same. The big decision here is continuous testing versus a single timed test cycle. So if we run ng test, by default, that's going to run the test and then wait to watch the files and rerun those tests again when the files change. We saw that in the previous demo. Under the covers, this is using Karma as the test runner to watch those file changes. Now we can also run a single time using that -sr flag. So if we do that, or -w false, I kind of like the -sr because it's shorter again, that's a great option for a CI server. Perhaps you're running it up in Jenkins or TFS, or some other build server. In that case, we can just run ng test -sr and that's going to allow us to run the tests, and then it will stop and not watch for files anymore, because we're just doing a one-time test. Okay, what about test code coverage? That was that cool flag we could use, the -cc or ---code-coverage. This is going to report out all the code coverage for branches, functions, statements, and lines. So where does this output go? It goes to the coverage folder, by default. But like most things in the Angular CLI, this is also configurable inside the angular-cli.json file. So we just simple say ng test -cc, and we can take a look at that code coverage. Now that we learned about some of these other options, let's go get some hands-on experience with them.
Let's take a closer look at how we can run some test coverage here. Now when we run ng test to do the test coverage, usually I turn on the single run flag first, since I only want to run it one time, 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 test, 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'll 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, and 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 we'll make this full-screen and we'll blow it up a little bit. Here 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 you can set that up as a Boolean, and by default let's set that e false. And let's assume that when we're starting out, if we have permission, we're going to do something. I will use the tooling features there to add the this. Now if we have permission we're going to go get some users, and 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 equal to users, but we'll also have some kind of error handling as well, assume that our error has kind of an e message, and we'll do console.log(e.message). Not very fancy, but just something to kind of get the point here. Now we don't have any get users 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 our property, but we can come down here and say getUsers like this, and we can take advantage of the async keyword in the 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 we have an email-blast as well that we can do in this application. We'll say email@example.com, and we'll just make a second object here just so 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 as 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 tests 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 and it 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, now we should be able to just refresh here, and notice our users actually went down in coverage. We have statements of 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 of that component, and again, we ca 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 you change that, notice what happens over on our test. This time it's going to run through the get users, so things should go up, right, because it's going to execute the get users 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 we 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 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 test. 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'll make it super easy for us to debug those. Let's take a look at what happens here. It'll 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 it a little bit roomier. And if we click over on Sources, and then up here we can hit Command plus 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 can actually put debug points here or we can 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 user.spec, so that's helpful as well. So inside of here we have some really 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, and we can put a 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 _____ value, and we can evaluate inside the console. It'll open it 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 set it equal to 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 is 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 Options
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? Well, that's when we test 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 the user wants it to. And under the covers the CLI is going to use Protractor with Angular. And the way we learn more about these different flags at the command line is to type ng e2e, and then --help. When we run ng e2e we require that a server exists so we can actually exercise the application. So it makes sense that most of the serve options are available, plus a couple of others. For example, we could override the default protractor.conf file by using the -c flag, or if we want to debug using protractor from the command line we can use the element explorer feature of protractor. We'll take a look at this in an upcoming demo. By default, we're always serving the end-to-end test, but we could actually disable this if we want to by setting -s false. Normally we want to exercise all of our end-to-end test specs, so that's the default, but if we want to specify individual specs we can use this flag. And finally, by default it's always going to try to update web driver, which is required to run these end-to-end tests, but that takes an extra second, so if you know you've got the most updated version you can actually set this to false. So how do I like to run with this? Well, when I run it, I usually just run ng e2e, and that's going to exercise the end-to-end test, it's going to compile it, it's going to serve it, and run my tests and tell me the output. But sometimes I like to debug those tests when I'm having problems, and that's when I'll run it with the -ee flag. That will open up the element explorer protractor and we can actually investigate what's happening inside the tests. So by default it's going to do most of what we need right out-of-the-box, but when we need to we can use one of these flags to debug it. Now let's take a closer look at how we can run end-to-end tests.
Executing and Debugging 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've got this protractor.conf file, and notice that it's already configured to run everything that's got e2e-spec.ts as an extension. Now notice that they're all inside the e2e folder. So let's think about that. Unit tests usually are associated with testing a discrete piece of functionality, for example here, this user.component.spec is side-by-side with all the user.component information because that's what it's going to test. And 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 there, and then maybe going to a different page. Well, that doesn't really associate with any particular feature, so generally end-to-end tests will sit outside of the source folder, and in this case going inside of the e2e folder. Of course, all of that is configurable again and we can change it if we want to, but this is how it runs out-of-the-box. Now there's a TypeScript configuration here for the end-to-end test, and then we've got a spec and a page object. The test that gets generated for us just goes to the basic page and then makes sure that that paragraphText that 'app works' is there, that's what was generated when we created the app. Now the page object, which is being used here, that's the page, is going to help us by basically abstracting some of the functionality like getParagraphText, which I can hover over and it'll jump into the page object. You don't necessarily need this page object, but some people feel like it helps abstract some of the functionality. You could technically just grab this code right there, and we could flip back over here and we could replace all of this like that, but if we did that, then we'd have to come over here and import all of this stuff in the other page, so it's just another way to abstract things. How you design your test is really up to you. Okay, so it's looking for some css here, looking for app-root and an h1 to get that text, and that text should equal 'app works!'. Let's go take a look at our app.component. So coming back over to the app.component.html, do we have an h1 that says app works? Well there's our h1, and there's our title, let's go ahead inside of the TypeScript, and we can see it says app works, so this should pass. Let's go back over to terminal now, and we'll type in ng e2e. Now we only have this one set of end-to-end tests right now, and generally we'll have far fewer end-to-end tests than we will unit tests, because this is testing basically the whole interaction of the app. So once it builds things up, it should serve the application in the browser, and then we can take a look at it. And it said right here, it should display a message saying app works, and it worked, great. Notice the browser, though, blinked really quick. What if we wanted to debug that a little bit? Well let's clear out our screen now and let's try to debug it a little bit. If we type in ng e2e, we could type out now the command for the element explorer, or we could just be a little bit quicker and say -ee. This will run through the same end-to-end test cycle by building and then serving it, but then it'll pause when it gets to the browser so we can run some protractor commands to actually test things out. Let's see how this works. Now, notice it opens in the browser and then it pauses, so I can kind of put it side by side again, and down here it's saying, look, you can run some commands and get all the bindings in the page. Now we know that inside this page there's an h1 that contains this app works, so we could type something in here like list, and then by css, and then look for the tag called 'h1', and voila, there we go. Now what if we want to exercise exactly what was in one of our specs? Well, back over here in the page object we had this return of element calling getText. Notice what it's doing is looking by css to look for the selector of app-root which contains an h1, and then it's taking that, grabbing the element from it, and then it's running the getText function on it. So let's run that over here inside the element explorer. And when we run that we get simply the text, app works. So this can be super helpful for debugging our tests. Now when we want to get out we can type .exit or we can simply just Ctrl+C to get out of there. So rest assured when it's time for you to write your own tests of Protractor, you can check out some of the great courses online at Pluralsight to learn more about it, but the Angular CLI is right here waiting for you to make it easy for you to run them.
In this chapter, we learned quite a bit at 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. Ideally, when we keep them running using the single run command of false or just the default, 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, and that'll exercise Protractor to run through things. And, of course, we can debug those as well using the different tools like the element explorer. We've learned a lot throughout this course about how the Angular CLI can create a new project for us and then generate different blueprints like components and services with a bunch of different flags to really customize to our needs. We can also set up our own linting rules or use the ones out-of-the-box so we can make sure our code is of high quality and following certain patterns that we want to follow. The ng lint helps us do that. We learned that when it comes time to build that it's super easy to use the built-in WebPack features to build with the Angular CLI doing ng build, or we can just serve for our development server with ng serve, and then, of course, we can also run our tests with ng test and ng e2e. With all of these features and then more coming of course, the Angular CLI is a great way to build Angular applications. I'm John Papa, and I want to thank you for watching my course on the Angular CLI. Have fun writing Angular code.
John Papa is a Principal Developer Advocate with Microsoft and an alumnus of the Google Developer Expert, Microsoft Regional Director, and MVP programs.
Released5 Apr 2017