Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle missing dynamic chunks after new deployment with Webpack

Tags:

I have an AngularJs (1.7) SPA with Webpack (4.x).

This is how we create chunknames:

  config.output = {
    path: PATHS.build,
    publicPath: '/dist/',
    filename:  `[name]${isDev ? '' : '.[contenthash:8]'}.bundle.js`,
    chunkFilename: `chunks/[name]${isDev ? '' : '.[contenthash:8]'}.chunk.js`
  };

The lazyloading is done in the state definitions in ui-router basically like this:

  $stateProvider
    .state('reports', {
      url: '/projects/:project_id/reports',
      lazyLoad: function($transition$) {
        const injector = $transition$.injector().get('$injector');
        return import(/* webpackChunkName: "admin.reports.module" */ './reports')
          .then(mod => {
            injector.loadNewModules([mod.default]);
          })
          .catch(err => {
            throw new Error('An error occured, ' + err);
          });
      }
    })

After a deployment due changes to a module in a "dynamic" chunk - the filename will change of this chunk ([contenthash] has changed).

When a logged in user (where all bundled assets are loaded before the last deployment) now tries to open a route with the new chunk - the chunk is not there (404) and it will fail with:

Transition Rejection($id: 4 type: 6, message: The transition errored, detail: Error: An error occured, Error: Loading chunk 14 failed.
(error: admin.reports.module.8fc31757.chunk.js))

Is there a common way to circumvent/deal with this?

Maybe more in general: How can changes to a bundled web app be detected? Is there a common way to trigger a reload? Is a manual refresh always neccessary?

like image 846
madflow Avatar asked Oct 31 '18 11:10

madflow


1 Answers

I think there are a few ways to circumvent this, since the javascript in the current context isn't aware of the new hash of the content generated by the latest build you could try:

1.) You could try setting up an http redirect on the hashed files: https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections The browser will request the old file and the server can point to the new file instead of returning 404. If all of your files follow a convention and only store one of the file at a time ex: component.hash.js then this should be pretty easy.

2.) A hacky client approach would be handling the transition-rejection in a try catch and reload the page, without the cache to get the new assets. https://developer.mozilla.org/en-US/docs/Web/API/Location/reload

There's always more than one approach, but this is what I could think of to solve the issue.

like image 156
Kyle Mills Avatar answered Nov 15 '22 04:11

Kyle Mills