Reputation: 1057
I am trying to achieve Vue.js dynamic async component
registration. This video gave me code that works perfectly fine, but it loads all modules even if they are not used.
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
// Require in a base component context
const requireComponent = require.context(
'../components/base', false, /base-[\w-]+\.vue$/,
)
requireComponent.keys().forEach(fileName => {
// Get component config
const componentConfig = requireComponent(fileName)
// Get PascalCase name of component
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//,
'').replace(/\.\w+$/,
'')),
)
// Register component globally
Vue.component(componentName, componentConfig.default || componentConfig)
})
What I tried to achieve was to create async components instead. Like so
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
// Require in a base component context
const requireComponent = require.context(
'../components/base', false, /base-[\w-]+\.vue$/,
)
requireComponent.keys().forEach(fileName => {
const componentPath = fileName.replace('./', '../components/base/');
// Get PascalCase name of component
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//,
'').replace(/\.\w+$/,
'')),
)
// Register component globally
Vue.component(componentName, () => import(componentPath))
})
If the case of the code above vue throws an error
vue.esm.js:591 [Vue warn]: Failed to resolve async component: function () {
return __webpack_require__("./lib lazy recursive")(componentPath);
}
Reason: Error: Cannot find module '../components/base/base-button.vue'
If I manually write down Vue.component('BaseButton', () => import('../components/base/base-button.vue'))
it works without problem but when I try to do that dynamically it fails. Is it possible to do such async component
registration if so how?
This doesn't work either:
const button = '../components/base/base-button.vue'
Vue.component('BaseButton', () => import(button))
only if I literally right the string into import function.
Upvotes: 1
Views: 1612
Reputation: 34286
import
cannot be used when the module path is fully dynamic. See the docs:
Fully dynamic statements, such as
import(foo)
, will fail because webpack requires at least some file location information. This is because foo could potentially be any path to any file in your system or project. Theimport()
must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.
You didn't specify the mode
argument for require.context
which defaults to "sync"; this means all modules matched will be loaded straight away. You want to use "lazy" which generates a lazy-loadable chunk for each module.
Untested, but I imagine it'll be something like this:
const context = require.context('../components/base', false, /base-[\w-]+\.vue$/, 'lazy');
context.keys().forEach(fileName => {
const componentPath = fileName.replace('./', '../components/base/');
// Get PascalCase name of component
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//,
'').replace(/\.\w+$/,
'')),
);
// Register component globally
Vue.component(componentName, () => context(fileName));
});
Upvotes: 3