奇怪的需求解决方案(三)

首先介绍下需求背景,是用pixi做一个小游戏,应用到了非常多的文字图片和配置的语音对话mp3等,因为一些原因,这些图片全部放在本地,项目中又没有明确的那部分请求那些图片,而是根据接口返回的字段判断请求那部分png和mp3。

import.meta.glob

因为项目中用的是vite,所以用了import.meta.glob,它是vite支持的,webpack支持的require。都是用来多模块导入的。匹配到的文件默认是懒加载的,通过动态导入实现,并会在构建时分离为独立的chunk。具体用法我就不多介绍,其他文档以及官方文档都有介绍,用起来也不难,我这就主要讲一讲我使用过程中遇到问题以及解决方案。

问题一、引入文件路径的问题

引入文件路径不能有任何的拼接写法,以及定义的变量都不行。

javascript 复制代码
// 这两种写法都是不行的
import.meta.glob(`@/assest/img/${url}`);
const url = 'url'
import.meta.glob(url)
问题二、如何匹配某文件夹下所有的png、mp3
ruby 复制代码
 // 一个 *:匹配当前目录下的文件;
 // 两个 *:匹配当前目录及其嵌套的全部子目录下的文件;
    
import.meta.glob('/assets/img/font/** // 匹配font文件夹下所有文件
import.meta.glob('/assets/audio/**/*.mp3') // 匹配audio下所有文件夹下的所有mp3 png同理,修改扩展名为png即可
问题三、引入之后没办法直接使用的问题

写了个方法转为Map,然后就可以直接根据文件名取对应的路径。

typescript 复制代码
// 这两个方法可以直接放到公共的方法封装文件中,用时引入即可
function extractString(text) {
  // 截取最后一个/及.前面的字符串
  const match = text.match(/([^/]+)$/)
  return match[1].match(/[^.]*/)[0]
}

export const exImgMap = (images) => {
  const imgMap = new Map<string, string>()
  Object.keys(images).map(
    (item) => {
      imgMap.set(extractString(item), images[item].default)
    }
  )
  return imgMap
}
typescript 复制代码
// 使用方法一
const imgMap = exImgMap(import.meta.glob('/assets/img/*.png', { eager: true }))

const url = imgMap.get('c_02_z_yu') // 参数为文件名

// 使用方法二
const imgMapList = exImgMap(import.meta.glob('/assets/img/game/*.png', { eager: true })).values() // 获取路径集合

// 因为这个方法可能会引入多个文件夹,所以写一个方法做一下匹配
const fileName = 'game'
const newMp3Array = []
  imgMapList?.forEach((v: string) => {
     if (v.includes(`/${fileName.value}/`)) newMp3Array.push(v)
  })
  console.log(newMp3Array)  // 此时就匹配了game文件夹下的所有的png图片(文件路径包含/game/)
问题四、项目打包后路径引入错误问题

一般咱们的项目都会做一些静态资源的打包配置,比如压缩,按类型分包等。 此时打包后的路径就变了,项目中的引入方法没问题,但是文件路径匹配方法却不行了,所以需要修改一下,做一些区分。

javascript 复制代码
// 以下代码是写在vite.config.ts中的,具体配置你可以根据自己的项目去修改,主要是在后面的取文件自己能匹配上即可。

build:{
 target: "modules",
        assetsInlineLimit: 1, // 这个配置不要删,不然过小的图片不打包,将找不到图片
        outDir: resolve(__dirname, 'dist_web'), // 输出目录,可以根据需要更改
        rollupOptions: {
            input: 'src/renderer/index.html',
            output: { // 静态文件按类型分包
                chunkFileNames: 'static/js/[name]-[hash].js',
                entryFileNames: 'static/js/[name]-[hash].js',
                // assetFileNames: 'static/[ext]/[name]-[hash].[ext]',// 其他资源文件
                assetFileNames: (assetInfo) => {
                    // 判断是否为图片文件
                    if ([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"].some((ext) => assetInfo.name.endsWith(ext))) {
                        if (assetInfo.originalFileName?.includes('/topicFont')) {
                            const name = assetInfo.originalFileName.split('/topicFont')[1].split('/').filter(v => v)
                            return `static/[ext]/${name[0]}_${name[1]}_${name[2]}_${assetInfo.name}`
                        } else if (assetInfo.originalFileName?.includes('/audio')) {
                            const name = assetInfo.originalFileName.split('/audio')[1].split('/').filter(v => v)
                            return `static/[ext]/${name[0]}_${name[1]}_${assetInfo.name}`
                        } else {
                            return 'static/[ext]/[name]-[hash].[ext]' // 其他资源文件按默认路径打包
                        }
                    } else if ([".mp3"].some((ext) => assetInfo.name.endsWith(ext)) && ['/audio/shengpang/', '/audio/xingpang/'].some(file => assetInfo.originalFileName?.includes(file))) {
                        const name = assetInfo.originalFileName.split('/audio')[1].split('/').filter(v => v)
                        return `static/[ext]/${name[0]}_${name[1]}_${assetInfo.name}`
                    } else {
                        return 'static/[ext]/[name]-[hash].[ext]' // 其他资源文件按默认路径打包
                    }
                },
            },
        }
  }
typescript 复制代码
// 处理这个问题时,因为我项目中有多处已经写了之前的匹配方案,所以我就直接在代码中加了区分环境的判断,写了两套匹配方案

if (import.meta.env.MODE === 'development') {
// xxx
}else {
const fileName = 'game'
const newMp3Array = []
  imgMapList?.forEach((v: string) => {
     if (v.includes(`/types_${fileName.value}_`)) newMp3Array.push(v) // 拼接的字段就是想要取的对应文件夹下的。
  })
  console.log(newMp3Array)  // 此时就匹配了game文件夹下的所有的png图片(文件路径包含/game/)
}

其他问题: 经过上面的问题,基本就解决的差不多了。但是还有一些小问题,记录一下。 vite打包后有些小图片不被打包,死活找不到。 1、vite 小图片被转为内联.有个配置assetsInlineLimit:0,关掉它。 2、此时修改后还是会有些图片找不到,因为我这项目中,会有些图片的文件夹名字相同,太多了,我也懒得改,解决方案是,①把图片扩大;②修改文件夹名。 尽量保持文件夹名不要一致。

特此记录,希望能对大家有所帮助

相关推荐
崔庆才丨静觅13 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606114 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了14 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅14 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅15 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅15 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment15 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅15 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊15 小时前
jwt介绍
前端
爱敲代码的小鱼15 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax