前言
在团队开发 Vue3 项目时,发现多人需要同时修改同一个入口文件,引入新的模块文件,容易导致代码冲突。为了优化协作流程,我开始思考是否可以通过动态引入的方式解决这一问题。通过动态加载模块,每个开发者只需新增模块文件,而无需手动修改入口文件,从根本上避免因同时修改同一个入口文件而引发的冲突。
以下代码实现了基于 import.meta.glob
的动态引入功能,并支持排除特定文件,将其封装为一个通用的解决方案。
使用场景
-
模块化的 API 管理 在项目中,可以将所有 API 接口方法存放在某一文件夹中,并通过该函数动态加载所有模块,而无需逐个导入。
-
增强代码的可维护性
- 在开发阶段,新增模块文件后无需在入口文件手动引入,提升开发效率。
- 通过统一的动态加载方式,简化模块的引入与管理。
目录结构
imports.js
为动态引入文件的功能函数。a.js
、b.js
、c.js
为需要动态引入的模块文件。index.js
入口文件。
a.js
、b.js
、c.js
代码实现
a.js
export default {
testA() {
console.log('testA')
}
}
b.js
export default {
testB() {
console.log('testB')
}
}
c.js
export default {
testC() {
console.log('testC')
}
}
imports.js
代码实现
export default function (excludes) {
const setData = new Set(excludes)
const modules = {};
let module = null;
let arr = []
// 使用 import.meta.glob 动态加载 src/modules 文件夹中的所有 JS 文件
// eager 表示文件应该被立即导入,而不是使用的时候才导入
const files = import.meta.glob('./*.js', {eager: true});
// 遍历所有文件
for (const path in files) {
arr = path.split('/')
if (setData.has(arr[arr.length - 1])) {
continue;
}
module = files[path]
// const moduleName = path.match(/./api/(.*).js$/)[1];
const moduleName = path.match(/([^/]+).js$/)[1];
modules[moduleName] = module.default;
}
return modules
};
index.js
代码实现
import modules from './imports';
// 排除文件
const exclude = ['index.js','imports.js']
export default modules(exclude)
使用
输出结果
功能分析
-
动态导入文件
- 通过
import.meta.glob
可以动态导入指定目录下的所有文件。 - 使用
eager: true
表示文件会被立即加载,而不是按需加载。这在需要立即使用模块时非常有用。
- 通过
-
参数说明
exclude
:传入一个数组,包含需要排除的文件名,如排除index.js
、imports.js
文件或特定工具模块。
-
处理逻辑
- 遍历导入的文件路径,通过正则匹配提取文件名。
- 如果文件名在
exclude
列表中,则跳过。 - 将剩余文件导入并存储在
modules
对象中,文件名作为键,对应模块的默认导出作为值。
-
返回值
- 函数最终返回一个包含所有动态加载模块的对象,键是模块名,值是模块内容。
兼容低版本 Vite
imports.js
代码如果运行报错,可能是 Vite
版本过低,如 Vite 2+
版本。
低版本使用以下代码
export default async function (exclude) {
const setData = new Set(exclude)
const modules = {};
let module = null;
let arr = []
let defaultFunc = null
// 使用 import.meta.glob 动态加载 src/modules 文件夹中的所有 JS 文件
const files = import.meta.glob('./*.js');
// 遍历所有文件
for (const path in files) {
arr = path.split('/')
if (setData.has(arr[arr.length - 1])) {
continue;
}
module = files[path]
const moduleName = path.match(/([^/]+).js$/)[1];
defaultFunc = await module()
modules[moduleName] = defaultFunc.default;
}
return modules
};
调用方式