Webpack 动态批量加载文件的三种实现方案
本文介绍在 Vue 项目中批量加载帧图片的三种方法。首先分析使用 public 目录直接引用路径的局限性,其次探讨常规 require 写法在构建阶段无法识别动态路径的问题。重点详解 webpack 提供的 require.context API,通过配置目录、子目录及正则过滤实现高效批量加载,并封装公共模块以提升复用性。
背景与需求
背景
近期工作中面临一项具体需求:
开发用于播放帧动画的组件
该需求逻辑简单,但需在组件内一次性引入十张静态图片,示例如下:
// 就是这么任性,下标从0开始~
import frame0 from './assets/frame_0.png'
import frame1 from './assets/frame_1.png'
import frame2 from './assets/frame_2.png'
// ..省略n张
import frame7 from './assets/frame_8.png'
import frame8 from './assets/frame_9.png'
import frame9 from './assets/frame_10.png'
秉持代码简洁原则,避免冗余代码,探索更优实现方案。
方法一:绕过 webpack
方案一:规避 webpack 处理
基于 vue-cli 3 环境,可将图片按固定规范存放于 public 目录,代码中通过绝对路径直接引用。据此可构建 URL 数组,简化代码如下:
const frames = []
_.times(10, v => {
frames.push(`/images/frame_${v}.png`)
})
// 然后你就得到 10个 url 的数组啦
此方案为 vue-cli 提供的临时解决方案,存在以下局限:
- 无法触发 webpack 资源处理机制,不生成内容哈希,不利于缓存策略更新
- 无法调用 url-loader 将资源内联为 base64 字符串,无法优化网络请求
方法二:使用 require
方案二:使用 require
鉴于 import 为静态语法,批量加载文件需借助 require,但直接采用如下写法无效:
const frames = []
_.times(10, v => {
const path = `./assets/images/frame_${v}.png`
frames.push(require(path))
}
上述代码中的 path 变量在程序运行时确定,属于 runtime 阶段;而 webpack 的 require 在构建阶段解析文件路径,导致 webpack 无法推断具体路径。
但可采用如下写法:
const frames = []
_.times(10, v => {
frames.push(require(`./assets/images/frame_${v}.png`))
}
// frames 中就得到 带 hash 值的路径
尽管两种写法语法相似,第二种写法在构建时向 webpack 提供了提示,webpack 会将 ./assets/images 目录下的所有文件纳入 bundle,确保运行时可正确访问对应文件。
尝试将方案二的批量加载逻辑封装至独立模块以实现复用:
export function loadAll (n, prefix, suffix) {
const frames = []
_.times(n, v => {
frames.push(require('./' + prefix + v + suffix))
})
return frames
}
该尝试失败,因封装后代码运行 context 属于另一模块,无法解析相对路径中的文件。
方法三:使用 require.context
方案三:使用 require.context
前两种方案均不够优雅,查阅 webpack 文档后,发现 require.context 方法:
require.context(
directory: String,
includeSubdirs: Boolean /* 可选的,默认值是 true */,
filter: RegExp /* 可选的,默认值是 /^\.\/.*$/,所有文件 */,
mode: String /* 可选的,'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once',默认值是 'sync' */
)
通过指定完整依赖关系,利用 directory 路径、includeSubdirs 选项、filter 正则表达式及 mode 加载方式,实现更精细的模块引入控制,并轻松解析模块。
参考前述示例:
const frames = []
const context = require.context('./assets/images', false, /frame_\d+.png/)
context.keys().forEach(k => {
frames.push(context(k))
})
此处代码通过 require.context 创建 require 上下文。
- 第一个参数指定待加载文件夹,即组件当前目录下的 ./assets/images 文件夹
- 第二个参数指定是否包含子目录,因无子目录,传入 false
- 第三个参数指定文件匹配规则,使用正则表达式表示
随后调用 context.keys() 获取该上下文下的文件路径列表,context 本身作为方法,相当于配置好上下文的 require,将 require 结果存入数组,数组路径包含 hash 值,如下为项目中的图片路径示例:
["/static/img/frame_0.965ef86f.png", "/static/img/frame_1.c7465967.png", "/static/img/frame_2.41e82904.png", "/static/img/frame_3.faef7de9.png", "/static/img/frame_4.27ebbe45.png", "/static/img/frame_5.d98cbebe.png", "/static/img/frame_6.c10859bc.png", "/static/img/frame_7.5e9cbdf0.png", "/static/img/frame_8.b3b92c71.png", "/static/img/frame_9.36660295.png"]
若配置图片内联,数组中可能包含图片的 base64 字符串。
代码重构与复用
代码重构
方案三已解决批量加载问题,并可批量 require 指定文件夹内的文件。但 forEach 逻辑存在重复,故将其提取,以便多组件调用时直接引入:
公共模块代码:
/**
* 批量加载帧图片
* @param {Function} context - require.context 创建的函数
* @returns {Array<string>} 返回的所有图片
*/
function loadFrames (context) {
const frames = []
context.keys().forEach(k => {
frames.push(context(k))
})
return frames
}
组件中调用示例:
const context = require.context('./assets/images', false, /frame_\d+.png/)
const frames = loadFrames(context)
实现完成!感兴趣者可点击文末链接查看详细文档。
参考链接 require.context webpack dynamic require
至此,关于 webpack 动态批量加载文件的实现方法介绍完毕,更多相关内容请搜索本站历史文章或继续浏览下方相关文章,希望大家以后多多支持本站!
Docker 部署 Wiki.js 完整教程:从安装到初始化配置
2026-11-04 10:36:31
从其他平台迁移数据到 Wiki.js 的方法与注意事项
2026-11-03 23:50:05
Wiki.js 启动报错或数据库连接失败怎么排查解决
2026-11-03 09:49:52
macOS 使用 Homebrew 或 nvm 升级 Node.js 的最佳实践
2026-11-03 08:29:29
前端项目部署后如何提示用户版本更新详解
2026-11-01 02:17:48
