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

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

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

相关推荐
cwj&xyp23 分钟前
Python(二)str、list、tuple、dict、set
前端·python·算法
dlnu201525062225 分钟前
ssr实现方案
前端·javascript·ssr
古木201930 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王3 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发3 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪4 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端