Learn how to perform serverside rendering (SSR) with Angular Universal, then deploy to Firebase Cloud Functions or GCP AppEngine https://fireship.io/lessons/angular-universal-firebase/ for better perf and SEO

Universal - https://angular.io/guide/universal
Functions - https://firebase.google.com/docs/functions
GCP https://cloud.google.com/sdk
2024-02-04T07:02:01.948Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
30cba5f9-cd62-4431-b748-196dc641f464
4524390a8e18edbdce4f5e080f32ab6c7260ef4964ae16491c01b5cf01fcaf87
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
One of the biggest challenges with building a single page application is making the app visible to search engines and link bots.
Fortunately with Angular Universal, So we have a reliable package for rendering our apps on the server.
Not only does this provide SEO, but it can also improve the initial page load speed.
In today's video, you'll learn how to server side render an Angular app, then deploy it to Google App Engine or Firebase Cloud Functions.
If you're new here, like and and make sure to follow along with the full source code on Fireship IO.
Let's start by talking about what server side rendering is and when you would wanna use it.
In any normal JavaScript app, whether it be Angular, View, or React, you will provide the browser with a JavaScript bundle, then the browser will parse that bundle of script and figure out how to render the HTML.
That's a great way to build a modern web app because it will make the user experience feel very fast and responsive like a native app.
But the problem is that a lot of bots out there don't execute JavaScript.
So that means if somebody shares a deep link in your app and that link renders some kind of dynamic Content, the only thing the bot will see is your initial index HTML file.
So the purpose of Angular Universal and server side rendering is to offload some of this work to the server.
So when the user first visits a deep link, they'll get some rendered HTML with the dynamic content already included.
For example, the Twitter bot just wants to read the meta tags in the head of the document, it's just going to grab that HTML and then not worry about executing any JavaScript on the page.
When you have just a regular user, they'll get that same prerendered GML, so this usually results in a faster initial page load.
Then Angular's JavaScript will take over, so it'll behave just like a regular Angular app on subsequent navigations.
In order to make this possible, we can't really use Firebase Hosting directly because it's just a static host.
We need an actual Node.
Js server to dynamically render the content when a page is requested.
We have 2 good deployment options for a Firebase project, Google App Engine and Firebase Cloud Functions.
There are some trade offs between the 2, but I'll show you how to set up both of them in this video.
And they can both be used on the free tier.
I'm starting out from a brand new Angular 7 app, and the great thing about Universal is that there's a schematic so we can simply add all the boilerplate to our project by running this command.
N g add universal express engine and then specify the client project as your project name.
That will create 5 new files in this project.
So let's take a look at each one of those now.
The first one is the webpack server config, and its job is to package and compile the server dotts file.
So let's jump into server dotts, and you'll see that this is our actual Express JS app.
Express is a tool that can receive a web request and then send a response back to the browser.
So Express will see the initial request.
Angular Universal will kick in and render the actual HTML, then Express will send that HTML as a response to the browser.
You'll also see a main server dot TS file, which is just the entry point into the server side app, and it also has its own TS config.
From there, we'll jump into the app directory, and you'll see we also have an app server module.
It's basically just a wrapper around the app module.
And at this point, you don't have to make any changes to any of these files.
Once we get to the Firebase stuff, I'll show you exactly what needs to change and where.
So let's go ahead and install AngularFire and Firebase And then we'll jump into the app module.
You'll notice one change here and that's that the browser module is now calling with server That just allows the app to be rendered on the server and then transition into a normal Angular app after the initial page load.
From there, you can import all of the AngularFire stuff that you want to use in your project.
None of this stuff is actually required for Angular Universal, but I'm just making the assumption that you have Firebase in your project because there's a few caveats that we'll look at later.
That takes care of the initial setup.
Now let's go into the package JSON, and you'll see that the n g add command added a few new npm scripts to this file.
The ones that you'll wanna use primarily are build SSR and serve SSR.
1st, we'll build the app, and then we'll go ahead and serve it just to make sure everything is working at this point.
Now just a quick side note, I highly recommend using Node version 8.14 when working in your local development environment.
That's the version used on GCP and Cloud Functions, and that's what I used to build this tutorial.
After running the build command, you should see a disk directory.
And inside of that, you should see a browser build and a server build as well as a server JS file.
At this point, our app doesn't really do anything, so I'm gonna go ahead and generate a new component that represents the about page for this app.
Then we'll have this page dynamically render its own meta tags so it can be used with a Twitter card or any other social media site.
If you run n g generate components, you'll probably get Error saying it's missing the module.
You can fix that by adding flag m with app to your command.
That happens because there's 2 modules in the app directory, and it doesn't know which one to use.
When it comes to SEO, you'll most likely want to set a title and some meta tags when this component is rendered.
And Angular provides a couple of services for you to do that called title and meta.
Then I'm going to create an object with just some static data, but you could also pull this data from the database.
From there, we'll go ahead and inject our dependencies in the constructor.
And then with title, we can just simply call set title and then pass the dynamic data to it.
Then the meta service has an add tags method, which we can pass an array of multiple meta tags.
You can learn how to format metatags by going to the open graph docs or to Twitter or Facebook.
But, basically, Angular is just going to add these tags to the head of the document when this Component is initialized.
The one thing that is very important is that you use this service to set the meta tags and not do it manually on the document or window itself.
For example, if we wanted to get the URL, it's tempting to call window location path name.
But the window doesn't exist in Node.
Js, So this will result in an error when we try to server side render the app.
So when using Universal, you always wanna keep that in mind and just try to avoid touching the DOM directly.
So in order for this to be useful to us, we need to have this component loaded by the router.
If we jump over to the app routing module, we can just set up a single path to about that loads the about component.
At this point, you should be able to load the app in the browser just using ng serve and you should see the meta tags in the head of the document.
So at this point, we have dynamic meta tags but if we were to share this link on social media, we'd end up with something like this.
And again, that's because the meta tags are rendered by the JavaScript.
Now let's go ahead and serve this app with Universal so the meta tags are rendered in advance.
1st, run the build SSR command.
After that's done, run serve SSR.
That will serve the app on local host 4,000.
But if you're using Firebase in your project, you should end up with an error like this.
That's because Firebase uses a few things in the DOM that are not available in node by default, but we can easily fix that by just adding polyfills for them.
1st, install WebSockets and XHR 2 into your development environment.
From there, go into the server ts file and then add these two lines to the very top of it.
You run the serve command again, it should work, but it'll still give you a couple of warnings.
You can clear out these warnings by installing these packages, and that command is available in the full article.
And anytime you make changes to this file, make sure to run the build SSR command first and then serve SSR after.
At this point, you can go to local host 4,000, and your app should look and behave just like a normal Angular app.
But you can validate that your server side rendering is working by opening up the page source.
This is how the page looks when it's served to the browser, so before any JavaScript is run.
And you know it's working if you see your meta tags and your dynamic title in this HTML.
Now we have a big decision to make.
Do we deploy this to Google App Engine or to Firebase Cloud Functions?
On App Engine, our project will become a containerized app so it can be Play on App Engine or any other cloud.
And there's a free tier for Node.
Js and it will scale up automatically as needed.
And the pricing works out to be around $25 per month per container.
But they will auto scale based on the traffic and demand, so that pricing will vary.
App Engine is also very easy to deploy too.
So in my opinion, it's the better way to go in most cases.
But it's also possible to deploy to cloud functions, which gives you a tighter integration with Firebase.
And it's hard to do a direct price comparison, but I suspect cloud functions would be less expensive.
Pricing is based on the number of invocations of the function which is free up to a 125,000 per month.
So those are the trade offs.
Let's go ahead and deploy to App Engine first.
You need to have the Google Cloud command line tools installed.
So you should be able to run the gcloud command and then we'll create a file called app dot yaml.
The only line you need in this file is the runtime as Node JS 8, but you can also specify a different scaling options here as well.
When you deploy, it's going to be looking for the npm run Start command.
So you'll wanna go into your package JSON and have that point to the serve SSR command.
From there, it's just a matter of running gcloud app deploy And that will push the container to Google Cloud and start running it as a service.
That should take a couple minutes but when it's done it will give you a URL and when you go there it should have the same exact app that we were looking at on local host.
And the nice thing about App Engine is that we have this dashboard where we can look at the different versions, we can look at the debug logs, and we can even look at source code.
So that was super easy.
Now let's take a look at Cloud Functions which requires a few more steps.
The first thing we wanna do is run Firebase init for hosting and functions.
I'm going to use TypeScript functions, but the process is almost identical for JavaScript functions.
From there, go ahead and point to the dist browser directory, And you'll say yes to configuring the app as a single page app.
We'll go ahead and configure it to rewrite all of the traffic to a Cloud Function instead of the index HTML like it normally does.
You can name this whatever you want, but I'll just go ahead and call it SSR.
Now we need to CD into the functions directory and we need a way to get our Angular code into our functions environment because Universal needs that source code in the runtime to render the actual content.
I'm going to write a little node script here to handle that and to make life a little bit easier, I'm installing file system Then we'll create a file called cpdashangular.js.
Now there are many different ways we can do this, but this is the way I chose to do it.
Basically, we just have a function that will copy the files from the disk directory in Angular over to a disk folder in the functions directory.
Then we'll also always want to remove the copied files on each new build of Cloud Functions just to make sure we're always working with the latest Angular code.
From there, go into the package JSON 4 functions and run node cp angular in your build command.
And while we're in here, let's also set the engine to node 8 so that it Ploys our function as a note eight function.
Now we'll go to the source index TS and write the function itself.
It's actually super easy.
We have to do is take the universal app and then pass it into an HTTP function.
As you can see here, we're actually importing the universal app from our current working directory.
So that's why we have to copy it over to the functions environment.
And that's all there is to the function side of things.
But in order for this to work, we need to make a couple of tweaks to the original server code in Angular.
Open up the server ts file and then add an export in front of the app variable.
Then go all the way down to the bottom and comment out the listener.
Cloud Functions is already doing the listening so we don't want this line in our code.
And we need to make sure that our code gets exported as a library that we can consume.
So add library app and library target UMD.
And if you have issues bundling you may want to add Firebase as an external.
Now it's time for the moment of truth.
1st, make sure to rebuild your app using the build SSR command in Angular, then go into the functions directory and run the build command there.
From there, run firebase serve which will serve your hosting and your function simultaneously.
Hopefully, everything went well and you're seeing the rendered meta tags when you go to local host 5000.
If that's the case, go ahead and run Firebase deploy, and that will deploy the function and hosting.
And now you have a fully server side rendered app running on Firebase Cloud functions.
After it deploys, head over to the Twitter card validator just to make sure that everything is working as expected.
I'm gonna go ahead and wrap things up there.
If you run into any issues, let me know in the comments or on Slack.
Thanks for watching, and I will talk to you soon.

Speaker 0: One of the biggest challenges with building a single page application is making the app visible to search engines and link bots. Fortunately with Angular Universal, So we have a reliable package for rendering our apps on the server. Not only does this provide SEO, but it can also improve the initial page load speed. In today's video, you'll learn how to server side render an Angular app, then deploy it to Google App Engine or Firebase Cloud Functions. If you're new here, like and and make sure to follow along with the full source code on Fireship IO.

Let's start by talking about what server side rendering is and when you would wanna use it. In any normal JavaScript app, whether it be Angular, View, or React, you will provide the browser with a JavaScript bundle, then the browser will parse that bundle of script and figure out how to render the HTML. That's a great way to build a modern web app because it will make the user experience feel very fast and responsive like a native app. But the problem is that a lot of bots out there don't execute JavaScript. So that means if somebody shares a deep link in your app and that link renders some kind of dynamic Content, the only thing the bot will see is your initial index HTML file.

So the purpose of Angular Universal and server side rendering is to offload some of this work to the server. So when the user first visits a deep link, they'll get some rendered HTML with the dynamic content already included. For example, the Twitter bot just wants to read the meta tags in the head of the document, it's just going to grab that HTML and then not worry about executing any JavaScript on the page. When you have just a regular user, they'll get that same prerendered GML, so this usually results in a faster initial page load. Then Angular's JavaScript will take over, so it'll behave just like a regular Angular app on subsequent navigations.

In order to make this possible, we can't really use Firebase Hosting directly because it's just a static host. We need an actual Node. Js server to dynamically render the content when a page is requested. We have 2 good deployment options for a Firebase project, Google App Engine and Firebase Cloud Functions. There are some trade offs between the 2, but I'll show you how to set up both of them in this video.

And they can both be used on the free tier. I'm starting out from a brand new Angular 7 app, and the great thing about Universal is that there's a schematic so we can simply add all the boilerplate to our project by running this command. N g add universal express engine and then specify the client project as your project name. That will create 5 new files in this project. So let's take a look at each one of those now.

The first one is the webpack server config, and its job is to package and compile the server dotts file. So let's jump into server dotts, and you'll see that this is our actual Express JS app. Express is a tool that can receive a web request and then send a response back to the browser. So Express will see the initial request. Angular Universal will kick in and render the actual HTML, then Express will send that HTML as a response to the browser.

You'll also see a main server dot TS file, which is just the entry point into the server side app, and it also has its own TS config. From there, we'll jump into the app directory, and you'll see we also have an app server module. It's basically just a wrapper around the app module. And at this point, you don't have to make any changes to any of these files. Once we get to the Firebase stuff, I'll show you exactly what needs to change and where.

So let's go ahead and install AngularFire and Firebase And then we'll jump into the app module. You'll notice one change here and that's that the browser module is now calling with server That just allows the app to be rendered on the server and then transition into a normal Angular app after the initial page load. From there, you can import all of the AngularFire stuff that you want to use in your project. None of this stuff is actually required for Angular Universal, but I'm just making the assumption that you have Firebase in your project because there's a few caveats that we'll look at later. That takes care of the initial setup.

Now let's go into the package JSON, and you'll see that the n g add command added a few new npm scripts to this file. The ones that you'll wanna use primarily are build SSR and serve SSR. 1st, we'll build the app, and then we'll go ahead and serve it just to make sure everything is working at this point. Now just a quick side note, I highly recommend using Node version 8.14 when working in your local development environment. That's the version used on GCP and Cloud Functions, and that's what I used to build this tutorial.

After running the build command, you should see a disk directory. And inside of that, you should see a browser build and a server build as well as a server JS file. At this point, our app doesn't really do anything, so I'm gonna go ahead and generate a new component that represents the about page for this app. Then we'll have this page dynamically render its own meta tags so it can be used with a Twitter card or any other social media site. If you run n g generate components, you'll probably get Error saying it's missing the module.

You can fix that by adding flag m with app to your command. That happens because there's 2 modules in the app directory, and it doesn't know which one to use. When it comes to SEO, you'll most likely want to set a title and some meta tags when this component is rendered. And Angular provides a couple of services for you to do that called title and meta. Then I'm going to create an object with just some static data, but you could also pull this data from the database.

From there, we'll go ahead and inject our dependencies in the constructor. And then with title, we can just simply call set title and then pass the dynamic data to it. Then the meta service has an add tags method, which we can pass an array of multiple meta tags. You can learn how to format metatags by going to the open graph docs or to Twitter or Facebook. But, basically, Angular is just going to add these tags to the head of the document when this Component is initialized.

The one thing that is very important is that you use this service to set the meta tags and not do it manually on the document or window itself. For example, if we wanted to get the URL, it's tempting to call window location path name. But the window doesn't exist in Node. Js, So this will result in an error when we try to server side render the app. So when using Universal, you always wanna keep that in mind and just try to avoid touching the DOM directly.

So in order for this to be useful to us, we need to have this component loaded by the router. If we jump over to the app routing module, we can just set up a single path to about that loads the about component. At this point, you should be able to load the app in the browser just using ng serve and you should see the meta tags in the head of the document. So at this point, we have dynamic meta tags but if we were to share this link on social media, we'd end up with something like this. And again, that's because the meta tags are rendered by the JavaScript.

Now let's go ahead and serve this app with Universal so the meta tags are rendered in advance. 1st, run the build SSR command. After that's done, run serve SSR. That will serve the app on local host 4,000. But if you're using Firebase in your project, you should end up with an error like this.

That's because Firebase uses a few things in the DOM that are not available in node by default, but we can easily fix that by just adding polyfills for them. 1st, install WebSockets and XHR 2 into your development environment. From there, go into the server ts file and then add these two lines to the very top of it. You run the serve command again, it should work, but it'll still give you a couple of warnings. You can clear out these warnings by installing these packages, and that command is available in the full article.

And anytime you make changes to this file, make sure to run the build SSR command first and then serve SSR after. At this point, you can go to local host 4,000, and your app should look and behave just like a normal Angular app. But you can validate that your server side rendering is working by opening up the page source. This is how the page looks when it's served to the browser, so before any JavaScript is run. And you know it's working if you see your meta tags and your dynamic title in this HTML.

Now we have a big decision to make. Do we deploy this to Google App Engine or to Firebase Cloud Functions? On App Engine, our project will become a containerized app so it can be Play on App Engine or any other cloud. And there's a free tier for Node. Js and it will scale up automatically as needed.

And the pricing works out to be around $25 per month per container. But they will auto scale based on the traffic and demand, so that pricing will vary. App Engine is also very easy to deploy too. So in my opinion, it's the better way to go in most cases. But it's also possible to deploy to cloud functions, which gives you a tighter integration with Firebase.

And it's hard to do a direct price comparison, but I suspect cloud functions would be less expensive. Pricing is based on the number of invocations of the function which is free up to a 125,000 per month. So those are the trade offs. Let's go ahead and deploy to App Engine first. You need to have the Google Cloud command line tools installed.

So you should be able to run the gcloud command and then we'll create a file called app dot yaml. The only line you need in this file is the runtime as Node JS 8, but you can also specify a different scaling options here as well. When you deploy, it's going to be looking for the npm run Start command. So you'll wanna go into your package JSON and have that point to the serve SSR command. From there, it's just a matter of running gcloud app deploy And that will push the container to Google Cloud and start running it as a service.

That should take a couple minutes but when it's done it will give you a URL and when you go there it should have the same exact app that we were looking at on local host. And the nice thing about App Engine is that we have this dashboard where we can look at the different versions, we can look at the debug logs, and we can even look at source code. So that was super easy. Now let's take a look at Cloud Functions which requires a few more steps. The first thing we wanna do is run Firebase init for hosting and functions.

I'm going to use TypeScript functions, but the process is almost identical for JavaScript functions. From there, go ahead and point to the dist browser directory, And you'll say yes to configuring the app as a single page app. We'll go ahead and configure it to rewrite all of the traffic to a Cloud Function instead of the index HTML like it normally does. You can name this whatever you want, but I'll just go ahead and call it SSR. Now we need to CD into the functions directory and we need a way to get our Angular code into our functions environment because Universal needs that source code in the runtime to render the actual content.

I'm going to write a little node script here to handle that and to make life a little bit easier, I'm installing file system Then we'll create a file called cpdashangular.js. Now there are many different ways we can do this, but this is the way I chose to do it. Basically, we just have a function that will copy the files from the disk directory in Angular over to a disk folder in the functions directory. Then we'll also always want to remove the copied files on each new build of Cloud Functions just to make sure we're always working with the latest Angular code. From there, go into the package JSON 4 functions and run node cp angular in your build command.

And while we're in here, let's also set the engine to node 8 so that it Ploys our function as a note eight function. Now we'll go to the source index TS and write the function itself. It's actually super easy. We have to do is take the universal app and then pass it into an HTTP function. As you can see here, we're actually importing the universal app from our current working directory.

So that's why we have to copy it over to the functions environment. And that's all there is to the function side of things. But in order for this to work, we need to make a couple of tweaks to the original server code in Angular. Open up the server ts file and then add an export in front of the app variable. Then go all the way down to the bottom and comment out the listener.

Cloud Functions is already doing the listening so we don't want this line in our code. And we need to make sure that our code gets exported as a library that we can consume. So add library app and library target UMD. And if you have issues bundling you may want to add Firebase as an external. Now it's time for the moment of truth.

1st, make sure to rebuild your app using the build SSR command in Angular, then go into the functions directory and run the build command there. From there, run firebase serve which will serve your hosting and your function simultaneously. Hopefully, everything went well and you're seeing the rendered meta tags when you go to local host 5000. If that's the case, go ahead and run Firebase deploy, and that will deploy the function and hosting. And now you have a fully server side rendered app running on Firebase Cloud functions.

After it deploys, head over to the Twitter card validator just to make sure that everything is working as expected. I'm gonna go ahead and wrap things up there. If you run into any issues, let me know in the comments or on Slack. Thanks for watching, and I will talk to you soon.
One of the biggest challenges with building a single page application is making the app visible to search engines and link bots. Fortunately with Angular Universal, So we have a reliable package for rendering our apps on the server. Not only does this provide SEO, but it can also improve the initial page load speed.
google
In today's video, you'll learn how to server side render an Angular app, then deploy it to Google App Engine or Firebase Cloud Functions. If you're new here, like and and make sure to follow along with the full source code on Fireship IO. Let's start by talking about what server side rendering is and when you would wanna use it. In any normal JavaScript app, whether it be Angular, View, or React, you will provide the browser with a JavaScript bundle, then the browser will parse that bundle of script and figure out how to render the HTML. That's a great way to build a modern web app because it will make the user experience feel very fast and responsive like a native app. But the problem is that a lot of bots out there don't execute JavaScript. So that means if somebody shares a deep link in your app and that link renders some kind of dynamic Content, the only thing the bot will see is your initial index HTML file. So the purpose of Angular Universal and server side rendering is to offload some of this work to the server. So when the user first visits a deep link, they'll get some rendered HTML with the dynamic content already included. For example, the Twitter bot just wants to read the meta tags in the head of the document, it's just going to grab that HTML and then not worry about executing any JavaScript on the page. When you have just a regular user, they'll get that same prerendered GML, so this usually results in a faster initial page load. Then Angular's JavaScript will take over, so it'll behave just like a regular Angular app on subsequent navigations. In order to make this possible, we can't really use Firebase Hosting directly because it's just a static host. We need an actual Node. Js server to dynamically render the content when a page is requested. We have 2 good deployment options for a Firebase project, Google App Engine and Firebase Cloud Functions. There are some trade offs between the 2, but I'll show you how to set up both of them in this video. And they can both be used on the free tier. I'm starting out from a brand new Angular 7 app, and the great thing about Universal is that there's a schematic so we can simply add all the boilerplate to our project by running this command.
N g add universal express engine and then specify the client project as your project name. That will create 5 new files in this project. So let's take a look at each one of those now. The first one is the webpack server config, and its job is to package and compile the server dotts file.
software development
software
So let's jump into server dotts, and you'll see that this is our actual Express JS app. Express is a tool that can receive a web request and then send a response back to the browser. So Express will see the initial request. Angular Universal will kick in and render the actual HTML, then Express will send that HTML as a response to the browser. You'll also see a main server dot TS file, which is just the entry point into the server side app, and it also has its own TS config. From there, we'll jump into the app directory, and you'll see we also have an app server module. It's basically just a wrapper around the app module. And at this point, you don't have to make any changes to any of these files. Once we get to the Firebase stuff, I'll show you exactly what needs to change and where. So let's go ahead and install AngularFire and Firebase And then we'll jump into the app module. You'll notice one change here and that's that the browser module is now calling with server That just allows the app to be rendered on the server and then transition into a normal Angular app after the initial page load. From there, you can import all of the AngularFire stuff that you want to use in your project. None of this stuff is actually required for Angular Universal, but I'm just making the assumption that you have Firebase in your project because there's a few caveats that we'll look at later.
That takes care of the initial setup. Now let's go into the package JSON, and you'll see that the n g add command added a few new npm scripts to this file. The ones that you'll wanna use primarily are build SSR and serve SSR. 1st, we'll build the app, and then we'll go ahead and serve it just to make sure everything is working at this point. Now just a quick side note, I highly recommend using Node version 8.14 when working in your local development environment.
software development
software
That's the version used on GCP and Cloud Functions, and that's what I used to build this tutorial. After running the build command, you should see a disk directory. And inside of that, you should see a browser build and a server build as well as a server JS file. At this point, our app doesn't really do anything, so I'm gonna go ahead and generate a new component that represents the about page for this app. Then we'll have this page dynamically render its own meta tags so it can be used with a Twitter card or any other social media site. If you run n g generate components, you'll probably get Error saying it's missing the module. You can fix that by adding flag m with app to your command. That happens because there's 2 modules in the app directory, and it doesn't know which one to use. When it comes to SEO, you'll most likely want to set a title and some meta tags when this component is rendered.
And Angular provides a couple of services for you to do that called title and meta. Then I'm going to create an object with just some static data, but you could also pull this data from the database. From there, we'll go ahead and inject our dependencies in the constructor.
databases
And then with title, we can just simply call set title and then pass the dynamic data to it. Then the meta service has an add tags method, which we can pass an array of multiple meta tags. You can learn how to format metatags by going to the open graph docs or to Twitter or Facebook. But, basically, Angular is just going to add these tags to the head of the document when this Component is initialized. The one thing that is very important is that you use this service to set the meta tags and not do it manually on the document or window itself. For example, if we wanted to get the URL, it's tempting to call window location path name. But the window doesn't exist in Node. Js, So this will result in an error when we try to server side render the app. So when using Universal, you always wanna keep that in mind and just try to avoid touching the DOM directly. So in order for this to be useful to us, we need to have this component loaded by the router. If we jump over to the app routing module, we can just set up a single path to about that loads the about component. At this point, you should be able to load the app in the browser just using ng serve and you should see the meta tags in the head of the document. So at this point, we have dynamic meta tags but if we were to share this link on social media, we'd end up with something like this. And again, that's because the meta tags are rendered by the JavaScript. Now let's go ahead and serve this app with Universal so the meta tags are rendered in advance. 1st, run the build SSR command. After that's done, run serve SSR. That will serve the app on local host 4,000. But if you're using Firebase in your project, you should end up with an error like this. That's because Firebase uses a few things in the DOM that are not available in node by default, but we can easily fix that by just adding polyfills for them. 1st, install WebSockets and XHR 2 into your development environment. From there, go into the server ts file and then add these two lines to the very top of it. You run the serve command again, it should work, but it'll still give you a couple of warnings. You can clear out these warnings by installing these packages, and that command is available in the full article. And anytime you make changes to this file, make sure to run the build SSR command first and then serve SSR after. At this point, you can go to local host 4,000, and your app should look and behave just like a normal Angular app. But you can validate that your server side rendering is working by opening up the page source. This is how the page looks when it's served to the browser, so before any JavaScript is run. And you know it's working if you see your meta tags and your dynamic title in this HTML. Now we have a big decision to make.
Do we deploy this to Google App Engine or to Firebase Cloud Functions? On App Engine, our project will become a containerized app so it can be Play on App Engine or any other cloud. And there's a free tier for Node. Js and it will scale up automatically as needed.
software development
And the pricing works out to be around $25 per month per container.
But they will auto scale based on the traffic and demand, so that pricing will vary. App Engine is also very easy to deploy too. So in my opinion, it's the better way to go in most cases. But it's also possible to deploy to cloud functions, which gives you a tighter integration with Firebase.
software
And it's hard to do a direct price comparison, but I suspect cloud functions would be less expensive. Pricing is based on the number of invocations of the function which is free up to a 125,000 per month.
So those are the trade offs. Let's go ahead and deploy to App Engine first. You need to have the Google Cloud command line tools installed. So you should be able to run the gcloud command and then we'll create a file called app dot yaml. The only line you need in this file is the runtime as Node JS 8, but you can also specify a different scaling options here as well.
software
When you deploy, it's going to be looking for the npm run Start command. So you'll wanna go into your package JSON and have that point to the serve SSR command. From there, it's just a matter of running gcloud app deploy And that will push the container to Google Cloud and start running it as a service. That should take a couple minutes but when it's done it will give you a URL and when you go there it should have the same exact app that we were looking at on local host.
And the nice thing about App Engine is that we have this dashboard where we can look at the different versions, we can look at the debug logs, and we can even look at source code. So that was super easy. Now let's take a look at Cloud Functions which requires a few more steps.
software
software development
The first thing we wanna do is run Firebase init for hosting and functions. I'm going to use TypeScript functions, but the process is almost identical for JavaScript functions. From there, go ahead and point to the dist browser directory, And you'll say yes to configuring the app as a single page app. We'll go ahead and configure it to rewrite all of the traffic to a Cloud Function instead of the index HTML like it normally does. You can name this whatever you want, but I'll just go ahead and call it SSR. Now we need to CD into the functions directory and we need a way to get our Angular code into our functions environment because Universal needs that source code in the runtime to render the actual content. I'm going to write a little node script here to handle that and to make life a little bit easier, I'm installing file system Then we'll create a file called cpdashangular.js. Now there are many different ways we can do this, but this is the way I chose to do it. Basically, we just have a function that will copy the files from the disk directory in Angular over to a disk folder in the functions directory. Then we'll also always want to remove the copied files on each new build of Cloud Functions just to make sure we're always working with the latest Angular code. From there, go into the package JSON 4 functions and run node cp angular in your build command. And while we're in here, let's also set the engine to node 8 so that it Ploys our function as a note eight function. Now we'll go to the source index TS and write the function itself. It's actually super easy. We have to do is take the universal app and then pass it into an HTTP function. As you can see here, we're actually importing the universal app from our current working directory. So that's why we have to copy it over to the functions environment. And that's all there is to the function side of things. But in order for this to work, we need to make a couple of tweaks to the original server code in Angular. Open up the server ts file and then add an export in front of the app variable. Then go all the way down to the bottom and comment out the listener.
Cloud Functions is already doing the listening so we don't want this line in our code. And we need to make sure that our code gets exported as a library that we can consume. So add library app and library target UMD. And if you have issues bundling you may want to add Firebase as an external.
software development
software
Now it's time for the moment of truth. 1st, make sure to rebuild your app using the build SSR command in Angular, then go into the functions directory and run the build command there. From there, run firebase serve which will serve your hosting and your function simultaneously. Hopefully, everything went well and you're seeing the rendered meta tags when you go to local host 5000. If that's the case, go ahead and run Firebase deploy, and that will deploy the function and hosting. And now you have a fully server side rendered app running on Firebase Cloud functions.
After it deploys, head over to the Twitter card validator just to make sure that everything is working as expected. I'm gonna go ahead and wrap things up there. If you run into any issues, let me know in the comments or on Slack. Thanks for watching, and I will talk to you soon.
twitter
One of the biggest challenges with building a single page application is making the app visible to search engines and link bots. Fortunately with Angular Universal, So we have a reliable package for rendering our apps on the server. Not only does this provide SEO, but it can also improve the initial page load speed. In today's video, you'll learn how to server side render an Angular app, then deploy it to Google App Engine or Firebase Cloud Functions. If you're new here, like and and make sure to follow along with the full source code on Fireship IO. Let's start by talking about what server side rendering is and when you would wanna use it. In any normal JavaScript app, whether it be Angular, View, or React, you will provide the browser with a JavaScript bundle, then the browser will parse that bundle of script and figure out how to render the HTML. That's a great way to build a modern web app because it will make the user experience feel very fast and responsive like a native app. But the problem is that a lot of bots out there don't execute JavaScript. So that means if somebody shares a deep link in your app and that link renders some kind of dynamic Content, the only thing the bot will see is your initial index HTML file. So the purpose of Angular Universal and server side rendering is to offload some of this work to the server. So when the user first visits a deep link, they'll get some rendered HTML with the dynamic content already included. For example, the Twitter bot just wants to read the meta tags in the head of the document, it's just going to grab that HTML and then not worry about executing any JavaScript on the page. When you have just a regular user, they'll get that same prerendered GML, so this usually results in a faster initial page load. Then Angular's JavaScript will take over, so it'll behave just like a regular Angular app on subsequent navigations. In order to make this possible, we can't really use Firebase Hosting directly because it's just a static host. We need an actual Node. Js server to dynamically render the content when a page is requested. We have 2 good deployment options for a Firebase project, Google App Engine and Firebase Cloud Functions. There are some trade offs between the 2, but I'll show you how to set up both of them in this video. And they can both be used on the free tier. I'm starting out from a brand new Angular 7 app, and the great thing about Universal is that there's a schematic so we can simply add all the boilerplate to our project by running this command. N g add universal express engine and then specify the client project as your project name. That will create 5 new files in this project. So let's take a look at each one of those now. The first one is the webpack server config, and its job is to package and compile the server dotts file. So let's jump into server dotts, and you'll see that this is our actual Express JS app. Express is a tool that can receive a web request and then send a response back to the browser. So Express will see the initial request. Angular Universal will kick in and render the actual HTML, then Express will send that HTML as a response to the browser. You'll also see a main server dot TS file, which is just the entry point into the server side app, and it also has its own TS config. From there, we'll jump into the app directory, and you'll see we also have an app server module. It's basically just a wrapper around the app module. And at this point, you don't have to make any changes to any of these files. Once we get to the Firebase stuff, I'll show you exactly what needs to change and where. So let's go ahead and install AngularFire and Firebase And then we'll jump into the app module. You'll notice one change here and that's that the browser module is now calling with server That just allows the app to be rendered on the server and then transition into a normal Angular app after the initial page load. From there, you can import all of the AngularFire stuff that you want to use in your project. None of this stuff is actually required for Angular Universal, but I'm just making the assumption that you have Firebase in your project because there's a few caveats that we'll look at later. That takes care of the initial setup. Now let's go into the package JSON, and you'll see that the n g add command added a few new npm scripts to this file. The ones that you'll wanna use primarily are build SSR and serve SSR. 1st, we'll build the app, and then we'll go ahead and serve it just to make sure everything is working at this point. Now just a quick side note, I highly recommend using Node version 8.14 when working in your local development environment. That's the version used on GCP and Cloud Functions, and that's what I used to build this tutorial. After running the build command, you should see a disk directory. And inside of that, you should see a browser build and a server build as well as a server JS file. At this point, our app doesn't really do anything, so I'm gonna go ahead and generate a new component that represents the about page for this app. Then we'll have this page dynamically render its own meta tags so it can be used with a Twitter card or any other social media site. If you run n g generate components, you'll probably get Error saying it's missing the module. You can fix that by adding flag m with app to your command. That happens because there's 2 modules in the app directory, and it doesn't know which one to use. When it comes to SEO, you'll most likely want to set a title and some meta tags when this component is rendered. And Angular provides a couple of services for you to do that called title and meta. Then I'm going to create an object with just some static data, but you could also pull this data from the database. From there, we'll go ahead and inject our dependencies in the constructor. And then with title, we can just simply call set title and then pass the dynamic data to it. Then the meta service has an add tags method, which we can pass an array of multiple meta tags. You can learn how to format metatags by going to the open graph docs or to Twitter or Facebook. But, basically, Angular is just going to add these tags to the head of the document when this Component is initialized. The one thing that is very important is that you use this service to set the meta tags and not do it manually on the document or window itself. For example, if we wanted to get the URL, it's tempting to call window location path name. But the window doesn't exist in Node. Js, So this will result in an error when we try to server side render the app. So when using Universal, you always wanna keep that in mind and just try to avoid touching the DOM directly. So in order for this to be useful to us, we need to have this component loaded by the router. If we jump over to the app routing module, we can just set up a single path to about that loads the about component. At this point, you should be able to load the app in the browser just using ng serve and you should see the meta tags in the head of the document. So at this point, we have dynamic meta tags but if we were to share this link on social media, we'd end up with something like this. And again, that's because the meta tags are rendered by the JavaScript. Now let's go ahead and serve this app with Universal so the meta tags are rendered in advance. 1st, run the build SSR command. After that's done, run serve SSR. That will serve the app on local host 4,000. But if you're using Firebase in your project, you should end up with an error like this. That's because Firebase uses a few things in the DOM that are not available in node by default, but we can easily fix that by just adding polyfills for them. 1st, install WebSockets and XHR 2 into your development environment. From there, go into the server ts file and then add these two lines to the very top of it. You run the serve command again, it should work, but it'll still give you a couple of warnings. You can clear out these warnings by installing these packages, and that command is available in the full article. And anytime you make changes to this file, make sure to run the build SSR command first and then serve SSR after. At this point, you can go to local host 4,000, and your app should look and behave just like a normal Angular app. But you can validate that your server side rendering is working by opening up the page source. This is how the page looks when it's served to the browser, so before any JavaScript is run. And you know it's working if you see your meta tags and your dynamic title in this HTML. Now we have a big decision to make. Do we deploy this to Google App Engine or to Firebase Cloud Functions? On App Engine, our project will become a containerized app so it can be Play on App Engine or any other cloud. And there's a free tier for Node. Js and it will scale up automatically as needed. And the pricing works out to be around $25 per month per container. But they will auto scale based on the traffic and demand, so that pricing will vary. App Engine is also very easy to deploy too. So in my opinion, it's the better way to go in most cases. But it's also possible to deploy to cloud functions, which gives you a tighter integration with Firebase. And it's hard to do a direct price comparison, but I suspect cloud functions would be less expensive. Pricing is based on the number of invocations of the function which is free up to a 125,000 per month. So those are the trade offs. Let's go ahead and deploy to App Engine first. You need to have the Google Cloud command line tools installed. So you should be able to run the gcloud command and then we'll create a file called app dot yaml. The only line you need in this file is the runtime as Node JS 8, but you can also specify a different scaling options here as well. When you deploy, it's going to be looking for the npm run Start command. So you'll wanna go into your package JSON and have that point to the serve SSR command. From there, it's just a matter of running gcloud app deploy And that will push the container to Google Cloud and start running it as a service. That should take a couple minutes but when it's done it will give you a URL and when you go there it should have the same exact app that we were looking at on local host. And the nice thing about App Engine is that we have this dashboard where we can look at the different versions, we can look at the debug logs, and we can even look at source code. So that was super easy. Now let's take a look at Cloud Functions which requires a few more steps. The first thing we wanna do is run Firebase init for hosting and functions. I'm going to use TypeScript functions, but the process is almost identical for JavaScript functions. From there, go ahead and point to the dist browser directory, And you'll say yes to configuring the app as a single page app. We'll go ahead and configure it to rewrite all of the traffic to a Cloud Function instead of the index HTML like it normally does. You can name this whatever you want, but I'll just go ahead and call it SSR. Now we need to CD into the functions directory and we need a way to get our Angular code into our functions environment because Universal needs that source code in the runtime to render the actual content. I'm going to write a little node script here to handle that and to make life a little bit easier, I'm installing file system Then we'll create a file called cpdashangular.js. Now there are many different ways we can do this, but this is the way I chose to do it. Basically, we just have a function that will copy the files from the disk directory in Angular over to a disk folder in the functions directory. Then we'll also always want to remove the copied files on each new build of Cloud Functions just to make sure we're always working with the latest Angular code. From there, go into the package JSON 4 functions and run node cp angular in your build command. And while we're in here, let's also set the engine to node 8 so that it Ploys our function as a note eight function. Now we'll go to the source index TS and write the function itself. It's actually super easy. We have to do is take the universal app and then pass it into an HTTP function. As you can see here, we're actually importing the universal app from our current working directory. So that's why we have to copy it over to the functions environment. And that's all there is to the function side of things. But in order for this to work, we need to make a couple of tweaks to the original server code in Angular. Open up the server ts file and then add an export in front of the app variable. Then go all the way down to the bottom and comment out the listener. Cloud Functions is already doing the listening so we don't want this line in our code. And we need to make sure that our code gets exported as a library that we can consume. So add library app and library target UMD. And if you have issues bundling you may want to add Firebase as an external. Now it's time for the moment of truth. 1st, make sure to rebuild your app using the build SSR command in Angular, then go into the functions directory and run the build command there. From there, run firebase serve which will serve your hosting and your function simultaneously. Hopefully, everything went well and you're seeing the rendered meta tags when you go to local host 5000. If that's the case, go ahead and run Firebase deploy, and that will deploy the function and hosting. And now you have a fully server side rendered app running on Firebase Cloud functions. After it deploys, head over to the Twitter card validator just to make sure that everything is working as expected. I'm gonna go ahead and wrap things up there. If you run into any issues, let me know in the comments or on Slack. Thanks for watching, and I will talk to you soon.
One
one
of
of
the
the
biggest
biggest
challenges
challenges
with
with
building
building
a
a
single
single
page
page
application
application
is
is
making
making
the
the
app
app
visible
visible
to
to
search
search
engines
engines
and
and
link
link
bots.
bots
Fortunately
fortunately
with
with
Angular
angular
Universal,
universal
So
so
we
we
have
have
a
a
reliable
reliable
package
package
for
for
rendering
rendering
our
our
apps
apps
on
on
the
the
server.
server
Not
not
only
only
does
does
this
this
provide
provide
SEO,
seo
but
but
it
it
can
can
also
also
improve
improve
the
the
initial
initial
page
page
load
load
speed.
speed
In
in
today's
today's
video,
video
you'll
you'll
learn
learn
how
how
to
to
server
server
side
side
render
render
an
an
Angular
angular
app,
app
then
then
deploy
deploy
it
it
to
to
Google
google
App
app
Engine
engine
or
or
Firebase
firebase
Cloud
cloud
Functions.
functions
If
if
you're
you're
new
new
here,
here
like
like
and
and
and
and
make
make
sure
sure
to
to
follow
follow
along
along
with
with
the
the
full
full
source
source
code
code
on
on
Fireship
fireship
IO.
io
Let's
let's
start
start
by
by
talking
talking
about
about
what
what
server
server
side
side
rendering
rendering
is
is
and
and
when
when
you
you
would
would
wanna
wanna
use
use
it.
it
In
in
any
any
normal
normal
JavaScript
javascript
app,
app
whether
whether
it
it
be
be
Angular,
angular
View,
view
or
or
React,
react
you
you
will
will
provide
provide
the
the
browser
browser
with
with
a
a
JavaScript
javascript
bundle,
bundle
then
then
the
the
browser
browser
will
will
parse
parse
that
that
bundle
bundle
of
of
script
script
and
and
figure
figure
out
out
how
how
to
to
render
render
the
the
HTML.
html
That's
that's
a
a
great
great
way
way
to
to
build
build
a
a
modern
modern
web
web
app
app
because
because
it
it
will
will
make
make
the
the
user
user
experience
experience
feel
feel
very
very
fast
fast
and
and
responsive
responsive
like
like
a
a
native
native
app.
app
But
but
the
the
problem
problem
is
is
that
that
a
a
lot
lot
of
of
bots
bots
out
out
there
there
don't
don't
execute
execute
JavaScript.
javascript
So
so
that
that
means
means
if
if
somebody
somebody
shares
shares
a
a
deep
deep
link
link
in
in
your
your
app
app
and
and
that
that
link
link
renders
renders
some
some
kind
kind
of
of
dynamic
dynamic
Content,
content
the
the
only
only
thing
thing
the
the
bot
bot
will
will
see
see
is
is
your
your
initial
initial
index
index
HTML
html
file.
file
So
so
the
the
purpose
purpose
of
of
Angular
angular
Universal
universal
and
and
server
server
side
side
rendering
rendering
is
is
to
to
offload
offload
some
some
of
of
this
this
work
work
to
to
the
the
server.
server
So
so
when
when
the
the
user
user
first
first
visits
visits
a
a
deep
deep
link,
link
they'll
they'll
get
get
some
some
rendered
rendered
HTML
html
with
with
the
the
dynamic
dynamic
content
content
already
already
included.
included
For
for
example,
example
the
the
Twitter
twitter
bot
bot
just
just
wants
wants
to
to
read
read
the
the
meta
meta
tags
tags
in
in
the
the
head
head
of
of
the
the
document,
document
it's
it's
just
just
going
going
to
to
grab
grab
that
that
HTML
html
and
and
then
then
not
not
worry
worry
about
about
executing
executing
any
any
JavaScript
javascript
on
on
the
the
page.
page
When
when
you
you
have
have
just
just
a
a
regular
regular
user,
user
they'll
they'll
get
get
that
that
same
same
prerendered
prerendered
GML,
gml
so
so
this
this
usually
usually
results
results
in
in
a
a
faster
faster
initial
initial
page
page
load.
load
Then
then
Angular's
angular's
JavaScript
javascript
will
will
take
take
over,
over
so
so
it'll
it'll
behave
behave
just
just
like
like
a
a
regular
regular
Angular
angular
app
app
on
on
subsequent
subsequent
navigations.
navigations
In
in
order
order
to
to
make
make
this
this
possible,
possible
we
we
can't
can't
really
really
use
use
Firebase
firebase
Hosting
hosting
directly
directly
because
because
it's
it's
just
just
a
a
static
static
host.
host
We
we
need
need
an
an
actual
actual
Node.
node
Js
js
server
server
to
to
dynamically
dynamically
render
render
the
the
content
content
when
when
a
a
page
page
is
is
requested.
requested
We
we
have
have
2
2
good
good
deployment
deployment
options
options
for
for
a
a
Firebase
firebase
project,
project
Google
google
App
app
Engine
engine
and
and
Firebase
firebase
Cloud
cloud
Functions.
functions
There
there
are
are
some
some
trade
trade
offs
offs
between
between
the
the
2,
2
but
but
I'll
i'll
show
show
you
you
how
how
to
to
set
set
up
up
both
both
of
of
them
them
in
in
this
this
video.
video
And
and
they
they
can
can
both
both
be
be
used
used
on
on
the
the
free
free
tier.
tier
I'm
i'm
starting
starting
out
out
from
from
a
a
brand
brand
new
new
Angular
angular
7
7
app,
app
and
and
the
the
great
great
thing
thing
about
about
Universal
universal
is
is
that
that
there's
there's
a
a
schematic
schematic
so
so
we
we
can
can
simply
simply
add
add
all
all
the
the
boilerplate
boilerplate
to
to
our
our
project
project
by
by
running
running
this
this
command.
command
N
n
g
g
add
add
universal
universal
express
express
engine
engine
and
and
then
then
specify
specify
the
the
client
client
project
project
as
as
your
your
project
project
name.
name
That
that
will
will
create
create
5
5
new
new
files
files
in
in
this
this
project.
project
So
so
let's
let's
take
take
a
a
look
look
at
at
each
each
one
one
of
of
those
those
now.
now
The
the
first
first
one
one
is
is
the
the
webpack
webpack
server
server
config,
config
and
and
its
its
job
job
is
is
to
to
package
package
and
and
compile
compile
the
the
server
server
dotts
dotts
file.
file
So
so
let's
let's
jump
jump
into
into
server
server
dotts,
dotts
and
and
you'll
you'll
see
see
that
that
this
this
is
is
our
our
actual
actual
Express
express
JS
js
app.
app
Express
express
is
is
a
a
tool
tool
that
that
can
can
receive
receive
a
a
web
web
request
request
and
and
then
then
send
send
a
a
response
response
back
back
to
to
the
the
browser.
browser
So
so
Express
express
will
will
see
see
the
the
initial
initial
request.
request
Angular
angular
Universal
universal
will
will
kick
kick
in
in
and
and
render
render
the
the
actual
actual
HTML,
html
then
then
Express
express
will
will
send
send
that
that
HTML
html
as
as
a
a
response
response
to
to
the
the
browser.
browser
You'll
you'll
also
also
see
see
a
a
main
main
server
server
dot
dot
TS
ts
file,
file
which
which
is
is
just
just
the
the
entry
entry
point
point
into
into
the
the
server
server
side
side
app,
app
and
and
it
it
also
also
has
has
its
its
own
own
TS
ts
config.
config
From
from
there,
there
we'll
we'll
jump
jump
into
into
the
the
app
app
directory,
directory
and
and
you'll
you'll
see
see
we
we
also
also
have
have
an
an
app
app
server
server
module.
module
It's
it's
basically
basically
just
just
a
a
wrapper
wrapper
around
around
the
the
app
app
module.
module
And
and
at
at
this
this
point,
point
you
you
don't
don't
have
have
to
to
make
make
any
any
changes
changes
to
to
any
any
of
of
these
these
files.
files
Once
once
we
we
get
get
to
to
the
the
Firebase
firebase
stuff,
stuff
I'll
i'll
show
show
you
you
exactly
exactly
what
what
needs
needs
to
to
change
change
and
and
where.
where
So
so
let's
let's
go
go
ahead
ahead
and
and
install
install
AngularFire
angularfire
and
and
Firebase
firebase
And
and
then
then
we'll
we'll
jump
jump
into
into
the
the
app
app
module.
module
You'll
you'll
notice
notice
one
one
change
change
here
here
and
and
that's
that's
that
that
the
the
browser
browser
module
module
is
is
now
now
calling
calling
with
with
server
server
That
that
just
just
allows
allows
the
the
app
app
to
to
be
be
rendered
rendered
on
on
the
the
server
server
and
and
then
then
transition
transition
into
into
a
a
normal
normal
Angular
angular
app
app
after
after
the
the
initial
initial
page
page
load.
load
From
from
there,
there
you
you
can
can
import
import
all
all
of
of
the
the
AngularFire
angularfire
stuff
stuff
that
that
you
you
want
want
to
to
use
use
in
in
your
your
project.
project
None
none
of
of
this
this
stuff
stuff
is
is
actually
actually
required
required
for
for
Angular
angular
Universal,
universal
but
but
I'm
i'm
just
just
making
making
the
the
assumption
assumption
that
that
you
you
have
have
Firebase
firebase
in
in
your
your
project
project
because
because
there's
there's
a
a
few
few
caveats
caveats
that
that
we'll
we'll
look
look
at
at
later.
later
That
that
takes
takes
care
care
of
of
the
the
initial
initial
setup.
setup
Now
now
let's
let's
go
go
into
into
the
the
package
package
JSON,
json
and
and
you'll
you'll
see
see
that
that
the
the
n
n
g
g
add
add
command
command
added
added
a
a
few
few
new
new
npm
npm
scripts
scripts
to
to
this
this
file.
file
The
the
ones
ones
that
that
you'll
you'll
wanna
wanna
use
use
primarily
primarily
are
are
build
build
SSR
ssr
and
and
serve
serve
SSR.
ssr
1st,
1st
we'll
we'll
build
build
the
the
app,
app
and
and
then
then
we'll
we'll
go
go
ahead
ahead
and
and
serve
serve
it
it
just
just
to
to
make
make
sure
sure
everything
everything
is
is
working
working
at
at
this
this
point.
point
Now
now
just
just
a
a
quick
quick
side
side
note,
note
I
i
highly
highly
recommend
recommend
using
using
Node
node
version
version
8.14
8.14
when
when
working
working
in
in
your
your
local
local
development
development
environment.
environment
That's
that's
the
the
version
version
used
used
on
on
GCP
gcp
and
and
Cloud
cloud
Functions,
functions
and
and
that's
that's
what
what
I
i
used
used
to
to
build
build
this
this
tutorial.
tutorial
After
after
running
running
the
the
build
build
command,
command
you
you
should
should
see
see
a
a
disk
disk
directory.
directory
And
and
inside
inside
of
of
that,
that
you
you
should
should
see
see
a
a
browser
browser
build
build
and
and
a
a
server
server
build
build
as
as
well
well
as
as
a
a
server
server
JS
js
file.
file
At
at
this
this
point,
point
our
our
app
app
doesn't
doesn't
really
really
do
do
anything,
anything
so
so
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
generate
generate
a
a
new
new
component
component
that
that
represents
represents
the
the
about
about
page
page
for
for
this
this
app.
app
Then
then
we'll
we'll
have
have
this
this
page
page
dynamically
dynamically
render
render
its
its
own
own
meta
meta
tags
tags
so
so
it
it
can
can
be
be
used
used
with
with
a
a
Twitter
twitter
card
card
or
or
any
any
other
other
social
social
media
media
site.
site
If
if
you
you
run
run
n
n
g
g
generate
generate
components,
components
you'll
you'll
probably
probably
get
get
Error
error
saying
saying
it's
it's
missing
missing
the
the
module.
module
You
you
can
can
fix
fix
that
that
by
by
adding
adding
flag
flag
m
m
with
with
app
app
to
to
your
your
command.
command
That
that
happens
happens
because
because
there's
there's
2
2
modules
modules
in
in
the
the
app
app
directory,
directory
and
and
it
it
doesn't
doesn't
know
know
which
which
one
one
to
to
use.
use
When
when
it
it
comes
comes
to
to
SEO,
seo
you'll
you'll
most
most
likely
likely
want
want
to
to
set
set
a
a
title
title
and
and
some
some
meta
meta
tags
tags
when
when
this
this
component
component
is
is
rendered.
rendered
And
and
Angular
angular
provides
provides
a
a
couple
couple
of
of
services
services
for
for
you
you
to
to
do
do
that
that
called
called
title
title
and
and
meta.
meta
Then
then
I'm
i'm
going
going
to
to
create
create
an
an
object
object
with
with
just
just
some
some
static
static
data,
data
but
but
you
you
could
could
also
also
pull
pull
this
this
data
data
from
from
the
the
database.
database
From
from
there,
there
we'll
we'll
go
go
ahead
ahead
and
and
inject
inject
our
our
dependencies
dependencies
in
in
the
the
constructor.
constructor
And
and
then
then
with
with
title,
title
we
we
can
can
just
just
simply
simply
call
call
set
set
title
title
and
and
then
then
pass
pass
the
the
dynamic
dynamic
data
data
to
to
it.
it
Then
then
the
the
meta
meta
service
service
has
has
an
an
add
add
tags
tags
method,
method
which
which
we
we
can
can
pass
pass
an
an
array
array
of
of
multiple
multiple
meta
meta
tags.
tags
You
you
can
can
learn
learn
how
how
to
to
format
format
metatags
metatags
by
by
going
going
to
to
the
the
open
open
graph
graph
docs
docs
or
or
to
to
Twitter
twitter
or
or
Facebook.
facebook
But,
but
basically,
basically
Angular
angular
is
is
just
just
going
going
to
to
add
add
these
these
tags
tags
to
to
the
the
head
head
of
of
the
the
document
document
when
when
this
this
Component
component
is
is
initialized.
initialized
The
the
one
one
thing
thing
that
that
is
is
very
very
important
important
is
is
that
that
you
you
use
use
this
this
service
service
to
to
set
set
the
the
meta
meta
tags
tags
and
and
not
not
do
do
it
it
manually
manually
on
on
the
the
document
document
or
or
window
window
itself.
itself
For
for
example,
example
if
if
we
we
wanted
wanted
to
to
get
get
the
the
URL,
url
it's
it's
tempting
tempting
to
to
call
call
window
window
location
location
path
path
name.
name
But
but
the
the
window
window
doesn't
doesn't
exist
exist
in
in
Node.
node
Js,
js
So
so
this
this
will
will
result
result
in
in
an
an
error
error
when
when
we
we
try
try
to
to
server
server
side
side
render
render
the
the
app.
app
So
so
when
when
using
using
Universal,
universal
you
you
always
always
wanna
wanna
keep
keep
that
that
in
in
mind
mind
and
and
just
just
try
try
to
to
avoid
avoid
touching
touching
the
the
DOM
dom
directly.
directly
So
so
in
in
order
order
for
for
this
this
to
to
be
be
useful
useful
to
to
us,
us
we
we
need
need
to
to
have
have
this
this
component
component
loaded
loaded
by
by
the
the
router.
router
If
if
we
we
jump
jump
over
over
to
to
the
the
app
app
routing
routing
module,
module
we
we
can
can
just
just
set
set
up
up
a
a
single
single
path
path
to
to
about
about
that
that
loads
loads
the
the
about
about
component.
component
At
at
this
this
point,
point
you
you
should
should
be
be
able
able
to
to
load
load
the
the
app
app
in
in
the
the
browser
browser
just
just
using
using
ng
ng
serve
serve
and
and
you
you
should
should
see
see
the
the
meta
meta
tags
tags
in
in
the
the
head
head
of
of
the
the
document.
document
So
so
at
at
this
this
point,
point
we
we
have
have
dynamic
dynamic
meta
meta
tags
tags
but
but
if
if
we
we
were
were
to
to
share
share
this
this
link
link
on
on
social
social
media,
media
we'd
we'd
end
end
up
up
with
with
something
something
like
like
this.
this
And
and
again,
again
that's
that's
because
because
the
the
meta
meta
tags
tags
are
are
rendered
rendered
by
by
the
the
JavaScript.
javascript
Now
now
let's
let's
go
go
ahead
ahead
and
and
serve
serve
this
this
app
app
with
with
Universal
universal
so
so
the
the
meta
meta
tags
tags
are
are
rendered
rendered
in
in
advance.
advance
1st,
1st
run
run
the
the
build
build
SSR
ssr
command.
command
After
after
that's
that's
done,
done
run
run
serve
serve
SSR.
ssr
That
that
will
will
serve
serve
the
the
app
app
on
on
local
local
host
host
4,000.
4,000
But
but
if
if
you're
you're
using
using
Firebase
firebase
in
in
your
your
project,
project
you
you
should
should
end
end
up
up
with
with
an
an
error
error
like
like
this.
this
That's
that's
because
because
Firebase
firebase
uses
uses
a
a
few
few
things
things
in
in
the
the
DOM
dom
that
that
are
are
not
not
available
available
in
in
node
node
by
by
default,
default
but
but
we
we
can
can
easily
easily
fix
fix
that
that
by
by
just
just
adding
adding
polyfills
polyfills
for
for
them.
them
1st,
1st
install
install
WebSockets
websockets
and
and
XHR
xhr
2
2
into
into
your
your
development
development
environment.
environment
From
from
there,
there
go
go
into
into
the
the
server
server
ts
ts
file
file
and
and
then
then
add
add
these
these
two
two
lines
lines
to
to
the
the
very
very
top
top
of
of
it.
it
You
you
run
run
the
the
serve
serve
command
command
again,
again
it
it
should
should
work,
work
but
but
it'll
it'll
still
still
give
give
you
you
a
a
couple
couple
of
of
warnings.
warnings
You
you
can
can
clear
clear
out
out
these
these
warnings
warnings
by
by
installing
installing
these
these
packages,
packages
and
and
that
that
command
command
is
is
available
available
in
in
the
the
full
full
article.
article
And
and
anytime
anytime
you
you
make
make
changes
changes
to
to
this
this
file,
file
make
make
sure
sure
to
to
run
run
the
the
build
build
SSR
ssr
command
command
first
first
and
and
then
then
serve
serve
SSR
ssr
after.
after
At
at
this
this
point,
point
you
you
can
can
go
go
to
to
local
local
host
host
4,000,
4,000
and
and
your
your
app
app
should
should
look
look
and
and
behave
behave
just
just
like
like
a
a
normal
normal
Angular
angular
app.
app
But
but
you
you
can
can
validate
validate
that
that
your
your
server
server
side
side
rendering
rendering
is
is
working
working
by
by
opening
opening
up
up
the
the
page
page
source.
source
This
this
is
is
how
how
the
the
page
page
looks
looks
when
when
it's
it's
served
served
to
to
the
the
browser,
browser
so
so
before
before
any
any
JavaScript
javascript
is
is
run.
run
And
and
you
you
know
know
it's
it's
working
working
if
if
you
you
see
see
your
your
meta
meta
tags
tags
and
and
your
your
dynamic
dynamic
title
title
in
in
this
this
HTML.
html
Now
now
we
we
have
have
a
a
big
big
decision
decision
to
to
make.
make
Do
do
we
we
deploy
deploy
this
this
to
to
Google
google
App
app
Engine
engine
or
or
to
to
Firebase
firebase
Cloud
cloud
Functions?
functions
On
on
App
app
Engine,
engine
our
our
project
project
will
will
become
become
a
a
containerized
containerized
app
app
so
so
it
it
can
can
be
be
Play
play
on
on
App
app
Engine
engine
or
or
any
any
other
other
cloud.
cloud
And
and
there's
there's
a
a
free
free
tier
tier
for
for
Node.
node
Js
js
and
and
it
it
will
will
scale
scale
up
up
automatically
automatically
as
as
needed.
needed
And
and
the
the
pricing
pricing
works
works
out
out
to
to
be
be
around
around
$25
$25
per
per
month
month
per
per
container.
container
But
but
they
they
will
will
auto
auto
scale
scale
based
based
on
on
the
the
traffic
traffic
and
and
demand,
demand
so
so
that
that
pricing
pricing
will
will
vary.
vary
App
app
Engine
engine
is
is
also
also
very
very
easy
easy
to
to
deploy
deploy
too.
too
So
so
in
in
my
my
opinion,
opinion
it's
it's
the
the
better
better
way
way
to
to
go
go
in
in
most
most
cases.
cases
But
but
it's
it's
also
also
possible
possible
to
to
deploy
deploy
to
to
cloud
cloud
functions,
functions
which
which
gives
gives
you
you
a
a
tighter
tighter
integration
integration
with
with
Firebase.
firebase
And
and
it's
it's
hard
hard
to
to
do
do
a
a
direct
direct
price
price
comparison,
comparison
but
but
I
i
suspect
suspect
cloud
cloud
functions
functions
would
would
be
be
less
less
expensive.
expensive
Pricing
pricing
is
is
based
based
on
on
the
the
number
number
of
of
invocations
invocations
of
of
the
the
function
function
which
which
is
is
free
free
up
up
to
to
a
a
125,000
125,000
per
per
month.
month
So
so
those
those
are
are
the
the
trade
trade
offs.
offs
Let's
let's
go
go
ahead
ahead
and
and
deploy
deploy
to
to
App
app
Engine
engine
first.
first
You
you
need
need
to
to
have
have
the
the
Google
google
Cloud
cloud
command
command
line
line
tools
tools
installed.
installed
So
so
you
you
should
should
be
be
able
able
to
to
run
run
the
the
gcloud
gcloud
command
command
and
and
then
then
we'll
we'll
create
create
a
a
file
file
called
called
app
app
dot
dot
yaml.
yaml
The
the
only
only
line
line
you
you
need
need
in
in
this
this
file
file
is
is
the
the
runtime
runtime
as
as
Node
node
JS
js
8,
8
but
but
you
you
can
can
also
also
specify
specify
a
a
different
different
scaling
scaling
options
options
here
here
as
as
well.
well
When
when
you
you
deploy,
deploy
it's
it's
going
going
to
to
be
be
looking
looking
for
for
the
the
npm
npm
run
run
Start
start
command.
command
So
so
you'll
you'll
wanna
wanna
go
go
into
into
your
your
package
package
JSON
json
and
and
have
have
that
that
point
point
to
to
the
the
serve
serve
SSR
ssr
command.
command
From
from
there,
there
it's
it's
just
just
a
a
matter
matter
of
of
running
running
gcloud
gcloud
app
app
deploy
deploy
And
and
that
that
will
will
push
push
the
the
container
container
to
to
Google
google
Cloud
cloud
and
and
start
start
running
running
it
it
as
as
a
a
service.
service
That
that
should
should
take
take
a
a
couple
couple
minutes
minutes
but
but
when
when
it's
it's
done
done
it
it
will
will
give
give
you
you
a
a
URL
url
and
and
when
when
you
you
go
go
there
there
it
it
should
should
have
have
the
the
same
same
exact
exact
app
app
that
that
we
we
were
were
looking
looking
at
at
on
on
local
local
host.
host
And
and
the
the
nice
nice
thing
thing
about
about
App
app
Engine
engine
is
is
that
that
we
we
have
have
this
this
dashboard
dashboard
where
where
we
we
can
can
look
look
at
at
the
the
different
different
versions,
versions
we
we
can
can
look
look
at
at
the
the
debug
debug
logs,
logs
and
and
we
we
can
can
even
even
look
look
at
at
source
source
code.
code
So
so
that
that
was
was
super
super
easy.
easy
Now
now
let's
let's
take
take
a
a
look
look
at
at
Cloud
cloud
Functions
functions
which
which
requires
requires
a
a
few
few
more
more
steps.
steps
The
the
first
first
thing
thing
we
we
wanna
wanna
do
do
is
is
run
run
Firebase
firebase
init
init
for
for
hosting
hosting
and
and
functions.
functions
I'm
i'm
going
going
to
to
use
use
TypeScript
typescript
functions,
functions
but
but
the
the
process
process
is
is
almost
almost
identical
identical
for
for
JavaScript
javascript
functions.
functions
From
from
there,
there
go
go
ahead
ahead
and
and
point
point
to
to
the
the
dist
dist
browser
browser
directory,
directory
And
and
you'll
you'll
say
say
yes
yes
to
to
configuring
configuring
the
the
app
app
as
as
a
a
single
single
page
page
app.
app
We'll
we'll
go
go
ahead
ahead
and
and
configure
configure
it
it
to
to
rewrite
rewrite
all
all
of
of
the
the
traffic
traffic
to
to
a
a
Cloud
cloud
Function
function
instead
instead
of
of
the
the
index
index
HTML
html
like
like
it
it
normally
normally
does.
does
You
you
can
can
name
name
this
this
whatever
whatever
you
you
want,
want
but
but
I'll
i'll
just
just
go
go
ahead
ahead
and
and
call
call
it
it
SSR.
ssr
Now
now
we
we
need
need
to
to
CD
cd
into
into
the
the
functions
functions
directory
directory
and
and
we
we
need
need
a
a
way
way
to
to
get
get
our
our
Angular
angular
code
code
into
into
our
our
functions
functions
environment
environment
because
because
Universal
universal
needs
needs
that
that
source
source
code
code
in
in
the
the
runtime
runtime
to
to
render
render
the
the
actual
actual
content.
content
I'm
i'm
going
going
to
to
write
write
a
a
little
little
node
node
script
script
here
here
to
to
handle
handle
that
that
and
and
to
to
make
make
life
life
a
a
little
little
bit
bit
easier,
easier
I'm
i'm
installing
installing
file
file
system
system
Then
then
we'll
we'll
create
create
a
a
file
file
called
called
cpdashangular.js.
cpdashangular.js
Now
now
there
there
are
are
many
many
different
different
ways
ways
we
we
can
can
do
do
this,
this
but
but
this
this
is
is
the
the
way
way
I
i
chose
chose
to
to
do
do
it.
it
Basically,
basically
we
we
just
just
have
have
a
a
function
function
that
that
will
will
copy
copy
the
the
files
files
from
from
the
the
disk
disk
directory
directory
in
in
Angular
angular
over
over
to
to
a
a
disk
disk
folder
folder
in
in
the
the
functions
functions
directory.
directory
Then
then
we'll
we'll
also
also
always
always
want
want
to
to
remove
remove
the
the
copied
copied
files
files
on
on
each
each
new
new
build
build
of
of
Cloud
cloud
Functions
functions
just
just
to
to
make
make
sure
sure
we're
we're
always
always
working
working
with
with
the
the
latest
latest
Angular
angular
code.
code
From
from
there,
there
go
go
into
into
the
the
package
package
JSON
json
4
4
functions
functions
and
and
run
run
node
node
cp
cp
angular
angular
in
in
your
your
build
build
command.
command
And
and
while
while
we're
we're
in
in
here,
here
let's
let's
also
also
set
set
the
the
engine
engine
to
to
node
node
8
8
so
so
that
that
it
it
Ploys
ploys
our
our
function
function
as
as
a
a
note
note
eight
eight
function.
function
Now
now
we'll
we'll
go
go
to
to
the
the
source
source
index
index
TS
ts
and
and
write
write
the
the
function
function
itself.
itself
It's
it's
actually
actually
super
super
easy.
easy
We
we
have
have
to
to
do
do
is
is
take
take
the
the
universal
universal
app
app
and
and
then
then
pass
pass
it
it
into
into
an
an
HTTP
http
function.
function
As
as
you
you
can
can
see
see
here,
here
we're
we're
actually
actually
importing
importing
the
the
universal
universal
app
app
from
from
our
our
current
current
working
working
directory.
directory
So
so
that's
that's
why
why
we
we
have
have
to
to
copy
copy
it
it
over
over
to
to
the
the
functions
functions
environment.
environment
And
and
that's
that's
all
all
there
there
is
is
to
to
the
the
function
function
side
side
of
of
things.
things
But
but
in
in
order
order
for
for
this
this
to
to
work,
work
we
we
need
need
to
to
make
make
a
a
couple
couple
of
of
tweaks
tweaks
to
to
the
the
original
original
server
server
code
code
in
in
Angular.
angular
Open
open
up
up
the
the
server
server
ts
ts
file
file
and
and
then
then
add
add
an
an
export
export
in
in
front
front
of
of
the
the
app
app
variable.
variable
Then
then
go
go
all
all
the
the
way
way
down
down
to
to
the
the
bottom
bottom
and
and
comment
comment
out
out
the
the
listener.
listener
Cloud
cloud
Functions
functions
is
is
already
already
doing
doing
the
the
listening
listening
so
so
we
we
don't
don't
want
want
this
this
line
line
in
in
our
our
code.
code
And
and
we
we
need
need
to
to
make
make
sure
sure
that
that
our
our
code
code
gets
gets
exported
exported
as
as
a
a
library
library
that
that
we
we
can
can
consume.
consume
So
so
add
add
library
library
app
app
and
and
library
library
target
target
UMD.
umd
And
and
if
if
you
you
have
have
issues
issues
bundling
bundling
you
you
may
may
want
want
to
to
add
add
Firebase
firebase
as
as
an
an
external.
external
Now
now
it's
it's
time
time
for
for
the
the
moment
moment
of
of
truth.
truth
1st,
1st
make
make
sure
sure
to
to
rebuild
rebuild
your
your
app
app
using
using
the
the
build
build
SSR
ssr
command
command
in
in
Angular,
angular
then
then
go
go
into
into
the
the
functions
functions
directory
directory
and
and
run
run
the
the
build
build
command
command
there.
there
From
from
there,
there
run
run
firebase
firebase
serve
serve
which
which
will
will
serve
serve
your
your
hosting
hosting
and
and
your
your
function
function
simultaneously.
simultaneously
Hopefully,
hopefully
everything
everything
went
went
well
well
and
and
you're
you're
seeing
seeing
the
the
rendered
rendered
meta
meta
tags
tags
when
when
you
you
go
go
to
to
local
local
host
host
5000.
5000
If
if
that's
that's
the
the
case,
case
go
go
ahead
ahead
and
and
run
run
Firebase
firebase
deploy,
deploy
and
and
that
that
will
will
deploy
deploy
the
the
function
function
and
and
hosting.
hosting
And
and
now
now
you
you
have
have
a
a
fully
fully
server
server
side
side
rendered
rendered
app
app
running
running
on
on
Firebase
firebase
Cloud
cloud
functions.
functions
After
after
it
it
deploys,
deploys
head
head
over
over
to
to
the
the
Twitter
twitter
card
card
validator
validator
just
just
to
to
make
make
sure
sure
that
that
everything
everything
is
is
working
working
as
as
expected.
expected
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
you
you
run
run
into
into
any
any
issues,
issues
let
let
me
me
know
know
in
in
the
the
comments
comments
or
or
on
on
Slack.
slack
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The speaker discusses the challenges of building a single page application with Angular Universal, including offloading work to the server and improving page load speed. They recommend using Google Cloud command line tools for deployment and discuss the cost-effectiveness of using the App Engine. The process of installing Angularipping and integrating apps and setting up titles and meta tags is discussed, along with the use of the title and meta service for setting meta tags and the process of rebuilding app using SSR command and API. The cost-effectiveness of deploying to Google Cloud is also discussed, along with instructions on accessing the moment of truth in Angular.
Angular Universal on Cloud Functions or AppEngine
One of the biggest challenges with building a single page application is making the app visible to search engines and link bots. Fortunately with Angular Universal, So we have a reliable package for rendering our apps on the server. Not only does this provide SEO, but it can also improve the initial page load speed. In today's video, you'll learn how to server side render an Angular app, then deploy it to Google App Engine or Firebase Cloud Functions. If you're new here, like and and make sure to follow along with the full source code on Fireship IO. Let's start by talking about what server side rendering is and when you would wanna use it. In any normal JavaScript app, whether it be Angular, View, or React, you will provide the browser with a JavaScript bundle, then the browser will parse that bundle of script and figure out how to render the HTML. That's a great way to build a modern web app because it will make the user experience feel very fast and responsive like a native app. But the problem is that a lot of bots out there don't execute JavaScript. So that means if somebody shares a deep link in your app and that link renders some kind of dynamic Content, the only thing the bot will see is your initial index HTML file. So the purpose of Angular Universal and server side rendering is to offload some of this work to the server. So when the user first visits a deep link, they'll get some rendered HTML with the dynamic content already included. For example, the Twitter bot just wants to read the meta tags in the head of the document, it's just going to grab that HTML and then not worry about executing any JavaScript on the page. When you have just a regular user, they'll get that same prerendered GML, so this usually results in a faster initial page load. Then Angular's JavaScript will take over, so it'll behave just like a regular Angular app on subsequent navigations. In order to make this possible, we can't really use Firebase Hosting directly because it's just a static host. We need an actual Node. Js server to dynamically render the content when a page is requested. We have 2 good deployment options for a Firebase project, Google App Engine and Firebase Cloud Functions. There are some trade offs between the 2, but I'll show you how to set up both of them in this video. And they can both be used on the free tier. I'm starting out from a brand new Angular 7 app, and the great thing about Universal is that there's a schematic so we can simply add all the boilerplate to our project by running this command. N g add universal express engine and then specify the client project as your project name. That will create 5 new files in this project. So let's take a look at each one of those now. The first one is the webpack server config, and its job is to package and compile the server dotts file. So let's jump into server dotts, and you'll see that this is our actual Express JS app. Express is a tool that can receive a web request and then send a response back to the browser. So Express will see the initial request. Angular Universal will kick in and render the actual HTML, then Express will send that HTML as a response to the browser. You'll also see a main server dot TS file, which is just the entry point into the server side app, and it also has its own TS config. From there, we'll jump into the app directory, and you'll see we also have an app server module. It's basically just a wrapper around the app module. And at this point, you don't have to make any changes to any of these files. Once we get to the Firebase stuff, I'll show you exactly what needs to change and where. So let's go ahead and install AngularFire and Firebase And then we'll jump into the app module. You'll notice one change here and that's that the browser module is now calling with server That just allows the app to be rendered on the server and then transition into a normal Angular app after the initial page load. From there, you can import all of the AngularFire stuff that you want to use in your project. None of this stuff is actually required for Angular Universal, but I'm just making the assumption that you have Firebase in your project because there's a few caveats that we'll look at later. That takes care of the initial setup. Now let's go into the package JSON, and you'll see that the n g add command added a few new npm scripts to this file. The ones that you'll wanna use primarily are build SSR and serve SSR. 1st, we'll build the app, and then we'll go ahead and serve it just to make sure everything is working at this point. Now just a quick side note, I highly recommend using Node version 8.14 when working in your local development environment. That's the version used on GCP and Cloud Functions, and that's what I used to build this tutorial. After running the build command, you should see a disk directory. And inside of that, you should see a browser build and a server build as well as a server JS file. At this point, our app doesn't really do anything, so I'm gonna go ahead and generate a new component that represents the about page for this app. Then we'll have this page dynamically render its own meta tags so it can be used with a Twitter card or any other social media site. If you run n g generate components, you'll probably get Error saying it's missing the module. You can fix that by adding flag m with app to your command. That happens because there's 2 modules in the app directory, and it doesn't know which one to use. When it comes to SEO, you'll most likely want to set a title and some meta tags when this component is rendered. And Angular provides a couple of services for you to do that called title and meta. Then I'm going to create an object with just some static data, but you could also pull this data from the database. From there, we'll go ahead and inject our dependencies in the constructor. And then with title, we can just simply call set title and then pass the dynamic data to it. Then the meta service has an add tags method, which we can pass an array of multiple meta tags. You can learn how to format metatags by going to the open graph docs or to Twitter or Facebook. But, basically, Angular is just going to add these tags to the head of the document when this Component is initialized. The one thing that is very important is that you use this service to set the meta tags and not do it manually on the document or window itself. For example, if we wanted to get the URL, it's tempting to call window location path name. But the window doesn't exist in Node. Js, So this will result in an error when we try to server side render the app. So when using Universal, you always wanna keep that in mind and just try to avoid touching the DOM directly. So in order for this to be useful to us, we need to have this component loaded by the router. If we jump over to the app routing module, we can just set up a single path to about that loads the about component. At this point, you should be able to load the app in the browser just using ng serve and you should see the meta tags in the head of the document. So at this point, we have dynamic meta tags but if we were to share this link on social media, we'd end up with something like this. And again, that's because the meta tags are rendered by the JavaScript. Now let's go ahead and serve this app with Universal so the meta tags are rendered in advance. 1st, run the build SSR command. After that's done, run serve SSR. That will serve the app on local host 4,000. But if you're using Firebase in your project, you should end up with an error like this. That's because Firebase uses a few things in the DOM that are not available in node by default, but we can easily fix that by just adding polyfills for them. 1st, install WebSockets and XHR 2 into your development environment. From there, go into the server ts file and then add these two lines to the very top of it. You run the serve command again, it should work, but it'll still give you a couple of warnings. You can clear out these warnings by installing these packages, and that command is available in the full article. And anytime you make changes to this file, make sure to run the build SSR command first and then serve SSR after. At this point, you can go to local host 4,000, and your app should look and behave just like a normal Angular app. But you can validate that your server side rendering is working by opening up the page source. This is how the page looks when it's served to the browser, so before any JavaScript is run. And you know it's working if you see your meta tags and your dynamic title in this HTML. Now we have a big decision to make. Do we deploy this to Google App Engine or to Firebase Cloud Functions? On App Engine, our project will become a containerized app so it can be Play on App Engine or any other cloud. And there's a free tier for Node. Js and it will scale up automatically as needed. And the pricing works out to be around $25 per month per container. But they will auto scale based on the traffic and demand, so that pricing will vary. App Engine is also very easy to deploy too. So in my opinion, it's the better way to go in most cases. But it's also possible to deploy to cloud functions, which gives you a tighter integration with Firebase. And it's hard to do a direct price comparison, but I suspect cloud functions would be less expensive. Pricing is based on the number of invocations of the function which is free up to a 125,000 per month. So those are the trade offs. Let's go ahead and deploy to App Engine first. You need to have the Google Cloud command line tools installed. So you should be able to run the gcloud command and then we'll create a file called app dot yaml. The only line you need in this file is the runtime as Node JS 8, but you can also specify a different scaling options here as well. When you deploy, it's going to be looking for the npm run Start command. So you'll wanna go into your package JSON and have that point to the serve SSR command. From there, it's just a matter of running gcloud app deploy And that will push the container to Google Cloud and start running it as a service. That should take a couple minutes but when it's done it will give you a URL and when you go there it should have the same exact app that we were looking at on local host. And the nice thing about App Engine is that we have this dashboard where we can look at the different versions, we can look at the debug logs, and we can even look at source code. So that was super easy. Now let's take a look at Cloud Functions which requires a few more steps. The first thing we wanna do is run Firebase init for hosting and functions. I'm going to use TypeScript functions, but the process is almost identical for JavaScript functions. From there, go ahead and point to the dist browser directory, And you'll say yes to configuring the app as a single page app. We'll go ahead and configure it to rewrite all of the traffic to a Cloud Function instead of the index HTML like it normally does. You can name this whatever you want, but I'll just go ahead and call it SSR. Now we need to CD into the functions directory and we need a way to get our Angular code into our functions environment because Universal needs that source code in the runtime to render the actual content. I'm going to write a little node script here to handle that and to make life a little bit easier, I'm installing file system Then we'll create a file called cpdashangular.js. Now there are many different ways we can do this, but this is the way I chose to do it. Basically, we just have a function that will copy the files from the disk directory in Angular over to a disk folder in the functions directory. Then we'll also always want to remove the copied files on each new build of Cloud Functions just to make sure we're always working with the latest Angular code. From there, go into the package JSON 4 functions and run node cp angular in your build command. And while we're in here, let's also set the engine to node 8 so that it Ploys our function as a note eight function. Now we'll go to the source index TS and write the function itself. It's actually super easy. We have to do is take the universal app and then pass it into an HTTP function. As you can see here, we're actually importing the universal app from our current working directory. So that's why we have to copy it over to the functions environment. And that's all there is to the function side of things. But in order for this to work, we need to make a couple of tweaks to the original server code in Angular. Open up the server ts file and then add an export in front of the app variable. Then go all the way down to the bottom and comment out the listener. Cloud Functions is already doing the listening so we don't want this line in our code. And we need to make sure that our code gets exported as a library that we can consume. So add library app and library target UMD. And if you have issues bundling you may want to add Firebase as an external. Now it's time for the moment of truth. 1st, make sure to rebuild your app using the build SSR command in Angular, then go into the functions directory and run the build command there. From there, run firebase serve which will serve your hosting and your function simultaneously. Hopefully, everything went well and you're seeing the rendered meta tags when you go to local host 5000. If that's the case, go ahead and run Firebase deploy, and that will deploy the function and hosting. And now you have a fully server side rendered app running on Firebase Cloud functions. After it deploys, head over to the Twitter card validator just to make sure that everything is working as expected. I'm gonna go ahead and wrap things up there. If you run into any issues, let me know in the comments or on Slack. Thanks for watching, and I will talk to you soon.
The speaker discusses the challenges of building a single page application with Angular Universal, including offloading work to the server and improving page load speed. They recommend using Google Cloud command line tools for deployment and discuss the cost-effectiveness of using the App Engine. The process of installing Angularipping and integrating apps and setting up titles and meta tags is discussed, along with the use of the title and meta service for setting meta tags and the process of rebuilding app using SSR command and API. The cost-effectiveness of deploying to Google Cloud is also discussed, along with instructions on accessing the moment of truth in Angular.