Open IPWright83 opened 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.
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
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
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
@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!
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?
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.
@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?
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.
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
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
the same issue
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
Ran into this locally with sveltekit 1.22 and it was caused by ad-blocker (ublock origin) as suggested above.
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.
This error is annoying and every time you receive notifications about it in flare.
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
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
@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.
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
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
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
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 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
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?
@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
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
@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
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.
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?
vite version > 4.0.4 window 7 / some win10 show this problem,I didn't find a solution other than lowering the vite version
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?
+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.....
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....
~~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~~
~~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
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
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.
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:
**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.
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?
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 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?
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-chunkfilenamesyou 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.
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:
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.
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();
}
},
});
};
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:
- 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.
- 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.
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
Same issue as well
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
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;
}
});
This should be looked into by the vite team.... I'm having sane issue on production and I'm yet to find a solution
I also faced a same issue on production. I implemented the @doutatsu approach and works well.
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.
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:
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
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 asetTimeout
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 believeReact.lazy
is required.Clone the above repository
npm install
npm run build
open a 2nd terminal
Terminal 1 npx serve dist (starts a web server)
Browser open the URL (usually localhost:3000)
Text Editor modify src/Foo.jsx changing the string "Foo" to something else (within 30s of launching the page - increase the setTimeout in App.jsx if this is not long enough)
Terminal 2 npm run build
Wait... 30s after loading the page you should see a blank page render with errors in the browser console:
If you were to reload the page, you can see that
Foo-b53985a6.js
has been renamed toFoo-535d5a10.js
(or similar new hash)System Info