7
votes

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?

6
do the ng build files not work on your localhost? Or are you only referring to the files from ng serve? - wentjun
they do. ng serve is working, but not communicating with the service worker - Yuvals
service workers don't work on ng serve, use any other server, angular.io/guide/… - Ashish Ranjan
understood and have read the guide. The problem is - it makes it impossible to test without building and uploading every times. Is there no other way to develop locally and test without building? - Yuvals
You're running ng build and then hosting it with http-server, I understand how ng serve matters. Can you explain how it's being used? Also, can you post your angular.json file? Specifically the "configurations" -> "production" section - Vlad274

6 Answers

18
votes

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!

4
votes

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
3
votes

You can't serve your Angular project with service worker via ng serve, as the documentation for Service Workers state that it requires https. The only way to run it without https/on a server, is to use ng build and run the http-server locally to test your project.

Because ng serve does not work with service workers, you must use a separate HTTP server to test your project locally.

0
votes

If you want to use other browsers that don't support TimKVU answer then the solution is to use ngrok (https://ngrok.com)

It sets up a secure tunnel to whatever server you are using. You run it with:

ngrok http 4200

Simply connect to the domain shown on screen.

0
votes

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.

0
votes

Firstly, make sure in your angular.json file the following is present: "ServiceWorker": true

      "configurations": {
        "production": {
          "serviceWorker": true,
          "fileReplacements":
            ...

Second, install http-server and run

http-server -p 8080 -c-1 dist/app

Third, your service workers might not work on ip-addresses. Therefore, you should used the following instead:

http://localhost:8080/

Source: Getting an Angular PWA service worker installed on localhost