paint-brush
Deploying Angular Universal v6+ with Firebase šŸš€ šŸ”„ā€‚by@aaaronnte
14,407 reads
14,407 reads

Deploying Angular Universal v6+ with Firebase šŸš€ šŸ”„

by Aaron TeMay 7th, 2018
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Disclaimer: This blog post will be a focused step-by-step tutorial of how to deploy an <a href="https://hackernoon.com/tagged/angular" target="_blank">Angular</a> Universal App using <a href="https://hackernoon.com/tagged/firebase" target="_blank">Firebase</a> Hosting. For any explanations about Angular Universal and Server Side Rendering, Angular has a <a href="https://angular.io/guide/universal" target="_blank">great documentation</a> on their website.

Company Mentioned

Mention Thumbnail
featured image - Deploying Angular Universal v6+ with Firebase šŸš€ šŸ”„
Aaron Te HackerNoon profile picture

Disclaimer: This blog post will be a focused step-by-step tutorial of how to deploy an Angular Universal App using Firebase Hosting. For any explanations about Angular Universal and Server Side Rendering, Angular has a great documentation on their website.

You can also find the source code on Github.

Requirements

  • node.js (I am using v8.11.1 for this tutorial)
  • Angular 6+ (I have written a similar article for deploying Angular < v6)

Part I: Set Up Angular AppĀ šŸ› 

1. Install global dependencies

We are going to use @angular/cli and firebase-tools in command line to build and deploy your app.

2. Create a new AngularĀ project

Using @angular/cliĀ , we are going to create a new angular app. In this case, I will name it angular-universal-firebaseĀ .

3. Install @angular/platform-server

To build and render your universal app, we need to install @angular/platform-serverĀ .

4. Add Server Side Rendering Config

In @angular/[email protected]+Ā ,Ā .angular-cli.json is changed to angular.jsonĀ . This defines how our project is structured and the build configurations for this project. We would want to add a server configuration for the project in the projects.PROJECT_NAME.architect path.

Note that weā€™ve added server that defines the builder and options config for the server side version of our app.

5. Modify project output to FirebaseĀ folder

For simplicity, we will build the browser version of our app in the same directory as where we are building our sever version to be server side rendered in Firebase. To do this, edit angular.json ā€˜s PROJECT_NAME.architect.build.options.outputPath to functions/dist/browser.

6. Create necessary files for app serverĀ version

  • src/app/app.server.module.ts

Create a new module for the appā€™s server version.

https://github.com/aaronte/angular-universal-firebase/blob/master/src/app/app.server.module.ts

  • src/main-ssr.ts

Create an entry point for the server module. This is the main file we referenced in the server configuration in angular.jsonĀ .

https://github.com/aaronte/angular-universal-firebase/blob/master/src/main-ssr.ts

  • src/tsconfig.app-ssr.json

Create the tsconfig for the server version. Similar to the browser version except angularCompilerOptions.entryModule which will reference the entry module for the server version that we just created. This is also referenced in angular.json as tsConfig.

https://github.com/aaronte/angular-universal-firebase/blob/master/src/tsconfig.app-ssr.json

7. Include server transition in appā€™s browserĀ module

Since we are sending the server version of your app to the browser before the browser version, we need to addĀ .withServerTransition({ appId }) when adding BrowserModule in imports.

https://github.com/aaronte/angular-universal-firebase/blob/master/src/app/app.module.ts

Now we are ready to build the server and browser versions of our app!

8. Build browser and server versions of theĀ app

Using @angular/cli, we will build the two versions of the app.

  • ng build --prod: This will build the browser version of the app with prod configurations.
  • ng run PROJECT_NAME:server: This will build the server version of the app. It will generate a ngFactory file that we can use to render our app using node.

When both builds are done, you should now have a functions folder in your root directory with browser and server folders in it. Awesome!!! šŸŽ‰

Part II: Deploying with FirebaseĀ šŸš€

[1] Before continuing, you should have had created a firebase project here. I named mine _angular-universal-firebase_ for this case.

1. Log in to `firebase` in the commandĀ line

Log in to firebase in the command line with the same google account you used to create your firebase project in [1].

2. Initialize Firebase in the `angular` project

Initialize firebase configurations through the command line:

  • Select Functions and Hosting for features to set up

Firebase set up configuration (Functions andĀ Hosting)

Javascript as Cloud function language for simplicity

  • Select the firebase project you created in [1]. (In my case, itā€™s angular-universal-firebase.

  • Accept all defaults in this stage; we will configure the rest in later steps. (In this tutorial, we will write our functions in Javascript).

3. Add package dependencies to `functions`

Since we are using a node server through firebase-functions, We need to include angular dependencies in functions/package.json to render the server version of the app.

Aside: Right now, I donā€™t know any way to mitigate this duplication of dependency declaration since as far as I know, you canā€™t access files outside the _functions_ directory in any _firebase-functions_ javascript files. But if you know a way, please let me know!

https://github.com/aaronte/angular-universal-firebase/blob/master/functions/package.json

4. Install packages in `functions` directory

Install da dependencies!

5. Create Firebase function to serve theĀ app

We are going to use functions.https.onRequest Firebase function type to send the response from our express server. There are a lot of things going on in this file but the most notable are:

  • Importing AppServerModuleNgFactory which was generated in Part I: Step 8ā€Šā€”ā€Šserver version.
  • Creating an index variable which is getting the index.html file we generated from Part I: Step 8ā€Šā€”ā€Šbrowser version.
  • Using renderModuleFactory to generate an html file that we send as a response with url and document parameters.
  • url parameter determines which route of the app is going to be rendered. Specifying this allows renderModuleFactory to build the html of that route.
  • document is the full document HTML of that page that should be used to render. In this case, it will be the browser version of index.html of the app.

https://github.com/aaronte/angular-universal-firebase/blob/master/functions/index.js

7. Configure FirebaseĀ hosting

Now that we have built the function to render pages, we need to change the firebase hosting configuration to use this function. Change the hosting.rewrites in firebase.json. The first entry is to send static files (css and js) through our public folder. The second entry is to direct all requests to the ssr function.

https://github.com/aaronte/angular-universal-firebase/blob/master/firebase.json

8. Copy all content of `functions/dist/browser` toĀ `public`

Since we want to run our application like a normal application, we want to put all the files generated by building our platform for the browser in the public folder. This means the html, js, css, etc in the functions/dist/browser should all be present in the public folder. Note: We have to, however, change the name of index.html to index2.html because firebase wonā€™t run the ssr function if it finds index.html in the public folder.

9. Deploy to Firebase šŸš€Ā šŸ”„

If all things went well, you should be able to deploy your app to Firebase:

Thatā€™s it!Ā šŸ‘

You can check out the source code on Github.

I hope this tutorial was helpful in some way! If you have any feedback or questions, add them on the Github issues to ensure everyone looking at the code would benefit. šŸ˜„

Happy coding! šŸ˜ƒ