简体   繁体   中英

Vue Async Imports with Webpack

I have a VueJS 2 application in which I'm trying to load specific components depending on different flags in a config JSON file.

My file structure is as follows:

root
  config.json
  > src
  >> client
  >>> components
  >>>> dashboard
  >>>>> MenuBarBrand.vue
  > product
  >> product01
  >>> client
  >>>> components
  >>>>> branding
  >>>>>> MenuBrand.vue
  >> product02
  >>> client
  >>>> components
  >>>>> branding
  >>>>>> MenuBrand.vue

At the moment I've tried 2 different methods:

Using the webpack import syntax in my MenuBarBrand component:

<template>
    <b-navbar-brand href="/dashboard">
        <MenuBrand />
    </b-navbar-brand>
</template>

<script>
import config from '../../../../config.json';
const MenuBrand = import(`../../../../product/${config.product}/components/branding/MenuBrand`); 

export default {
    name: 'MenuBarBrand',
    components: {
         'MenuBrand',
    },
}
</script>

which results in the following error: 错误

or the Vue Async Components local registration syntax:

<template>
    <b-navbar-brand href="/dashboard">
        <MenuBrand />
    </b-navbar-brand>
</template>

<script>
import config from '../../../../config.json';

export default {
    name: 'MenuBarBrand',
    components: {
        'MenuBrand': () => import(`../../../../product/${config.product}/components/branding/MenuBrand`)
    },
}
</script>

which results in the following error: 错误

Are there any clear errors that I'm making or are there any specific babel/webpack plugins needed to enable this functionality?

Edit: Adding my loader configuration based on a comment I received:

module: {
    rules: [
        {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: {
                loaders: {
                    scss: [
                        'vue-style-loader',
                        'css-loader',
                        'sass-loader',
                    ],
                    sass: [
                        'vue-style-loader',
                        'css-loader',
                        'sass-loader?indentedSyntax',
                    ],
                },
            },
        },
        {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/,
        },
        {
            test: /\.(png|jpg|gif|svg)$/,
            loader: 'file-loader',
            options: {
                name: '[name].[ext]?[hash]',
            },
        },
        {
            test: /\.css$/,
            loader: 'style-loader!css-loader',
        },
        {
            test: /\.(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/,
            loader: 'file-loader?name=fonts/[name].[ext]',
        },
    ],
},

I solved this through an alternate method.

In the webpack config I pull in my product flag and create a path:

const config = require('./config.json');
const fs = require('fs');
const path = require('path');

const productPath = path.resolve(__dirname, 'product', config.product);

Then I set up an alias in the webpack config using this path:

resolve: {
    alias: {
        menuBrandingPath: productPath,
    },
    extensions: ['*', '.js', '.vue', '.json'],
},

This path is then used in my Vue component to import the proper component:

<template>
    <MenuBrand />
</template>

<script>
    import MenuBrand from 'menuBrandingPath/client/components/branding/MenuBrand'; // menuBrandingPath is an alias in the webpack config

    export default {
        name: 'MenuBar',
        components: {
            MenuBrand,
        },
    }
</script>

I've intentionally left out error checking with fs and the fallback path I used to make this example easier to understand. Hopefully it helps someone! :)

You need to use the vue-loader webpack plugin to process the .vue-files in your webpack setup. That enables the () => import(...) syntax.

module: {
    rules: [
        {
            test: /\.vue$/,
            loader: 'vue-loader'
        },
        (other loaders....)
    ]
},

Or, using require instead in your original example:

<template>
    <b-navbar-brand href="/dashboard">
        <MenuBrand />
    </b-navbar-brand>
</template>

<script>
import config from '../../../../config.json';
const MenuBrand = require(`../../../../product/${config.product}/components/branding/MenuBrand`); 

export default {
    name: 'MenuBarBrand',
    components: {
         'MenuBrand',
    },
}
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM