Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run service worker locally with Angular

I am following angular's best practice in order to make PWA. After making production build (ng build --prod --aot), I am also running the service worker from dist, on localhost: http-server -p 8080 -c-1 dist When I am trying to sync the worker with my Angular, using:

navigator.serviceWorker.ready.then(function(swRegistration) {

            console.log('swReady');
});

Nothing happens, and seems that SW is not communicating with Angular. Working with a remote server (uploading dist) does work. So seems that the problem is dist not working with ng serve. What am I doing wrong?

like image 651
Yuvals Avatar asked Apr 29 '19 14:04

Yuvals


3 Answers

It seems that currently we cannot use service worker with ng serve --prod. However we can make a workaround.

  1. We build the project ng build --prod

  2. From the dist location we take the ngsw-worker.js and ngsw.json files and copy them to the src folder.

  3. We modify our angular.json file in order to serve them. We find the property "projects": {"[my-project-name]": {... "architect": {... "build": {... "options": {... "assets": [... and there we add these two items – "src/ngsw-worker.js", "src/ngsw.json".

  4. We serve – ng serve --prod.

I have reached till that point. The browser says that the SW is activated and running. The only consideration now is that if we change something in the SW, we need to rebuild again and make the same steps. But I believe we can develop more rapidly.

Good luck!

like image 180
Anton Mitsev Avatar answered Sep 21 '22 14:09

Anton Mitsev


Note: this is based on Angular under Ionic. For plain Angular some paths are different (e.g. www -> dist) and 'ng' command should be used instead of 'ionic', so adjust accordingly.

Step 0. Add @angular/pwa, it will create service worker that is used in production (see any other instructions for that).

Step 1. Enable service worker use in debug build. Usually SW is enabled only for production, e.g. in file src/app/app.module.ts, one of two implementations, change 'enabled' to true (or can alternatively add property 'useServiceWorker' to 'environment.ts' and 'environment.production.ts' files and set them both to 'true', later when debugging is done, will need to change to 'false' only the setting in environment.ts file):

  imports: [ ...
-    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
+    ServiceWorkerModule.register('ngsw-worker.js', { enabled: true }),
  ],

or

  imports: [ ...
    ServiceWorkerModule.register('ngsw-worker.js'),
  ],
  providers: [ ...
-    { provide: SwRegistrationOptions, useFactory: () => ({ enabled: environment.production }) },
+    { provide: SwRegistrationOptions, useFactory: () => ({ enabled: true }) },

Step 2. Add some hooks to the 'scripts' in package.json file. They are aimed at ensuring that all file hashes are correct in 'ngsw.json' file and SW could load files properly:

{
    "scripts": { ...
+        "ionic:serve:before": "...(anything already there)... && echo {} > src/ngsw.json && cp www/ngsw.json src/ngsw.json",
+        "ionic:build:after":"...(anything already there)... && npm run ngsw:rebuild",
+        "postbuild": "...(anything already there)... && npm run ngsw:rebuild",
+        "ngsw:rebuild": "ngsw-config www ngsw-config.json && cp www/ngsw.json src/ngsw.json",

For ionic serve to pick that file, it adds a blank file src/ngsw.json in pre-build step and tries to copy calculated hashes from www folder. If 'ionic serve' fails, make sure to run 'ionic build' first. I know this step is iffy, but there are no better hooks e.g. in 'ng serve' - there are open feature requests for that.

Since 'src/ngsw.json' is created/generated, it should not be under source control/git, so add line '/src/ngsw.json' to '.gitignore' file.

Step 3. Add service worker source and config to your debug build. Add lines to file angular.json that would copy 'ngsw-worker.js' and 'ngsw.json' to www/ (production build does it automatically, this will copy it during debug build):

{
  "projects": {
    "app": {
      "architect": {
        "build": {
          "options": {
            "assets": [
+              {
+                "glob": "ngsw-worker.js",
+                "input": "node_modules/@angular/service-worker",
+                "output": "."
+              },
+              "src/ngsw.json",
...

Step 4. Build debug version (ensures current hashes in ngsw.json) and then serve with HTTPS. 'ionic serve' has --ssl and --external options (--external allows opening app on e.g. a phone):

ionic build
ionic ssl generate ;# creates SSL certs in .ionic/ssl/: cert.pem and key.pem
ionic serve --external --ssl

Another option is to use any appropriate HTTP server, which can do SSL and proxy for single-page apps (SPA). Package 'http-server' does not work well when proxy and ssl options are mixed, so use e.g. 'local-web-server' instead:

npm install -g local-web-server
ws -p 8100 --cert .ionic/ssl/cert.pem --key ,ionic/ssl/key.pem --https --spa index.html --directory www

Step 5. Add certificate to your browser CA list. Use the following steps for Chrome (or google it for other browsers):

https://www.nullalo.com/en/chrome-how-to-install-self-signed-ssl-certificates/

Done! Open Chrome and navigate to https://localhost:8100, see console for loaded Service Worker. If there are any errors in console, retrace prior steps - frameworks change rapidly and something might be already different.

like image 21
iva2k Avatar answered Sep 18 '22 14:09

iva2k


With Chrome, you can enable a flag for treating a specific host as if it is a secure origin, allowing service workers to work:

./chrome --unsafely-treat-insecure-origin-as-secure=http://your.insecure.site:8080

To launch chrome from the terminal, you do need to know the executable location. This will be system dependent. For MacOs:

open /Applications/Google\ Chrome.app/ --args  --unsafely-treat-insecure-origin-as-secure=http://your.insecure.site:8080
like image 31
TmKVU Avatar answered Sep 20 '22 14:09

TmKVU