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.
We are going to use @angular/cli
and firebase-tools
in command line to build and deploy your app.
Using @angular/cli
Ā , we are going to create a new angular
app. In this case, I will name it angular-universal-firebase
Ā .
To build and render your universal
app, we need to install @angular/platform-server
Ā .
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.
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
.
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
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!
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!!! š
[1] Before continuing, you should have had created a firebase project here. I named mine _angular-universal-firebase_
for this case.
firebase
` in the commandĀ lineLog in to firebase in the command line with the same google account you used to create your firebase project in [1].
Initialize firebase configurations through the command line:
Functions
and Hosting
for features to set up
Firebase set up configuration (Functions andĀ Hosting)
Javascript as Cloud function language for simplicity
angular-universal-firebase
.
Javascript
).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
functions
` directoryInstall da dependencies!
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:
AppServerModuleNgFactory
which was generated in Part I: Step 8āāāserver version.index
variable which is getting the index.html
file we generated from Part I: Step 8āāābrowser version.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
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
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.
If all things went well, you should be able to deploy your app to Firebase:
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! š