Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 7 - Service Worker PWA + SSR not working on server

I am struggling to make my Server Side Rendering and Service Worker cooperate on server Side.

Information regarding localhost -> Working

This is working as expected. The service worker works and updates my app on every update. Moreover; a curl localhost:8082 send me back my info.

I start my app with the following command : npm run ssr

 "ssr": "npm run build:ssr && npm run serve:ssr",
 "build:ssr": "npm run build:client-and-server-bundles",
 "serve:ssr": "node dist/server.js",
 "build:client-and-server-bundles": "ng build --prod && npm run webpack:server",
 "webpack:server": "webpack --config webpack.server.config.js --progress --colors"

Information regarding production: -> Not Working

Website is over HTTPS : https://airdropers.io Website process is running on a close port and has HAPROXY redirecting traffic from 443 to the port of the webserver

Issue visible on Webserver logs : Could not subscribe to notifications Error: Service workers are disabled or not supported by this browser

Extra info :

Node js on localhost and production are the same: v9.0.0 I build on production with the following process :

  1. git pull
  2. npm run build:ssr
  3. pm2 start dist/server.js

UPDATE 23/02/2019

I have now a deeper understanding. My issue is that I start my SSR/PWA server with a node command such as "node dist/server.js".

From my understanding "node dist/server.js" is not working for Service Worker (PWA) I quote (https://angular.io/guide/service-worker-getting-started)

Because ng serve does not work with service workers, you must use a separate HTTP server to test your project locally. You can use any HTTP server. The example below uses the http-server package from npm. To reduce the possibility of conflicts and avoid serving stale content, test on a dedicated port and disable caching.

I can not launch is with http-server dist/browser because I will loose the SSR Capability.

How can I start my PWA / SSR Server ? What command shall I use?
What build shall I do?

UPDATE 24/02/2019

As mentioned by @Gökhan Kurt the service worker is not working properly with my SSR server. I need SSR for SEO and I need a service worker for Browser Push Notification. What solution do I have to handle Browser User Push Notification? A third party lib such as One Signals?


Any ideas suggestions are well welcomed to help me make that work. Thank you for support, Alex

like image 976
aorfevre Avatar asked Feb 11 '19 15:02

aorfevre


1 Answers

It is actually not related to your server at all. The problem is, service worker is tried to be registered on the server side, which is not supported. What you can do is make it so that service worker will register on client side.

I haven't tried but this just may work for you. You need to put a separate script in the end of body in index.html to run on browser:

  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/ngsw-worker.js');
    }
  </script>

Be aware that this will only give you the basic caching functionality of service worker and will probably not work for SwPush or SwUpdate. You can check how service worker module works internally here.

Another thing you should know is, service workers are actually not suitable for SSR apps. The generated ngsw.json file will not include all the pages you have. You will have to either modify this file manually or serve it not as a static file but create it dynamically.

And Caching all the pages is not a thing you want to do (unless page contents are static). Because a cached page will always show the same thing since you are not doing an XHR request on client side. For example if your home page is cached for a client, that client will always see the same page regardless of the intended dynamic content.

At this point you should consider why you want SSR and Web APP at the same time. If you need SSR for SEO, you don't need a SW. Just do SSR when the user agent is of a crawler, and serve dynamic angular when the client is a normal user.

How to switch request based on User Agent

This is my thought and I don't know if anyone is doing this. But theoretically, it should work.

Firstly, you will have to build your app to two different directories (DIST_FOLDER/ssr and DIST_FOLDER/csr in my example) with server-side and client-side rendering configurations. You may exclude SW from SSR. You can use SW in CSR as usual.

I found this package that can detect crawler/bot user agents. For express and Angular, you would use it like:

app.get('*', (req, res) => {
  var CrawlerDetector = new Crawler(req)

  // check the current visitor's useragent
  if (CrawlerDetector.isCrawler())
  {
    // render the index html at server side
    res.render(path.join(DIST_FOLDER, 'ssr', 'index.html'), { req });
  }
  else {
    // serve static index.html file built without SSR and let the client render it
    res.sendFile(path.join(DIST_FOLDER, 'csr', 'index.html'));
  }
});

After implementing this, you can debug your application to see if it works correctly by changing your user agent to one that is written here (i.e. use Postman).

like image 190
Gokhan Kurt Avatar answered Sep 18 '22 21:09

Gokhan Kurt