前端动态导入(import.meta.glob) 的实用场景和详细示例

import.meta.glob 的各种实用场景和详细示例如下:

1. Vue 组件自动注册系统

typescript 复制代码
// components/index.ts
const components = import.meta.glob('./**/*.vue', { eager: true })

export function registerGlobalComponents(app) {
  Object.entries(components).forEach(([path, module]) => {
    // 提取组件名称
    // 例如:'./Button/index.vue' -> 'Button'
    //      './Form/Input.vue' -> 'FormInput'
    const componentName = path
      .split('/')
      .filter(segment => segment !== '.' && !segment.includes('.vue'))
      .join('')
    
    app.component(componentName, module.default)
  })
}

// 使用
import { createApp } from 'vue'
import { registerGlobalComponents } from './components'

const app = createApp(App)
registerGlobalComponents(app)

2. 高级路由配置系统

typescript 复制代码
// router/index.ts
const layouts = import.meta.glob('../layouts/*.vue', { eager: true })
const pages = import.meta.glob('../pages/**/*.vue')

// 处理布局组件
const layoutComponents = Object.entries(layouts).reduce((acc, [path, module]) => {
  const layoutName = path.match(/\.\.\/layouts\/(.*)\.vue$/)?.[1]
  if (layoutName) {
    acc[layoutName] = module.default
  }
  return acc
}, {})

// 生成路由配置
const routes = Object.entries(pages).map(([path, component]) => {
  // 从文件路径提取路由信息
  const routePath = path
    .replace('../pages', '')
    .replace('.vue', '')
    .replace(/\/index$/, '/')
    
  // 从文件名提取元数据
  const segments = path.split('/')
  const fileName = segments[segments.length - 1].replace('.vue', '')
  
  // 判断是否需要认证(例如:文件名以 Auth 开头)
  const requiresAuth = fileName.startsWith('Auth')
  
  // 确定使用的布局(可以基于目录结构)
  const layout = segments.includes('admin') ? 'AdminLayout' : 'DefaultLayout'
  
  return {
    path: routePath,
    component,
    meta: {
      requiresAuth,
      layout: layoutComponents[layout]
    }
  }
})

3. 多语言国际化系统

typescript 复制代码
// i18n/index.ts
const messages = import.meta.glob('./locales/**/*.json', {
  eager: true,
  as: 'string'
})

interface LocaleMessages {
  [locale: string]: {
    [key: string]: any
  }
}

// 处理语言文件
const i18nMessages: LocaleMessages = Object.entries(messages).reduce((acc, [path, content]) => {
  // 提取语言代码和命名空间
  // 例如:./locales/zh-CN/common.json -> { locale: 'zh-CN', namespace: 'common' }
  const match = path.match(/\.\/locales\/([^/]+)\/([^.]+)\.json$/)
  if (match) {
    const [, locale, namespace] = match
    if (!acc[locale]) {
      acc[locale] = {}
    }
    
    // 解析 JSON 内容并按命名空间存储
    acc[locale][namespace] = JSON.parse(content)
  }
  return acc
}, {})

// 创建 i18n 实例
import { createI18n } from 'vue-i18n'

export const i18n = createI18n({
  messages: i18nMessages,
  legacy: false,
  locale: 'zh-CN',
  fallbackLocale: 'en'
})

4. 动态 API 接口管理

typescript 复制代码
// api/index.ts
const apiModules = import.meta.glob('./modules/*.ts', { eager: true })

interface ApiDefinition {
  path: string
  method: 'GET' | 'POST' | 'PUT' | 'DELETE'
  auth?: boolean
}

// 收集所有 API 定义
const apiDefinitions = Object.entries(apiModules).reduce((acc, [path, module]) => {
  const namespace = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (namespace) {
    acc[namespace] = module.default
  }
  return acc
}, {})

// 创建请求实例
import axios from 'axios'

const instance = axios.create({
  baseURL: '/api'
})

// 生成 API 方法
export const api = Object.entries(apiDefinitions).reduce((acc, [namespace, definitions]) => {
  acc[namespace] = {}
  
  Object.entries(definitions).forEach(([key, def]: [string, ApiDefinition]) => {
    acc[namespace][key] = async (data?: any) => {
      const config = {
        url: def.path,
        method: def.method,
        ...(def.method === 'GET' ? { params: data } : { data })
      }
      
      if (def.auth) {
        // 添加认证信息
        config.headers = {
          Authorization: `Bearer ${localStorage.getItem('token')}`
        }
      }
      
      return instance(config)
    }
  })
  
  return acc
}, {})

5. 自动加载 Vuex/Pinia 模块

typescript 复制代码
// store/index.ts
const storeModules = import.meta.glob('./modules/*.ts', { eager: true })

// Vuex 示例
import { createStore } from 'vuex'

const modules = Object.entries(storeModules).reduce((acc, [path, module]) => {
  const moduleName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (moduleName) {
    acc[moduleName] = module.default
  }
  return acc
}, {})

export const store = createStore({
  modules
})

// Pinia 示例
const stores = Object.entries(storeModules).reduce((acc, [path, module]) => {
  const storeName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (storeName) {
    acc[storeName] = module.default
  }
  return acc
}, {})

// 自动注册 store
export function registerStores(app) {
  const pinia = createPinia()
  app.use(pinia)
  
  Object.entries(stores).forEach(([name, store]) => {
    pinia.use(store)
  })
}

6. 自动注册指令系统

typescript 复制代码
// directives/index.ts
const directives = import.meta.glob('./modules/*.ts', { eager: true })

export function registerDirectives(app) {
  Object.entries(directives).forEach(([path, module]) => {
    const directiveName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
    if (directiveName) {
      // 转换指令名称为 kebab-case
      // 例如:clickOutside -> v-click-outside
      const kebabName = directiveName
        .replace(/([A-Z])/g, '-$1')
        .toLowerCase()
        .replace(/^-/, '')
      
      app.directive(kebabName, module.default)
    }
  })
}

这些示例展示了 import.meta.glob 在实际项目中的高级应用。每个示例都包含了:

  • 文件组织结构的建议
  • 命名规范的处理
  • 类型安全的考虑
  • 实际业务场景的适配

通过这些模式,可以构建出更加模块化、可维护的项目结构。

相关推荐
front_explorers1 分钟前
Umi项目必看,从Webpack到Rspack,KMI引领性能革命🚀
前端
旺仔牛仔QQ糖2 分钟前
都写那么多项目了, 傻傻分不清楚NODE_ENV 和 模式(Mode) 两者区别是什么
前端·面试
xcLeigh7 分钟前
HTML5实现简洁的体育赛事网站源码
前端·html
棉花糖超人10 分钟前
【从0-1的CSS】第1篇:CSS简介,选择器已经常用样式
前端·css
GISer_Jing15 分钟前
XHR / Fetch / Axios 请求的取消请求与请求重试
前端·javascript·网络
天涯学馆18 分钟前
微前端架构设计:从理论到实践的全面指南
前端·javascript·面试
Verin29 分钟前
Next.js+Wagmi+rainbowkit构建以太坊合约交互模版
前端·web3·以太坊
KenXu32 分钟前
🚀 Cursor 1.0 重磅发布!AI代码编辑器迎来革命性升级
前端
凌辰揽月34 分钟前
Web后端基础(Maven基础)
前端·pycharm·maven
梦想CAD控件38 分钟前
(VUE3集成CAD)在线CAD实现焊接符号自定义
前端·javascript·vue.js