Webpack 动态批量加载文件的三种实现方案

作者:望舒

时间:2026-10-23

浏览:606

本文介绍在 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 动态批量加载文件的实现方法介绍完毕,更多相关内容请搜索本站历史文章或继续浏览下方相关文章,希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章