vue3 动态引入文件避免代码冲突

393 阅读3分钟

前言

在团队开发 Vue3 项目时,发现多人需要同时修改同一个入口文件,引入新的模块文件,容易导致代码冲突。为了优化协作流程,我开始思考是否可以通过动态引入的方式解决这一问题。通过动态加载模块,每个开发者只需新增模块文件,而无需手动修改入口文件,从根本上避免因同时修改同一个入口文件而引发的冲突。

以下代码实现了基于 import.meta.glob 的动态引入功能,并支持排除特定文件,将其封装为一个通用的解决方案。


使用场景

  1. 模块化的 API 管理 在项目中,可以将所有 API 接口方法存放在某一文件夹中,并通过该函数动态加载所有模块,而无需逐个导入。

  2. 增强代码的可维护性

    • 在开发阶段,新增模块文件后无需在入口文件手动引入,提升开发效率。
    • 通过统一的动态加载方式,简化模块的引入与管理。

目录结构

image.png

  1. imports.js 为动态引入文件的功能函数。
  2. a.jsb.jsc.js 为需要动态引入的模块文件。
  3. index.js 入口文件。

a.jsb.jsc.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)

使用

image.png

输出结果

image.png

功能分析

  1. 动态导入文件

    • 通过 import.meta.glob 可以动态导入指定目录下的所有文件。
    • 使用 eager: true 表示文件会被立即加载,而不是按需加载。这在需要立即使用模块时非常有用。
  2. 参数说明

    • exclude:传入一个数组,包含需要排除的文件名,如排除index.jsimports.js文件或特定工具模块。
  3. 处理逻辑

    • 遍历导入的文件路径,通过正则匹配提取文件名。
    • 如果文件名在 exclude 列表中,则跳过。
    • 将剩余文件导入并存储在 modules 对象中,文件名作为键,对应模块的默认导出作为值。
  4. 返回值

    • 函数最终返回一个包含所有动态加载模块的对象,键是模块名,值是模块内容。

兼容低版本 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
};

调用方式

image.png