feathers-reactive with Angular Universal

March 24, 2018 0 Comments

feathers-reactive with Angular Universal

 

 

feathers-reactive is an awesome library that extends feather with Observables. The Observable listens to service events and updates accordingly. And because Observables and Angular are best friends it is highly likely that you use feathers-reactive with your Angular app.

To use it you prepend your usual service method call with .watch():

The configuration is also rather simple:

I created a simple data service that works beautifully if it runs on the client:

But if you want to render your app on the server with Angular Universal you do not get any response. This is because ngZone recognizes that a websocket is created and as long as the websocket is established keeps the zone unstable (see Issue). The point is that Angular Universal waits until the zone is stable before it renders the content. Of course, this never happens. And therefore Angular Universal waits and waits and waits… 😴

Because we do not need a constant stream of updated data on the server, we could just fallback to feathers rest implementation. We just get the first response and are good to go.

There is only one problem. The API is different. As I pointed out in the beginning you need to prepend your service method call with .watch() if you are using Observables. But the normal (rest) API just uses .find() without .watch(). To avoid refactoring your whole code you cloud provide a “fake” .watch() method on the server that passes all calls to the original method:

It just calls the original method and wraps the returned Promise in an Observable. I copied most of the code from the original feathers-reactive index.js file.

To use our shiny new rxUniversal function we need to improve our data service:

If it is in the browser it opens the websocket and gets real-time updates. On the server it falls back to a rest call.

BUT: It does not work 😢
If you build the server and access one of your route you will see that no data is rendered. The request is actually done but it seems like Angular Universal does not wait until it is rendered in the GUI.

It seems that you need to wrap some functions into ngZone.run() or something similar. But I could not figure out what to do. Interestingly if I’m using Angulars HttpClient instead of feathers it all works. Luckily I found some undocumented (PR to documentation will be out soon) API to get the feathers rest client work with Angulars HttpClient. The code below shows the full data service with the fix in row 25:

The solution is actually quite simple but it took me a while to get there. Now it works and renders the requested data on the server into the HTML 😁

Hope this helps someone out there.


Tag cloud