• 作者:老汪软件技巧
  • 发表时间:2024-10-03 21:01
  • 浏览量:

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

import.meta.glob

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

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

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

// 这两种写法都是不行的
import.meta.glob(`@/assest/img/${url}`);
const url = 'url'
import.meta.glob(url)

问题二、如何匹配某文件夹下所有的png、mp3

 // 一个 *:匹配当前目录下的文件;
 // 两个 *:匹配当前目录及其嵌套的全部子目录下的文件;
    
import.meta.glob('/assets/img/font/** // 匹配font文件夹下所有文件
import.meta.glob('/assets/audio/**/*.mp3') // 匹配audio下所有文件夹下的所有mp3 png同理,修改扩展名为png即可

问题三、引入之后没办法直接使用的问题

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

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

// 这两个方法可以直接放到公共的方法封装文件中,用时引入即可
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
}

// 使用方法一
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/)

问题四、项目打包后路径引入错误问题

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

// 以下代码是写在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]' // 其他资源文件按默认路径打包
                    }
                },
            },
        }
  }

// 处理这个问题时,因为我项目中有多处已经写了之前的匹配方案,所以我就直接在代码中加了区分环境的判断,写了两套匹配方案
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、此时修改后还是会有些图片找不到,因为我这项目中,会有些图片的文件夹名字相同,太多了,我也懒得改,解决方案是,①把图片扩大;②修改文件夹名。 尽量保持文件夹名不要一致。

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