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!
Advertisement
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, }) }