Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: module lazyLoading and missing chunk

We are using Lazy Loading for Router Modules.

  {
    path: 'users',
    loadChildren: 'app/users/users.module#UsersModule',
  },

But when we update version of our app (upload new bundle to the server) it's always broken: old app (that user has already downloaded) tries to get old chunk file that is not on the server anymore.

Live example: https://alexshakura.github.io/chunk-error/ (I've just rename the chunk to highlight the error)

What is the correct way to handle this error?


Let me describes the steps:

  1. AppVersion1 is loaded by a user (without lazy loaded chunks)
  2. We updated the app and uploaded bundle to the server (so currently AppVersion2 is correct one)
  3. User (who still has AppVersion1) goes to route that loads lazy module, BUT it tries to load chunk from AppVersion1 that does not exist anymore.
like image 642
Stepan Suvorov Avatar asked Mar 06 '18 16:03

Stepan Suvorov


1 Answers

You can try using the ng service worker to do this for you.

The service worker will have its own manifest that will enable the worker to keep track of app versions and cached assets. Every time a user reloads the page, the cached version of the app will be served. Then, in background, the service worker will fetch the current manifest, parse it and if there is a version change, it will cache the new app version in the background. The next user's reload will display the new version of the app.

You can enable the service worker functionality by putting "serviceWorker": true to your .angular-cli.json into your app section.

Then create a ngsw-config.json file in your src dir. The defaults should look like this:

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }]
}

And finally, put NGSW module initialization into your app.module:

@NgModule({
  // ...
  imports: [
    // ...
    ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
  ]
})
export class AppModule {}

Running ng build --prod will provide all the rest for you.

You can find more about service workers in the official docs.

like image 127
Heehaaw Avatar answered Oct 20 '22 12:10

Heehaaw