Learn how to server-side render your Firebase app with Angular Universal to make deep links readable by social media bots and search engines. https://angularfirebase.com/lessons/server-side-rendering-firebase-angular-universal/

- Universal https://angular.io/guide/universalf
- Firestore https://firebase.google.com/docs/firestore/
- AngularFire2 https://github.com/angular/angularfire2
2024-02-04T07:38:23.243Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
428521d1-9b72-4c2a-99aa-e816ae0f650f
3bd07c9e3c0541ac06d7f15d60d4cda11e78f15143e7befdaf18a005011d9aeb
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Today, we're finally going to answer the question of how do we combine Firebase with Angular Universal to build a search engine optimized JavaScript app.
Recent changes to AngularFire 2 now make it possible to perform server side rendering with Universal.
Unisole.
What this means is that our app's content can be understood by search engines and used by social media link bots, and we might even get some good page load performance gains out of it.
Unity.
If you're new here, make sure to like and subscribe, and I highly recommend that you follow along with the source code on angularfirebase.com.
First, let's talk about what server side rendering is.
Normally, we just let the browser parcel of the JavaScript and render it out to HTML.
But this becomes a problem if your app has routes that need to be indexed in a search engine or shared on social media.
Most bots that visit your site only understand HTML and don't make any effort to parse the JavaScript that's there.
What we can do is make our Angular app behave more like a traditional web application that responds with HTML from a server.
On the first page visit, it will render the app to HTML and then send it over to the browser, which will then take over and transition it to work just like a regular Angular app.
In this demo, I'll show you how to go from 0 to deployed Angular Universal app, and we'll generate all of the content with this collection of animals that I have stored in the Firestore database.
I should warn you that we have a lot of code to get through, but most of it's configuration related stuff that you can just copy and paste into your project.
But I documented everything step by step in the main article so so you can follow along with that if you get lost.
Step 1 is to generate a new Angular app and make sure that it has a routing module.
Then install the latest version of AngularFire 2 and Firebase, and then send a thank you card to James from Firebase because he made some pretty epic changes to this library to make Universal support possible.
After that's done, install platform server from Angular.
And if you're doing lazy loading, you'll also need this NG Universal, Module Map, NG Factory Loader, and TS Loader as well.
When it comes to social media bots, They're going to be looking for meta tags in the head of the document.
You can find the specific requirements on the Facebook and Twitter developer docs, But what I wanna show you first is how to efficiently set these metatags with an Angular service.
Let's call this our SEO service, and we'll add it to the app module.
Angular's browser platform has a couple helpers to set meta tags as well as the document title.
So we'll import those and then inject them in the constructor.
Then I'm going to define a method that will take an object as its argument.
Different social media sites have different requirements for meta tags, which are often very similar.
Unity.
So to keep our code dry, we're going to set some defaults and then just override these defaults with whatever we pass in this tags object, UI, which will ultimately be data that we pull from Firestore.
1st, we can use the title service to set the document title, UI, and then we'll set our meta tags.
As far as I know, we have to call update tag on each one of these because there's no way in Angular to update them all in bulk.
Now that that's done, we need a component that gets loaded by the router and use it to set these meta tags.
Let's go ahead and call this our animal detail component.
Then we'll use this component in our router, and we'll make sure to set up a route param for the name, which should match the document ID that we have saved in Firebase for a given animal.
The next step is to go into the component, and we'll need a variety of things here, including our SEO service as well as the Firestore database.
Then we'll use activated route to get the current animal name from the URL that that user navigated to.
Again, that is the document ID in Firestore, and we can get it by calling route snapshot param map followed by git name.
If we look at this data in Firestore quickly, You'll see we have a variety of documents with an ID of bird, cat, elephant, etcetera.
Then each of these documents has a bio as well as an image URL and a name.
What we need to do is read this document, and then once we have the document data, use it to set the meta tags on the DOM.
AngularFire 2 gives us the data as an observable, so we can pipe in the tap operator.
Then once we have the data, we can use our SEO service to generate the tags.
But this does bring up one problem.
Because we're going to read this document on the server and then transition back to the browser, it will read the document twice and the user will see a brief flash in between those requests.
This has slowed down significantly, but notice how we get some initial data from the server.
It goes blank, then it comes back online after we've transitioned into the browser.
Fortunately, Universal gives us some tools to transition state from the server side to the client side.
It just allows you to set a key value pair on the server and then read it on the browser.
So we'll import transfer state as well as make state key.
Then we'll set up a constant here with make state key and give it the name of animal.
When we get data on the server, we'll set it as this animal key and then read it when we get back to the browser.
And transfer state is a service, so we'll add that to our constructor.
And then I'm going to Define this as its own isolated method so you can reuse it if you have use for this in your own app.
So what we're going to do in this method is first check if a document already exists.
This should always return false on the server.
It takes the Kiwi defined as the first argument and then a default value as the second argument.
And just like we did before, we'll get our Firestore document as an observable and pipe in the tap operator.
But this time, we will set the animal key with the document data.
And we can also set our meta tag values here like we did before.
UI.
So the only question that remains is how do we use this existing document for our observable value once we transition to the browser?
And the answer is super easy.
We have an RxJS operator called start with, and we can just pass it that existing object.
So instead of null, you still have your existing document from the server.
But it is worth noting that this will execute 2 document reads in Firestore, so that may or may not be an issue for you.
Keep in mind that you only server side render on a full page load, so it's unlikely that that would be an issue in most cases.
The last thing we need to do is go in to the animal detail component and subscribe to the animal observable, which we can do with the async pipe.
That takes care of our front end Angular app portion.
Now we have a whole bunch of configuration stuff to do with Angular Universal.
Most of this stuff is copy and paste configuration for right now, but hopefully, some of this comes to the Angular CLI in future.
1st, we'll go into the existing app module and add with server transition to the browser module import and set any random app ID that you want.
And then make sure to import the transfer state module if you're doing a state transfer as well.
Then the next thing you'll need to do is create an app server module, And it should also live inside the app directory.
Basically, all this is doing is taking your app module and then importing it into another module that is set up to be rendered on the server.
Then if you're transferring state, you'll need the server transfer state module and also the module map loader if UI doing lazy loading in your app.
You wouldn't want lazy loading on the server, so that module takes care of that aspect for you.
That should take care of everything in the app directory.
Now we're going to move up to the source directory and add a new file called main.server.ts.
All it has to do is import the app server module that we just created.
This is more of a formality because main is our main entry point into the app.
We also need to create a TS config for our main server TS file.
So create tsconfig.server.json.
One of the main differences between the browser build and the server build is that our server build needs to be in common JS so it can work on Node.
Js.
The next thing we need to do is configure our app with the Angular CLI so the CLI knows how to bundle it and where to transpile all the code.
The next thing we'll do is build our actual server code, which uses Express JS, which is one of the most popular HTTP frameworks for Node.
Js.
Create the server TS file and then copy and paste all of this Express JS code into that file.
This code was taken from the official Angular Universal demo, and only a few little modifications were made here and there to make it work with Firebase.
For example, Firebase uses a few things that aren't available in Node.
Js such as WebSockets.
But a way to get around this is is to set them on the global object, which is the equivalent to the window object in a browser.
There's a handful of things you might need in your project to make the server environment compatible with Firebase, I was able to install them with this command which you can find in the main article.
UI.
If you look at the Express JS app, you'll notice that it's not the prettiest code ever.
The most important thing to understand here is that this Express app is capturing all of the routes in our Angular application and then rendering them to HTML based on wherever the user navigates.
So that means they can navigate to a deep link, And we'll get the rendered HTML for that page.
The one thing about Express is that it's completely separate from our Angular application.
The Angular CLI has no way to compile this down to a production build for us, and we can roll out our own webpack config to do that.
Create another file called webpack.server.config.js.
And we're gonna add some more not so pretty code to it.
But essentially, what we're doing is what the Angular CLI does under the hood.
In this case, it's taking our TypeScript file and compiling it down to JavaScript that can run on Node.
You should be able to copy and paste this and just forget about it as long as you're placing all of your files in the same place that we did in this lesson.
We're getting really close to the end here.
The next thing we need to do is go up into the root of the project and in the angularcli.json file, at a configuration for our server app.
You'll notice that the apps option is an array.
That's because we can add multiple apps to the Angular CLI configuration, which is exactly what we need to do here.
Again, we're doing another copy and paste style thing where we take the existing app, and then we make a few modifications to it 2 point to the resources for our server app.
We will point the main entry point to the main dot server dot ts file.
We can also remove polyfills because they're not needed on the server, and you'll want to set service worker to false if using a worker.
At this point, we need to build 3 different apps, our Express JS server, our Angular browser app, and Angular server app.
We can do this in the package JSON in the scripts object.
Basically, we're just combining our ng build commands with our webpack config to run everything all at once.
UI.
We can run these 2 commands together by doing npm run build colon ssr and serve colon ssr.
When the build finishes, it should serve your express app on local host 4,000 and you should see all 3 apps in the dist folder.
But it really shouldn't feel any different than a normal Angular UI.
It just has this secret power to be understood by link bots and search engines.
If you copy a link from your app and paste it into the Twitter card validator, you should CU valid card even though this data is pulled from the Firestore database asynchronously.
And you'll also want to check to see if you've achieved any performance gains from SSR.
For this demo, I ran a lighthouse audit and achieved a score of 94, which is really good for an Angular app pulling data from Fire UI based.
I'm gonna go ahead and wrap things up there.
If this video helped you, please like and subscribe.
And if you wanna talk about more advanced SSR scenarios, consider becoming a pro member at AngularFirebase.com.
You'll get access to all kinds of exclusive content designed to help you ship apps on the Angular Firebase stack.
Unity.
Thanks for watching, and I'll see you soon.

Speaker 0: Today, we're finally going to answer the question of how do we combine Firebase with Angular Universal to build a search engine optimized JavaScript app. Recent changes to AngularFire 2 now make it possible to perform server side rendering with Universal. Unisole. What this means is that our app's content can be understood by search engines and used by social media link bots, and we might even get some good page load performance gains out of it. Unity.

If you're new here, make sure to like and subscribe, and I highly recommend that you follow along with the source code on angularfirebase.com. First, let's talk about what server side rendering is. Normally, we just let the browser parcel of the JavaScript and render it out to HTML. But this becomes a problem if your app has routes that need to be indexed in a search engine or shared on social media. Most bots that visit your site only understand HTML and don't make any effort to parse the JavaScript that's there.

What we can do is make our Angular app behave more like a traditional web application that responds with HTML from a server. On the first page visit, it will render the app to HTML and then send it over to the browser, which will then take over and transition it to work just like a regular Angular app. In this demo, I'll show you how to go from 0 to deployed Angular Universal app, and we'll generate all of the content with this collection of animals that I have stored in the Firestore database. I should warn you that we have a lot of code to get through, but most of it's configuration related stuff that you can just copy and paste into your project. But I documented everything step by step in the main article so so you can follow along with that if you get lost.

Step 1 is to generate a new Angular app and make sure that it has a routing module. Then install the latest version of AngularFire 2 and Firebase, and then send a thank you card to James from Firebase because he made some pretty epic changes to this library to make Universal support possible. After that's done, install platform server from Angular. And if you're doing lazy loading, you'll also need this NG Universal, Module Map, NG Factory Loader, and TS Loader as well. When it comes to social media bots, They're going to be looking for meta tags in the head of the document.

You can find the specific requirements on the Facebook and Twitter developer docs, But what I wanna show you first is how to efficiently set these metatags with an Angular service. Let's call this our SEO service, and we'll add it to the app module. Angular's browser platform has a couple helpers to set meta tags as well as the document title. So we'll import those and then inject them in the constructor. Then I'm going to define a method that will take an object as its argument.

Different social media sites have different requirements for meta tags, which are often very similar. Unity. So to keep our code dry, we're going to set some defaults and then just override these defaults with whatever we pass in this tags object, UI, which will ultimately be data that we pull from Firestore. 1st, we can use the title service to set the document title, UI, and then we'll set our meta tags. As far as I know, we have to call update tag on each one of these because there's no way in Angular to update them all in bulk.

Now that that's done, we need a component that gets loaded by the router and use it to set these meta tags. Let's go ahead and call this our animal detail component. Then we'll use this component in our router, and we'll make sure to set up a route param for the name, which should match the document ID that we have saved in Firebase for a given animal. The next step is to go into the component, and we'll need a variety of things here, including our SEO service as well as the Firestore database. Then we'll use activated route to get the current animal name from the URL that that user navigated to.

Again, that is the document ID in Firestore, and we can get it by calling route snapshot param map followed by git name. If we look at this data in Firestore quickly, You'll see we have a variety of documents with an ID of bird, cat, elephant, etcetera. Then each of these documents has a bio as well as an image URL and a name. What we need to do is read this document, and then once we have the document data, use it to set the meta tags on the DOM. AngularFire 2 gives us the data as an observable, so we can pipe in the tap operator.

Then once we have the data, we can use our SEO service to generate the tags. But this does bring up one problem. Because we're going to read this document on the server and then transition back to the browser, it will read the document twice and the user will see a brief flash in between those requests. This has slowed down significantly, but notice how we get some initial data from the server. It goes blank, then it comes back online after we've transitioned into the browser.

Fortunately, Universal gives us some tools to transition state from the server side to the client side. It just allows you to set a key value pair on the server and then read it on the browser. So we'll import transfer state as well as make state key. Then we'll set up a constant here with make state key and give it the name of animal. When we get data on the server, we'll set it as this animal key and then read it when we get back to the browser.

And transfer state is a service, so we'll add that to our constructor. And then I'm going to Define this as its own isolated method so you can reuse it if you have use for this in your own app. So what we're going to do in this method is first check if a document already exists. This should always return false on the server. It takes the Kiwi defined as the first argument and then a default value as the second argument.

And just like we did before, we'll get our Firestore document as an observable and pipe in the tap operator. But this time, we will set the animal key with the document data. And we can also set our meta tag values here like we did before. UI. So the only question that remains is how do we use this existing document for our observable value once we transition to the browser?

And the answer is super easy. We have an RxJS operator called start with, and we can just pass it that existing object. So instead of null, you still have your existing document from the server. But it is worth noting that this will execute 2 document reads in Firestore, so that may or may not be an issue for you. Keep in mind that you only server side render on a full page load, so it's unlikely that that would be an issue in most cases.

The last thing we need to do is go in to the animal detail component and subscribe to the animal observable, which we can do with the async pipe. That takes care of our front end Angular app portion. Now we have a whole bunch of configuration stuff to do with Angular Universal. Most of this stuff is copy and paste configuration for right now, but hopefully, some of this comes to the Angular CLI in future. 1st, we'll go into the existing app module and add with server transition to the browser module import and set any random app ID that you want.

And then make sure to import the transfer state module if you're doing a state transfer as well. Then the next thing you'll need to do is create an app server module, And it should also live inside the app directory. Basically, all this is doing is taking your app module and then importing it into another module that is set up to be rendered on the server. Then if you're transferring state, you'll need the server transfer state module and also the module map loader if UI doing lazy loading in your app. You wouldn't want lazy loading on the server, so that module takes care of that aspect for you.

That should take care of everything in the app directory. Now we're going to move up to the source directory and add a new file called main.server.ts. All it has to do is import the app server module that we just created. This is more of a formality because main is our main entry point into the app. We also need to create a TS config for our main server TS file.

So create tsconfig.server.json. One of the main differences between the browser build and the server build is that our server build needs to be in common JS so it can work on Node. Js. The next thing we need to do is configure our app with the Angular CLI so the CLI knows how to bundle it and where to transpile all the code. The next thing we'll do is build our actual server code, which uses Express JS, which is one of the most popular HTTP frameworks for Node.

Js. Create the server TS file and then copy and paste all of this Express JS code into that file. This code was taken from the official Angular Universal demo, and only a few little modifications were made here and there to make it work with Firebase. For example, Firebase uses a few things that aren't available in Node. Js such as WebSockets.

But a way to get around this is is to set them on the global object, which is the equivalent to the window object in a browser. There's a handful of things you might need in your project to make the server environment compatible with Firebase, I was able to install them with this command which you can find in the main article. UI. If you look at the Express JS app, you'll notice that it's not the prettiest code ever. The most important thing to understand here is that this Express app is capturing all of the routes in our Angular application and then rendering them to HTML based on wherever the user navigates.

So that means they can navigate to a deep link, And we'll get the rendered HTML for that page. The one thing about Express is that it's completely separate from our Angular application. The Angular CLI has no way to compile this down to a production build for us, and we can roll out our own webpack config to do that. Create another file called webpack.server.config.js. And we're gonna add some more not so pretty code to it.

But essentially, what we're doing is what the Angular CLI does under the hood. In this case, it's taking our TypeScript file and compiling it down to JavaScript that can run on Node. You should be able to copy and paste this and just forget about it as long as you're placing all of your files in the same place that we did in this lesson. We're getting really close to the end here. The next thing we need to do is go up into the root of the project and in the angularcli.json file, at a configuration for our server app.

You'll notice that the apps option is an array. That's because we can add multiple apps to the Angular CLI configuration, which is exactly what we need to do here. Again, we're doing another copy and paste style thing where we take the existing app, and then we make a few modifications to it 2 point to the resources for our server app. We will point the main entry point to the main dot server dot ts file. We can also remove polyfills because they're not needed on the server, and you'll want to set service worker to false if using a worker.

At this point, we need to build 3 different apps, our Express JS server, our Angular browser app, and Angular server app. We can do this in the package JSON in the scripts object. Basically, we're just combining our ng build commands with our webpack config to run everything all at once. UI. We can run these 2 commands together by doing npm run build colon ssr and serve colon ssr.

When the build finishes, it should serve your express app on local host 4,000 and you should see all 3 apps in the dist folder. But it really shouldn't feel any different than a normal Angular UI. It just has this secret power to be understood by link bots and search engines. If you copy a link from your app and paste it into the Twitter card validator, you should CU valid card even though this data is pulled from the Firestore database asynchronously. And you'll also want to check to see if you've achieved any performance gains from SSR.

For this demo, I ran a lighthouse audit and achieved a score of 94, which is really good for an Angular app pulling data from Fire UI based. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna talk about more advanced SSR scenarios, consider becoming a pro member at AngularFirebase.com. You'll get access to all kinds of exclusive content designed to help you ship apps on the Angular Firebase stack.

Unity. Thanks for watching, and I'll see you soon.
Today, we're finally going to answer the question of how do we combine Firebase with Angular Universal to build a search engine optimized JavaScript app. Recent changes to AngularFire 2 now make it possible to perform server side rendering with Universal. Unisole. What this means is that our app's content can be understood by search engines and used by social media link bots, and we might even get some good page load performance gains out of it. Unity. If you're new here, make sure to like and subscribe, and I highly recommend that you follow along with the source code on angularfirebase.com. First, let's talk about what server side rendering is. Normally, we just let the browser parcel of the JavaScript and render it out to HTML.
But this becomes a problem if your app has routes that need to be indexed in a search engine or shared on social media. Most bots that visit your site only understand HTML and don't make any effort to parse the JavaScript that's there. What we can do is make our Angular app behave more like a traditional web application that responds with HTML from a server.
google
On the first page visit, it will render the app to HTML and then send it over to the browser, which will then take over and transition it to work just like a regular Angular app. In this demo, I'll show you how to go from 0 to deployed Angular Universal app, and we'll generate all of the content with this collection of animals that I have stored in the Firestore database.
I should warn you that we have a lot of code to get through, but most of it's configuration related stuff that you can just copy and paste into your project. But I documented everything step by step in the main article so so you can follow along with that if you get lost.
documentation
Step 1 is to generate a new Angular app and make sure that it has a routing module. Then install the latest version of AngularFire 2 and Firebase, and then send a thank you card to James from Firebase because he made some pretty epic changes to this library to make Universal support possible. After that's done, install platform server from Angular. And if you're doing lazy loading, you'll also need this NG Universal, Module Map, NG Factory Loader, and TS Loader as well. When it comes to social media bots, They're going to be looking for meta tags in the head of the document. You can find the specific requirements on the Facebook and Twitter developer docs, But what I wanna show you first is how to efficiently set these metatags with an Angular service. Let's call this our SEO service, and we'll add it to the app module. Angular's browser platform has a couple helpers to set meta tags as well as the document title. So we'll import those and then inject them in the constructor. Then I'm going to define a method that will take an object as its argument. Different social media sites have different requirements for meta tags, which are often very similar. Unity. So to keep our code dry, we're going to set some defaults and then just override these defaults with whatever we pass in this tags object, UI, which will ultimately be data that we pull from Firestore. 1st, we can use the title service to set the document title, UI, and then we'll set our meta tags. As far as I know, we have to call update tag on each one of these because there's no way in Angular to update them all in bulk. Now that that's done, we need a component that gets loaded by the router and use it to set these meta tags. Let's go ahead and call this our animal detail component. Then we'll use this component in our router, and we'll make sure to set up a route param for the name, which should match the document ID that we have saved in Firebase for a given animal. The next step is to go into the component, and we'll need a variety of things here, including our SEO service as well as the Firestore database. Then we'll use activated route to get the current animal name from the URL that that user navigated to. Again, that is the document ID in Firestore, and we can get it by calling route snapshot param map followed by git name.
If we look at this data in Firestore quickly, You'll see we have a variety of documents with an ID of bird, cat, elephant, etcetera. Then each of these documents has a bio as well as an image URL and a name. What we need to do is read this document, and then once we have the document data, use it to set the meta tags on the DOM.
documentation
AngularFire 2 gives us the data as an observable, so we can pipe in the tap operator. Then once we have the data, we can use our SEO service to generate the tags. But this does bring up one problem. Because we're going to read this document on the server and then transition back to the browser, it will read the document twice and the user will see a brief flash in between those requests. This has slowed down significantly, but notice how we get some initial data from the server. It goes blank, then it comes back online after we've transitioned into the browser. Fortunately, Universal gives us some tools to transition state from the server side to the client side. It just allows you to set a key value pair on the server and then read it on the browser. So we'll import transfer state as well as make state key. Then we'll set up a constant here with make state key and give it the name of animal. When we get data on the server, we'll set it as this animal key and then read it when we get back to the browser.
And transfer state is a service, so we'll add that to our constructor. And then I'm going to Define this as its own isolated method so you can reuse it if you have use for this in your own app. So what we're going to do in this method is first check if a document already exists.
documentation
This should always return false on the server. It takes the Kiwi defined as the first argument and then a default value as the second argument. And just like we did before, we'll get our Firestore document as an observable and pipe in the tap operator. But this time, we will set the animal key with the document data. And we can also set our meta tag values here like we did before. UI. So the only question that remains is how do we use this existing document for our observable value once we transition to the browser? And the answer is super easy. We have an RxJS operator called start with, and we can just pass it that existing object. So instead of null, you still have your existing document from the server.
But it is worth noting that this will execute 2 document reads in Firestore, so that may or may not be an issue for you. Keep in mind that you only server side render on a full page load, so it's unlikely that that would be an issue in most cases.
publishing
The last thing we need to do is go in to the animal detail component and subscribe to the animal observable, which we can do with the async pipe. That takes care of our front end Angular app portion. Now we have a whole bunch of configuration stuff to do with Angular Universal. Most of this stuff is copy and paste configuration for right now, but hopefully, some of this comes to the Angular CLI in future. 1st, we'll go into the existing app module and add with server transition to the browser module import and set any random app ID that you want. And then make sure to import the transfer state module if you're doing a state transfer as well. Then the next thing you'll need to do is create an app server module, And it should also live inside the app directory. Basically, all this is doing is taking your app module and then importing it into another module that is set up to be rendered on the server. Then if you're transferring state, you'll need the server transfer state module and also the module map loader if UI doing lazy loading in your app. You wouldn't want lazy loading on the server, so that module takes care of that aspect for you. That should take care of everything in the app directory. Now we're going to move up to the source directory and add a new file called main.server.ts. All it has to do is import the app server module that we just created. This is more of a formality because main is our main entry point into the app. We also need to create a TS config for our main server TS file. So create tsconfig.server.json. One of the main differences between the browser build and the server build is that our server build needs to be in common JS so it can work on Node. Js. The next thing we need to do is configure our app with the Angular CLI so the CLI knows how to bundle it and where to transpile all the code. The next thing we'll do is build our actual server code, which uses Express JS, which is one of the most popular HTTP frameworks for Node. Js. Create the server TS file and then copy and paste all of this Express JS code into that file. This code was taken from the official Angular Universal demo, and only a few little modifications were made here and there to make it work with Firebase. For example, Firebase uses a few things that aren't available in Node. Js such as WebSockets. But a way to get around this is is to set them on the global object, which is the equivalent to the window object in a browser. There's a handful of things you might need in your project to make the server environment compatible with Firebase, I was able to install them with this command which you can find in the main article. UI. If you look at the Express JS app, you'll notice that it's not the prettiest code ever. The most important thing to understand here is that this Express app is capturing all of the routes in our Angular application and then rendering them to HTML based on wherever the user navigates. So that means they can navigate to a deep link, And we'll get the rendered HTML for that page. The one thing about Express is that it's completely separate from our Angular application. The Angular CLI has no way to compile this down to a production build for us, and we can roll out our own webpack config to do that. Create another file called webpack.server.config.js. And we're gonna add some more not so pretty code to it. But essentially, what we're doing is what the Angular CLI does under the hood. In this case, it's taking our TypeScript file and compiling it down to JavaScript that can run on Node. You should be able to copy and paste this and just forget about it as long as you're placing all of your files in the same place that we did in this lesson. We're getting really close to the end here. The next thing we need to do is go up into the root of the project and in the angularcli.json file, at a configuration for our server app. You'll notice that the apps option is an array. That's because we can add multiple apps to the Angular CLI configuration, which is exactly what we need to do here. Again, we're doing another copy and paste style thing where we take the existing app, and then we make a few modifications to it 2 point to the resources for our server app. We will point the main entry point to the main dot server dot ts file. We can also remove polyfills because they're not needed on the server, and you'll want to set service worker to false if using a worker. At this point, we need to build 3 different apps, our Express JS server, our Angular browser app, and Angular server app. We can do this in the package JSON in the scripts object.
Basically, we're just combining our ng build commands with our webpack config to run everything all at once. UI. We can run these 2 commands together by doing npm run build colon ssr and serve colon ssr. When the build finishes, it should serve your express app on local host 4,000 and you should see all 3 apps in the dist folder. But it really shouldn't feel any different than a normal Angular UI. It just has this secret power to be understood by link bots and search engines.
programming
architecture
If you copy a link from your app and paste it into the Twitter card validator, you should CU valid card even though this data is pulled from the Firestore database asynchronously. And you'll also want to check to see if you've achieved any performance gains from SSR. For this demo, I ran a lighthouse audit and achieved a score of 94, which is really good for an Angular app pulling data from Fire UI based.
I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna talk about more advanced SSR scenarios, consider becoming a pro member at AngularFirebase.com. You'll get access to all kinds of exclusive content designed to help you ship apps on the Angular Firebase stack.
youtube
Unity. Thanks for watching, and I'll see you soon.
Today, we're finally going to answer the question of how do we combine Firebase with Angular Universal to build a search engine optimized JavaScript app. Recent changes to AngularFire 2 now make it possible to perform server side rendering with Universal. Unisole. What this means is that our app's content can be understood by search engines and used by social media link bots, and we might even get some good page load performance gains out of it. Unity. If you're new here, make sure to like and subscribe, and I highly recommend that you follow along with the source code on angularfirebase.com. First, let's talk about what server side rendering is. Normally, we just let the browser parcel of the JavaScript and render it out to HTML. But this becomes a problem if your app has routes that need to be indexed in a search engine or shared on social media. Most bots that visit your site only understand HTML and don't make any effort to parse the JavaScript that's there. What we can do is make our Angular app behave more like a traditional web application that responds with HTML from a server. On the first page visit, it will render the app to HTML and then send it over to the browser, which will then take over and transition it to work just like a regular Angular app. In this demo, I'll show you how to go from 0 to deployed Angular Universal app, and we'll generate all of the content with this collection of animals that I have stored in the Firestore database. I should warn you that we have a lot of code to get through, but most of it's configuration related stuff that you can just copy and paste into your project. But I documented everything step by step in the main article so so you can follow along with that if you get lost. Step 1 is to generate a new Angular app and make sure that it has a routing module. Then install the latest version of AngularFire 2 and Firebase, and then send a thank you card to James from Firebase because he made some pretty epic changes to this library to make Universal support possible. After that's done, install platform server from Angular. And if you're doing lazy loading, you'll also need this NG Universal, Module Map, NG Factory Loader, and TS Loader as well. When it comes to social media bots, They're going to be looking for meta tags in the head of the document. You can find the specific requirements on the Facebook and Twitter developer docs, But what I wanna show you first is how to efficiently set these metatags with an Angular service. Let's call this our SEO service, and we'll add it to the app module. Angular's browser platform has a couple helpers to set meta tags as well as the document title. So we'll import those and then inject them in the constructor. Then I'm going to define a method that will take an object as its argument. Different social media sites have different requirements for meta tags, which are often very similar. Unity. So to keep our code dry, we're going to set some defaults and then just override these defaults with whatever we pass in this tags object, UI, which will ultimately be data that we pull from Firestore. 1st, we can use the title service to set the document title, UI, and then we'll set our meta tags. As far as I know, we have to call update tag on each one of these because there's no way in Angular to update them all in bulk. Now that that's done, we need a component that gets loaded by the router and use it to set these meta tags. Let's go ahead and call this our animal detail component. Then we'll use this component in our router, and we'll make sure to set up a route param for the name, which should match the document ID that we have saved in Firebase for a given animal. The next step is to go into the component, and we'll need a variety of things here, including our SEO service as well as the Firestore database. Then we'll use activated route to get the current animal name from the URL that that user navigated to. Again, that is the document ID in Firestore, and we can get it by calling route snapshot param map followed by git name. If we look at this data in Firestore quickly, You'll see we have a variety of documents with an ID of bird, cat, elephant, etcetera. Then each of these documents has a bio as well as an image URL and a name. What we need to do is read this document, and then once we have the document data, use it to set the meta tags on the DOM. AngularFire 2 gives us the data as an observable, so we can pipe in the tap operator. Then once we have the data, we can use our SEO service to generate the tags. But this does bring up one problem. Because we're going to read this document on the server and then transition back to the browser, it will read the document twice and the user will see a brief flash in between those requests. This has slowed down significantly, but notice how we get some initial data from the server. It goes blank, then it comes back online after we've transitioned into the browser. Fortunately, Universal gives us some tools to transition state from the server side to the client side. It just allows you to set a key value pair on the server and then read it on the browser. So we'll import transfer state as well as make state key. Then we'll set up a constant here with make state key and give it the name of animal. When we get data on the server, we'll set it as this animal key and then read it when we get back to the browser. And transfer state is a service, so we'll add that to our constructor. And then I'm going to Define this as its own isolated method so you can reuse it if you have use for this in your own app. So what we're going to do in this method is first check if a document already exists. This should always return false on the server. It takes the Kiwi defined as the first argument and then a default value as the second argument. And just like we did before, we'll get our Firestore document as an observable and pipe in the tap operator. But this time, we will set the animal key with the document data. And we can also set our meta tag values here like we did before. UI. So the only question that remains is how do we use this existing document for our observable value once we transition to the browser? And the answer is super easy. We have an RxJS operator called start with, and we can just pass it that existing object. So instead of null, you still have your existing document from the server. But it is worth noting that this will execute 2 document reads in Firestore, so that may or may not be an issue for you. Keep in mind that you only server side render on a full page load, so it's unlikely that that would be an issue in most cases. The last thing we need to do is go in to the animal detail component and subscribe to the animal observable, which we can do with the async pipe. That takes care of our front end Angular app portion. Now we have a whole bunch of configuration stuff to do with Angular Universal. Most of this stuff is copy and paste configuration for right now, but hopefully, some of this comes to the Angular CLI in future. 1st, we'll go into the existing app module and add with server transition to the browser module import and set any random app ID that you want. And then make sure to import the transfer state module if you're doing a state transfer as well. Then the next thing you'll need to do is create an app server module, And it should also live inside the app directory. Basically, all this is doing is taking your app module and then importing it into another module that is set up to be rendered on the server. Then if you're transferring state, you'll need the server transfer state module and also the module map loader if UI doing lazy loading in your app. You wouldn't want lazy loading on the server, so that module takes care of that aspect for you. That should take care of everything in the app directory. Now we're going to move up to the source directory and add a new file called main.server.ts. All it has to do is import the app server module that we just created. This is more of a formality because main is our main entry point into the app. We also need to create a TS config for our main server TS file. So create tsconfig.server.json. One of the main differences between the browser build and the server build is that our server build needs to be in common JS so it can work on Node. Js. The next thing we need to do is configure our app with the Angular CLI so the CLI knows how to bundle it and where to transpile all the code. The next thing we'll do is build our actual server code, which uses Express JS, which is one of the most popular HTTP frameworks for Node. Js. Create the server TS file and then copy and paste all of this Express JS code into that file. This code was taken from the official Angular Universal demo, and only a few little modifications were made here and there to make it work with Firebase. For example, Firebase uses a few things that aren't available in Node. Js such as WebSockets. But a way to get around this is is to set them on the global object, which is the equivalent to the window object in a browser. There's a handful of things you might need in your project to make the server environment compatible with Firebase, I was able to install them with this command which you can find in the main article. UI. If you look at the Express JS app, you'll notice that it's not the prettiest code ever. The most important thing to understand here is that this Express app is capturing all of the routes in our Angular application and then rendering them to HTML based on wherever the user navigates. So that means they can navigate to a deep link, And we'll get the rendered HTML for that page. The one thing about Express is that it's completely separate from our Angular application. The Angular CLI has no way to compile this down to a production build for us, and we can roll out our own webpack config to do that. Create another file called webpack.server.config.js. And we're gonna add some more not so pretty code to it. But essentially, what we're doing is what the Angular CLI does under the hood. In this case, it's taking our TypeScript file and compiling it down to JavaScript that can run on Node. You should be able to copy and paste this and just forget about it as long as you're placing all of your files in the same place that we did in this lesson. We're getting really close to the end here. The next thing we need to do is go up into the root of the project and in the angularcli.json file, at a configuration for our server app. You'll notice that the apps option is an array. That's because we can add multiple apps to the Angular CLI configuration, which is exactly what we need to do here. Again, we're doing another copy and paste style thing where we take the existing app, and then we make a few modifications to it 2 point to the resources for our server app. We will point the main entry point to the main dot server dot ts file. We can also remove polyfills because they're not needed on the server, and you'll want to set service worker to false if using a worker. At this point, we need to build 3 different apps, our Express JS server, our Angular browser app, and Angular server app. We can do this in the package JSON in the scripts object. Basically, we're just combining our ng build commands with our webpack config to run everything all at once. UI. We can run these 2 commands together by doing npm run build colon ssr and serve colon ssr. When the build finishes, it should serve your express app on local host 4,000 and you should see all 3 apps in the dist folder. But it really shouldn't feel any different than a normal Angular UI. It just has this secret power to be understood by link bots and search engines. If you copy a link from your app and paste it into the Twitter card validator, you should CU valid card even though this data is pulled from the Firestore database asynchronously. And you'll also want to check to see if you've achieved any performance gains from SSR. For this demo, I ran a lighthouse audit and achieved a score of 94, which is really good for an Angular app pulling data from Fire UI based. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna talk about more advanced SSR scenarios, consider becoming a pro member at AngularFirebase.com. You'll get access to all kinds of exclusive content designed to help you ship apps on the Angular Firebase stack. Unity. Thanks for watching, and I'll see you soon.
Today,
today
we're
we're
finally
finally
going
going
to
to
answer
answer
the
the
question
question
of
of
how
how
do
do
we
we
combine
combine
Firebase
firebase
with
with
Angular
angular
Universal
universal
to
to
build
build
a
a
search
search
engine
engine
optimized
optimized
JavaScript
javascript
app.
app
Recent
recent
changes
changes
to
to
AngularFire
angularfire
2
2
now
now
make
make
it
it
possible
possible
to
to
perform
perform
server
server
side
side
rendering
rendering
with
with
Universal.
universal
Unisole.
unisole
What
what
this
this
means
means
is
is
that
that
our
our
app's
app's
content
content
can
can
be
be
understood
understood
by
by
search
search
engines
engines
and
and
used
used
by
by
social
social
media
media
link
link
bots,
bots
and
and
we
we
might
might
even
even
get
get
some
some
good
good
page
page
load
load
performance
performance
gains
gains
out
out
of
of
it.
it
Unity.
unity
If
if
you're
you're
new
new
here,
here
make
make
sure
sure
to
to
like
like
and
and
subscribe,
subscribe
and
and
I
i
highly
highly
recommend
recommend
that
that
you
you
follow
follow
along
along
with
with
the
the
source
source
code
code
on
on
angularfirebase.com.
angularfirebase.com
First,
first
let's
let's
talk
talk
about
about
what
what
server
server
side
side
rendering
rendering
is.
is
Normally,
normally
we
we
just
just
let
let
the
the
browser
browser
parcel
parcel
of
of
the
the
JavaScript
javascript
and
and
render
render
it
it
out
out
to
to
HTML.
html
But
but
this
this
becomes
becomes
a
a
problem
problem
if
if
your
your
app
app
has
has
routes
routes
that
that
need
need
to
to
be
be
indexed
indexed
in
in
a
a
search
search
engine
engine
or
or
shared
shared
on
on
social
social
media.
media
Most
most
bots
bots
that
that
visit
visit
your
your
site
site
only
only
understand
understand
HTML
html
and
and
don't
don't
make
make
any
any
effort
effort
to
to
parse
parse
the
the
JavaScript
javascript
that's
that's
there.
there
What
what
we
we
can
can
do
do
is
is
make
make
our
our
Angular
angular
app
app
behave
behave
more
more
like
like
a
a
traditional
traditional
web
web
application
application
that
that
responds
responds
with
with
HTML
html
from
from
a
a
server.
server
On
on
the
the
first
first
page
page
visit,
visit
it
it
will
will
render
render
the
the
app
app
to
to
HTML
html
and
and
then
then
send
send
it
it
over
over
to
to
the
the
browser,
browser
which
which
will
will
then
then
take
take
over
over
and
and
transition
transition
it
it
to
to
work
work
just
just
like
like
a
a
regular
regular
Angular
angular
app.
app
In
in
this
this
demo,
demo
I'll
i'll
show
show
you
you
how
how
to
to
go
go
from
from
0
0
to
to
deployed
deployed
Angular
angular
Universal
universal
app,
app
and
and
we'll
we'll
generate
generate
all
all
of
of
the
the
content
content
with
with
this
this
collection
collection
of
of
animals
animals
that
that
I
i
have
have
stored
stored
in
in
the
the
Firestore
firestore
database.
database
I
i
should
should
warn
warn
you
you
that
that
we
we
have
have
a
a
lot
lot
of
of
code
code
to
to
get
get
through,
through
but
but
most
most
of
of
it's
it's
configuration
configuration
related
related
stuff
stuff
that
that
you
you
can
can
just
just
copy
copy
and
and
paste
paste
into
into
your
your
project.
project
But
but
I
i
documented
documented
everything
everything
step
step
by
by
step
step
in
in
the
the
main
main
article
article
so
so
so
so
you
you
can
can
follow
follow
along
along
with
with
that
that
if
if
you
you
get
get
lost.
lost
Step
step
1
1
is
is
to
to
generate
generate
a
a
new
new
Angular
angular
app
app
and
and
make
make
sure
sure
that
that
it
it
has
has
a
a
routing
routing
module.
module
Then
then
install
install
the
the
latest
latest
version
version
of
of
AngularFire
angularfire
2
2
and
and
Firebase,
firebase
and
and
then
then
send
send
a
a
thank
thank
you
you
card
card
to
to
James
james
from
from
Firebase
firebase
because
because
he
he
made
made
some
some
pretty
pretty
epic
epic
changes
changes
to
to
this
this
library
library
to
to
make
make
Universal
universal
support
support
possible.
possible
After
after
that's
that's
done,
done
install
install
platform
platform
server
server
from
from
Angular.
angular
And
and
if
if
you're
you're
doing
doing
lazy
lazy
loading,
loading
you'll
you'll
also
also
need
need
this
this
NG
ng
Universal,
universal
Module
module
Map,
map
NG
ng
Factory
factory
Loader,
loader
and
and
TS
ts
Loader
loader
as
as
well.
well
When
when
it
it
comes
comes
to
to
social
social
media
media
bots,
bots
They're
they're
going
going
to
to
be
be
looking
looking
for
for
meta
meta
tags
tags
in
in
the
the
head
head
of
of
the
the
document.
document
You
you
can
can
find
find
the
the
specific
specific
requirements
requirements
on
on
the
the
Facebook
facebook
and
and
Twitter
twitter
developer
developer
docs,
docs
But
but
what
what
I
i
wanna
wanna
show
show
you
you
first
first
is
is
how
how
to
to
efficiently
efficiently
set
set
these
these
metatags
metatags
with
with
an
an
Angular
angular
service.
service
Let's
let's
call
call
this
this
our
our
SEO
seo
service,
service
and
and
we'll
we'll
add
add
it
it
to
to
the
the
app
app
module.
module
Angular's
angular's
browser
browser
platform
platform
has
has
a
a
couple
couple
helpers
helpers
to
to
set
set
meta
meta
tags
tags
as
as
well
well
as
as
the
the
document
document
title.
title
So
so
we'll
we'll
import
import
those
those
and
and
then
then
inject
inject
them
them
in
in
the
the
constructor.
constructor
Then
then
I'm
i'm
going
going
to
to
define
define
a
a
method
method
that
that
will
will
take
take
an
an
object
object
as
as
its
its
argument.
argument
Different
different
social
social
media
media
sites
sites
have
have
different
different
requirements
requirements
for
for
meta
meta
tags,
tags
which
which
are
are
often
often
very
very
similar.
similar
Unity.
unity
So
so
to
to
keep
keep
our
our
code
code
dry,
dry
we're
we're
going
going
to
to
set
set
some
some
defaults
defaults
and
and
then
then
just
just
override
override
these
these
defaults
defaults
with
with
whatever
whatever
we
we
pass
pass
in
in
this
this
tags
tags
object,
object
UI,
ui
which
which
will
will
ultimately
ultimately
be
be
data
data
that
that
we
we
pull
pull
from
from
Firestore.
firestore
1st,
1st
we
we
can
can
use
use
the
the
title
title
service
service
to
to
set
set
the
the
document
document
title,
title
UI,
ui
and
and
then
then
we'll
we'll
set
set
our
our
meta
meta
tags.
tags
As
as
far
far
as
as
I
i
know,
know
we
we
have
have
to
to
call
call
update
update
tag
tag
on
on
each
each
one
one
of
of
these
these
because
because
there's
there's
no
no
way
way
in
in
Angular
angular
to
to
update
update
them
them
all
all
in
in
bulk.
bulk
Now
now
that
that
that's
that's
done,
done
we
we
need
need
a
a
component
component
that
that
gets
gets
loaded
loaded
by
by
the
the
router
router
and
and
use
use
it
it
to
to
set
set
these
these
meta
meta
tags.
tags
Let's
let's
go
go
ahead
ahead
and
and
call
call
this
this
our
our
animal
animal
detail
detail
component.
component
Then
then
we'll
we'll
use
use
this
this
component
component
in
in
our
our
router,
router
and
and
we'll
we'll
make
make
sure
sure
to
to
set
set
up
up
a
a
route
route
param
param
for
for
the
the
name,
name
which
which
should
should
match
match
the
the
document
document
ID
id
that
that
we
we
have
have
saved
saved
in
in
Firebase
firebase
for
for
a
a
given
given
animal.
animal
The
the
next
next
step
step
is
is
to
to
go
go
into
into
the
the
component,
component
and
and
we'll
we'll
need
need
a
a
variety
variety
of
of
things
things
here,
here
including
including
our
our
SEO
seo
service
service
as
as
well
well
as
as
the
the
Firestore
firestore
database.
database
Then
then
we'll
we'll
use
use
activated
activated
route
route
to
to
get
get
the
the
current
current
animal
animal
name
name
from
from
the
the
URL
url
that
that
that
that
user
user
navigated
navigated
to.
to
Again,
again
that
that
is
is
the
the
document
document
ID
id
in
in
Firestore,
firestore
and
and
we
we
can
can
get
get
it
it
by
by
calling
calling
route
route
snapshot
snapshot
param
param
map
map
followed
followed
by
by
git
git
name.
name
If
if
we
we
look
look
at
at
this
this
data
data
in
in
Firestore
firestore
quickly,
quickly
You'll
you'll
see
see
we
we
have
have
a
a
variety
variety
of
of
documents
documents
with
with
an
an
ID
id
of
of
bird,
bird
cat,
cat
elephant,
elephant
etcetera.
etcetera
Then
then
each
each
of
of
these
these
documents
documents
has
has
a
a
bio
bio
as
as
well
well
as
as
an
an
image
image
URL
url
and
and
a
a
name.
name
What
what
we
we
need
need
to
to
do
do
is
is
read
read
this
this
document,
document
and
and
then
then
once
once
we
we
have
have
the
the
document
document
data,
data
use
use
it
it
to
to
set
set
the
the
meta
meta
tags
tags
on
on
the
the
DOM.
dom
AngularFire
angularfire
2
2
gives
gives
us
us
the
the
data
data
as
as
an
an
observable,
observable
so
so
we
we
can
can
pipe
pipe
in
in
the
the
tap
tap
operator.
operator
Then
then
once
once
we
we
have
have
the
the
data,
data
we
we
can
can
use
use
our
our
SEO
seo
service
service
to
to
generate
generate
the
the
tags.
tags
But
but
this
this
does
does
bring
bring
up
up
one
one
problem.
problem
Because
because
we're
we're
going
going
to
to
read
read
this
this
document
document
on
on
the
the
server
server
and
and
then
then
transition
transition
back
back
to
to
the
the
browser,
browser
it
it
will
will
read
read
the
the
document
document
twice
twice
and
and
the
the
user
user
will
will
see
see
a
a
brief
brief
flash
flash
in
in
between
between
those
those
requests.
requests
This
this
has
has
slowed
slowed
down
down
significantly,
significantly
but
but
notice
notice
how
how
we
we
get
get
some
some
initial
initial
data
data
from
from
the
the
server.
server
It
it
goes
goes
blank,
blank
then
then
it
it
comes
comes
back
back
online
online
after
after
we've
we've
transitioned
transitioned
into
into
the
the
browser.
browser
Fortunately,
fortunately
Universal
universal
gives
gives
us
us
some
some
tools
tools
to
to
transition
transition
state
state
from
from
the
the
server
server
side
side
to
to
the
the
client
client
side.
side
It
it
just
just
allows
allows
you
you
to
to
set
set
a
a
key
key
value
value
pair
pair
on
on
the
the
server
server
and
and
then
then
read
read
it
it
on
on
the
the
browser.
browser
So
so
we'll
we'll
import
import
transfer
transfer
state
state
as
as
well
well
as
as
make
make
state
state
key.
key
Then
then
we'll
we'll
set
set
up
up
a
a
constant
constant
here
here
with
with
make
make
state
state
key
key
and
and
give
give
it
it
the
the
name
name
of
of
animal.
animal
When
when
we
we
get
get
data
data
on
on
the
the
server,
server
we'll
we'll
set
set
it
it
as
as
this
this
animal
animal
key
key
and
and
then
then
read
read
it
it
when
when
we
we
get
get
back
back
to
to
the
the
browser.
browser
And
and
transfer
transfer
state
state
is
is
a
a
service,
service
so
so
we'll
we'll
add
add
that
that
to
to
our
our
constructor.
constructor
And
and
then
then
I'm
i'm
going
going
to
to
Define
define
this
this
as
as
its
its
own
own
isolated
isolated
method
method
so
so
you
you
can
can
reuse
reuse
it
it
if
if
you
you
have
have
use
use
for
for
this
this
in
in
your
your
own
own
app.
app
So
so
what
what
we're
we're
going
going
to
to
do
do
in
in
this
this
method
method
is
is
first
first
check
check
if
if
a
a
document
document
already
already
exists.
exists
This
this
should
should
always
always
return
return
false
false
on
on
the
the
server.
server
It
it
takes
takes
the
the
Kiwi
kiwi
defined
defined
as
as
the
the
first
first
argument
argument
and
and
then
then
a
a
default
default
value
value
as
as
the
the
second
second
argument.
argument
And
and
just
just
like
like
we
we
did
did
before,
before
we'll
we'll
get
get
our
our
Firestore
firestore
document
document
as
as
an
an
observable
observable
and
and
pipe
pipe
in
in
the
the
tap
tap
operator.
operator
But
but
this
this
time,
time
we
we
will
will
set
set
the
the
animal
animal
key
key
with
with
the
the
document
document
data.
data
And
and
we
we
can
can
also
also
set
set
our
our
meta
meta
tag
tag
values
values
here
here
like
like
we
we
did
did
before.
before
UI.
ui
So
so
the
the
only
only
question
question
that
that
remains
remains
is
is
how
how
do
do
we
we
use
use
this
this
existing
existing
document
document
for
for
our
our
observable
observable
value
value
once
once
we
we
transition
transition
to
to
the
the
browser?
browser
And
and
the
the
answer
answer
is
is
super
super
easy.
easy
We
we
have
have
an
an
RxJS
rxjs
operator
operator
called
called
start
start
with,
with
and
and
we
we
can
can
just
just
pass
pass
it
it
that
that
existing
existing
object.
object
So
so
instead
instead
of
of
null,
null
you
you
still
still
have
have
your
your
existing
existing
document
document
from
from
the
the
server.
server
But
but
it
it
is
is
worth
worth
noting
noting
that
that
this
this
will
will
execute
execute
2
2
document
document
reads
reads
in
in
Firestore,
firestore
so
so
that
that
may
may
or
or
may
may
not
not
be
be
an
an
issue
issue
for
for
you.
you
Keep
keep
in
in
mind
mind
that
that
you
you
only
only
server
server
side
side
render
render
on
on
a
a
full
full
page
page
load,
load
so
so
it's
it's
unlikely
unlikely
that
that
that
that
would
would
be
be
an
an
issue
issue
in
in
most
most
cases.
cases
The
the
last
last
thing
thing
we
we
need
need
to
to
do
do
is
is
go
go
in
in
to
to
the
the
animal
animal
detail
detail
component
component
and
and
subscribe
subscribe
to
to
the
the
animal
animal
observable,
observable
which
which
we
we
can
can
do
do
with
with
the
the
async
async
pipe.
pipe
That
that
takes
takes
care
care
of
of
our
our
front
front
end
end
Angular
angular
app
app
portion.
portion
Now
now
we
we
have
have
a
a
whole
whole
bunch
bunch
of
of
configuration
configuration
stuff
stuff
to
to
do
do
with
with
Angular
angular
Universal.
universal
Most
most
of
of
this
this
stuff
stuff
is
is
copy
copy
and
and
paste
paste
configuration
configuration
for
for
right
right
now,
now
but
but
hopefully,
hopefully
some
some
of
of
this
this
comes
comes
to
to
the
the
Angular
angular
CLI
cli
in
in
future.
future
1st,
1st
we'll
we'll
go
go
into
into
the
the
existing
existing
app
app
module
module
and
and
add
add
with
with
server
server
transition
transition
to
to
the
the
browser
browser
module
module
import
import
and
and
set
set
any
any
random
random
app
app
ID
id
that
that
you
you
want.
want
And
and
then
then
make
make
sure
sure
to
to
import
import
the
the
transfer
transfer
state
state
module
module
if
if
you're
you're
doing
doing
a
a
state
state
transfer
transfer
as
as
well.
well
Then
then
the
the
next
next
thing
thing
you'll
you'll
need
need
to
to
do
do
is
is
create
create
an
an
app
app
server
server
module,
module
And
and
it
it
should
should
also
also
live
live
inside
inside
the
the
app
app
directory.
directory
Basically,
basically
all
all
this
this
is
is
doing
doing
is
is
taking
taking
your
your
app
app
module
module
and
and
then
then
importing
importing
it
it
into
into
another
another
module
module
that
that
is
is
set
set
up
up
to
to
be
be
rendered
rendered
on
on
the
the
server.
server
Then
then
if
if
you're
you're
transferring
transferring
state,
state
you'll
you'll
need
need
the
the
server
server
transfer
transfer
state
state
module
module
and
and
also
also
the
the
module
module
map
map
loader
loader
if
if
UI
ui
doing
doing
lazy
lazy
loading
loading
in
in
your
your
app.
app
You
you
wouldn't
wouldn't
want
want
lazy
lazy
loading
loading
on
on
the
the
server,
server
so
so
that
that
module
module
takes
takes
care
care
of
of
that
that
aspect
aspect
for
for
you.
you
That
that
should
should
take
take
care
care
of
of
everything
everything
in
in
the
the
app
app
directory.
directory
Now
now
we're
we're
going
going
to
to
move
move
up
up
to
to
the
the
source
source
directory
directory
and
and
add
add
a
a
new
new
file
file
called
called
main.server.ts.
main.server.ts
All
all
it
it
has
has
to
to
do
do
is
is
import
import
the
the
app
app
server
server
module
module
that
that
we
we
just
just
created.
created
This
this
is
is
more
more
of
of
a
a
formality
formality
because
because
main
main
is
is
our
our
main
main
entry
entry
point
point
into
into
the
the
app.
app
We
we
also
also
need
need
to
to
create
create
a
a
TS
ts
config
config
for
for
our
our
main
main
server
server
TS
ts
file.
file
So
so
create
create
tsconfig.server.json.
tsconfig.server.json
One
one
of
of
the
the
main
main
differences
differences
between
between
the
the
browser
browser
build
build
and
and
the
the
server
server
build
build
is
is
that
that
our
our
server
server
build
build
needs
needs
to
to
be
be
in
in
common
common
JS
js
so
so
it
it
can
can
work
work
on
on
Node.
node
Js.
js
The
the
next
next
thing
thing
we
we
need
need
to
to
do
do
is
is
configure
configure
our
our
app
app
with
with
the
the
Angular
angular
CLI
cli
so
so
the
the
CLI
cli
knows
knows
how
how
to
to
bundle
bundle
it
it
and
and
where
where
to
to
transpile
transpile
all
all
the
the
code.
code
The
the
next
next
thing
thing
we'll
we'll
do
do
is
is
build
build
our
our
actual
actual
server
server
code,
code
which
which
uses
uses
Express
express
JS,
js
which
which
is
is
one
one
of
of
the
the
most
most
popular
popular
HTTP
http
frameworks
frameworks
for
for
Node.
node
Js.
js
Create
create
the
the
server
server
TS
ts
file
file
and
and
then
then
copy
copy
and
and
paste
paste
all
all
of
of
this
this
Express
express
JS
js
code
code
into
into
that
that
file.
file
This
this
code
code
was
was
taken
taken
from
from
the
the
official
official
Angular
angular
Universal
universal
demo,
demo
and
and
only
only
a
a
few
few
little
little
modifications
modifications
were
were
made
made
here
here
and
and
there
there
to
to
make
make
it
it
work
work
with
with
Firebase.
firebase
For
for
example,
example
Firebase
firebase
uses
uses
a
a
few
few
things
things
that
that
aren't
aren't
available
available
in
in
Node.
node
Js
js
such
such
as
as
WebSockets.
websockets
But
but
a
a
way
way
to
to
get
get
around
around
this
this
is
is
is
is
to
to
set
set
them
them
on
on
the
the
global
global
object,
object
which
which
is
is
the
the
equivalent
equivalent
to
to
the
the
window
window
object
object
in
in
a
a
browser.
browser
There's
there's
a
a
handful
handful
of
of
things
things
you
you
might
might
need
need
in
in
your
your
project
project
to
to
make
make
the
the
server
server
environment
environment
compatible
compatible
with
with
Firebase,
firebase
I
i
was
was
able
able
to
to
install
install
them
them
with
with
this
this
command
command
which
which
you
you
can
can
find
find
in
in
the
the
main
main
article.
article
UI.
ui
If
if
you
you
look
look
at
at
the
the
Express
express
JS
js
app,
app
you'll
you'll
notice
notice
that
that
it's
it's
not
not
the
the
prettiest
prettiest
code
code
ever.
ever
The
the
most
most
important
important
thing
thing
to
to
understand
understand
here
here
is
is
that
that
this
this
Express
express
app
app
is
is
capturing
capturing
all
all
of
of
the
the
routes
routes
in
in
our
our
Angular
angular
application
application
and
and
then
then
rendering
rendering
them
them
to
to
HTML
html
based
based
on
on
wherever
wherever
the
the
user
user
navigates.
navigates
So
so
that
that
means
means
they
they
can
can
navigate
navigate
to
to
a
a
deep
deep
link,
link
And
and
we'll
we'll
get
get
the
the
rendered
rendered
HTML
html
for
for
that
that
page.
page
The
the
one
one
thing
thing
about
about
Express
express
is
is
that
that
it's
it's
completely
completely
separate
separate
from
from
our
our
Angular
angular
application.
application
The
the
Angular
angular
CLI
cli
has
has
no
no
way
way
to
to
compile
compile
this
this
down
down
to
to
a
a
production
production
build
build
for
for
us,
us
and
and
we
we
can
can
roll
roll
out
out
our
our
own
own
webpack
webpack
config
config
to
to
do
do
that.
that
Create
create
another
another
file
file
called
called
webpack.server.config.js.
webpack.server.config.js
And
and
we're
we're
gonna
gonna
add
add
some
some
more
more
not
not
so
so
pretty
pretty
code
code
to
to
it.
it
But
but
essentially,
essentially
what
what
we're
we're
doing
doing
is
is
what
what
the
the
Angular
angular
CLI
cli
does
does
under
under
the
the
hood.
hood
In
in
this
this
case,
case
it's
it's
taking
taking
our
our
TypeScript
typescript
file
file
and
and
compiling
compiling
it
it
down
down
to
to
JavaScript
javascript
that
that
can
can
run
run
on
on
Node.
node
You
you
should
should
be
be
able
able
to
to
copy
copy
and
and
paste
paste
this
this
and
and
just
just
forget
forget
about
about
it
it
as
as
long
long
as
as
you're
you're
placing
placing
all
all
of
of
your
your
files
files
in
in
the
the
same
same
place
place
that
that
we
we
did
did
in
in
this
this
lesson.
lesson
We're
we're
getting
getting
really
really
close
close
to
to
the
the
end
end
here.
here
The
the
next
next
thing
thing
we
we
need
need
to
to
do
do
is
is
go
go
up
up
into
into
the
the
root
root
of
of
the
the
project
project
and
and
in
in
the
the
angularcli.json
angularcli.json
file,
file
at
at
a
a
configuration
configuration
for
for
our
our
server
server
app.
app
You'll
you'll
notice
notice
that
that
the
the
apps
apps
option
option
is
is
an
an
array.
array
That's
that's
because
because
we
we
can
can
add
add
multiple
multiple
apps
apps
to
to
the
the
Angular
angular
CLI
cli
configuration,
configuration
which
which
is
is
exactly
exactly
what
what
we
we
need
need
to
to
do
do
here.
here
Again,
again
we're
we're
doing
doing
another
another
copy
copy
and
and
paste
paste
style
style
thing
thing
where
where
we
we
take
take
the
the
existing
existing
app,
app
and
and
then
then
we
we
make
make
a
a
few
few
modifications
modifications
to
to
it
it
2
2
point
point
to
to
the
the
resources
resources
for
for
our
our
server
server
app.
app
We
we
will
will
point
point
the
the
main
main
entry
entry
point
point
to
to
the
the
main
main
dot
dot
server
server
dot
dot
ts
ts
file.
file
We
we
can
can
also
also
remove
remove
polyfills
polyfills
because
because
they're
they're
not
not
needed
needed
on
on
the
the
server,
server
and
and
you'll
you'll
want
want
to
to
set
set
service
service
worker
worker
to
to
false
false
if
if
using
using
a
a
worker.
worker
At
at
this
this
point,
point
we
we
need
need
to
to
build
build
3
3
different
different
apps,
apps
our
our
Express
express
JS
js
server,
server
our
our
Angular
angular
browser
browser
app,
app
and
and
Angular
angular
server
server
app.
app
We
we
can
can
do
do
this
this
in
in
the
the
package
package
JSON
json
in
in
the
the
scripts
scripts
object.
object
Basically,
basically
we're
we're
just
just
combining
combining
our
our
ng
ng
build
build
commands
commands
with
with
our
our
webpack
webpack
config
config
to
to
run
run
everything
everything
all
all
at
at
once.
once
UI.
ui
We
we
can
can
run
run
these
these
2
2
commands
commands
together
together
by
by
doing
doing
npm
npm
run
run
build
build
colon
colon
ssr
ssr
and
and
serve
serve
colon
colon
ssr.
ssr
When
when
the
the
build
build
finishes,
finishes
it
it
should
should
serve
serve
your
your
express
express
app
app
on
on
local
local
host
host
4,000
4,000
and
and
you
you
should
should
see
see
all
all
3
3
apps
apps
in
in
the
the
dist
dist
folder.
folder
But
but
it
it
really
really
shouldn't
shouldn't
feel
feel
any
any
different
different
than
than
a
a
normal
normal
Angular
angular
UI.
ui
It
it
just
just
has
has
this
this
secret
secret
power
power
to
to
be
be
understood
understood
by
by
link
link
bots
bots
and
and
search
search
engines.
engines
If
if
you
you
copy
copy
a
a
link
link
from
from
your
your
app
app
and
and
paste
paste
it
it
into
into
the
the
Twitter
twitter
card
card
validator,
validator
you
you
should
should
CU
cu
valid
valid
card
card
even
even
though
though
this
this
data
data
is
is
pulled
pulled
from
from
the
the
Firestore
firestore
database
database
asynchronously.
asynchronously
And
and
you'll
you'll
also
also
want
want
to
to
check
check
to
to
see
see
if
if
you've
you've
achieved
achieved
any
any
performance
performance
gains
gains
from
from
SSR.
ssr
For
for
this
this
demo,
demo
I
i
ran
ran
a
a
lighthouse
lighthouse
audit
audit
and
and
achieved
achieved
a
a
score
score
of
of
94,
94
which
which
is
is
really
really
good
good
for
for
an
an
Angular
angular
app
app
pulling
pulling
data
data
from
from
Fire
fire
UI
ui
based.
based
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
And
and
if
if
you
you
wanna
wanna
talk
talk
about
about
more
more
advanced
advanced
SSR
ssr
scenarios,
scenarios
consider
consider
becoming
becoming
a
a
pro
pro
member
member
at
at
AngularFirebase.com.
angularfirebase.com
You'll
you'll
get
get
access
access
to
to
all
all
kinds
kinds
of
of
exclusive
exclusive
content
content
designed
designed
to
to
help
help
you
you
ship
ship
apps
apps
on
on
the
the
Angular
angular
Firebase
firebase
stack.
stack
Unity.
unity
Thanks
thanks
for
for
watching,
watching
and
and
I'll
i'll
see
see
you
you
soon.
soon
success
The speakers discuss how to combineese and Angular Universal in optimizing a search engine for JavaScript app. They provide instructions on how to generate content and set meta tags, including setting up a route parameter and constant, and how to create a document. They also discuss the process of updating media tags and configuring app servers, including setting up a new file and importting existing ones. They emphasize the importance of building multiple apps and warn of potential issues with the Angular UI. They end with a recommendation to check for performance gains and mention a link to a website for more information.
Angular Universal with Firebase
Today, we're finally going to answer the question of how do we combine Firebase with Angular Universal to build a search engine optimized JavaScript app. Recent changes to AngularFire 2 now make it possible to perform server side rendering with Universal. Unisole. What this means is that our app's content can be understood by search engines and used by social media link bots, and we might even get some good page load performance gains out of it. Unity. If you're new here, make sure to like and subscribe, and I highly recommend that you follow along with the source code on angularfirebase.com. First, let's talk about what server side rendering is. Normally, we just let the browser parcel of the JavaScript and render it out to HTML. But this becomes a problem if your app has routes that need to be indexed in a search engine or shared on social media. Most bots that visit your site only understand HTML and don't make any effort to parse the JavaScript that's there. What we can do is make our Angular app behave more like a traditional web application that responds with HTML from a server. On the first page visit, it will render the app to HTML and then send it over to the browser, which will then take over and transition it to work just like a regular Angular app. In this demo, I'll show you how to go from 0 to deployed Angular Universal app, and we'll generate all of the content with this collection of animals that I have stored in the Firestore database. I should warn you that we have a lot of code to get through, but most of it's configuration related stuff that you can just copy and paste into your project. But I documented everything step by step in the main article so so you can follow along with that if you get lost. Step 1 is to generate a new Angular app and make sure that it has a routing module. Then install the latest version of AngularFire 2 and Firebase, and then send a thank you card to James from Firebase because he made some pretty epic changes to this library to make Universal support possible. After that's done, install platform server from Angular. And if you're doing lazy loading, you'll also need this NG Universal, Module Map, NG Factory Loader, and TS Loader as well. When it comes to social media bots, They're going to be looking for meta tags in the head of the document. You can find the specific requirements on the Facebook and Twitter developer docs, But what I wanna show you first is how to efficiently set these metatags with an Angular service. Let's call this our SEO service, and we'll add it to the app module. Angular's browser platform has a couple helpers to set meta tags as well as the document title. So we'll import those and then inject them in the constructor. Then I'm going to define a method that will take an object as its argument. Different social media sites have different requirements for meta tags, which are often very similar. Unity. So to keep our code dry, we're going to set some defaults and then just override these defaults with whatever we pass in this tags object, UI, which will ultimately be data that we pull from Firestore. 1st, we can use the title service to set the document title, UI, and then we'll set our meta tags. As far as I know, we have to call update tag on each one of these because there's no way in Angular to update them all in bulk. Now that that's done, we need a component that gets loaded by the router and use it to set these meta tags. Let's go ahead and call this our animal detail component. Then we'll use this component in our router, and we'll make sure to set up a route param for the name, which should match the document ID that we have saved in Firebase for a given animal. The next step is to go into the component, and we'll need a variety of things here, including our SEO service as well as the Firestore database. Then we'll use activated route to get the current animal name from the URL that that user navigated to. Again, that is the document ID in Firestore, and we can get it by calling route snapshot param map followed by git name. If we look at this data in Firestore quickly, You'll see we have a variety of documents with an ID of bird, cat, elephant, etcetera. Then each of these documents has a bio as well as an image URL and a name. What we need to do is read this document, and then once we have the document data, use it to set the meta tags on the DOM. AngularFire 2 gives us the data as an observable, so we can pipe in the tap operator. Then once we have the data, we can use our SEO service to generate the tags. But this does bring up one problem. Because we're going to read this document on the server and then transition back to the browser, it will read the document twice and the user will see a brief flash in between those requests. This has slowed down significantly, but notice how we get some initial data from the server. It goes blank, then it comes back online after we've transitioned into the browser. Fortunately, Universal gives us some tools to transition state from the server side to the client side. It just allows you to set a key value pair on the server and then read it on the browser. So we'll import transfer state as well as make state key. Then we'll set up a constant here with make state key and give it the name of animal. When we get data on the server, we'll set it as this animal key and then read it when we get back to the browser. And transfer state is a service, so we'll add that to our constructor. And then I'm going to Define this as its own isolated method so you can reuse it if you have use for this in your own app. So what we're going to do in this method is first check if a document already exists. This should always return false on the server. It takes the Kiwi defined as the first argument and then a default value as the second argument. And just like we did before, we'll get our Firestore document as an observable and pipe in the tap operator. But this time, we will set the animal key with the document data. And we can also set our meta tag values here like we did before. UI. So the only question that remains is how do we use this existing document for our observable value once we transition to the browser? And the answer is super easy. We have an RxJS operator called start with, and we can just pass it that existing object. So instead of null, you still have your existing document from the server. But it is worth noting that this will execute 2 document reads in Firestore, so that may or may not be an issue for you. Keep in mind that you only server side render on a full page load, so it's unlikely that that would be an issue in most cases. The last thing we need to do is go in to the animal detail component and subscribe to the animal observable, which we can do with the async pipe. That takes care of our front end Angular app portion. Now we have a whole bunch of configuration stuff to do with Angular Universal. Most of this stuff is copy and paste configuration for right now, but hopefully, some of this comes to the Angular CLI in future. 1st, we'll go into the existing app module and add with server transition to the browser module import and set any random app ID that you want. And then make sure to import the transfer state module if you're doing a state transfer as well. Then the next thing you'll need to do is create an app server module, And it should also live inside the app directory. Basically, all this is doing is taking your app module and then importing it into another module that is set up to be rendered on the server. Then if you're transferring state, you'll need the server transfer state module and also the module map loader if UI doing lazy loading in your app. You wouldn't want lazy loading on the server, so that module takes care of that aspect for you. That should take care of everything in the app directory. Now we're going to move up to the source directory and add a new file called main.server.ts. All it has to do is import the app server module that we just created. This is more of a formality because main is our main entry point into the app. We also need to create a TS config for our main server TS file. So create tsconfig.server.json. One of the main differences between the browser build and the server build is that our server build needs to be in common JS so it can work on Node. Js. The next thing we need to do is configure our app with the Angular CLI so the CLI knows how to bundle it and where to transpile all the code. The next thing we'll do is build our actual server code, which uses Express JS, which is one of the most popular HTTP frameworks for Node. Js. Create the server TS file and then copy and paste all of this Express JS code into that file. This code was taken from the official Angular Universal demo, and only a few little modifications were made here and there to make it work with Firebase. For example, Firebase uses a few things that aren't available in Node. Js such as WebSockets. But a way to get around this is is to set them on the global object, which is the equivalent to the window object in a browser. There's a handful of things you might need in your project to make the server environment compatible with Firebase, I was able to install them with this command which you can find in the main article. UI. If you look at the Express JS app, you'll notice that it's not the prettiest code ever. The most important thing to understand here is that this Express app is capturing all of the routes in our Angular application and then rendering them to HTML based on wherever the user navigates. So that means they can navigate to a deep link, And we'll get the rendered HTML for that page. The one thing about Express is that it's completely separate from our Angular application. The Angular CLI has no way to compile this down to a production build for us, and we can roll out our own webpack config to do that. Create another file called webpack.server.config.js. And we're gonna add some more not so pretty code to it. But essentially, what we're doing is what the Angular CLI does under the hood. In this case, it's taking our TypeScript file and compiling it down to JavaScript that can run on Node. You should be able to copy and paste this and just forget about it as long as you're placing all of your files in the same place that we did in this lesson. We're getting really close to the end here. The next thing we need to do is go up into the root of the project and in the angularcli.json file, at a configuration for our server app. You'll notice that the apps option is an array. That's because we can add multiple apps to the Angular CLI configuration, which is exactly what we need to do here. Again, we're doing another copy and paste style thing where we take the existing app, and then we make a few modifications to it 2 point to the resources for our server app. We will point the main entry point to the main dot server dot ts file. We can also remove polyfills because they're not needed on the server, and you'll want to set service worker to false if using a worker. At this point, we need to build 3 different apps, our Express JS server, our Angular browser app, and Angular server app. We can do this in the package JSON in the scripts object. Basically, we're just combining our ng build commands with our webpack config to run everything all at once. UI. We can run these 2 commands together by doing npm run build colon ssr and serve colon ssr. When the build finishes, it should serve your express app on local host 4,000 and you should see all 3 apps in the dist folder. But it really shouldn't feel any different than a normal Angular UI. It just has this secret power to be understood by link bots and search engines. If you copy a link from your app and paste it into the Twitter card validator, you should CU valid card even though this data is pulled from the Firestore database asynchronously. And you'll also want to check to see if you've achieved any performance gains from SSR. For this demo, I ran a lighthouse audit and achieved a score of 94, which is really good for an Angular app pulling data from Fire UI based. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna talk about more advanced SSR scenarios, consider becoming a pro member at AngularFirebase.com. You'll get access to all kinds of exclusive content designed to help you ship apps on the Angular Firebase stack. Unity. Thanks for watching, and I'll see you soon.
The speakers discuss how to combineese and Angular Universal in optimizing a search engine for JavaScript app. They provide instructions on how to generate content and set meta tags, including setting up a route parameter and constant, and how to create a document. They also discuss the process of updating media tags and configuring app servers, including setting up a new file and importting existing ones. They emphasize the importance of building multiple apps and warn of potential issues with the Angular UI. They end with a recommendation to check for performance gains and mention a link to a website for more information.