vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.06k stars 6.02k forks source link

TypeError: Failed to fetch dynamically imported module #11804

Open IPWright83 opened 1 year ago

IPWright83 commented 1 year ago

Describe the bug

Since switching to Vite we noticed a new production issue, where sometimes users are encountering an error if we deploy while they have an active session:

TypeError: Failed to fetch dynamically imported module

I believe this is because if any code is modified in an area that Vite would turn into a dynamic module, then the file hash changes, however when they try to visit an area that would trigger the dynamic load, those files no longer exist so they hit the error message above.

Quoting from https://stackoverflow.com/a/74057337/21061

When you dynamically import a route/component, during build it creates a separate chunk. By default, chunk filenames are hashed according to their content – Overview.abc123.js. If you don't change the component code, the hash remains the same. If the component code changes, the hash changes too - Overview.32ab1c.js. This is great for caching.

Now this is what happens when you get this error:

  • You deploy the application
  • Your Home chunk has a link to /overview route, which would load Overview.abc123.js
  • Client visits your site
  • You make changes in your code, not necessarily to the Overview component itself, but maybe to some children components that Overview imports.
  • You deploy changes, and Overview is built with a different hash now - Overview.32ab1c.js
  • Client clicks on /overview link - gets the Failed to fetch dynamically imported module error, because Overview.abc123.js no longer exists

That is why the errors correlate with deployments. One way to fix it is to not use lazy loaded routes, but that's not a great solution when you have many heavy routes - it will make your main bundle large

What I expect to happen, is not to encounter any errors if the users session remains active during a deployment.

I have been unable to come up with a good workaround (specifically for me using React ErrorBoundary is the best I can do so far with a re-direct similar to https://stackoverflow.com/a/74861436/21061 which is a mitigation and provides quite a poor user experience flashing an error message).

Reproduction

https://github.com/IPWright83/vite-dynamic-import

Steps to reproduce

The above repository has been set up to mimick a production deployment as obviously that is a much more complicated set-up. It leverages React.lazy to force a dynamic module and uses a setTimeout to provide a delay with which to simulate a user navigation to a page requiring a module. In a real production scenario I don't believe React.lazy is required.

Wait... 30s after loading the page you should see a blank page render with errors in the browser console:

image

If you were to reload the page, you can see that Foo-b53985a6.js has been renamed to Foo-535d5a10.js (or similar new hash)

System Info

❯ npx envinfo --system --npmPackages '{vite,@vitejs/*}' --binaries --browsers

  System:
    OS: Linux 5.15 Ubuntu 20.04.5 LTS (Focal Fossa)
    CPU: (12) x64 Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
    Memory: 18.36 GB / 31.10 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 16.14.0 - ~/.nvm/versions/node/v16.14.0/bin/node
    Yarn: 1.22.18 - ~/.nvm/versions/node/v16.14.0/bin/yarn
    npm: 8.3.1 - ~/.nvm/versions/node/v16.14.0/bin/npm
  Browsers:
    Chrome: 109.0.5414.74
    Chromium: 109.0.5414.74
    Firefox: 109.0


### Used Package Manager

pnpm

### Logs

_No response_

### Validations

- [X] Follow our [Code of Conduct](https://github.com/vitejs/vite/blob/main/CODE_OF_CONDUCT.md)
- [X] Read the [Contributing Guidelines](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md).
- [X] Read the [docs](https://vitejs.dev/guide).
- [X] Check that there isn't [already an issue](https://github.com/vitejs/vite/issues) that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to [vuejs/core](https://github.com/vuejs/core) instead.
- [X] Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/vitejs/vite/discussions) or join our [Discord Chat Server](https://chat.vitejs.dev/).
- [X] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
y-nk commented 1 year ago

I've been running into this cryptic error message as well and did not find any solution BUT opening my page with Safari revealed more infos about the root cause (i had a require and a module hidden in my codebase causing the dynamic module errors at compile time). it's not clear why this error shows in Chrome and another shows in Safari, but this unblocked me.

hoping this'll help.

Bryanoxx commented 1 year ago

Hello, Vercel just introduced "Skew protection" and it aims to resolve this exact problem, they're using a "deployment id" to link the front and the back of a same deployment, for now it seems to be only available for Next.js but I hope it will be implemented to vite-related project soon !

The blog post here : https://vercel.com/blog/version-skew-protection

doutatsu commented 1 year ago

I don't think it's the same problem as their feature. This is completely a client only issue - where the chunk has changed and the client still trying to fetch the old one, using a now expired URL. It has nothing to do with backend changes

jamesj2 commented 1 year ago

So this problem is really slowing me down by forcing me to reload the web page too often. I started thinking it has something to do with tailwind. Having PHP pages rendering with an additional class after page submitting a form would trigger it. Hitting reload would clear the error until the class list changed again. But I’m also having issues with Datatables.net. So I started Vite with the debug option. I noticed pdfmake.js, version 0.2.7, takes a long time to load. After disabling that specific import, the import failures went away and my pages loads faster. Also I’m able to the use the minified version of pdfmake without the import error, but it does slow down the page load some. And I don’t know why pdfmake hits the cache then gets transformed. This doesn't seem to happen with the minified version of pdfmake.

 vite:resolve 0.58ms pdfmake -> /project/node_modules/pdfmake/build/pdfmake.js +1ms
…snip
  vite:resolve 1.65ms pdfmake -> /project/node_modules/.vite/deps/pdfmake.js?v=77b18612 +2ms
…snip
vite:import-analysis /node_modules/.vite/deps/pdfmake.js?v=77b18612 needs interop +6ms
…snip
vite:optimize-deps load /project/.vite/deps/pdfmake.js +6ms
…snip
  vite:load 87.75ms [plugin] /node_modules/.vite/deps/pdfmake.js?v=77b18612 +6ms
  vite:cache [memory] /node_modules/.vite/deps/chunk-TFWDKVI3.js?v=81ea351f +414ms
  vite:import-analysis 18.41ms [1 imports rewritten] node_modules/.vite/deps/pdfmake.js?v=77b18612 +414ms
  vite:transform 408.89ms /node_modules/.vite/deps/pdfmake.js?v=77b18612 +414ms
…snip
  vite:cache [memory] /node_modules/.vite/deps/pdfmake.js?v=77b18612 +0ms
  vite:time 59.64ms /node_modules/.vite/deps/pdfmake.js?v=77b18612 +60ms
Bryanoxx commented 1 year ago

@doutatsu By backend I meant server, by definition if there is a "fetch error" (like here) it means it's trying to fetch a ressource on a server, but the server doesn't have the ressource because of a new deployment between the start of the session of the user and the fetch request he's trying to make. It can be resolved by keeping the ressources of the previous deployment, like the Vercel feature I talked about, that's what I understand from all of this!

luca-aurelia commented 1 year ago

Another data point for folks trying to figure this out.

In an effort to fix this error, we recently updated our deployment system so that it keeps copies of the JS and CSS files for every deployment. That helped a lot -- we went from 500+ times per day to about 50 times per day. But it's still happening, and we've confirmed that it happens even for files that definitely exist.

(For folks considering a similar approach, we started uploading all of our assets to an S3 bucket. Then we put Bunny CDN in front of the bucket and load the assets from there.)

Our best guess currently is that sometimes loading the assets times out?

mattmbt commented 1 year ago

This happens usually after deployment when your app has code splitting, and I think its expected behaviour. You can mimic it by by just shutting down npm run dev, and then interacting with your app that lazy loads a new component.

This is similar to Webpack's ChunkLoadError when your app is using chunk versions which in reality are not from the same deployment or it just cant fetch a chunk from the server because its already been busted.

Vite hashes each js/css bundle on production by default as a cache busting strategy. But the catch is that the browser might be using a cached version of the index.html file which refers to older js/css assets.

Adding<meta http-equiv="Cache-Control" content="no-cache" /> to your index.html will ensure that the user's browser will not use the cached html unless its validated from the server response that its okay to use when they load the page the next time.

But it wont solve users who just actively have their page open during and after a deployment (they'll still be using the index.html that refers to older js/css assets) so we've opted to just catch this error via ErrorBoundary and present them a page prompt to refresh the page so they can have the latest index.html that refers to latest js/css assets.

doutatsu commented 1 year ago

@patak-dev considering #12084 is now in main with the release of 4.4, should this be marked as resolved, considering it provides the ability to catch this error and handle it? I presume Vite won't be adding any kind of automatic resolution like Nuxt has anyways?

jamesj2 commented 1 year ago

There could be multiple types of issues here. I haven't push anything Vite into production yet. I'm still refactoring from web pack in development. Ever since I removed pdfmake.js from my imports it has been working fine for me. The error is generic and doesn't really explain what fails to import. Hopefully #12084 will provide more information.

SGDS666 commented 1 year ago

I also encountered this issue during the migration process, but I found that this issue masked the possibility of bugs in the component itself. If the page being migrated is imported using lazy, internal component bugs will not be thrown. Only the error prompt that cannot be dynamically imported may be the reason why this issue is so common I would suggest that when migrating pages, you first confirm that there are no issues with static import before switching to dynamic import. This may be helpful

vettloffah commented 1 year ago

For us, the issue was that we have the deployment hosted on vercel, and the proxy option turned on in our Cloudflare DNS, and Cloudflare wasn't aware when there was a new deployment. This was causing intermittent issues that resulted in errors described in this post.

This was really hard to narrow down, but once we turned off the proxy option in Cloudflare the issues immediately cleared up.

This Cloudflare issue is actually described right in the vercel docs here: https://vercel.com/guides/using-cloudflare-with-vercel

mxismean commented 1 year ago

the same issue

ThePiyushAggarwal commented 1 year ago

I am having this issue only when redeployments happen. So, I am going with refreshing page in error boundary if the failed to fetch dynamically imported module error occurs. I am only using the dynamic imports on page change so doesn't seem like the user will have issues like the page gets refreshed when the user has filled out some form. I had the same problem while using CRA. At the time, I was refreshing when error contains chunk

Yelinz commented 1 year ago

Ran into this locally with sveltekit 1.22 and it was caused by ad-blocker (ublock origin) as suggested above.

Merzaad commented 1 year ago

When caching chunks on the client side, whether through service workers or other methods, users who haven't downloaded a chunk from a previous build experience TypeError: Failed to fetch dynamically imported module when they request for that chunk and the chunk has changes and its hashed name has changed as well. One possible solution is to have the same name for chunks in every build.

    rollupOptions: {
        output: {
          chunkFileNames: 'assets/abc.js',
        }
    }
     // abc.js, abc2.js, abc3.js, ...

But this can cause problems if there are dependencies between the chunks and the user downloads the new chunk when using previous build. As far as I understand, there will always be some potential problems with new build deployments if files are cached.

mreduar commented 1 year ago

This error is annoying and every time you receive notifications about it in flare.

tang-yue commented 1 year ago
let flag = false
router.onError((error, to) => {
  if (error.message.includes('Failed to fetch dynamically imported module')) {
    if (!flag) {
      flag = true
      window.location.href = window.location.origin + '/mallManage/#' + to.fullPath as any
      window.location.reload()
      flag = false
    }
  }
})

The above code solves this problem.

Using window.location = to.fullPath, sometimes the address changes, but the page content is not updated, occasionally it doesn't work, and errors keep occurring

but, Is there a way to write without refreshing the page?

@patak-dev Do you have time to look at this problem? Relatively urgent Or you can ask someone else in the group to take a look

tang-yue commented 1 year ago

I wrote a library to attempt to solve this issue, https://github.com/cj0x39e/retrying-dynamic-import (if the file does not exist on the server, you must refresh the page)

When I look at your library, I feel that there is no way to solve this problem, your working principle is to request a.js failed, request a.js? t=xx is similar, but in this case, even if you ask a.js? ts=xx also fails

jamesj2 commented 1 year ago

@tang-yue Is your issue only in production? If so, you may want to keep the older builds available for your users. I have yet to move Vite into production but keeping the older builds around for webpack helped me. When the older builds are available page reload won't be required. If the problem also happens in dev then it might be a module issue. Since I removed pdfmake.js from my imports my dev side has been working properly. I think it was taking too long to process it.

doutatsu commented 1 year ago

I think the majority of people here have the issue in production. I am still working on the nuxt.js-like fix to reload the page when new Vite error shows up, but considering it's a cache issue, you have to reload the page

P.S. I do hope Vite does provide a more config-free way of handling this. The new event emit is helpful, but I wish Vite would handle this automatically, considering how many people suffer from this error

mreduar commented 1 year ago

P.S. I do hope Vite does provide a more config-free way of handling this. The new event emit is helpful, but I wish Vite would handle this automatically, considering how many people suffer from this error

I agree

yakobe commented 1 year ago

Or if it is not possible for whatever reasons, it would be great to have some examples/recipes in the docs to solve it for various frameworks etc

lmiller1990 commented 1 year ago

This is a huge problem for us using Vite are a dev server in Cypress, many CI runs are lost due to it. I am unsure why it's so prevalent on CI machines, but it is.

I spent many days digging into this, I have no idea how / why it happens and cannot consistently reproduce it. I often get "optimizing dependencies" for things I've registered to be pre-optimized. I could be doing it wrong?

I think this is not really solvable without some kind of definitive cause / reproduction.

tang-yue commented 1 year ago

@tang-yue Is your issue only in production? If so, you may want to keep the older builds available for your users. I have yet to move Vite into production but keeping the older builds around for webpack helped me. When the older builds are available page reload won't be required. If the problem also happens in dev then it might be a module issue. Since I removed pdfmake.js from my imports my dev side has been working properly. I think it was taking too long to process it.

@jamesj2 Yes, there is a problem in the production environment

ps-20x commented 1 year ago

Stupid question but has anyone tried to adapt the caching headers on the webserver? For example like said in that article: https://medium.com/@pratheekhegde/setting-caching-headers-for-a-spa-in-nginx-eb2f75f52441

So the index file will never be cached and always requested new?

tang-yue commented 1 year ago

@patak-dev Do you have time to look at this problem? Relatively urgent Or you can ask someone else in the group to take a look

titenis commented 1 year ago

Stupid question but has anyone tried to adapt the caching headers on the webserver? For example like said in that article: https://medium.com/@pratheekhegde/setting-caching-headers-for-a-spa-in-nginx-eb2f75f52441

So the index file will never be cached and always requested new?

This wont work for users that have already fetched old index.html and have fetched some modules and in the mean time deployment occurs. I had caching headers configured, but that did not fully resolved this issue. You should understand that index.html refetching happens only on new page load or page refreshing, if user keeps window open for long enough for a deployment to occur - he will face this issue

doutatsu commented 1 year ago

@patak-dev considering #12084 is now in main with the release of 4.4, should this be marked as resolved, considering it provides the ability to catch this error and handle it? I presume Vite won't be adding any kind of automatic resolution like Nuxt has anyways?

So after implementing work done in https://github.com/vitejs/vite/pull/12084 - I've hit this error personally again, confirming using vite preload hook does not work as a solution to this problem... @patak-dev could vite team take a look at this thread again, as to me it still feels like a high priority issue to investigate, as lots of people are struggling with this problem

jauyeunggithub commented 1 year ago

I can reproduce this when the service worker generated with Vite PWA is on. Once I have selfDestroying set to true then this error goes away.

But then we wouldn't if the latest version of the app is downloaded with either setting added to the Vite PWA options.

trisys3 commented 1 year ago

I'm experiencing the case where the outer bundle finishes building before the inner bundle, NOT the case where the old bundle is deleted before the user's cache is updated.

Wouldn't it make sense for vite to wait until the inner bundle is output before it outputs the outer bundle? Or even wait to start building the outer bundle until the inner bundle is completely built and output to disk? I don't know much about the vite internals, so I could very well be missing something blatantly obvious.

For example, if I have outer.js and inner.js (WARNING: Super contrived example incoming!):

outer.js

const inner = import('./inner');

...

inner.js

console.log('inner.js');

and I change inner.js to:

inner.js

console.log('inner');

Let's say the bundle with outer.js is called "outer-before.js" before the change, and "outer-after.js" after the change. And, equivalently, let's call the inner.js bundle "inner-before.js" before the rebuild, and "inner-after.js" after the rebuild.

Could vite perhaps wait to output outer-after.js to disk until after inner-after.js is output to disk? Alternatively, if outer.js is the true outer JavaScript file, and is referenced directly in the index.html, could vite wait to swap the path in the <script> tag in the built index.html until both inner-after.js and outer-after.js are finished building and output to disk?

Basically, could the I/O stage of the build process always start from the inside and proceed outward?

warmthsea commented 12 months ago

vite version > 4.0.4 window 7 / some win10 show this problem,I didn't find a solution other than lowering the vite version

916390667eac7e13edcfa8b38799cad7_

isaiahscheel commented 11 months ago

I am running into this with a Sveltekit app in an Azure app service. Everytime we deploy to prod we are getting reports of a "blank page" and we are seeing it in QA as well when we deploy. When we get the new code, we get 404s for some immutable files and about nothing displays other than some dev information coming from the outer +layout.svelte file. Anyone know of a way to fix in sveltekit using vite?

shivghai commented 11 months ago

+1, seeing this in production, switched back to Webpack for now. Seems like this should be prioritized because it may be affecting real production use cases instead of just quickly hacked projects. What do I know.....

doutatsu commented 11 months ago

Hopefully, someone from Vite team will look at this issue again, considering this is 4th most commented issue and one that's been open for awhile. Not to mention the severity of its effects in production....

image
dangenendt commented 11 months ago

~~Exaclty same problem here. React + Vite App with static bundled files within a caddy image deployed to k8s... Random users reporting blank page errors ('failed to fetch dynamically imported module...') after deployments because the browser returns an old index.html including an unexisting import~~

image ~~Here you can see some funny things... the requested index.html (including a current timestamp with "&tstamp=xyz") gets requested and returns a non-cached response with an imported bundle which does not exist. Im not getting it 🥴~~

In this explicit case i've mixed up the console error... just ignore it. If there will be some new insights, i'll let you know Although the discussed topic is not the issue in my case, i also had the same case as other users. I will share infos when i can reproduce again

isaiahscheel commented 11 months ago

Exaclty same problem here. React + Vite App with static bundled files within a caddy image deployed to k8s... Random users reporting blank page errors ('failed to fetch dynamically imported module...') after deployments because the browser returns an old index.html including an unexisting import

image Here you can see some funny things... the requested index.html (including a current timestamp with "&tstamp=xyz") gets requested and returns a non-cached response with an imported bundle which does not exist. Im not getting it 🥴

I am seeing something suuuuper similar for a sveltekit + Vite app.

image

Basically what I am seeing is that app.b1450e6.js is the old hash and when I am sitting there refreshing, I am getting it back just fine.

However, as soon as I get the new app I am requesting app.b71b41c6.js which is 404ing. BUT, it seems like app.b1450e6.js (the old one) is ALSO getting requested. This is succeeding, but the app is not going to use it because it is the newer app that needs the new hashed app.

I am a bit confused on why the old file is also getting requested but from the screenshot, it seems like the old version is still around and the new one is not, but the requested html isn't going to use the new one because that is not what its asking for like here:

image

**Interesting point I want to make clear. In the original issue, it is hypothesized that a new version of the app is deployed but user's are requesting old versions that are no longer there. From my experience and debugging it is actually the reverse. As you can see in the screenshot above, it is the NEW file that is not quite there yet and the old file still succeeds. However, the html that is from the new app is not wanting those old files so it just blanks.

EskelCz commented 11 months ago

I think the whole issue could be solved by better error handling. I just need a way to show the user a message, something like "Your application is out of date, please refresh the page" and not throw an unhandled error for Sentry to send.

But frankly I don't even know where to handle it in the tech stack. :-/ Should it be handled by Vite, Svelte, Routify, Vercel, or my code?

hasan-mehboob commented 11 months ago

This worked in my case. Vite version: 4.4.9 build: { rollupOptions: { output: { entryFileNames: "[name].js", chunkFileNames: "[name].js", }, }, } ,

https://rollupjs.org/configuration-options/#output-chunkfilenames

mreduar commented 11 months ago

This worked in my case. Vite version: 4.4.9 build: { rollupOptions: { output: { entryFileNames: "[name].js", chunkFileNames: "[name].js", }, }, } ,

https://rollupjs.org/configuration-options/#output-chunkfilenames

you mean you solved this problem with that?

IPWright83 commented 11 months ago

This worked in my case. Vite version: 4.4.9 build: { rollupOptions: { output: { entryFileNames: "[name].js", chunkFileNames: "[name].js", }, }, } , https://rollupjs.org/configuration-options/#output-chunkfilenames

you mean you solved this problem with that?

I think it'll likely solve the dynamic module loading issue - at the risk of hitting JavaScript issues as there's no way to force the cache to clear. So the end user could be running stale modules with new modules... which is fine if no interfaces have changed. But otherwise could cause runtime errors.

elektronik2k5 commented 11 months ago

I think it'll likely solve the dynamic module loading issue - at the risk of hitting JavaScript issues as there's no way to force the cache to clear. So the end user could be running stale modules with new modules... which is fine if no interfaces have changed. But otherwise could cause runtime errors.

Exactly. At the very least it is as much of a "fix" as a painkiller at a death squad. And at worst, it'll break the app completely in unpredictable ways.

The only necessary "fix" is to avoid the problem entirely by following best practices we've established over 20 years ago:

  1. fingerprint all asset names (the opposite of removing the hashes from the file names). That's what Vite does by default and with good reason.
  2. never delete old assets - they must remain available forever (or to be precise, as long as the TTL of your cache headers). This is the problem source.

That's it - there's nothing more to it. It is a solved problem and a non issue if you just follow these two rules.

I think the entire thread exists due to how many deployments nowadays became container based instead of just using a CDN (or any kind of static file hosting) for the built app files. But container based deployments lose the temporality aspect of already deployed apps and their users. Thus, a deployment workflow which doesn't preserve the previously deployed assets is fundamentally broken. Moreover, it isn't something that Vite will ever be able to fix because it doesn't deploy or serve your built code.

Serving static files from a container is not only 100% wasteful, but is actively harmful because it creates problems such as this one. Containers are great for building apps and running server side code. NOT for static assets.

If your setup is container based and you can't switch to a CDN then the workaround is to copy all the old assets from all previous deployments (as part of the deployment) to the new container, so they're still available alongside the newly built files. Your container size will grow with each deployment, but that's a small price to pay for preventing the app from breaking.

victorlmneves commented 11 months ago

This worked in my case. Vite version: 4.4.9 build: { rollupOptions: { output: { entryFileNames: "[name].js", chunkFileNames: "[name].js", }, }, } ,

https://rollupjs.org/configuration-options/#output-chunkfilenames

This doesn't solve all related errors as there different reasons. In my case, the majority of the errors are caused by existing files and it's not related to deploys where it will generate a "new" file name. My app uses a lot of components that are imported dynamically.

So, what I did was to extend the initial implementation of the dynamic import by adding a "retry" functionality that after 3 tries will serve an "error" component with a basic message so the user is able to understand that something went wrong and it contains a button to trigger a reload of the page

import { defineAsyncComponent } from "vue";
import LoadingComponent from "/@/components/LoadingComponent/LoadingComponent.vue";
import BaseLoadingError from '/@/components/BaseLoadingError/BaseLoadingError.vue';

export const useComponent = (name: string) => {
    if (!name || name === 'UnknownComponent') return;

    return defineAsyncComponent({
        loader: () => import(`../components/${name}/${name}.vue`),
        loadingComponent: LoadingComponent,
        errorComponent: BaseLoadingError,
        delay: 500, // default: 200
        timeout: 3000, // default: Infinity
        onError(error, retry, fail, attempts) {
            console.warn('🚀 ~ useComponent onError:', error);
            if (error.message.match(/fetch/) && attempts <= 3) {
                retry();
            } else {
                fail();
            }
        },
    });
};
IPWright83 commented 11 months ago

I think it'll likely solve the dynamic module loading issue - at the risk of hitting JavaScript issues as there's no way to force the cache to clear. So the end user could be running stale modules with new modules... which is fine if no interfaces have changed. But otherwise could cause runtime errors.

Exactly. At the very least it is as much of a "fix" as a painkiller at a death squad. And at worst, it'll break the app completely in unpredictable ways.

The only necessary "fix" is to avoid the problem entirely by following best practices we've established over 20 years ago:

  1. fingerprint all asset names (the opposite of removing the hashes from the file names). That's what Vite does by default and with good reason.
  2. never delete old assets - they must remain available forever (or to be precise, as long as the TTL of your caching headers). This is the problem source.

That's it. There's nothing more to it. It is a solved problem and a non issue if you just follow these two rules.

I think the entire thread exists due to how many deployments nowadays became container based instead of just using a CDN (or any kind of static file hosting) for the built app files. Serving static files from a container is not only 100% wasteful, but is actively harmful because it creates problems such as this one. Containers are great for building apps and hosting server side code. NOT for static assets.

I think there's more to it, as we leave the default hashing on within Vite, and don't remove old assets (we've an S3 bucket with a lot of content) but still hit this issue.

vicodinvic1 commented 10 months ago

same issue, vite version is 4.4.8

I do not update it to the latest one (which is 4.4.9 currently) because 4.4.9 has broken build chunk strategy: React.lazy() loaded modules don't split into separate chunks

Killa4 commented 10 months ago

Same issue as well

salvisb commented 10 months ago

I'm using Ionic + Vue + Vite and experiencing similar issue - every build is triggering the below error. In this particular example - md.transition-97346d73.js - which is the previous, non-existing asset hash. After a page refresh error goes away.

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec. index-b2c141bc.js:189 TypeError: Failed to fetch dynamically imported module: ../assets/md.transition-97346d73.js

doutatsu commented 10 months ago

For anyone looking, I decided to go ahead with @victorlmneves approach, which has proven to work well - while the error is still raised, it doesn't break the UI, as the page is automatically refreshed and then redirected to the page the user was trying to navigate. This appears to be the best solution to the issue at this moment:

// Hard-reload the page when chunk load errors match the navigation error
const routerInstance = router();
routerInstance.onError((error, to) => {
  const errors = ['Failed to fetch dynamically imported module', 'Unable to preload CSS'];

  if (errors.some((e) => error.message.includes(e))) {
    window.location = to.fullPath;
  }
});
ayodejikeza commented 10 months ago

This should be looked into by the vite team.... I'm having sane issue on production and I'm yet to find a solution

andredifs commented 10 months ago

I also faced a same issue on production. I implemented the @doutatsu approach and works well.

safdar-azeem commented 10 months ago

Hey everyone,

If you're experiencing the "Failed to fetch dynamically imported module" error in Vite, I encountered the same issue and found a solution that worked for me.

I used the @originjs/vite-plugin-commonjs to resolve that issue. Here's how you can set it up in your vite.config.js:

import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'

export default {
  plugins: [
    viteCommonjs(),
  ],
  optimizeDeps: {
    esbuildOptions: {
      plugins: [
        esbuildCommonjs(['packageNameYouWantToResolve'])
      ],
    },
  },
};

Replace packageNameYouWantToResolve with the actual package name you want to resolve.

I hope this solution helps you as well.