From e832a3a6093f3470aa3f88cbfd47f64034d81904 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Tue, 1 Jul 2025 15:02:03 +0200 Subject: [PATCH] Fix Vite stale chunk lazy loading error. (#12984) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes a bug that happens when a user tries to load an app chunk that is not available anymore, because a new build happened between the moment the user loaded its page and the moment he's requesting a chunk. Example : - The user loads the settings profile page - He leaves his computer for a few minutes - The CI triggers a new front build - The user comes back and tries to navigate to the accounts settings page - The page he has loaded only knows the chunk of the previous build and tries to request it - Since the server that serves the front chunks has the new chunks it sends an error - The code that lazy loads the chunk throws a `TypeError: Failed to fetch dynamically imported module` The fix is to trigger a `window.location.reload()` if this error is thrown. While this is a temporary and imperfect fix it should at least provide a better UX for the user. See follow-up issue : https://github.com/twentyhq/twenty/issues/12987 After : https://github.com/user-attachments/assets/edd7eda0-cdfa-4584-92bd-2eec9f866ab3 Fixes https://github.com/twentyhq/twenty/issues/12851 --------- Co-authored-by: Félix Malfait --- .../modules/error-handler/components/AppErrorBoundary.tsx | 8 ++++++++ .../utils/checkIfItsAViteStaleChunkLazyLoadingError.ts | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 packages/twenty-front/src/modules/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError.ts diff --git a/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx b/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx index d2d95b7e6..b3c81959a 100644 --- a/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx @@ -1,5 +1,6 @@ import { AppErrorBoundaryEffect } from '@/error-handler/components/internal/AppErrorBoundaryEffect'; import { CustomError } from '@/error-handler/CustomError'; +import { checkIfItsAViteStaleChunkLazyLoadingError } from '@/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError'; import { ErrorInfo, ReactNode } from 'react'; import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; import { isDefined } from 'twenty-shared/utils'; @@ -36,6 +37,13 @@ export const AppErrorBoundary = ({ // eslint-disable-next-line no-console console.error('Failed to capture exception with Sentry:', sentryError); } + + const isViteStaleChunkLazyLoadingError = + checkIfItsAViteStaleChunkLazyLoadingError(error); + + if (isViteStaleChunkLazyLoadingError) { + window.location.reload(); + } }; const handleReset = () => { diff --git a/packages/twenty-front/src/modules/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError.ts b/packages/twenty-front/src/modules/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError.ts new file mode 100644 index 000000000..39dd2f8aa --- /dev/null +++ b/packages/twenty-front/src/modules/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError.ts @@ -0,0 +1,3 @@ +export const checkIfItsAViteStaleChunkLazyLoadingError = (error: Error) => { + return error.message.includes('Failed to fetch dynamically imported module'); +};