Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Fast Inline Images With React and Webpack
Request Metrics profile imageTodd H. Gardner
Todd H. Gardner forRequest Metrics

Posted on • Originally published atrequestmetrics.com on

     

Fast Inline Images With React and Webpack

Webpack is great for building React applications, but did you know it can help you optimize app performance too? Webpack can automatically inline image data, improving performance by reducing the number of requests your page needs to make. Let’s learn how.

Image Inlining

Normally, every image on a webpage is a unique file that the browser must make a HTTP request to display. The more requests the browser needs to make, the longer page loading will take. Conversely, reducing the total number of requests will generally improve performance.

Image inlining reduces the number of additional requests needed for page load by embedding image data directly into the HTML or Javascript bundle. As with anything, this optimization doesn’t come for free: The total number of image requests is reduced at the price of a larger initial payload. This results in a performance sweet spot where small images are inlined, but larger images are loaded normally with an additional HTTP requests.

Hey! Don’t want to read all the in’s and outs of bending Webpack into shape?Jump to the final webpack configuration.

A Simple React App

To test image inlining we’ve created a simple React app:

Files in a base React app
Basic React App Source Directory

Aindex.html file is used to bootstrap the single (compiled) JSX file:

<html><header><title>React With Inline Images</title></header><body><divclass="images-container"></div></body><scriptsrc="index.js"></script></html>
Enter fullscreen modeExit fullscreen mode
importReactfrom"react"importReactDOMfrom"react-dom/client"// Just to convince webpack to copy the fileimportindexHtmlfrom"./index.html"functionSomeImages(props){return(<div><h2>{props.title}</h2><p><h3>Somesmallimages:</h3><imgsrc="images/small-bee.png"/><imgsrc="images/small-chick.png"/><imgsrc="images/small-puppy.png"/><imgsrc="images/small-tree.png"/></p><p><h3>Somelargerimages:</h3><imgsrc="images/medium-duckling.jpg"/><br/><imgsrc="images/medium-squirrel.jpg"/></p></div>)}varcontainerDiv=document.querySelector(".images-container");varroot=ReactDOM.createRoot(containerDiv);root.render(SomeImages({title:"React with Inline Images"}));
Enter fullscreen modeExit fullscreen mode

Building React JSX Files with Webpack

First, Webpack and React dependencies need to be installed with NPM:

npminstallreact react-domnpminstall--save-dev webpack webpack-cli babel-loader @babel/preset-react
Enter fullscreen modeExit fullscreen mode

Webpack doesn’t compile JSX out of the box. Adding a module rule towebpack.config.js tells Webpack to use Babel when compiling JSX files. There is an additional rule for copying our bootstrap html to the output folder. More on “asset modules” later:

varpath=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]"}}]}};
Enter fullscreen modeExit fullscreen mode

Runningwebpack from the command line compiles our JSX into an output folder nameddist/, but there are some issues that need to be fixed.

Importing/Requiring Images

Well, things ALMOST work. All our image tags are broken when we load the compiled app:

Webpack Images Not Working

And no images were output to ourdist/ folder:

No images in Webpack output directory

Images aren’t displaying because Webpack doesn’t read the urls insrc attributes. None of our image files are copied to thedist/ folder because Webpack assumed we are referencing an external dependency that it doesn’t need to worry about. The JSX needs to import or require the images so that Webpack knows we need those images:

// BEFORE:<p><h3>Some small images:</h3><imgsrc="images/small-bee.png"/><imgsrc="images/small-chick.png"/><imgsrc="images/small-puppy.png"/><imgsrc="images/small-tree.png"/></p><p><h3>Some larger images:</h3><imgsrc="images/medium-duckling.jpg"/><br/><imgsrc="images/medium-squirrel.jpg"/></p>// AFTER:<p><h3>Some small images:</h3><imgsrc={require("./images/small-bee.png")}/><imgsrc={require("./images/small-chick.png")}/><imgsrc={require("./images/small-puppy.png")}/><imgsrc={require("./images/small-tree.png")}/></p><p><h3>Some larger images:</h3><imgsrc={require("./images/medium-duckling.jpg")}/><br/><imgsrc={require("./images/medium-squirrel.jpg")}/></p>
Enter fullscreen modeExit fullscreen mode

Using Asset Modules For Image Files

And, things are still broken. Webpack knows about our images now, but is throwing errors:

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

Webpack is failing because it doesn’t know what to do with our image files. Just as with JSX, we need a module rule telling Webpack what to do when it encounters an image.

Webpack 5 has a new feature calledAsset Modules which is meant to replace theurl-loader,file-loader, andraw-loader’s used in Webpack 4 for this situation. Just to get things working, we’ll tell Webpack to always copy image files to the output folder:

// Added to webpack.config.js:module:{rules:[// ...snip...{test:/\.(png|jpg)$/i,type:'asset/resource'}]}
Enter fullscreen modeExit fullscreen mode

Finally, webpack is including images in the compiled output:

Webpack output directory with images

And our page is working:

React app with images

Place All Images in Their Own Folder

Webpack is copying our image files, but all the images are in the root of the output directory with un-intelligible hashes for names. Any more images and thedist/ folder is going to be a mess. We can tell the asset module to name our images better and place them in their own folder:

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

Now images are all in a separate folder with understandable names. Keeping the hash helps with cache busting:

Webpack output directory with all images in their own folder

Automatically Clean Webpack’s Output Directory

Why is my dist directory so cluttered? As the webpack configuration has changed, we’ve manually cleaned up old files from thedist/ directory. By default, Webpack never removes old files that are no longer neeed. We can configure Webpack to automatically clean the dist folder each build:

output:{//...snip...clean:true},
Enter fullscreen modeExit fullscreen mode

Inline Small Images

Finally, images are working and we can do what we came here for: inline small images! Webpack’s baseasset Asset Module automatically handles inlining for us. Webpack will inline anything under 8KB by default, but we can also explicitly set the size threshold. Images over the limit will be output into thedist/ folder as they were previously:

module:{rules:[//...snip...{test:/\.(png|jpg)$/i,//Previouslywehaddisabledinliningbyusing'asset/resource'type:'asset',parser:{dataUrlCondition:{maxSize:10*1024//Inlineimagesunder10KB}},generator:{filename:'images/[name]-[hash][ext]'}}]}
Enter fullscreen modeExit fullscreen mode

The smaller images are inlined and the output directory only contains larger images:

Webpack output directory with only large images

We can see the Base64 encoded images if we inspect the rendered page:

Base64 images in Chrome Dev Tools inspector

TLDR: Final Webpack Configuration

Now we’ve got Webpack automatically inlining images along with a few quality of life improvements. With everything working, our webpack configuration looks like this:

varpath=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// Inline images under 10KB}},generator:{filename:'images/[name]-[hash][ext]'}}]}};
Enter fullscreen modeExit fullscreen mode

Conclusion

We successfully convinced Webpack to automatically inline our images. This reduced the number of network requests our page needs to make, but did it make our page faster? That’s the kind of question Request Metrics was built to answer.Try it out today to measure how your site performs for real users in production.

We’ve covered just one way to optimize images here, but there are many other ways tooptimize image performance.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Let's make your website fast.

We help developers, agencies, and technical marketers understand web performance and how to boost their SEO and visitor satisfaction with simple reports and recommendations.

More fromRequest Metrics

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp