Zephyrnet-logo

Snelle inline afbeeldingen met React en Webpack

Datum:

webpack is geweldig voor het bouwen van React-applicaties, maar wist je dat het je ook kan helpen de app-prestaties te optimaliseren? Webpack kan automatisch afbeeldingsgegevens inline plaatsen, waardoor de prestaties worden verbeterd door het aantal verzoeken dat uw pagina moet doen te verminderen. Laten we leren hoe.

Afbeelding Invoering

Normaal gesproken is elke afbeelding op een webpagina een uniek bestand dat de browser een HTTP-verzoek moet doen om weer te geven. Hoe meer verzoeken de browser moet doen, hoe langer het laden van de pagina duurt. Omgekeerd zal het verminderen van het totale aantal verzoeken over het algemeen de prestaties verbeteren.

Inlining van afbeeldingen vermindert het aantal extra verzoeken dat nodig is voor het laden van pagina's door afbeeldingsgegevens rechtstreeks in de HTML- of Javascript-bundel in te sluiten. Zoals met alles is deze optimalisatie niet gratis: het totale aantal afbeeldingsverzoeken wordt verminderd tegen de prijs van een grotere initiële payload. Dit resulteert in een prestatie-sweet spot waar kleine afbeeldingen inline zijn, maar grotere afbeeldingen normaal worden geladen met extra HTTP-verzoeken.

Hoi! Geen zin om alle in's en outs van het in vorm buigen van Webpack te lezen? Ga naar de definitieve webpack-configuratie.

Een eenvoudige reactie-app

Om beeldinlining te testen, hebben we een eenvoudige React-app gemaakt:

Basis Reageer-app-bronmap

A index.html bestand wordt gebruikt om het enkele (gecompileerde) JSX-bestand op te starten:

<html>
    <header>
        <title>React With Inline Images</title>
    </header>
    <body>
        <div class="images-container"></div>
    </body>
    <script src="index.js"></script>
</html>
import React from "react"
import ReactDOM from "react-dom/client"


import indexHtml from "./index.html"

function SomeImages(props) {
    return (
        <div>
            <h2>{props.title}</h2>
            <p>
                <h3>Some small images:</h3>
                <img src="images/small-bee.png" />
                <img src="images/small-chick.png" />
                <img src="images/small-puppy.png" />
                <img src="images/small-tree.png" />
            </p>
            <p>
                <h3>Some larger images:</h3>
                <img src="images/medium-duckling.jpg" /><br />
                <img src="images/medium-squirrel.jpg" />
            </p>
        </div>
    )
}

var containerDiv = document.querySelector(".images-container");
var root = ReactDOM.createRoot(containerDiv);
root.render(SomeImages({ title: "React with Inline Images" }));

React JSX-bestanden bouwen met Webpack

Eerst moeten Webpack- en React-afhankelijkheden worden geïnstalleerd met NPM:

npm install react react-dom
npm install --save-dev webpack webpack-cli babel-loader @babel/preset-react

Webpack compileert JSX niet uit de doos. Een moduleregel toevoegen aan webpack.config.js vertelt Webpack om Babel te gebruiken bij het compileren van JSX-bestanden. Er is een extra regel voor het kopiëren van onze bootstrap-html naar de uitvoermap. Later meer over “assetmodules”:

var path = require("path");

module.exports = {
    mode: "development",
    entry: "./src/index.jsx",
    output: {
        filename: "index.js",
        path: path.resolve("dist/"),
    },
    module: {
        rules: [
            {
                test: /.jsx?$/,
                loader: "babel-loader",
                options: {
                    "presets": ["@babel/preset-react"]
                }
            },
            {
                test: /.html$/i,
                type: "asset/resource",
                generator: {
                    filename: "[name][ext]"
                }
            }
        ]
    }
};

Hardlopen webpack vanaf de opdrachtregel compileert onze JSX in een uitvoermap met de naam dist/, maar er zijn enkele problemen die moeten worden opgelost.

Afbeeldingen importeren/vereisen

Nou, dingen werken BIJNA. Al onze afbeeldingstags worden verbroken wanneer we de gecompileerde app laden:

Webpack-afbeeldingen werken niet

En er werden geen afbeeldingen naar onze dist/ map:

Geen afbeeldingen in de uitvoermap van Webpack

Afbeeldingen worden niet weergegeven omdat Webpack de URL's niet leest src attributen. Geen van onze afbeeldingsbestanden wordt gekopieerd naar de dist/ map omdat Webpack aannam dat we verwijzen naar een externe afhankelijkheid waar het zich geen zorgen over hoeft te maken. De JSX moet de afbeeldingen importeren of vereisen, zodat Webpack weet dat we die afbeeldingen nodig hebben:

// BEFORE:
<p>
    <h3>Some small images:</h3>
    <img src="images/small-bee.png" />
    <img src="images/small-chick.png" />
    <img src="images/small-puppy.png" />
    <img src="images/small-tree.png" />
</p>
<p>
    <h3>Some larger images:</h3>
    <img src="images/medium-duckling.jpg" /><br />
    <img src="images/medium-squirrel.jpg" />
</p>

// AFTER:
<p>
    <h3>Some small images:</h3>
    <img src={require("./images/small-bee.png")} />
    <img src={require("./images/small-chick.png")} />
    <img src={require("./images/small-puppy.png")} />
    <img src={require("./images/small-tree.png")} />
</p>
<p>
    <h3>Some larger images:</h3>
    <img src={require("./images/medium-duckling.jpg")} /><br />
    <img src={require("./images/medium-squirrel.jpg")} />
</p>

Activamodules gebruiken voor afbeeldingsbestanden

En er zijn nog steeds dingen kapot. Webpack is nu op de hoogte van onze afbeeldingen, maar geeft fouten:

ERROR in ./src/images/medium-duckling.jpg 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, /
    currently no loaders are configured to process this file. /
    See https://webpack.js.org/concepts
(Source code omitted for this binary file)
 @ ./src/index.jsx 16:9-48

Webpack werkt niet omdat het niet weet wat het met onze afbeeldingsbestanden moet doen. Net als bij JSX hebben we een moduleregel nodig die Webpack vertelt wat te doen als het een afbeelding tegenkomt.

Webpack 5 heeft een nieuwe functie genaamd Activamodules die bedoeld is om de te vervangen url-loader, file-loader en raw-loader's gebruikt in Webpack 4 voor deze situatie. Om alles werkend te krijgen, vertellen we Webpack om altijd afbeeldingsbestanden naar de uitvoermap te kopiëren:


module: {
    rules: [

        {
            test: /.(png|jpg)$/i,
            type: 'asset/resource'
        }
    ]
}

Ten slotte neemt webpack afbeeldingen op in de gecompileerde uitvoer:

Webpack-uitvoermap met afbeeldingen

En onze pagina werkt:

Reageer app met afbeeldingen

Plaats alle afbeeldingen in hun eigen map

Webpack kopieert onze afbeeldingsbestanden, maar alle afbeeldingen staan ​​in de hoofdmap van de uitvoermap met onverstaanbare hashes voor namen. Nog meer afbeeldingen en de dist/ map wordt een puinhoop. We kunnen de activamodule vertellen om onze afbeeldingen een betere naam te geven en ze in hun eigen map te plaatsen:

{
    test: /.(png|jpg)$/i,
    type: 'asset/resource'
    // Added:
    generator: {
        filename: 'images/[name]-[hash][ext]'
    }
}

Nu staan ​​afbeeldingen allemaal in een aparte map met begrijpelijke namen. Het bewaren van de hash helpt bij het breken van de cache:

Webpack-uitvoermap met alle afbeeldingen in hun eigen map

Automatisch de uitvoermap van Webpack opschonen

Waarom is mijn dist-map zo rommelig? Omdat de configuratie van het webpack is gewijzigd, hebben we handmatig oude bestanden van de dist/ map. Webpack verwijdert standaard nooit oude bestanden die niet meer nodig zijn. We kunnen Webpack configureren om de dist-map automatisch op te schonen bij elke build:

output: {
    // ...snip...
    clean: true
},

Inline kleine afbeeldingen

Eindelijk werken de afbeeldingen en kunnen we doen waarvoor we hier kwamen: inline kleine afbeeldingen! De basis van Webpack asset Asset Module regelt automatisch de inlining voor ons. Webpack zal standaard alles onder de 8 KB inline plaatsen, maar we kunnen ook expliciet de drempelwaarde voor de grootte instellen. Afbeeldingen die de limiet overschrijden, worden uitgevoerd naar de dist/ map zoals ze voorheen waren:

module: {
        rules: [
            // ...snip...
            {
                test: /.(png|jpg)$/i,
                // Previously we had disabled inlining by using 'asset/resource'
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024 // Inline images under 10KB
                    }
                },
                generator: {
                    filename: 'images/[name]-[hash][ext]'
                }
            }
        ]
    }

De kleinere afbeeldingen zijn inline en de uitvoermap bevat alleen grotere afbeeldingen:

Webpack-uitvoermap met alleen grote afbeeldingen

We kunnen de Base64-gecodeerde afbeeldingen zien als we de gerenderde pagina inspecteren:

Base64-afbeeldingen in Chrome Dev Tools-inspecteur

TLDR: definitieve webpack-configuratie

Nu hebben we Webpack die automatisch afbeeldingen inline samen met een paar verbeteringen in de kwaliteit van leven. Als alles werkt, ziet onze webpack-configuratie er als volgt uit:

var path = require("path");

module.exports = {
    mode: "development",
    entry: "./src/index.jsx",
    output: {
        filename: "index.js",
        path: path.resolve("dist/"),
        clean: true
    },
    module: {
        rules: [
            {
                test: /.jsx?$/,
                loader: "babel-loader",
                options: {
                    "presets": ["@babel/preset-react"]
                }
            },
            {
                test: /.html$/i,
                type: "asset/resource",
                generator: {
                    filename: "[name][ext]"
                }
            },
            {
                test: /.(png|jpg)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024
                    }
                },
                generator: {
                    filename: 'images/[name]-[hash][ext]'
                }
            }
        ]
    }
};

Conclusie

We hebben Webpack met succes overtuigd om onze afbeeldingen automatisch inline te plaatsen. Dit verminderde het aantal netwerkverzoeken dat onze pagina moest doen, maar heeft het onze pagina sneller gemaakt? Dat is het soort vraag dat Request Metrics moest beantwoorden. Probeer het vandaag nog om te meten hoe uw site presteert voor echte gebruikers in productie.

We hebben hier slechts één manier besproken om afbeeldingen te optimaliseren, maar er zijn veel andere manieren om beeldprestaties optimaliseren.

spot_img

Laatste intelligentie

spot_img

Chat met ons

Hallo daar! Hoe kan ik u helpen?