WICG / import-maps

How to control the behavior of JavaScript imports
https://html.spec.whatwg.org/multipage/webappapis.html#import-maps
Other
2.65k stars 69 forks source link

Retrying failed to fetch dynamically imported modules #116

Open blittle opened 5 years ago

blittle commented 5 years ago

I'm trying to understand how to resolve the following scenario:

  1. The user is online and loads my web app.
  2. Later, the user goes offline and navigates somewhere in the app which triggers a dynamically imported module resolved via an import map.
  3. Because I'm offline, the module loading will result in an error of Failed to fetch dynamically imported module. The app notifies the user that they are offline.
  4. Now the user reconnects and becomes online.
  5. We retry the original module fetch, which fails because the browser never retries the original request.

If I wasn't using import maps, I could force a retry by adding a query parameter to the URL I'm importing. With module maps, is there any way to retry a module import that has previously failed?

Note: in my scenario above, I could solve the problem by building a wrapper around the native import() that keeps track of whether the user is online/offline and prevent a module request from going out unless they are online. But that doesn't resolve all of the scenarios where a module resolution might fail, and the app may want to retry.

domenic commented 5 years ago

With module maps, is there any way to retry a module import that has previously failed?

Sure. You could add a query parameter to the URL you're importing.

blittle commented 5 years ago

@domenic that's easy when not using import maps. But how do I do that when using import maps? As far as I can tell, import('lodash?retry=1') isn't supported.

blittle commented 5 years ago

Also, because import maps can't be dynamically changed post resolution, I also can't dynamically change the import map to point to a new URL with a query parameter.

guybedford commented 5 years ago

This use case relies on at the very least a registry "delete" API. Any type of JS registry reflection spec is still a long way off unfortunately.

blittle commented 5 years ago

@guybedford it seems as though, when using native modules defined in an import map, the best option is to keep track of navigator.onLine and only request the module when the browser thinks it is connected to the internet. Not an ideal solution, because navigator.onLine throws many false positives.

guybedford commented 5 years ago

@blittle can you not manage this at the service worker level? That probably seems preferable for these use cases.

blittle commented 5 years ago

@guybedford generally I would agree, but I think there is still an edge case to handle due to:

However, service workers are not available on first load. Thus, they can't really be a part of the critical infrastructure used to load modules. They can only be used as a progressive enhancement on top of fetches that will otherwise generally work.

Imagine a scenario where the app is loaded for the first time, and no service worker is available. Then for some reason the browser gets intermittent connectivity, and there are subsequent modules defined in the module map that are now failing to load, and no service worker is available intercept.

guybedford commented 5 years ago

@blittle as mentioned I think the best solution is the dependency reflection and registry delete API combination in such a case:

import('app').catch(async err => {
  if (!isNetworkError(err)) throw err;
  unloadModuleAndDependencies(import.meta.resolve('app'));
  return import('app');
});t

function unloadModuleAndDependencies (moduleId) {
  const deps = ModuleReflect.getDependencies(moduleId);
  if (deps) {
    ModuleReflect.delete(moduleId);
    deps.forEach(unloadModuleAndDependencies);
  }
}

The above depends on the hypothetical specifications for ModuleReflect.delete , import.meta.resolve and ModuleReflect.getDependencies which as I say are all quite far off into the future still.

I didn't realise Service Worker still hasn't solved the first-load attachment case... but I wouldn't bet on the above arriving any sooner :P

guybedford commented 5 years ago

(and in case it isn't clear - ModuleReflect is a really really bad strawman used just for discussion here, and is by no means anything being discussed or proposed, and likely shouldn't be).

blittle commented 5 years ago

I think some sort of API like that would make sense. Whether or not it gets added to the spec, 🤷‍♀️, but I figure this issue could stay open to document the use case.

On Thu, May 16, 2019 at 7:53 PM Guy Bedford notifications@github.com wrote:

(and in case it isn't clear - ModuleReflect is a really really bad strawman used just for discussion here, and is by no means anything being discussed or proposed, and likely shouldn't be).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WICG/import-maps/issues/116?email_source=notifications&email_token=AAL6RFLDHNTLYHKID2OSJ6DPVYF3BA5CNFSM4G76HC6KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVTQCXA#issuecomment-493289820, or mute the thread https://github.com/notifications/unsubscribe-auth/AAL6RFIOSGEV3KL6DXI5M2TPVYF3BANCNFSM4G76HC6A .

-- Bret Little Cell: 801-477-7618

AlonMiz commented 1 year ago

I am joining this train a bit late, but it's still an issue. I would love to be able to delete the asset/map to the failed asset. in the first place, I think the failed response shouldn't be cached. We came up with a hacky workaround. it partially solves the problem. Anyhow, you are welcome to try this, to be able to "retry" dynamic module failure The solution is "partially" solved as the rest of the tree will not be retried. We cannot programmatically add a query param to them. I wrote a quick article about that: https://medium.com/@alonmiz1234/retry-dynamic-imports-with-react-lazy-c7755a7d557a