Use import.meta.glob for Dynamic Component Registration in Vite
Impact: MEDIUM - When migrating from Webpack to Vite or starting a new Vite project, the require.context pattern for dynamically registering components won't work. Vite uses import.meta.glob instead. Using the wrong approach will cause build errors or runtime failures.
Task Checklist
- [ ] Replace
require.contextwithimport.meta.globin Vite projects - [ ] Update component registration patterns when migrating from Vue CLI to Vite
- [ ] Use
{ eager: true }for synchronous loading when needed - [ ] Handle async components appropriately with
defineAsyncComponent
Incorrect (Webpack pattern - doesn't work in Vite):
// main.js - WRONG for Vite
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// This Webpack-specific API doesn't exist in Vite
const requireComponent = require.context(
'./components/base',
false,
/Base[A-Z]\w+\.vue$/
)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
app.component(componentName, componentConfig.default || componentConfig)
})
app.mount('#app')Correct (Vite pattern):
// main.js - Correct for Vite
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// Vite's glob import - eager loading for synchronous registration
const modules = import.meta.glob('./components/base/Base*.vue', { eager: true })
for (const path in modules) {
// Extract component name from path: './components/base/BaseButton.vue' -> 'BaseButton'
const componentName = path.split('/').pop().replace('.vue', '')
app.component(componentName, modules[path].default)
}
app.mount('#app')Lazy Loading with Async Components
// main.js - Lazy loading variant
import { createApp, defineAsyncComponent } from 'vue'
import App from './App.vue'
const app = createApp(App)
// Without { eager: true }, returns functions that return Promises
const modules = import.meta.glob('./components/base/Base*.vue')
for (const path in modules) {
const componentName = path.split('/').pop().replace('.vue', '')
// Wrap in defineAsyncComponent for lazy loading
app.component(componentName, defineAsyncComponent(modules[path]))
}
app.mount('#app')Glob Pattern Examples
// All .vue files in a directory (not recursive)
import.meta.glob('./components/*.vue', { eager: true })
// All .vue files recursively
import.meta.glob('./components/**/*.vue', { eager: true })
// Specific naming pattern
import.meta.glob('./components/Base*.vue', { eager: true })
// Multiple patterns
import.meta.glob([
'./components/Base*.vue',
'./components/App*.vue'
], { eager: true })
// Exclude patterns
import.meta.glob('./components/**/*.vue', {
eager: true,
ignore: ['**/*.test.vue', '**/*.spec.vue']
})TypeScript Support
// main.ts - with proper typing
import { createApp, Component } from 'vue'
import App from './App.vue'
const app = createApp(App)
const modules = import.meta.glob<{ default: Component }>(
'./components/base/Base*.vue',
{ eager: true }
)
for (const path in modules) {
const componentName = path.split('/').pop()!.replace('.vue', '')
app.component(componentName, modules[path].default)
}
app.mount('#app')Migration Checklist (Webpack to Vite)
| Webpack | Vite |
|---|---|
require.context(dir, recursive, regex) | import.meta.glob(pattern, options) |
| Synchronous by default | Use { eager: true } for sync |
.keys() returns array | Returns object with paths as keys |
| Returns module directly | Access via .default for ES modules |