Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vue-router lazy load] View cannot be loaded after network connection is restored #1333

Closed
linhx opened this issue Mar 8, 2022 · 8 comments

Comments

@linhx
Copy link

linhx commented Mar 8, 2022

Version

4.0.13

Reproduction link

codesandbox.io

Steps to reproduce

  • Load the home page
  • Disconnect internet: F12 > Tab Network > set network throttling to "offline"
  • Click link "Test" on the home page
  • Reconnect internet: set network throttling to "No throttling"
  • Click link "Test" on the root page

What is expected?

The "Test" page can be loaded

What is actually happening?

The "Test" page cannot be loaded
Error:
TypeError: Failed to fetch dynamically imported module: <js file>

@posva
Copy link
Member

posva commented Mar 9, 2022

This looks like a caching issue, unrelated to Vue Router which only calls the dynamic import and reports back the error.

@posva posva closed this as completed Mar 9, 2022
@linhx
Copy link
Author

linhx commented Mar 9, 2022

For now, I'm catching the exception and then using window.location.href to redirect. The behavior is just like MPA, but I hope there is a better solution that can keep the state of the app.

@linhx
Copy link
Author

linhx commented Mar 10, 2022

This looks like a caching issue, unrelated to Vue Router which only calls the dynamic import and reports back the error.

okay, I understand. But the problem is the behavior.

  • Lost internet connection
  • Click link > nothing happened
  • Internet connection has been restored
  • Click link > still nothing happened

I saw that react-router-dom handle this case by let user go to the url but with blank page. At least user will know there is something wrong.

@abrthel
Copy link

abrthel commented May 6, 2022

We're running into this exact issue in one of our apps. We deal with lots of users who have flaky network connections and unfortunately we can't just hard reload the page on failure because we rely on the current page state and if we navigate at all it causes all sorts of other issues. Think education/scorm environment.

We have other apps built with vue2 that don't have this issue but I suppose the problem could be connected with Vite. What I do know is that if you lose connection then try to load a route, that route will forever fail to load until you refresh the page and that is a pretty terrible user experience.

@linhx
Copy link
Author

linhx commented May 6, 2022

@abrthel
Because vue2 adds link prefetching of the view's chunk to the index.html. That makes the view's chunk loaded after the page is loaded.
But Vite does not do that. The view's chunk only load when you access the route.

This is my solution:

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/test',
      component() {
        return import('./views/Test.vue').catch(() => {
          if (!navigator.onLine || xmlHttpRequestFailed) { // xmlHttpRequestFailed: must do a XMLHttpRequest, navigator.onLine is not enough
            alert('Please check your internet connection!');
          } else {
            return import('./views/Test.vue?v=' + new Date().toISOString());
          }
        });
      }
    }
  ]
});

But it works perfectly if the view does not depend on other module. for example view_A depends on module_B, this is the risk:
image

It would be better if the browser didn't cache the failed files.
Another solution is implementing an importing method likes the code above, and replace all of the import method.

@abrthel
Copy link

abrthel commented May 6, 2022

Linhx, you are absolutely right and I was thinking about this issue all wrong. I didn't think vite was using js dynamic imports in production builds and just assumed import calls were being re-written during the rollup build process.

I'll have to investigate your solution more, though I can indeed see scenarios in my own projects where view_a could rely on module_b. At least I have somewhere to start looking. Thank you!

For anyone else coming to this issue later see:

@cj0x39e
Copy link

cj0x39e commented Jun 19, 2023

I wrote a library to attempt to solve this issue, https://github.com/cj0x39e/retrying-dynamic-import

@nathnolt
Copy link

Dirty hack to solve it:
component: () => import('../views/AboutView.vue?r=' + Date.now())

By adding ?r=' + Date.now() after the resource, it makes it so the URL is never the same, and thus it will keep retrying it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants