require['context'] 与 require.context——下

import lodash from 'lodash'
import { clientType, decorType } from '@/utils/decor-types'

export function getModules() {
  let modulesObj = {}
  let requireModules
  if (clientType === 'pc') {
    requireModules = require['context']('@/components/decor/pc', true, /[A-Za-z]\w+\.(vue|js)$/)
  } else {
    requireModules = require['context']('@/components/decor/mobile', true, /[A-Za-z]\w+\.(vue|js)$/)
  }
  const requireModulesKeys = requireModules.keys()

  // 遍历所有引入的文件中的index.js
  // 将index.js中的配置装入modulesObj中
  // 就相当于查找到了所有的装修模块
  requireModulesKeys.forEach(fileName => {
    if (fileName.indexOf('index.js') === -1) return
    const moduleConfig = requireModules(fileName).default
    const name = lodash.kebabCase(moduleConfig.name)
    // 过滤一下装修类型
    const { decor_type } = moduleConfig
    if (decor_type !== undefined && (!decor_type.split(',').includes(decorType))) return
    modulesObj[name] = moduleConfig
  })

  // 遍历modulesObj,也就是遍历所有模块
  // 再根据模块名称name,过滤所有文件名
  // 如果有模块名+Setting.vue的文件,将has_setting设为true,表示有Setting组件
  Object.keys(modulesObj).forEach(key => {
    let setting_name = lodash.camelCase(`${key}-setting`)
    setting_name = lodash.upperFirst(setting_name) + '.vue'
    const index = requireModulesKeys.findIndex(fileName => fileName.indexOf(setting_name) !== -1)
    if (index !== -1) {
      modulesObj[key]['has_setting'] = true
    }
  })
  
  // 遍历modulesObj,把模块放入Modules数组中
  // 顺便按照index.js中的sort字段排个序
  const Modules = []
  Object.keys(modulesObj).forEach(key => {
    Modules.push(modulesObj[key])
    Modules.sort((a, b) => a.sort - b.sort)
  })
  
  return Modules
}

结论先说:

  • requireModules 不是“数据对象”,也不是 ES6 的 import 方法。
  • 它是 Webpack 的 require.context 返回的“上下文 require 函数”——一个既能被调用又带有属性的方法对象。

为什么能“像函数那样调用”:

  • require.context(directory, useSubdirectories, regExp) 会返回一个函数,这个函数用来按 key 动态加载匹配到的模块。
  • 这个函数本身还挂了几个属性/方法:keys()、resolve()、id。
  • 在 JavaScript 里,函数本身就是对象,可以同时“可调用”并拥有属性,这是正常的。

结合你的代码位置

  • 中:
    • requireModules = require'context' 得到的是“上下文 require 函数”。
    • requireModules(fileName) 就是“动态导入这个 fileName 对应的模块”。
    • .default 的原因:被导入的 index.js 或 .vue 使用了 ES Module 的 export default 导出,因此要取 default 才是默认导出。如果某模块是用 module.exports 导出的,则不需要 .default。

你可以这样理解返回值形态

  • typeof requireModules === 'function' 为 true;
  • requireModules.keys() 会给出可用的 fileName 列表(如 './Foo/index.js');
  • requireModules(fileName) 返回模块的导出对象,经常需要 .default 取默认导出。

如果想写得更“健壮”一点(兼容两种导出风格),可以这样处理返回值:

  • const mod = requireModules(fileName);
  • const moduleConfig = mod.default || mod;

这样就不管模块是 export default 还是 module.exports 都能拿到正确的配置对象。

posted @ 2025-08-26 16:14  jialiangzai  阅读(9)  评论(0)    收藏  举报