diff --git a/changes/changelog.d/resolve-axios-race-condition.bugfix b/changes/changelog.d/resolve-axios-race-condition.bugfix new file mode 100644 index 000000000..11d7b7e46 --- /dev/null +++ b/changes/changelog.d/resolve-axios-race-condition.bugfix @@ -0,0 +1,2 @@ +Resolve race condition regarding axios when initializing the frontend +Prevent sending same language setting to backend multiple times diff --git a/front/src/main.ts b/front/src/main.ts index d7ffdbb7d..b9bb82224 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -1,4 +1,4 @@ -import type { InitModule } from '~/types' +import type { InitModule, InitModuleContext } from '~/types' import store, { key } from '~/store' import router from '~/router' @@ -22,6 +22,7 @@ const app = createApp({ data: () => ({ ready: false }), mounted () { this.ready = true + logger.info('Everything loaded!') }, render () { if (this.ready) { @@ -35,19 +36,35 @@ const app = createApp({ app.use(router) app.use(store, key) -const modules: Array> = [] -for (const module of Object.values(import.meta.glob('./init/*.ts', { eager: true })) as { install?: InitModule }[]) { - modules.push(module.install?.({ - app, - router, - store - })) +const modules: Record = import.meta.glob('./init/*.ts', { eager: true }) +const moduleContext: InitModuleContext = { + app, + router, + store } -// Wait for all modules to load -Promise.all(modules).finally(() => { - app.mount('#app') - logger.info('Everything loaded!') -}) +// NOTE: Other modules may depend on network requests and we need to ensure +// that all axios interceptors are set before any requests are made +// and that the instance url is set before any requests are made +const IMPORTANT_MODULES_QUEUE = ['axios', 'instance'] +const waitForImportantModules = async () => { + for (const moduleName of IMPORTANT_MODULES_QUEUE) { + const path = `./init/${moduleName}.ts` + if (!(path in modules)) { + logger.error(`Failed to load important module: ${path}`) + continue + } + + await modules[path].install?.(moduleContext) + delete modules[path] + } +} + +waitForImportantModules() + // NOTE: We load the modules in parallel + .then(() => Promise.all(Object.values(modules).map(module => module.install?.(moduleContext)))) + .catch(error => logger.error('Failed to load modules:', error)) + // NOTE: We need to mount the app after all modules are loaded + .finally(() => app.mount('#app')) // TODO (wvffle): Rename filters from useSharedLabels to filters from backend