To be able to use universal with your Angularfire app, make sure to install the latest angularfire2 package.
| npm install @angular/fire firebase --save
|
Next set up the Firebase config to environments variable.
You will usually do this in your enironment.ts files.
| export const environment = {
production: false,
firebase: {
apiKey: '', authDomain: '',
databaseURL: '', projectId: '',
storageBucket: '', messagingSenderId: ''
}
};
|
Now lets import the angularfire2 module to our app.module.ts and the config the firebase variables.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { environment } from '../environments/environment';
@NgModule({
declarations: [ AppComponent ],
imports: [
BrowserModule.withServerTransition({ appId: 'my-app' }),
BrowserAnimationsModule,
AngularFireModule.initializeApp(environment.firebase, 'my-app'), // imports firebase/app needed for everything
AngularFirestoreModule, // imports firebase/firestore, only needed for database features
AngularFireAuthModule, // imports firebase/auth, only needed for auth features,
AngularFireStorageModule, // imports firebase/storage only needed for storage features
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
|
Now that we have Angularfire2 set up and import, lets make sure it's working...
Go to ```app.component.ts``` and set up your database to get some data from firebase
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | import { Component } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',
template: `{{item.title}}`,
styleUrls: ['./app.component.scss']
}) export class AppComponent {
title = 'my-app';
items: Observable;
constructor(db: AngularFirestore) {
this.items = db.collection('items').valueChanges();
}
}
|
Assuming you have a collection in your firebase project call ```items``` with a document that has field ```title```.
Adding Universal for Seo
Now that we have our app working and displaying list items from firebase, it's time to add universal to our app. First thing to do is add the universal package to our project. Lucky for us all is packed we just need to run the following command:
| ng generate universal --client-project
|
Make sure to replace all instances of ```my-app``` with your app-name.
```ng generate universal``` will create some new files and do necessary updates. That means you don't have to do much manually. Now that, almost everything is done by ng universal, we need to add some files manually. Just two files to be specific.
Build a Server with ExpressJS
Create a file call ```server.ts``` in the root of your project.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 | // server.ts
// These are important and needed before anything else
import 'zone.js/dist/zone-node'; import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import * as express from 'express'; import { join } from 'path';
import { readFileSync } from 'fs';
// Polyfills required for Firebase
(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');
// Faster renders in prod mode
enableProdMode();
// Export our express server
export const app = express();
const DIST_FOLDER = join(process.cwd(), 'dist');
const APP_NAME = 'my-app'; // TODO: replace me!
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require(`./dist/${APP_NAME}-server/main`);
// index.html template
const template = readFileSync(join(DIST_FOLDER, APP_NAME, 'index.html')).toString();
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [ provideModuleMap(LAZY_MODULE_MAP) ]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, APP_NAME));
// Serve static files
app.get('*.*', express.static(join(DIST_FOLDER, APP_NAME)));
// All regular routes use the Universal engine
app.get('*', (req, res) => { res.render(join(DIST_FOLDER, APP_NAME, 'index.html'), { req }); });
// If we're not in the Cloud Functions environment, spin up a Node server
if (!process.env.FUNCTION_NAME) { const PORT = process.env.PORT || 4000; app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
}
|
Now lets bundle our server app with webpack
Add a Webpack Config for the Express Server
create another file call ```webpack.server.config.js```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 | // webpack.server.config.js file
const path = require('path');
const webpack = require('webpack');
const APP_NAME = 'my-app'; // TODO: replace me!
module.exports = {
entry: { server: './server.ts' },
resolve: { extensions: ['.js', '.ts'] },
mode: 'development',
target: 'node',
externals: [
/* Firebase has some troubles being webpacked when in
in the Node environment, let's skip it.
Note: you may need to exclude other dependencies depending
on your project. */
/^firebase/
],
output: {
// Export a UMD of the webpacked server.ts & deps, for
// rendering in Cloud Functions
path: path.join(__dirname, `dist/${APP_NAME}-webpack`),
library: 'app',
libraryTarget: 'umd',
filename: '[name].js'
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' }
]
},
plugins: [
new webpack.ContextReplacementPlugin(
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
}
|
All we need to do now is add our build scripts to ```package.json```
| // ... omitted
"build": "ng build && npm run build:ssr",
"build:ssr": "ng run my-app:server && npm run webpack:ssr",
"webpack:ssr": "webpack --config webpack.server.config.js",
"serve:ssr": "node dist/my-app-webpack/server.js"
|
That's it! To test your app locally
| npm run build && npm run serve:ssr
npm run serve:ssr
|
opens a server at http://localhost:4000/.
You can navigate there, and view app source to confirm your universal app is all working well.