{"id":840,"date":"2017-12-06T14:40:54","date_gmt":"2017-12-06T11:40:54","guid":{"rendered":"https:\/\/iamakulov.com\/notes\/?p=840"},"modified":"2017-12-06T15:57:50","modified_gmt":"2017-12-06T12:57:50","slug":"optimize-images-webpack","status":"publish","type":"post","link":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/","title":{"rendered":"How to optimize images in webpack"},"content":{"rendered":"<p>Images take <a href=\"http:\/\/httparchive.org\/interesting.php?a=All&#038;l=Nov%2015%202017\">more than a half<\/a> of the size of an average page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png\" alt=\"A pie chart. Title: \u201cAverage bytes per page per content type.\u201d Text in the bottom: \u201cTotal 3422 kB\u201d. The largest pie chart section: \u201cImages \u2013 1818 kB.\u201d\" width=\"400\" height=\"225\" class=\"alignnone size-full wp-image-846\" style=\"padding: 20px; border: 1px solid #ccc;\" srcset=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png 400w, https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled-300x169.png 300w\" sizes=\"(max-width: 400px) 85vw, 400px\" \/><\/p>\n<p>That\u2019s a lot of traffic! But with webpack, it\u2019s easy to decrease it.<\/p>\n<h1 id=\"1-inline-small-png-jpg-and-gif-images\">1. Inline small PNG, JPG and GIF images<a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#1-inline-small-png-jpg-and-gif-images\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>Use <a href=\"https:\/\/github.com\/webpack-contrib\/url-loader\"><code>url-loader<\/code><\/a> to embed small PNG, JPG and GIF images into the bundle.<\/p>\n<p><code>url-loader<\/code> converts a file (if it\u2019s smaller than the specified size) into <a href=\"https:\/\/css-tricks.com\/data-uris\/\">a Base64 URL<\/a> and inserts this URL into the bundle. This helps to avoid extra image requests (<a href=\"https:\/\/blog.octo.com\/en\/http2-arrives-but-sprite-sets-aint-no-dead\/\">which is useful even with HTTP\/2<\/a>).<\/p>\n<p>The limit of 5-10 KB is OK:<\/p>\n<pre><code >\/\/ webpack.config.js\r\nmodule.exports = {\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: \/\\.(jpe?g|png|gif)$\/,\r\n        loader: 'url-loader',\r\n        options: {\r\n          \/\/ Images larger than 10 KB won\u2019t be inlined\r\n          limit: 10 * 1024\r\n        }\r\n      }\r\n    ]\r\n  }\r\n};\r\n<\/code><\/pre>\n<h1 id=\"2-inline-small-svg-images\">2. Inline small SVG images<a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#2-inline-small-svg-images\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>Use <a href=\"https:\/\/github.com\/bhovhannes\/svg-url-loader\"><code>svg-url-loader<\/code><\/a> to embed small SVG images.<\/p>\n<p>This loader works like <code>url-loader<\/code>, but it encodes files using <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/percent-encoding\">the URL encoding<\/a> instead of the Base64 one. Because SVG is text, the result of the URL encoding is smaller.<\/p>\n<p>The limit of 5-10 KB is also OK:<\/p>\n<pre><code class=\"javascript\">\/\/ webpack.config.js\r\nmodule.exports = {\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: \/\\.svg$\/,\r\n        loader: 'svg-url-loader',\r\n        options: {\r\n          \/\/ Images larger than 10 KB won\u2019t be inlined\r\n          limit: 10 * 1024,\r\n          \/\/ Remove quotes around the encoded URL \u2013\r\n          \/\/ they\u2019re rarely useful\r\n          noquotes: true,\r\n        }\r\n      }\r\n    ]\r\n  }\r\n};\r\n<\/code><\/pre>\n<h1 id=\"3-optimize-image-size\">3. Optimize image size<a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#3-optimize-image-size\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>Use <a href=\"https:\/\/github.com\/tcoopman\/image-webpack-loader\"><code>image-webpack-loader<\/code><\/a> to make images smaller.<\/p>\n<p>This loader compresses PNG, JPG, GIF and SVG images by passing them through optimizers. Since it just pipes images through itself and doesn\u2019t insert them into the bundle, it should be used with <code>url-loader<\/code>\/<code>svg-url-loader<\/code>.<\/p>\n<p>The default loader settings are OK:<\/p>\n<pre><code class=\"javascript\">\/\/ webpack.config.js\r\nmodule.exports = {\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: \/\\.(jpg|png|gif|svg)$\/,\r\n        loader: 'image-webpack-loader',\r\n        \/\/ Specify enforce: 'pre' to apply the loader\r\n        \/\/ before url-loader\/svg-url-loader\r\n        \/\/ and not duplicate it in rules with them\r\n        enforce: 'pre'\r\n      }\r\n    ]\r\n  }\r\n};\r\n<\/code><\/pre>\n<h1 id=\"questions\">Questions<a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#questions\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p><em>\u201cWhy is this important?\u201d<\/em><br \/>\nAs I\u2019ve said, images take more than 50% of the average page size, and optimizing them is super-easy. Through, at the same time, I\u2019ve rarely seen webpack configs that do it. We seriously should always optimize them.<\/p>\n<p><em>\u201cWhat should I do?\u201d<\/em><br \/>\nGo and add these loaders to your config.<\/p>\n<p><em>\u201cAre the any side effects?\u201d<\/em><br \/>\nA couple:<\/p>\n<ul>\n<li><code>image-webpack-loader<\/code> increases the build time, so it\u2019s better to disable it during development (pass the <code>bypassOnDebug: true<\/code> option to do that)<\/li>\n<li>\n<div class='annotated-element annotated-element_has-code_no annotated-element_keep-size_no annotated-element_mobile-direction_content-then-annotation'>\n<div class='annotated-element__annotation'><a href='https:\/\/iamakulov.com\/notes\/caching\/'><img src='https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/09\/ApplicationFrameHost_2017-09-06_21-57-03-300x158.png' alt='' style='max-width: 150px'>Short basics of caching<\/a><\/div>\n<div class='annotated-element__content'>\n<p><code>url-loader<\/code> and <code>svg-url-loader<\/code> remove extra image requests, but break caching of these images and increase the JS loading\/parsing time and memory consumption. If you inline large images or lots of images, you might experience issues. (Thanks to <a href=\"https:\/\/twitter.com\/addyosmani\">Addy Osmani<\/a> for noting this.)<\/p>\n<\/div>\n<\/div>\n<\/li>\n<\/ul>\n<h1 id=\"further-reading\">Further reading<a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#further-reading\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<ul>\n<li>Addy Osmani\u2019s excellent <a href=\"https:\/\/images.guide\/\">guide on image optimization<\/a><\/li>\n<li>My article about <a href=\"https:\/\/iamakulov.com\/notes\/webpack-front-end-size-caching\/\">optimizing bundle size with webpack<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Images take more than a half of the size of an average page: That\u2019s a lot of traffic! But with webpack, it\u2019s easy to decrease it. 1. Inline small PNG, JPG and GIF images# Use url-loader to embed small PNG, JPG and GIF images into the bundle. url-loader converts a file (if it\u2019s smaller than &hellip; <a href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;How to optimize images in webpack&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[15,12],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v23.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to optimize images in webpack - Ivan Akulov\u2019s blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to optimize images in webpack\" \/>\n<meta property=\"og:description\" content=\"Images take more than a half of the size of an average page! But optimizing them is easy\" \/>\n<meta property=\"og:url\" content=\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\" \/>\n<meta property=\"og:site_name\" content=\"Ivan Akulov\u2019s blog\" \/>\n<meta property=\"article:publisher\" content=\"http:\/\/facebook.com\/iamakulov.page\" \/>\n<meta property=\"article:published_time\" content=\"2017-12-06T11:40:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-12-06T12:57:50+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/Screenshot-2017-12-6-CodePen-Post-cover-designer.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"945\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ivan Akulov\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"How to optimize images in webpack\" \/>\n<meta name=\"twitter:description\" content=\"Images take more than a half of the size of an average page! But optimizing them is easy\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/Screenshot-2017-12-6-CodePen-Post-cover-designer1-1.png\" \/>\n<meta name=\"twitter:creator\" content=\"@iamakulov\" \/>\n<meta name=\"twitter:site\" content=\"@iamakulov\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ivan Akulov\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\",\"url\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\",\"name\":\"How to optimize images in webpack - Ivan Akulov\u2019s blog\",\"isPartOf\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png\",\"datePublished\":\"2017-12-06T11:40:54+00:00\",\"dateModified\":\"2017-12-06T12:57:50+00:00\",\"author\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81\"},\"breadcrumb\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage\",\"url\":\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png\",\"contentUrl\":\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png\",\"width\":400,\"height\":225,\"caption\":\"A pie chart. Title: \u201cAverage bytes per page per content type.\u201d Text in the bottom: \u201cTotal 3422 kB\u201d. The largest pie chart section: \u201cImages \u2013 1818 kB.\u201d\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/iamakulov.com\/notes\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to optimize images in webpack\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#website\",\"url\":\"https:\/\/iamakulov.com\/notes\/\",\"name\":\"Ivan Akulov\u2019s blog\",\"description\":\"Ivan Akulov writes about his front-end experience, React, webpack, and performance optimizations.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/iamakulov.com\/notes\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81\",\"name\":\"Ivan Akulov\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f68e4cd477cef1577c339e6f09736d3a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f68e4cd477cef1577c339e6f09736d3a?s=96&d=mm&r=g\",\"caption\":\"Ivan Akulov\"},\"description\":\"I'm a software engineer specializing in web performance, JavaScript, and React. I\u2019m also a Google Developer Expert. I work at Framer.\",\"sameAs\":[\"http:\/\/iamakulov.com\",\"https:\/\/x.com\/iamakulov\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to optimize images in webpack - Ivan Akulov\u2019s blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/","og_locale":"en_US","og_type":"article","og_title":"How to optimize images in webpack","og_description":"Images take more than a half of the size of an average page! But optimizing them is easy","og_url":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/","og_site_name":"Ivan Akulov\u2019s blog","article_publisher":"http:\/\/facebook.com\/iamakulov.page","article_published_time":"2017-12-06T11:40:54+00:00","article_modified_time":"2017-12-06T12:57:50+00:00","og_image":[{"width":1800,"height":945,"url":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/Screenshot-2017-12-6-CodePen-Post-cover-designer.png","type":"image\/png"}],"author":"Ivan Akulov","twitter_card":"summary_large_image","twitter_title":"How to optimize images in webpack","twitter_description":"Images take more than a half of the size of an average page! But optimizing them is easy","twitter_image":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/Screenshot-2017-12-6-CodePen-Post-cover-designer1-1.png","twitter_creator":"@iamakulov","twitter_site":"@iamakulov","twitter_misc":{"Written by":"Ivan Akulov","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/","url":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/","name":"How to optimize images in webpack - Ivan Akulov\u2019s blog","isPartOf":{"@id":"https:\/\/iamakulov.com\/notes\/#website"},"primaryImageOfPage":{"@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage"},"image":{"@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage"},"thumbnailUrl":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png","datePublished":"2017-12-06T11:40:54+00:00","dateModified":"2017-12-06T12:57:50+00:00","author":{"@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81"},"breadcrumb":{"@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#primaryimage","url":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png","contentUrl":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/12\/untitled.png","width":400,"height":225,"caption":"A pie chart. Title: \u201cAverage bytes per page per content type.\u201d Text in the bottom: \u201cTotal 3422 kB\u201d. The largest pie chart section: \u201cImages \u2013 1818 kB.\u201d"},{"@type":"BreadcrumbList","@id":"https:\/\/iamakulov.com\/notes\/optimize-images-webpack\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/iamakulov.com\/notes\/"},{"@type":"ListItem","position":2,"name":"How to optimize images in webpack"}]},{"@type":"WebSite","@id":"https:\/\/iamakulov.com\/notes\/#website","url":"https:\/\/iamakulov.com\/notes\/","name":"Ivan Akulov\u2019s blog","description":"Ivan Akulov writes about his front-end experience, React, webpack, and performance optimizations.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/iamakulov.com\/notes\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81","name":"Ivan Akulov","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/f68e4cd477cef1577c339e6f09736d3a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f68e4cd477cef1577c339e6f09736d3a?s=96&d=mm&r=g","caption":"Ivan Akulov"},"description":"I'm a software engineer specializing in web performance, JavaScript, and React. I\u2019m also a Google Developer Expert. I work at Framer.","sameAs":["http:\/\/iamakulov.com","https:\/\/x.com\/iamakulov"]}]}},"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/840"}],"collection":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/comments?post=840"}],"version-history":[{"count":33,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/840\/revisions"}],"predecessor-version":[{"id":882,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/840\/revisions\/882"}],"wp:attachment":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/media?parent=840"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/categories?post=840"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/tags?post=840"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}