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/cli@v6.0.0+
, .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 withprod
configurations.ng run PROJECT_NAME:server
: This will build the server version of the app. It will generate angFactory
file that we can use to render our app usingnode
.
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
andHosting
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 theindex.html
file we generated from Part I: Step 8āāābrowser version. - Using
renderModuleFactory
to generate anhtml
file that we send as a response withurl
anddocument
parameters. url
parameter determines which route of the app is going to be rendered. Specifying this allowsrenderModuleFactory
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 ofindex.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! š