1

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

Exlord
  • 5,009
  • 4
  • 31
  • 51

1 Answers1

1

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.

Exlord
  • 5,009
  • 4
  • 31
  • 51