12
votes

UPDATE: I created a new project with every angular update there was and now on 8.2.0 it seems to be working. Just follow the instructions below, BUT there's currently a bug within webpack. So, after building "npm run build:ssr" open the server.js in functions/dist and edit lines 3 & 7 like so:

if(typeof exports === 'object' && typeof module === 'object')
    module.exports = factory(require("./server/main"));
else if(typeof define === 'function' && define.amd)
    define(["require(\"./server/main\")"], factory);
else if(typeof exports === 'object')
    exports["app"] = factory(require("./server/main"));
else
    root["app"] = factory(root["require(\"./server/main\")"]);

(before: "factory(require("require(\"./server/main\")"));")

BIG thanks goes out to Michele Da Rin Fioretto for helping me out with this one on "https://blog.daudr.me/painless-angular-ssr/#comment-4605393279". If you were facing the same problem please head over there and thank him for this.


I have a working Angular (8) shop webapp, that uses firebase. But since i'm not using Angular-Universal, i can't set title/meta tags on product-sites. To tackle that problem i tried to add angular-universal and deploy the app to firebase cloud-functions, but as soon as firebase takes over, no routes can't be matched anymore.

I followed the official guide on angular.io, then switched over to the tutorial of the brilliant Jeff Delanay of fireship.io link to the tutorial and read some medium articles on this topic like this one. I created (several) new apps and tried it repeatedly. Everything works fine (except the new angular 8 lazy loading arrow function) as long as the ssr-express server handles requests. "npm run build:ssr" followed by "npm run serve:ssr" works great, but as soon as the code gets prepped for firebase cloud functions and "firebase serve" takes over, "localhost:5000" works, but opening any link directly, like the "/about" example, console output states that no routes could be matched. Since i tried the official documentation and several medium articles, this has to be a very common problem, but i couldn't find any questions on here regarding this topic.

Since i can't see how this would be reviewable on stackblitz or anywhere else, i'll try to describe (briefly) what i did and show the corresponding code where required.

tl;dr: (outdated) Firebase Server Github Repo

(basically open the firebase server, click the button and hit f5)

The necessary prebuilt:

ng new cloudfunctionsangularuniversal && cd cloudfunctionsangularuniversal
ng add @angular/fire
ng add @nguniversal/express-engine --clientProject cloudfunctionsangularuniversal
ng g c landing
ng g c ssrtesting

/src/app/app-routing.module.ts: Update Routes

//..
const routes: Routes = [
  { path: '', component: LandingComponent },
  { path: 'ssrtesting', component: SsrtestingComponent }
];

Since i want to use firebase in my project, i need the XMLHttpRequest variable

npm install ws xhr2 bufferutil utf-8-validate  -D

/server.ts: Update the Server with the just installed packages

(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');
// ...

At this point "npm run build:ssr" followed by "npm run serve:ssr" fires up an express server, which handles all incoming requests properly.

But to use the app with firebase, several changes are necessary.

Init firebase (choose functions&hosting)

firebase init 

/firebase.json: rewrite all traffic to a function.

//...
"hosting": {
  "public": "dist/browser",
  "ignore": [
    "firebase.json",
    "**/.*",
    "**/node_modules/**"
  ],
  "rewrites": [
    {
      "source": "**",
      "function": "ssr"
    }
  ]
},
//...

/server.ts: export the app const, then remove the call to listen.

export const app = express();
// ...
// app.listen(PORT, () => {
//   console.log(`Node Express server listening on http://localhost:${PORT}`);
// });

/webpack.server.config.js: Make your app a library

// ...
output: {
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    library: 'app',
    libraryTarget: 'umd',
    filename: '[name].js',
  },
// ...

/movedist.js: Create a helper that copies over the build app from your "dist" folder to "functions/dist"

const fs = require('fs-extra');

(async() => {

    const src = './dist';
    const copy = './functions/dist';

    await fs.remove(copy);
    await fs.copy(src, copy);

})();

install the required package

npm i --save fs-extra

/package.json: Update your build command

//...
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server && node movedist && cd functions && npm run build"
//...

Finally, create the used app /functions/src/index.ts

import * as functions from 'firebase-functions';
const universal = require(`${process.cwd()}/dist/server`).app;

export const ssr = functions.https.onRequest(universal);

Now run

npm run build:ssr

Everything should be ready, so test it with

firebase serve

When opening "localhost:5000" everything seems fine. But open it up in the incognito window and open "localhost:5000/ssrtesting" and the console will give you

"ERROR { Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'cloudfunctionsangularuniversal/us-central1/ssr/ssrtesting'"

before successfully rendering the page. That doesn't happen on the firebase server thogh. Online it fires a 404.

Firebase Server Github Repo

Any help would be appreciated.

1
facing same issue from ages.Anil
make sure you have an empty route in your app-routing.module { path: '', component: AppComponent, pathMatch: 'full' },Jonathan

1 Answers

0
votes

Try adding /^firebase/ inside externals in webpack.server.config.js