Skip to content
Advertisement

Vue dynamic component loading problem with Nginx deployment

I have the following situation:

I have a component in my vue app that dynamically loads components depending on an API query. Here is my template:

<template>
  <main class="flex-1">
    <div class="py-6">
      <div class="px-4 sm:px-6 md:px-0 space-y-6">
        <LoadingComponent v-if="chosenSideBarItem === null" />
        <component v-else :is="getComponent(chosenSideBarItem.component)" />
      </div>
    </div>
  </main>
</template>

Here is my script part

const componentMap = {
  Comp1: "./components/Comp1.vue",
  Comp2: "./components/Comp2.vue",
  Comp3: "./components/Comp3.vue",
};

Object.entries(componentMap).forEach(([key, value]) => {
  asyncComponents[key] = defineAsyncComponent({
    loader: () => import(value),
    loadingComponent: LoadingComponent,
    delay: 200,
    errorComponent: ErrorComponent,
    timeout: 3000,
  })
});


function getComponent(name : string) {
  return asyncComponents[name];
}

So basically the app dynamically loads a given component depending on some string. This works perfectly fine on my dev environment, however if i try to deploy it in my docker container with nginx, i get a MIME error

Loading module from “http://localhost/assets/components/Comp1.vue” was blocked because of a disallowed MIME type (“text/html”).

Probably because that directory doesn’t exist. Here is my nginx.conf

worker_processes 4;

events { worker_connections 1024; }

http {
   server {
          listen       80;
          server_name  localhost;

          location / {
              root   /usr/share/nginx/html;
              index  index.html index.htm;
              include  /etc/nginx/mime.types;
              try_files $uri $uri/ /index.html;
          }
    }
}

Thanks in advance!

Answer

It is not clear whether you are using Vite or Webpack (Vue CLI) but both have a very similar limitations when using dynamic imports (import(...))

Here is a documentation for @rollup/plugin-dynamic-import-vars used by Vite

Most important limitation is based on the fact that import() must be processed by a bundler at compile time. So the bundler must be able to statically at compile time be able to analyze the argument and deduce what are the possible imports. Using variable is of course out of the question…

So one way to fix it is this:

const componentLoaders = {
  Comp1: () => import("./components/Comp1.vue"),
  Comp2: () => import("./components/Comp2.vue"),
  Comp3: () => import("./components/Comp3.vue"),
};

Object.entries(componentLoaders).forEach(([key, loader]) => {
  asyncComponents[key] = defineAsyncComponent({
    loader,
    loadingComponent: LoadingComponent,
    delay: 200,
    errorComponent: ErrorComponent,
    timeout: 3000,
  })
});


function getComponent(name : string) {
  return asyncComponents[name];
}

…or without using the map:

function getAsyncComponent(name : string) {
  return defineAsyncComponent({
    loader: () => import(`./components/${name}.vue`) ,
    loadingComponent: LoadingComponent,
    delay: 200,
    errorComponent: ErrorComponent,
    timeout: 3000,
  })
}


Advertisement