I am trying to add retry functionality to defineAsyncComponent so I created a helper function
const MAX_TRY = 3;
const WAIT_TIME = 1000;
async function loadAsyncComponent(componentPath: string, tryCount = 1) {
if (tryCount > MAX_TRY) return Promise.reject();
return new Promise((resolve, reject) => {
const path = componentPath.replace('.vue', '').replace('@/modules/', '');
// https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
import(`../../../modules/${path}.vue`).then(resolve).catch((error) => {
console.error('loading async component failed : ', error);
captureException(error);
wait(WAIT_TIME).then(() => {
loadAsyncComponent(componentPath, ++tryCount)
.then(resolve)
.catch(reject);
});
});
});
}
export default function customAsyncComponent<T>(componentPath: string): T {
return defineAsyncComponent({
// the loader function
loader: () => loadAsyncComponent(componentPath) as any,
// A component to use while the async component is loading
loadingComponent: Loading,
// Delay before showing the loading component. Default: 200ms.
delay: 200,
// A component to use if the load fails
errorComponent: AsyncLoadFailed,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 10000,
});
}
This works in local DEV environment but when I build and deployed to prod it broke Error: Unknown variable dynamic import: ../../../modules/room/components/room/Room.vue
It seems that these dynamic imports are not included in the final build. Found this answer https://stackoverflow.com/a/72479802/1055015
Tryied these
rollupOptions: {
external: [path.resolve(__dirname, 'src/modules/room/components/room/Room.vue')],
},
rollupOptions: {
external: ['@/modules/room/components/room/Room.vue')],
},
After vite build The dynamically imported files are not generated in the dist folder
Any ideas ?
UPDATE: I found a workaround using glob-import testing it now
Solution 2:
The first solution left me with hundred's of small files , every single vue,ts,css file loading separately (~175),
I needed to preload them for better UX but and it started making 429 errors (too many request) on my server
So I made some changes on my custom loader and manually listed the files that needed to be preloaded
const PRELOAD_LIST = [
() => import('@/modules/X.vue'),
];
async function loadAsyncComponent(componentLoader: any, tryCount = 1) {
return new Promise((resolve, reject) => {
componentLoader() // <--------------- this part mostly
.then(resolve)
.catch((error) => {
console.error('loading async component failed : ', error);
captureException(error);
if (tryCount >= MAX_TRY) reject(error);
else {
wait(WAIT_TIME).then(() => {
loadAsyncComponent(componentLoader, ++tryCount)
.then(resolve)
.catch(reject);
});
}
});
});
}
const X = customAsyncComponent(() => import('@/modules/X.vue'));
Solution 1:
For now I used this approach :
const MODULES = import.meta.glob('../../../modules/**/*.vue');
this generates a key/value object list, the keys are the file path's and the values are import statements with static path
// code produced by vite
const MODULES = {
'../../../modules/dir/foo.vue': () => import('./modules/dir/foo.vue'),
'../../../modules/dir/bar.vue': () => import('./modules/dir/bar.vue')
}
Then you can just do MODULES[myPath]() to load the file/module.
This works but it also generates extra code for the modules at I don't really need to, so I am still looking for a better solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With