当前位置: 首页 > Web前端 > vue.js

webpack小技巧:动态批量加载文件

时间:2023-03-31 17:53:25 vue.js

背景最近笔者在工作中遇到了一个小需求:实现一个播放帧图片的组件需求并不复杂,但是需要一次引入十张图片到组件中时间。像下面这样://太任性了,下标从0开始~importframe0from'./assets/frame_0.png'importframe1from'./assets/frame_1.png'importframe2from'./assets/frame_2.png'//..omitnsheetsimportframe7from'./assets/frame_8.png'importframe8from'./assets/frame_9.png'importframe9from'./assets/frame_10.png'作为代码清洁度As作为一个程序员,我不允许这种重复的代码存在,所以我只是尝试看看有没有简单的方法。方法一:绕过webpack由于笔者使用的是vue-cli3,熟悉的朋友都知道图片是固定格式放在public文件夹下,然后在代码中直接用绝对路径导入的。这样就可以根据文件名构造一个url数组了。简单的代码如下:constframes=[]_.times(10,v=>{frames.push(`/images/frame_${v}.png`)})//然后得到一个10的数组网址。该方法本身是vue-cli提供的应急方法。它有几个缺点:不能使用webpack处理资源,不能生成内容哈希,不利于缓存更新。使用url-loader将资源内联成base64字符串,减少网络请求方法二:require由于import是static关键字,如果想批量加载文件,可以使用require,但是不能直接这样写:constframes=[]_.times(10,v=>{constpath=`./assets/images/frame_${v}.png`frames.push(require(path))}上面代码中的路径为in只能在程序运行的时候才能确定,也就是属于runtime阶段,而webpack中的require在构建阶段就确定了文件位置,所以webpack无法猜测路径在哪里。但是可以这样写像这样:constframes=[]_.times(10,v=>{frames.push(require(`./assets/images/frame_${v}.png`))}//具有哈希值的路径将begetinframes虽然这两种写法在语法上没有区别,但是第二种写法在构建的时候会提示webpack,webpack会把./assets/images里面的文件全部加入到bundl中e、这样运行的时候就可以找到对应的文件。作者在使用方法二时,尝试将批量加载的逻辑提取到其他模块中复用:(require('./'+prefix+v+suffix))})returnframes}但是显然失败了,因为提取出来的代码,运行上下文属于另外一个模块,所以找不到相对路径下的文件。方法三:上面两个require.context的方法都不是很优雅,于是去看了webpack的文档。终于找到了这样一个方法:require.contextrequire.context(directory:String,includeSubdirs:Boolean/*可选,默认为true*/,filter:RegExp/*可选,默认为/^\.\/.*$/,所有文件*/,mode:String/*optional,'sync'|'eager'|'weak'|'lazy'|'lazy-once',默认值为'sync'*/)指定一系列完整的依赖关系,通过一个目录路径,一个includeSubdirs选项,一个更细粒度的过滤器控制模块被导入,一个模式定义了它是如何加载的。然后可以轻松解析该模块。我们还是看上面的例子:constframes=[]constcontext=require.context('./assets/images',false,/frame_\d+.png/)context.keys().forEach(k=>{frames.push(context(k))})这里的代码通过require.context创建了一个requirecontext。第一个参数指定要加载的文件夹,即组件当前目录下的./assets/images文件夹。第二个参数指定是否包含子目录。由于没有子目录,传false,第三个参数指定需要包含文件的匹配规则,我们使用正则表达式,然后使用context.keys()获取context的文件路径列表,和context本身也是一个方法,相当于设置了上下文的require。我们将要求的文件放入一个数组中,数组中的路径其实是有一个哈希值的。下面是我项目中的图片:["/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块的逻辑明显是重复的,所以我们当然提取出来了,以后调用多个组件的时候才需要导入:publicmodule:/***批量加载帧图片*@param{Function}context-由require.context创建的函数*@returns{Array}返回所有图像*/functionloadFrames(context){constframes=[]context.keys().forEach(k=>{frames.push(context(k))})returnframes}component:constcontext=require.context('./assets/images',false,/frame_\d+.png/)constframes=loadFrames(context)就大功告成了!感兴趣的小伙伴可以点击文末链接查看详细文档~参考链接require.contextwebpack动态require