0

I have several menu types and want to configure the type of menu to be used in .env.local for example: VUE_APP_MENU_TYPE=2

In my javascript file I have the following:

let menu = false;
if (process.env.VUE_APP_MENU_TYPE === "2") {
  menu = require("./type2/Type2.vue");
}
if (menu === false) {//default menu if env is missing
  menu = require("./default/Default.vue");
}
export default menu;

This will result in an error Failed to mount component: template or render function not defined.

I can do the following:

import Default from "./default/Default.vue";
import Type2 from "./type2/Type2.vue";
let menu = Default;
if (process.env.VUE_APP_MENU_TYPE === "2") {
  menu = Type2;
}
export default menu;

This will work but all menus are compiled in the code, including menus that will never be used since VUE_APP_MENU_TYPE is known at compile time and will never change until you recompile.

Is it possible to import a component dynamically at compile time?

HMR
  • 37,593
  • 24
  • 91
  • 160

3 Answers3

2

Try menu = require("./type2/Type2.vue").default;

Explanation taken from this answer

when dealing with ES6 imports (export default MyComponent), the exported module is of the format {"default" : MyComponent}. The import statement correctly handles this assignment for you, however, you have to do the require("./mycomponent").default conversion yourself. If you want to avoid that, use module.exports instead of export default

Fort second part of question...

Is it possible to import a component dynamically at compile time?

Really never tried but I have my doubts. Webpack is not executing the code when building. It just scans it for some patterns.

  1. It scans for require() so it know what modules should be included in the bundle
  2. DefinePlugin is replacing strings like process.env.VUE_APP_MENU_TYPE with values from env files so it make code look like if ("3" === "2") {
  3. Other plugins are able to detect that if ("3" === "2") { is never true and eliminate "the death code"

Real question if what happens first - if require scanning happens before death code elimination, you will end up with all possible menu components in the bundle. But unfortunately I don't know - You'l have to try

On the other hand using dynamic async components (as mentioned in other answers) is sure bet. Yes, Webpack will build all possible menu components but each with it's own js chunk (js file in dist folder). If the app loads just one of them, it's seems fine to me (note that the loading will be async - at runtime - so it means one more server request)

tony19
  • 125,647
  • 18
  • 229
  • 307
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • I like the `require` way of doing this better than the alias webpack config so I'll go with that. Thank you for your answer. – HMR Jan 13 '21 at 12:45
1

I think that loading the component dynamically is the best option you have. https://v2.vuejs.org/v2/guide/components-dynamic-async.html

tony19
  • 125,647
  • 18
  • 229
  • 307
Cosimo Chellini
  • 1,560
  • 1
  • 14
  • 20
  • Thank you for your reply. I think using those methods will have the components be part of the build. Say I have 20 different types of menus then all 20 are part of the build but I only need 1 and that's the one I already know about when I build. I'm looking for a way so the other 19 won't be part of the build. – HMR Jan 13 '21 at 12:04
  • I already load the component dynamically but I don't know how to build it dynamically. The way I got it working needs all components to be part of the build, even the ones that I'll never use for that build – HMR Jan 13 '21 at 12:16
  • 1
    Dynamic async components are not made part of the bundle. Yes they are compiled but each into its own separate JS chunk. So the files will be there in `dist` folder but if app never loads em who cares ? – Michal Levý Jan 13 '21 at 12:39
  • 1
    @HMR the dynamic imports are packed into separate .chunk files, so the client won't load what's not needed. – Džuris Jan 13 '21 at 12:44
  • @MichalLevý Thank you, so async would be another option to do this. It'll build the needless code but never loads it. – HMR Jan 13 '21 at 12:47
0

I could have solved this with a webpack setting.

In vue.config.js

const path = require("path");

module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        MENU: path.resolve(
          __dirname,
          (() => {
            if (process.env.VUE_APP_MENU_TYPE === "2") {
              return "src/components/header/CategoriesMenu/Type2/Type2.vue";
            }
            return "src/components/header/CategoriesMenu/Default/Default.vue";
          })()
        ),
      },
    },
  },
};

In src/components/header/CategoriesMenu/index.js

import menu from "MENU";
export default menu;

But to be honest, I like the require better.

HMR
  • 37,593
  • 24
  • 91
  • 160