Vite 动态引入本地图片 以及打包404的问题

2,571 阅读1分钟

要引入一张文件名为动态的本地图片

原来使用vue-cli 或者 webpack 构建的vue程序 使用require就可以很好的解决

<div v-for="(item, index) in array">
    <img :src="require(`@/assets/icon/${index}.png`)" />
</div>

但是require这个东西是webpack环境才会有

于是查看vite静态资源处理

以及各种技术论坛博客 提到的最多的就是 new URL() 这种方式

image.png

文章中提到 通过相对路径我们就能得到一个被完整解析的静态资源URL

于是乎更改代码如下:

<div v-for="(item, index) in array">
    <img :src="getImageUrl(`${index}`)" />
</div>
function getImageUrl(name) { 
    return new URL(`../../assets/icon/${name}.png`, import.meta.url).href 
}

开发环境可以正常显示

但是打包后发现这几张图片根本没有进行打包,导致加载图片报错404

再次查看文档,发现有这么一段话

image.png

也就是说必须保证字符串是静态的。当然写大量的switch是可以解决的, 或者可以把图片放到public文件夹下

下面就说一下我的解决办法。

既然上面几种办法行不通,那我就试着把所有图片当成模块全部导入

import icon_1 from '@/assets/icon/1.png'
import icon_2 from '@/assets/icon/2.png'
// more
const images = {
    icon_1,
    icon_2
    // more
}
<div v-for="(item, index) in array">
    <img :src="images[`icon_${index}`]" />
</div>

然后打包, 发现icon全部打包进来了。

但是这样做有点傻有100张icon就要导入100次,有没有什么比较方便的api可以一次性导入某个文件夹下的所有图片呢?

全局导入 import.meta.glob

const modules = import.meta.glob('./dir/*.js')
// 编译后变成
const modules = { 
    './dir/foo.js': () => import('./dir/foo.js'), 
    './dir/bar.js': () => import('./dir/bar.js'), 
}

看的出来所有模块都是异步模块, 继续看文档发现有个globEager

const modules = import.meta.globEager('./dir/*.js')
// 编译后变成
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}

正好满足需求,于是改造代码

const modules = import.meta.glob('/src/assets/icon/*')  // 这里可以写 @ (路径别名) 或者 /src (绝对或相对路径)

const icons = (name) => {
    const path = '/src/assets/icon/${name}.png' // 这里不可以写路径别名,只可以写绝对或者相对路已经
    return modules[path]?.default
}
<div v-for="(item, index) in array">
    <img :src="icons(index)" />
</div>

编译打包,完美

另外: import.meta.globEager 在vite v3 已经弃用 可以使用选项{ eager: true }实现此功能

    import.meta.glob('*', { eager: true })

参考链接