使用 imagemin、imagemin-webp 优化图片加载

有个 vite+vue3 项目的首页图片较多,加载速度较慢,所以使用webp图片来优化一下页面加载速度。

1.安装依赖

处理图片相关:

npm install imagemin@8.0.1 imagemin-webp@7.0.0  cwebp-bin -D

处理路径相关:

npm install globby fs-extra path 

2.配置 imagemin

由于所有图片不是全在同一个文件夹下,命名也有可能会冲突,所以要把webp图片输出到对应文件夹下,新建 imagemin.js 文件:

import imagemin from 'imagemin';
import imageminWebp from 'imagemin-webp';
import path from 'path';
import fs from 'fs-extra';
import { globby } from 'globby';

(async () => {
    try {
        // 源目录和目标目录
        const SOURCE_DIR = 'src/assets/images';
        const OUTPUT_DIR = 'src/assets/webp';

        // 1. 获取所有图片文件的绝对路径
        const files = await globby([`${SOURCE_DIR}/**/*.{jpg,png}`]);

        // 2. 遍历处理每个文件
        for (const filePath of files) {
            // 计算相对路径
            const relativePath = path.relative(SOURCE_DIR, filePath);
            const outputPath = path.join(OUTPUT_DIR, path.dirname(relativePath), `${path.basename(filePath, path.extname(filePath))}.webp`);

            // 3. 创建目标目录结构
            await fs.ensureDir(path.dirname(outputPath));

            // 4. 转换并保存文件
            const [result] = await imagemin([filePath], {
                destination: path.dirname(outputPath),
                plugins: [imageminWebp({ quality: 75 })]
            });

            if (result) {
                console.log(`Converted: ${relativePath} → ${path.relative(OUTPUT_DIR, outputPath)}`);
            }
        }

        console.log('\n✅ 图片转换完成');
    } catch (error) {
        console.error('\n❌ 图片转换错误:', error);
        process.exit(1);
    }
})();

在 package.json 中添加:

"scripts": {
  "prebuild": "node imagemin.js",
  "build": "vite build"
}

然后运行:

npm run prebuild

可以看到生成配置目录下的所有图片的webp文件,则图片转换成功:

3.使用webp图片

使用<picture>标签来让支持webp图片的浏览器优先加载webp图片,在不支持webp的情况下回退到jpg或png格式:

            <picture>
                <source srcset="@/assets/webp/news/header-bg.webp" type="image/webp" />
                <img src="@/assets/images/news/header-bg.png" alt="" class="img" />
            </picture>

4.动态引入图片

图片很多,需要使用动态引入时,可以通过添加获取图片路径方法,传入图片名称及对应类型文件夹来访问图片。图片文件夹下新增config-name.js文件,存储图片的相对路径。

src/assets/images/news/config-name.js :

const newsImages = {
    news1: 'news1.png',
    news2: 'news2.png',
    news3: 'news3.png',
    headerBg: 'header-bg.png'
};

export default newsImages;

添加公共方法,方便多个页面调用,src/utils/imagesUtils.js :

// 获取原始图片路径
export function getOriginalImage(imagePath, folder) {
    return new URL(`/src/assets/images/${folder}/${imagePath}`, import.meta.url).href;
}

// 获取WebP图片路径
export function getWebPImage(imagePath, folder) {
    return new URL(`/src/assets/webp/${folder}/${imagePath.replace(/\.(jpg|png)$/, '.webp')}`, import.meta.url).href;
}

页面中调用,news.vue :

<script setup>
import { ref } from 'vue';
import NewsImages from '@/assets/images/news/config-name.js';
import { getWebPImage, getOriginalImage } from '@/utils/imageUtils';

const list = ref([
    {
        id: 1,
        imgUrl: 'news1'
    },
    {
        id: 2,
        imgUrl: 'news2'
    },
    {
        id: 3,
        imgUrl: 'news3'
    }
]);
</script>

<template>
    <div class="page">
        <div class="img-box" v-for="item in list" :key="item.id">
            <picture>
                <source :srcset="getWebPImage(NewsImages[item.imgUrl], 'news')" type="image/webp" />
                <img :src="getOriginalImage(NewsImages[item.imgUrl], 'news')" alt="" class="img" />
            </picture>
        </div>
    </div>
</template>

<style lang="scss" scoped>
.page {
    padding: 10px 20px;
    background: #fff;
    display: flex;
    .img-box {
        width: 20%;
        margin-right: 10px;
        .img {
            width: 100%;
            height: 100%;
        }
    }
}
</style>

谷歌浏览器中正常显示webp图片:

首页优化前:

使用webp图片之后,快多了~