Vue router lazy loading does not work in Vite (Error: Unknown variable dynamic import)

I've built the below code in Vue router and it works perfect in Vue-CLI.

        import store from "./../../store/index.js";
        
        function getView(view) {
          return () => import(`@/views/settings/${view}.vue`);
        }
        
        const routes = [
          {
            path: "/myProfile",
            name: "MyProfile",
            component: getView("MyProfile"),
            beforeEnter: (to, from, next) => {
              document.title = "Profile - " + store.getters.getAppName;
              if (store.getters["userStore/authenticated"]) {
                next();
              } else {
                next({ name: "Home" });
              }
            },
          }
        ]
        export default routes;

Now I am replacing Vue-CLI with Vite and it gives the below error.

TypeError: Failed to resolve module specifier '@/views/settings/MyProfile.vue'

When I remove the getView("MyProfile") function and directly use import as below, it works.

    const routes = [
          {
            path: "/myProfile",
            name: "MyProfile",
            component: () => import('@/views/settings/MyProfile.vue'),
            beforeEnter: (to, from, next) => {
              document.title = "Profile - " + store.getters.getAppName;
              if (store.getters["userStore/authenticated"]) {
                next();
              } else {
                next({ name: "Home" });
              }
            },
          }
        ]

Can someone please, explain why?

Upvotes: 2

Views: 6566

Answers (3)

After trying lots of options, I finally found this solution.

    import store from "./../../store/index.js";
    
    async function getView(view) {
      const comps = import.meta.glob("../views/**/*.vue");
      const match = comps[`../views/${view}.vue`];
      //For TS: const match: () => Promise<any> = comps[`../views/${view}.vue`];

      return (await match()).default;
    }
    
    const routes = [
      {
        path: "/myProfile",
        name: "MyProfile",
        component: () => getView("settings/MyProfile"),
        beforeEnter: (to, from, next) => {
          document.title = "Profile - " + store.getters.getAppName;
          if (store.getters["userStore/authenticated"]) {
            next();
          } else {
            next({ name: "Home" });
          }
        },
      }
    ]
    export default routes;

Hope, this will solve the problem. (This works for any route.)

Upvotes: 1

Rim
Rim

Reputation: 269

A little bit late but this should be the answer to your question, dynamic import in different bundlers will definitely have different behavior

We have Vite's case covered in the official documentation here: https://router.vuejs.org/guide/advanced/lazy-loading.html#with-vite

Hope that will help :)

Upvotes: 0

flydev
flydev

Reputation: 5674

Can someone please, explain why?

This is due to Rollup Limitations. All imports must start relative to the importing file and import should not start with a variable.

So to get the GetView() function working, you have to replace the alias (@/) with relative or absolute path ../views or /src/views :

function getView(view) {
  return () => import(`../views/settings/${view}.vue`);
}

Why it is working when you remove the getView() and you write directly the import directive ?

If you set a literal string, the alias is resolved (it end up to a relative or absolute path, respecting rollup requirement).

Upvotes: 5

Related Questions