可利用 import.meta.url 获取模块路径并结合 console.group 实现分层依赖日志:先标准化 moduleId,再通过 importStack 栈记录父模块,用 console.group 展开层级,开发时条件启用、去重且非阻塞。

可以利用 import.meta.url 获取当前模块路径,并结合 console.group 分层展开依赖关系,形成可折叠、带上下文的拓扑日志。关键在于在模块加载时主动记录自身被谁导入、又导入了谁,再用嵌套分组可视化层级。
获取并标准化模块标识
import.meta.url 返回完整的 file:// 或 https:// URL,直接使用可读性差。建议提取相对路径或文件名作为简明标识:
const moduleId = import.meta.url .replace(/^.*\/src\//, '') // 去掉公共前缀 .replace(/\?.*$/, '') // 去掉查询参数(如 ?t=123) .replace(/\.js$/, ''); // 去掉后缀
这样 src/utils/request.js 就变成 utils/request,便于日志识别。
记录导入者(父模块)信息
浏览器中无法直接获知“谁 import 了我”,但可在父模块中显式传入上下文。更实用的方式是:在每个模块顶部统一调用一个注册函数,由父模块在 import 后立即标记自己为“当前作用域”:
- 在入口或工具模块中定义全局追踪栈:
const importStack = []; - 父模块导入子模块前执行:
importStack.push('main/index'); - 子模块内通过
importStack.at(-1)拿到直接调用者 - 导入完成后执行
importStack.pop()维护栈结构
用 console.group 层级展开依赖链
对每个模块,先用 console.group(`${moduleId} ← ${parent || 'entry'}`) 开启分组,内部再打印它所 import 的子模块,并递归调用其日志逻辑:
// 示例:logDeps.js
export function logModule(moduleId, parent = 'entry') {
console.group(`? ${moduleId} ← ${parent}`);
console.log('✅ loaded');
// 这里可静态列出已知依赖(适用于构建时分析)
// 或配合 import() 动态收集(需额外 hook)
console.groupEnd();
}
若配合 ESM 动态导入,可在 import('./child.js').then(...) 中触发子模块的 logModule,自动延续层级。
避免重复与性能干扰
开发阶段启用,生产环境应完全移除。推荐封装成条件化函数:
- 用
if (import.meta.env?.DEV)控制日志开关(Vite / Webpack 支持) - 模块首次执行时记录,用
globalThis.__loggedModules ||= new Set()去重 - 不阻塞执行:所有
console.group调用放在微任务末尾,例如queueMicrotask(() => { ... })










