记录---前端动态导入(import.meta.glob)
🧑💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣
以下详细介绍 import.meta.glob
的使用:
1. 参数详解
import.meta.glob( pattern, // 匹配模式:字符串或字符串数组 { eager?: boolean, // 是否同步导入 import?: string | string[], // 指定导入的内容 query?: string|Record<string, string | number | boolean> // 查询参数 } )
2. 基础示例(带详细注释)
// 1. 基本异步导入 const modules = import.meta.glob('./modules/*.ts') async function loadModules() { // 遍历所有匹配的模块 for (const path in modules) { // 等待模块加载完成 const module = await modules[path]() // 输出模块路径和内容 console.log('模块路径:', path) console.log('模块内容:', module) } } // 2. 同步导入(eager 模式) const eagerModules = import.meta.glob('./modules/*.ts', { eager: true // 设置为 true 表示同步导入 }) // 3. 导入特定内容 const specificImports = import.meta.glob('./components/*.vue', { import: 'default', // 只导入默认导出 eager: true }) // 4. 多种导入内容 const multipleImports = import.meta.glob('./components/*.vue', { import: ['default', 'setup'], // 导入多个指定内容 eager: true }) // 5. 以 URL 形式导入 const imageUrls = import.meta.glob('./assets/*.png', { query: '?url' // 作为 URL 导入 }) // 6. 导入原始内容 const rawContents = import.meta.glob('./files/*.md', { query: '?raw' // 作为原始文本导入 }) // 7. 多模式匹配 const multiPattern = import.meta.glob([ './components/**/*.vue', // 匹配所有子目录的 Vue 文件 '!./components/ignored/*.vue' // 排除特定目录 ])
3. 实际使用场景
场景一:动态组件加载系统
// components/loader.ts // 定义组件模块的类型 interface ComponentModule { default: any; // Vue 组件 meta?: { name: string; version: string; } } // 导入所有组件 const componentModules = import.meta.glob<ComponentModule>('./*/index.vue') export class ComponentLoader { // 存储已加载的组件 private loadedComponents: Map<string, any> = new Map() // 加载组件 async loadComponent(name: string): Promise<any> { // 构建组件路径 const componentPath = `./${name}/index.vue` // 检查组件是否存在 if (!componentModules[componentPath]) { throw new Error(`组件 ${name} 不存在`) } // 检查是否已加载 if (this.loadedComponents.has(name)) { return this.loadedComponents.get(name) } try { // 加载组件 const module = await componentModules[componentPath]() // 存储组件 this.loadedComponents.set(name, module.default) return module.default } catch (error) { throw new Error(`加载组件 ${name} 失败: ${error.message}`) } } }
场景二:多语言文件管理系统
// i18n/loader.ts // 定义语言包类型 interface LocaleMessages { [key: string]: any; } // 导入所有语言文件 const localeFiles = import.meta.glob('./locales/**/*.json', { eager: true // 同步导入 }) export class I18nLoader { // 存储语言包 private messages: Record<string, LocaleMessages> = {} constructor() { // 初始化语言包 this.initializeLocales() } private initializeLocales() { // 遍历所有语言文件 Object.entries(localeFiles).forEach(([path, content]) => { // 解析路径获取语言代码和命名空间 // 例如: ./locales/zh-CN/common.json const matches = path.match(/\.\/locales\/([^/]+)\/([^.]+)\.json/) if (matches) { const [, locale, namespace] = matches // 初始化语言对象 if (!this.messages[locale]) { this.messages[locale] = {} } try { // 赋值 const messages = content // 按命名空间存储消息 this.messages[locale][namespace] = messages } catch (error) { console.error(`解析语言文件失败 ${path}:`, error) } } }) } // 获取特定语言的消息 getMessages(locale: string): LocaleMessages { return this.messages[locale] || {} } // 获取支持的语言列表 getSupportedLocales(): string[] { return Object.keys(this.messages) } }
场景三:插件系统
// plugins/manager.ts // 定义插件接口 interface Plugin { name: string; install: (app: any) => void; priority?: number; } // 导入所有插件 const pluginModules = import.meta.glob<{ default: Plugin }>('./*/index.ts') export class PluginManager { // 存储已加载的插件 private loadedPlugins: Plugin[] = [] // 加载所有插件 async loadPlugins(): Promise<void> { // 存储加载Promise const loadPromises: Promise<void>[] = [] // 遍历所有插件模块 for (const path in pluginModules) { const loadPromise = (async () => { try { // 加载插件模块 const module = await pluginModules[path]() const plugin = module.default // 验证插件格式 if (!plugin.name || !plugin.install) { throw new Error(`插件格式无效: ${path}`) } // 添加到已加载插件列表 this.loadedPlugins.push(plugin) } catch (error) { console.error(`加载插件失败 ${path}:`, error) } })() loadPromises.push(loadPromise) } // 等待所有插件加载完成 await Promise.all(loadPromises) // 按优先级排序 this.loadedPlugins.sort((a, b) => (b.priority || 0) - (a.priority || 0) ) } // 安装所有插件 async installPlugins(app: any): Promise<void> { // 确保插件已加载 if (this.loadedPlugins.length === 0) { await this.loadPlugins() } // 安装每个插件 for (const plugin of this.loadedPlugins) { try { await plugin.install(app) console.log(`插件 ${plugin.name} 安装成功`) } catch (error) { console.error(`插件 ${plugin.name} 安装失败:`, error) } } } }
4. 使用注意事项
- 路径规范:
// 正确用法 const modules = import.meta.glob('./components/*.vue') // 错误用法 - 不支持动态路径 // import.meta.glob 的参数都必须以字面量传入。 // 你不可以在其中使用变量或表达式。 const path = './components' const modules = import.meta.glob(`${path}/*.vue`) // ❌
- 性能考虑:
// 异步加载 - 代码分割,按需加载 const modules = import.meta.glob('./modules/*.ts') // 同步加载 - 所有模块打包在一起 const modules = import.meta.glob('./modules/*.ts', { eager: true })
- 类型支持:
// 定义模块类型 interface ModuleType { name: string; setup: () => void; } // 使用泛型指定类型 const modules = import.meta.glob<ModuleType>('./modules/*.ts', { eager: true })
这些示例展示了 import.meta.glob
在不同场景下的应用,每个示例都包含了详细的注释和错误处理,可以作为实际项目中的参考。