angular / mobile-toolkit

Tools for building progressive web apps with Angular
MIT License
1.34k stars 175 forks source link

Potential cache corruption from service worker #150

Open Ploppy3 opened 7 years ago

Ploppy3 commented 7 years ago

I noticed a problem on Chrome Android only, no matter the Android version nor Chrome version, the service worker will mess up the cache somehow. I tried for days to identify the issue but I'm unsuccessful. It could be an error on my side though, I could be missing a critical step.

Tested on Chrome on 3 devices, running different versions of Android, and tested on my device on 4 versions of Chrome (all the available branches). Version of the SW is 1.0.0-beta.13. I thought you fixed the bug in this release but it is still present.

As I can't debug my Android devices (a bit of laziness and lack of USB-C adapter 😄 ) I can only guess what the issue is. I think it's due to cache failure when the service worker caches the index.html into other critical .js files due to redirection.

I have 4 apps using the service worker all have the same problems. So I ended up creating the most simple app. An empty app with just the service worker which shows a number representing the app version and a text to warn when an update is installed in the background.

The thing I noticed, there are 2 ways to reproduce the bug:

1)

2)

These steps in image (Chrome Canary 60.0.3097.0):

In both cases, if you reload the app after the crash it will load but weird behaviors may appear such as version rollbacks (that's why I think it's related to the cache).

The test app is available here: https://test-service-worker-97321.firebaseapp.com/ (current version is 19) I can update it whenever you ask. For you to test as well.

Here is the code of the sample app:

ngsw-manifest.json

{
  "routing": {
    "index": "/index.html",
    "routes": {
      "/": {
        "prefix": false
      }
    }
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { ServiceWorkerModule } from "@angular/service-worker";

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    ServiceWorkerModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';
import { NgServiceWorker } from "@angular/service-worker";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [NgServiceWorker]
})
export class AppComponent {

  public version = 17;
  public pendingUpdateVersion: string;

  constructor(
    private sw: NgServiceWorker,
  ) {
    this.sw.updates.subscribe(res => {
      console.log(res);
      this.pendingUpdateVersion = res.version;
    });
  }

}

app.component.html

Version: {{version}}
<div *ngIf="pendingUpdateVersion"><b>An update is available</b></div>
Ploppy3 commented 7 years ago

I finally managed to get the log crash on remote device debugging mode with chrome 59.

capture

capture

stewones commented 7 years ago

same here =/

Ploppy3 commented 7 years ago

@webmaxru @alxhub Is the project still under development?

webmaxru commented 7 years ago

@Ploppy3 Yes. According the plan, there will be an updated version (as a part of the core) in Angular 5 (which is quite soon)

Ploppy3 commented 7 years ago

@webmaxru Will it be possible to upgrade from the current version to the version integrated to Angular ?

webmaxru commented 7 years ago

Refactoring will mainly affect ngsw-manifest (to make the settings and flow more flexible, consistent, universal). I don't have the information about upgrade: it could be backward compatibility mode or upgrade script. Anyway - this manifest is a simple json file, updating its format shouldn't be an issue even in manual mode.

Ploppy3 commented 6 years ago

@webmaxru I just tested and the new version does not seem to be retro-compatible, is there a solution?

Ploppy3 commented 6 years ago

It seems like you are working on it. https://github.com/angular/angular/issues/20899

webmaxru commented 6 years ago

@Ploppy3 you are right, the "old" NGSW (beta 1-16) is not compatible with the release version. They share the same idea, but the configuration files and flow are a bit different. Quickstart: https://www.youtube.com/watch?v=wFjw0DM1ui4

Ploppy3 commented 6 years ago

@webmaxru Hello, I'm pretty sure I saw somewhere that @webmaxru or @alxhub said an updater will be built at some point to migrate from the NGSW (beta 1-16) to NGSW (5.0.0). Is it still under work? Should I open an issue to track it in the @angular/angular repo ?

Ploppy3 commented 6 years ago

@webmaxru @alxhub Please an answer is really needed, as people like me who used the original service-worker are now stuck.

webmaxru commented 6 years ago

@Ploppy3 Which version of Angular and Angular CLI do you use for your project? I don't think there will be a migration script/util for NGSW just because after all it's a question of slightly modified JSON configuration. It's really simple to update it manually.

Ploppy3 commented 6 years ago

I'm not sure but I may I have explained it poorly. Let me reiterate. I don't have any problem upgrading my code to the new service-worker. My problem is that the new service-worker seems incompatible with the old one and the new version of the app is never loaded nor installed. (I'm using latest CLI & Angular)

Ploppy3 commented 6 years ago

@webmaxru Here are the files generated by the 'old' service-worker. image

These are the files generated by the 'new' service-worker script: image (those are 2 different apps I just took the screenshots to show how the files generated by the service-worker are different between the 2 versions, not only the names are different, the json, which is used to check for update if I'm exact has a different structure).

Just to be clear. At this point, if I upload the new app, the old service-worker will start because the old app is cached. Then, it will look for the ngsw-manifest.json, which it can't find because the new one uses a different file name, so a 404 is thrown and update is aborted.

I'm not sure what to do to make the old one update to the new one. Or maybe I need a script to uninstall the old service worker but I have no idea how to it.

Ploppy3 commented 6 years ago

@webmaxru I found this https://github.com/angular/angular/commit/db3e65fb1786179930704868f578429e47c399bf It leads to many questions. Does it mean it should be able to uninstall the old service worker? If it uninstalls any other service worker installed, it will probably uninstall the new one as well, does it means it's not a script meant for transition between 2 service workers?

webmaxru commented 6 years ago

@Ploppy3 If I understand correctly, the issue is:

In that case, you might want to serve a "kill switch" instead of worker-basic.min.js. Have a look at its contents here: https://stackoverflow.com/a/38980776/1310228

Ploppy3 commented 6 years ago

@webmaxru I attempted this in local and it seems to work. I will confirm later.