首先介绍下需求背景,是用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、此时修改后还是会有些图片找不到,因为我这项目中,会有些图片的文件夹名字相同,太多了,我也懒得改,解决方案是,①把图片扩大;②修改文件夹名。 尽量保持文件夹名不要一致。
特此记录,希望能对大家有所帮助