MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Webpack中图片与字体资源的性能优化技巧

2022-12-186.2k 阅读

Webpack中图片资源的性能优化技巧

在前端开发中,图片资源往往占据了较大的体积,对页面的加载性能有着显著影响。Webpack作为前端开发中常用的模块打包工具,提供了丰富的方法来优化图片资源。

图片格式选择与转换

  1. 常见图片格式特点
    • JPEG:适用于色彩丰富的照片等图像。它采用有损压缩算法,能够在保持较好视觉效果的同时大幅减小文件体积。例如,一张未经压缩的高清照片可能有几MB大小,经过适当压缩的JPEG格式图片可能只有几百KB。其压缩比可在一定范围内调整,通常质量设置在70 - 90之间能在视觉质量和文件大小之间取得较好平衡。
    • PNG:分为PNG - 8和PNG - 24。PNG - 8适合简单的图标、具有大面积纯色的图像,它采用无损压缩,支持透明度。PNG - 24适合对图像质量要求较高且需要透明度的复杂图像,但文件体积相对较大。比如一个简单的纯色图标,使用PNG - 8格式可能只有几KB,而如果是一个复杂的带有透明效果的图片,PNG - 24格式可能会达到几十KB甚至更大。
    • WebP:这是一种新兴的图片格式,由Google开发。它结合了JPEG和PNG的优点,既能实现高压缩比,又能支持透明度。在相同视觉质量下,WebP格式的图片文件大小通常比JPEG和PNG更小。例如,同样一张图片,JPEG格式为100KB,PNG格式为150KB,WebP格式可能只有60 - 80KB。然而,WebP的兼容性相对较差,一些旧版本的浏览器不支持。
  2. Webpack中图片格式转换 在Webpack中,可以使用image - webpack - loader来进行图片格式的转换和压缩。首先安装该loader:
npm install image - webpack - loader --save - dev

然后在Webpack的配置文件(通常是webpack.config.js)中进行如下配置:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(jpg|png|gif)$/,
                use: [
                    {
                        loader: 'file - loader',
                        options: {
                            name: 'images/[name].[ext]'
                        }
                    },
                    {
                        loader: 'image - webpack - loader',
                        options: {
                            mozjpeg: {
                                progressive: true,
                                quality: 65
                            },
                            // optipng.enabled: false will disable optipng
                            optipng: {
                                enabled: false
                            },
                            pngquant: {
                                quality: [0.65, 0.90],
                                speed: 4
                            },
                            gifsicle: {
                                interlaced: false
                            },
                            // the webp option will enable WEBP
                            webp: {
                                quality: 75
                            }
                        }
                    }
                ]
            }
        ]
    }
};

上述配置中,image - webpack - loader会对JPEG、PNG和GIF图片进行优化。mozjpeg用于配置JPEG图片的压缩参数,optipngpngquant用于PNG图片的优化,gifsicle用于GIF图片优化,webp则开启了WebP格式的转换,并设置了转换后的WebP图片质量。

图片压缩

  1. 无损压缩 无损压缩是在不损失图像信息的前提下减小文件体积。对于PNG图片,可以使用optipng工具。在image - webpack - loader的配置中,optipng相关配置如下:
optipng: {
    enabled: true,
    optimizationLevel: 7
}

enabled设置为true表示开启optipng压缩,optimizationLevel取值范围是0 - 7,数值越大压缩程度越高,但压缩时间也会越长。一般设置为5 - 7能在压缩效果和时间之间取得较好平衡。

对于JPEG图片,mozjpeg也可以进行无损压缩(通过调整quality接近100),例如:

mozjpeg: {
    progressive: true,
    quality: 98
}
  1. 有损压缩 有损压缩会牺牲一定的图像质量来换取更小的文件体积。对于JPEG图片,常见的做法是将quality设置在70 - 90之间。如:
mozjpeg: {
    progressive: true,
    quality: 80
}

对于PNG图片,pngquant是常用的有损压缩工具。在image - webpack - loader配置中:

pngquant: {
    quality: [0.65, 0.90],
    speed: 4
}

quality设置了压缩质量范围,speed表示压缩速度,取值范围是1 - 11,数值越大速度越快,但压缩效果可能会稍差。

图片的按需加载与懒加载

  1. 按需加载 按需加载可以根据实际需求加载图片,而不是一次性加载所有图片。在Webpack中,可以结合动态导入(Dynamic Imports)来实现。例如,在React项目中:
import React, { useState, useEffect } from'react';

const MyComponent = () => {
    const [image, setImage] = useState(null);
    useEffect(() => {
        const loadImage = async () => {
            const { default: img } = await import('./path/to/image.jpg');
            setImage(img);
        };
        loadImage();
    }, []);

    return (
        <div>
            {image && <img src={image} alt="My Image" />}
        </div>
    );
};

export default MyComponent;

上述代码中,只有在组件渲染并执行useEffect时,才会动态导入图片,实现了图片的按需加载。

  1. 懒加载 懒加载是指图片在进入浏览器可视区域时才进行加载。在Webpack项目中,可以使用react - lazyload(以React项目为例)来实现图片懒加载。首先安装:
npm install react - lazyload --save

然后在组件中使用:

import React from'react';
import LazyLoad from'react - lazyload';

const MyComponent = () => {
    return (
        <div>
            <LazyLoad>
                <img src="path/to/image.jpg" alt="Lazy Loaded Image" />
            </LazyLoad>
        </div>
    );
};

export default MyComponent;

react - lazyload会自动监听图片是否进入可视区域,当进入时才加载图片,从而提升页面的初始加载性能。

图片的雪碧图(Sprite)技术

  1. 雪碧图原理 雪碧图(Sprite)是将多个小图标合并成一张大图片,通过CSS的background - position属性来显示不同的图标。这样可以减少HTTP请求次数,因为浏览器每次请求图片都需要建立连接、发送请求、接收响应等过程,减少请求次数能有效提升性能。例如,一个页面中有10个小图标,如果每个图标单独作为一张图片,就需要10次HTTP请求,而将它们合并成一张雪碧图,只需要1次请求。
  2. Webpack中使用雪碧图 在Webpack中,可以使用css - sprites - webpack - plugin来生成雪碧图。首先安装:
npm install css - sprites - webpack - plugin --save - dev

然后在Webpack配置文件中:

const path = require('path');
const CssSpritesWebpackPlugin = require('css - sprites - webpack - plugin');

module.exports = {
    //...其他配置
    plugins: [
        new CssSpritesWebpackPlugin({
            spritePath: path.join(__dirname, 'dist/images/sprite.png'),
            spriteSheetName: 'sprite.css',
            algorithm: 'binary-tree',
            stylesheetPath: path.join(__dirname, 'dist/css'),
            spriteLayout: 'diagonal',
            retina: true
        })
    ]
};

上述配置中,spritePath指定了雪碧图的输出路径,spriteSheetName指定了生成的CSS文件名称,algorithm指定了合并图片的算法,stylesheetPath指定了CSS文件的输出路径,spriteLayout指定了图片在雪碧图中的排列方式,retina设置为true表示支持视网膜屏。

Webpack中字体资源的性能优化技巧

字体资源同样会影响页面的加载性能,特别是一些自定义字体。以下是在Webpack中优化字体资源的技巧。

字体格式选择

  1. 常见字体格式
    • TrueType(.ttf):是一种广泛支持的字体格式,几乎所有现代操作系统和浏览器都支持。它提供了高质量的字体渲染,适用于各种场景。例如,很多网站使用TrueType字体来展示正文内容,能保证在不同设备上都有较好的显示效果。
    • OpenType(.otf):与TrueType类似,但在字体设计和排版功能上更强大。它也具有良好的兼容性,常用于专业的排版和设计领域。一些高端的印刷字体或具有复杂排版需求的字体可能会采用OpenType格式。
    • Web Open Font Format(.woff)和.woff2:这两种格式是专门为Web设计的。.woff2是.woff的升级版,具有更高的压缩率。在相同字体文件内容下,.woff2文件大小通常比.woff小30% - 40%。例如,一个100KB的.woff字体文件,转换为.woff2格式后可能只有60 - 70KB。它们在现代浏览器中得到了广泛支持。
  2. Webpack中字体格式配置 在Webpack中,可以使用file - loaderurl - loader来处理字体文件,并指定输出的字体格式。以下是一个示例配置:
module.exports = {
    module: {
        rules: [
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'file - loader',
                        options: {
                            name: 'fonts/[name].[ext]'
                        }
                    }
                ]
            }
        ]
    }
};

上述配置将woffwoff2eotttfotf格式的字体文件输出到fonts目录下,并保持原文件名和扩展名。如果想使用url - loader,可以进行如下配置:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'url - loader',
                        options: {
                            limit: 8192,
                            name: 'fonts/[name].[ext]'
                        }
                    }
                ]
            }
        ]
    }
};

这里limit设置为8192(单位为字节,即8KB),表示如果字体文件小于8KB,会将其转换为Data URL嵌入到CSS或JavaScript文件中,减少HTTP请求;如果大于8KB,则会以文件形式输出。

字体子集化

  1. 字体子集化原理 字体子集化是指从完整的字体文件中提取出页面实际使用的字符子集,生成一个较小的字体文件。例如,一个完整的中文字体文件可能有几MB大小,但如果页面只使用了部分常用汉字,通过子集化可以将字体文件减小到几十KB甚至更小。这样可以显著减少字体文件的体积,加快页面加载速度。
  2. Webpack中字体子集化实现 在Webpack中,可以使用fonttools库来实现字体子集化。首先安装fonttools
npm install fonttools --save - dev

然后可以编写一个自定义的Webpack loader来进行字体子集化。以下是一个简单的示例:

const fonttools = require('fonttools');
const path = require('path');

module.exports = function (source) {
    const callback = this.async();
    const fontPath = path.join(this.context, this.resourcePath);
    const textToSubset = '这里填写页面中实际使用的字符';

    fonttools.ttf.subset(fontPath, {
        text: textToSubset,
        output: fontPath
    }).then(() => {
        callback(null, source);
    }).catch((error) => {
        callback(error);
    });
};

上述代码定义了一个Webpack loader,它会读取字体文件,并根据textToSubset中指定的字符进行子集化处理。在Webpack配置文件中,将该loader添加到字体文件的处理规则中:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(ttf)$/,
                use: [
                    {
                        loader: path.resolve(__dirname, 'font - subset - loader.js'),
                    },
                    {
                        loader: 'file - loader',
                        options: {
                            name: 'fonts/[name].[ext]'
                        }
                    }
                ]
            }
        ]
    }
};

这样,在Webpack打包过程中,.ttf字体文件会先经过子集化处理,然后再按照file - loader的规则输出。

字体加载策略

  1. 异步加载字体 异步加载字体可以避免字体加载阻塞页面的渲染。在Webpack项目中,可以通过动态导入字体文件来实现异步加载。例如,在CSS中使用@font - face引入字体时:
@font - face {
    font - family: 'MyFont';
    src: url('./fonts/myfont.woff2') format('woff2'),
         url('./fonts/myfont.woff') format('woff');
    font - weight: normal;
    font - style: normal;
}

在JavaScript中,可以动态导入该CSS文件:

const loadFont = async () => {
    await import('./styles/font.css');
};

loadFont();

这样,字体文件的加载不会阻塞页面的初始渲染,提升了用户体验。

  1. 字体加载优先级 合理设置字体加载优先级可以确保页面在字体加载过程中有较好的显示效果。通常可以先使用系统默认字体进行渲染,当自定义字体加载完成后再替换。例如:
body {
    font - family: Arial, sans - serif;
}

@font - face {
    font - family: 'MyFont';
    src: url('./fonts/myfont.woff2') format('woff2'),
         url('./fonts/myfont.woff') format('woff');
    font - weight: normal;
    font - style: normal;
    font - display: swap;
}

body {
    font - family: 'MyFont', Arial, sans - serif;
}

这里font - display: swap表示字体加载过程中,先使用系统默认字体显示文本,当自定义字体加载完成后再切换为自定义字体,避免了文本在字体加载过程中长时间空白的问题。

字体文件的压缩

  1. 压缩工具 与图片类似,字体文件也可以进行压缩。对于.woff2格式的字体文件,可以使用woff2_compress工具进一步压缩。首先安装:
npm install woff2_compress --save - dev

然后可以编写一个自定义的Webpack插件来调用该工具进行压缩。以下是一个简单示例:

const woff2Compress = require('woff2_compress');
const path = require('path');

class FontCompressPlugin {
    apply(compiler) {
        compiler.hooks.emit.tap('FontCompressPlugin', (compilation) => {
            const fontsDir = path.join(__dirname, 'dist/fonts');
            const fontFiles = Object.keys(compilation.assets).filter((fileName) => fileName.endsWith('.woff2'));
            fontFiles.forEach((fontFile) => {
                const fontPath = path.join(fontsDir, fontFile);
                const fontBuffer = compilation.assets[fontFile].source();
                const compressedFont = woff2Compress(buffer);
                compilation.assets[fontFile] = {
                    source: () => compressedFont,
                    size: () => compressedFont.length
                };
            });
        });
    }
}

module.exports = FontCompressPlugin;

在Webpack配置文件中添加该插件:

module.exports = {
    //...其他配置
    plugins: [
        new FontCompressPlugin()
    ]
};

上述插件会在Webpack打包生成字体文件后,对.woff2格式的字体文件进行压缩,进一步减小文件体积。

  1. 压缩效果与权衡 字体文件的压缩可以显著减小文件体积,但也可能会对字体的渲染质量产生轻微影响。在实际应用中,需要根据项目需求和目标用户群体进行权衡。如果项目对字体质量要求极高,可能需要适当降低压缩程度;如果对加载速度更为关注,且用户设备和浏览器兼容性较好,可以采用较高的压缩比。同时,在不同浏览器和设备上进行测试,确保字体显示效果符合预期。

通过上述对图片和字体资源在Webpack中的性能优化技巧,可以有效提升前端项目的加载性能和用户体验。在实际项目中,需要根据具体情况综合运用这些技巧,并不断进行测试和优化。