{"id":6657,"date":"2022-01-18T10:43:22","date_gmt":"2022-01-18T09:43:22","guid":{"rendered":"http:\/\/blog.bart.sk\/en\/?p=6657"},"modified":"2024-01-25T14:13:12","modified_gmt":"2024-01-25T13:13:12","slug":"e-shop-speed-optimization-part-3-frontend","status":"publish","type":"post","link":"https:\/\/blog.bart.sk\/en\/e-shop-speed-optimization-part-3-frontend\/","title":{"rendered":"E-shop Speed Optimization &#8211; Part 3 (Frontend)"},"content":{"rendered":"\n<p><span style=\"font-weight: 400;\">We dedicated the<\/span><a href=\"https:\/\/blog.bart.sk\/optimalizacia-rychlosti-eshopov-cast-2-backendserver\/\"><span style=\"font-weight: 400;\"> second part<\/span><\/a><span style=\"font-weight: 400;\"> of this series to backend and server optimizations. In this article, we&#8217;ll take a look at other optimizations that apply to the frontend.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Pictures<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">Images, along with scripts, usually pose the biggest problems with website speed.<\/span><\/p>\n\n\n\n<p><b>srcset<\/b><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">We can achieve image responsiveness by using the srcset attribute.<\/span><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/Screenshot-2024-01-22-at-12.13.09.png\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/Screenshot-2024-01-22-at-12.13.09.png\" alt=\"\" class=\"wp-image-11668\"\/><\/a><\/figure><\/div>\n\n\n<p><span style=\"font-weight: 400;\">Srcset allows us to define one source image in multiple sizes. The sizes attribute defines how much space a given image takes up at different screen sizes.<\/span><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/Screenshot-2024-01-22-at-12.13.17.png\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/Screenshot-2024-01-22-at-12.13.17.png\" alt=\"\" class=\"wp-image-11669\"\/><\/a><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><b>WebP<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">The WebP format allows us to reduce the size of images without compromising their quality. Support for WebP images is high in browsers, but for IE and older Safari it&#8217;s necessary to use the picture element, where we define the webp image source as well as the jpg image source for unsupported browsers.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">For images that we use directly in css using background-image, we can use Modernizr https:\/\/modernizr.com\/download?setclasses&amp;q=webp, which detects what features are available in a browser. If a browser doesn&#8217;t support webp, the no-webp class is added to the html element and subsequently it&#8217;s possible to use the image in the basic format in these cases.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Lazy Loading<\/b><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-weight: 400;\">&lt;img loading=\u201dlazy\u201d<\/span>&gt;<\/code><\/pre>\n\n\n\n<p><span style=\"font-weight: 400;\">The loading attribute with a lazy value allows us to delay the loading of images until the images need to be loaded (the user scrolls the page and is getting closer to the image). If we apply this attribute to images that we don&#8217;t need to load as soon as possible (such as a banner image that appears at the top of the page), this technique can speed up page loading and reduce the overall amount of data transferred. The attribute is available in most browsers except Safari.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><b>CSS Styles<\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">CSS styles are a fairly large part of websites. What usually helps us with CSS optimization are various tools or frameworks that prepare optimized CSS files for us when creating a production build.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Removing Unnecessary CSS Code \/ Code Splitting<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">To reduce the total amount of CSS code, it&#8217;s a good idea to remove generally unused CSS. In addition to the generally unused CSS, we&#8217;ll probably also use CSS specific to one subpage. In this case, it&#8217;s advisable not to load this CSS on the home page and to load it only after going to the subpage that will use the given code. Of course, it also depends on the size of the particular code, if it&#8217;s a small amount, then there is no need to split the CSS.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Minification<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">By minification we can reduce file size by removing redundant characters, unifying common classes without changing the functionality of that CSS. It&#8217;s possible to minimize CSS automatically, for example with Webpack, using <\/span><a href=\"https:\/\/github.com\/webpack-contrib\/mini-css-extract-plugin\"><span style=\"font-weight: 400;\">mini-css-extract-plugin<\/span><\/a><span style=\"font-weight: 400;\"> or <\/span><a href=\"https:\/\/webpack.js.org\/plugins\/css-minimizer-webpack-plugin\/\"><span style=\"font-weight: 400;\">css-minimizer-webpack-plugin<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><b>Scripts\/JavaScript<\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">The biggest problem and the thing that slows down today&#8217;s pages is JavaScript. Therefore, this section can bring us the biggest performance improvements.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Async\/Defer<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">We can use two attributes for &lt;script&gt; tags in HTML:<\/span><\/p>\n\n\n\n<ul>\n<li><span style=\"font-weight: 400;\">async &#8211; if the browser recognizes the async attribute when parsing HTML, it downloads the content of the script in parallel and at the same time continues to parse the page, after the download is completed, it stops parsing and executes the downloaded JavaScript<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">defer &#8211; the download works similarly to async, but before executing JavaScript, the parsing of the whole HTML is completed first<\/span><\/li>\n<\/ul>\n\n\n\n<p><span style=\"font-weight: 400;\">It&#8217;s good to use async for third-party scripts. It&#8217;s good to test the defer attribute to determine whether scripts work correctly with this attribute. With our website&#8217;s scripts, there may be a ranking issue with async loading, as the scripts may be of different sizes, so the script that was originally supposed to be executed later will be executed before another script. That&#8217;s why it&#8217;s better to use the defer attribute for larger applications.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Bundle Analysis<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">The first step in optimizing JavaScript is bundle analysis. We can perform the analysis using the <\/span><a href=\"https:\/\/github.com\/webpack-contrib\/webpack-bundle-analyzer\"><span style=\"font-weight: 400;\">webpack-bundle-analyzer<\/span><\/a><span style=\"font-weight: 400;\"> utility, which will create a comprehensible list of used libraries and the sizes of these libraries.<\/span><\/p>\n\n\n<div class=\"wp-block-image hoverZoomLink wp-image-8533 size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/image1.png\" alt=\"Uk\u00e1\u017eka interakt\u00edvneho stromu vytvoren\u00e9ho pomocou webpack-bundle-analyzer\" class=\"wp-image-8533\"\/><figcaption class=\"wp-element-caption\"><span style=\"font-weight: 400;\">Example of an interactive tree created using a webpack-bundle-analyzer<\/span><\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><b>Duplicates in the Resulting Bundle<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">In case we find duplicate libraries in a bundle, we can solve these duplicates using yarn resolutions:<\/span><\/p>\n\n\n<div class=\"wp-block-image hoverZoomLink wp-image-8537 size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/image4.png\" alt=\"Vyu\u017eitie yarn resolutions\" class=\"wp-image-8537\"\/><figcaption class=\"wp-element-caption\"><span style=\"font-weight: 400;\">Utilization of yarn resolutions<\/span><\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><b>Lazy Loading<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">Similarly to the pictures, lazy loading can help us delay loading. An example of such loading might be loading an external library only after clicking on the button when the library is first used:<\/span><\/p>\n\n\n<div class=\"wp-block-image hoverZoomLink wp-image-8540 size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/image1-2.png\" alt=\"Na\u010d\u00edtanie externej kni\u017enice a\u017e po kliknut\u00ed na tla\u010didlo\" class=\"wp-image-8540\"\/><figcaption class=\"wp-element-caption\"><span style=\"font-weight: 400;\">Loading an external library only after clicking on the button<\/span><\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><b>Code Splitting<\/b><\/h3>\n\n\n\n<p><span style=\"font-weight: 400;\">It often happens that the JavaScript used on the homepage is different from the category code. Therefore, splitting the code into smaller bundles by subpages or by visible content and content below the visible content can be a great optimization. E.g. for react-router, we can use lazy for such a division in React:<\/span><\/p>\n\n\n<div class=\"wp-block-image hoverZoomLink wp-image-8541 size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/blog.bart.sk\/wp-content\/uploads\/2022\/01\/image3.png\" alt=\"Code-splitting v React vyu\u017eit\u00edm lazy\" class=\"wp-image-8541\"\/><figcaption class=\"wp-element-caption\"><span style=\"font-weight: 400;\">Code-splitting in React using lazy<\/span><\/figcaption><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\"><b>Summary<\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">Finally, I offer 5 points that can be used to achieve the best possible optimization in the shortest possible time:<\/span><\/p>\n\n\n\n<ul>\n<li><span style=\"font-weight: 400;\">Minify CSS and JS + gzip<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">Images &#8211; use loading = &#8220;lazy&#8221; and WebP format<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">Use async for external scripts and, if possible, defer as well<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">Code splitting &#8211; split CSS and JS based on individual subpages<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">Upgrade of used external libraries, removal of libraries<\/span><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><b>Resources and further reading<\/b><\/h2>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-css-tricks wp-block-embed-css-tricks\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"mNq2VnNVns\"><a href=\"https:\/\/css-tricks.com\/using-webp-images\/\">Using WebP Images<\/a><\/blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Using WebP Images&#8221; &#8212; CSS-Tricks\" src=\"https:\/\/css-tricks.com\/using-webp-images\/embed\/#?secret=QuNJUt5LfP#?secret=mNq2VnNVns\" data-secret=\"mNq2VnNVns\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/img#attr-loading\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-css-tricks wp-block-embed-css-tricks\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"VliA2L5dZ8\"><a href=\"https:\/\/css-tricks.com\/a-guide-to-the-responsive-images-syntax-in-html\/\">A Guide to the Responsive Images Syntax in HTML<\/a><\/blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;A Guide to the Responsive Images Syntax in HTML&#8221; &#8212; CSS-Tricks\" src=\"https:\/\/css-tricks.com\/a-guide-to-the-responsive-images-syntax-in-html\/embed\/#?secret=HSgZTjvZCd#?secret=VliA2L5dZ8\" data-secret=\"VliA2L5dZ8\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/HTML\/Multimedia_and_embedding\/Responsive_images\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/web.dev\/minify-css\/\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/www.growingwiththeweb.com\/2014\/02\/async-vs-defer-attributes.html\n<\/div><\/figure>\n\n\n\n<div id=\"hzImg\" style=\"background: none; line-height: 0px; overflow: hidden; padding: 5px; position: absolute; z-index: 2147483647; visibility: visible; opacity: 1; top: 1585px; left: 441px; width: auto; height: auto; cursor: pointer; pointer-events: none;\">&nbsp;<\/div>\n\n\n\n<div id=\"hzImg\" style=\"background: none; line-height: 0px; overflow: hidden; padding: 5px; position: absolute; z-index: 2147483647; visibility: visible; opacity: 1; top: 2901px; left: 500px; width: auto; height: auto; cursor: pointer; pointer-events: none; display: none;\">&nbsp;<\/div>\n","protected":false},"excerpt":{"rendered":"We dedicated the second part of this series to backend and server optimizations. In this article, we&#8217;ll take&hellip;","protected":false},"author":26,"featured_media":6660,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","csco_display_header_overlay":false,"csco_singular_sidebar":"","csco_page_header_type":""},"categories":[199,211],"tags":[227,246,228],"_links":{"self":[{"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/posts\/6657"}],"collection":[{"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/comments?post=6657"}],"version-history":[{"count":6,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/posts\/6657\/revisions"}],"predecessor-version":[{"id":7333,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/posts\/6657\/revisions\/7333"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/media\/6660"}],"wp:attachment":[{"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/media?parent=6657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/categories?post=6657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bart.sk\/en\/wp-json\/wp\/v2\/tags?post=6657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}