Loading Optimization
topics
- Assets Loading
- Cache
- Resource Prioritization
- Image
- Web Font
- CDN
- Lazy Loading
The purpose of Loading Optimization
The goal of loading Optimization is managing all your assets loading and rendering meaningful content within 1000ms. Multiple techniques are required to deal with it such as prioritize your assets, cache, lazy loading. However, put simply, what you are to do is that reducing file size and fetching only necessary files, and reusing fetched files as much as possible.
Assets Loading
Asset Loading significantly effects to initial rendering. You can reduce the time of the assets loading by minimizing file size, preloading, cacheing, pre-cacheing assets, and splitting code. Since you can only fetch 6 files at the same time on HTTP1, you need to minimize each consider how many files and when client loads them.
Minimized file size
Put simply, reducing file size is completed by compressing (gzip), uglifying, tree shaking and splitting code.
Compress (Gzip)
Gzip is the one of compression utilities which reduces file size. Your server or proxy server like Nginx can handle compressing files by using gzip. It is very simple to set it up. And brotli is also another way to compress the files. Some analysis say brotli cut the file size more than gzip. It compresses your files and reduce file size.
https://www.techrepublic.com/article/how-to-configure-gzip-compression-with-nginx/
https://certsimple.com/blog/nginx-brotli
Minifying, uglifying & tree shaking
Uglifying is the key to reduce the file. "Uglify" means turning your files into unreadable but still runnable code as you wrote. Setting uglifying is pretty simple. It is typically provided library so the only you need to do is including it and running it on the process building files.
Minifying is much simpler techniques. It eliminates empty space and lines. Uglify tool does minifying at the same time.
Tree shaking is much advanced functionality and it eliminates unused code. All code base is represented as tree and live code is green so it will remain on bundle file but unused code (dead code) is brown so it will fall out of bundle file.
https://webpack.js.org/guides/tree-shaking/
The downside of uglify is that unreadable code makes hard to debug. Therefore, you should upload source map besides uglified code so that you can refer the actual code.
Splitting code
Since bundle file can be huge code base, you might want to split it into small pieces. The code is typically divided based on routes, which is accomplished by dynamically importing files. Suppose you have blog posts page and user profile page on your app, you don't need javascript or css files for user profile page while user is on blog posts page. In this situation, we can split code into user.js and blog.js so the the file size of blog.js will be reduced and render quickly. Webpack2 supports dynamic import by default so that it is easily done. Moreover, commonly used files and vendor files such as loadash, react, redux, jQuery should be also splitted from your own code.
If you use react and webpack, take a look
https://webpack.js.org/guides/code-splitting/
https://github.com/thejameskyle/react-loadable
https://github.com/faceyspacey/react-universal-component
Cache
Cache is helpful to optimize performance. Basically don't fetch same content. I would not talk about HTTP cache but how to make files cache friendly and pre cache and pre load strategy according to PRPL pattern.
Cache friendly assets
The directives Cache-Control and Etag on HTTP Header have information that wether your content is modified or not. In addition, you could add finger print on the file names and explicitly tell that the content of files was changed to the browser. You also might want to add Cache-Control: max-age=31536000
and cache files for 1 year. When if the content of files is changed, fingerprint will be changed so that cache age will not affect.
Resource Prioritization
Pre Load
PreLoading is fetching the file without waiting for window loading event. At the stage of preload, you should fetch only the files you are 100% going to use such as javascript for painting the current page, vendor files, and logo image so on.
<script src="/script2.js"></script>
<link rel="preload" href="/script3.js" as="script">
At this example, script2.js is loaded on the middle of parsing HTML as default. However, if you use preload, client does not have wait for it and makes request beforehand.
You also are able to preload images and font so you can make the time of text-to-paint and content-paint shorter.
<link rel="preload" as="image" href="//images.treebohotels.com/images/homepage-desktop-banner-29-12-17.jpg?fm=pjpg&auto=compress">
https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf
https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/
https://v8project.blogspot.com/2015/07/code-caching.html
https://caniuse.com/#feat=link-rel-preload
https://github.com/filamentgroup/loadCSS
Pre Fetch
Unlike pre-load, pre-fetch does fetch the files on the background (during idle time) and store them on browser cache. Therefor, the splitted script code for other pages should be pre-fetched at this moment.
Image
Images are typically the largest files on the applications. There is several techniques to reduce file size and load images.
As we have seen before, we could preload some images. Another way is Lazy Loading.
Beforehand, let's take a look at image format available on browser.
Image Format | Colors | Image Type | Compression | Best fit |
---|---|---|---|---|
png | Full | Raster | Lossless | Content that requires full range of color and full transparency |
png(8-bit) | 256 | Raster | Lossless | Content that does not require full range of content. Icons and pixel art |
gif | 256 | Raster | Lossless | same as png(8bit) but something requires to be animated |
jpeg | Full | Raster | Lossy | Photographs |
SVG | Full | Vector | Uncompressed (server compression) | Line art, diagrams, other non graphical contents |
WebP(Lossy) | Full | Raster | Lossy | Same as JPEG but supported transparency with the potential for better compression |
WebP(Lossless) | Full | Raster | Lossless | Same as PNG with the potential for better compression |
JPEG
There is two type of JPEG. Baseline JPEG and Progressive JPEG.
Baseline JPEG is rendered gradually from top to bottom. Progressive JPEG is rendered from low resolution to high resolution.
Baseline JPEG
Progressive JPEG
WebP
WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller than comparable JPEG images at equivalent SSIM quality index.
https://jmperezperez.com/webp-placeholder-images/
SVG
SVG stands for scalable vector graphics is and XML-based markup language for two dimension images. It is useful to display line arts and easy to scale. SVG optimization is different from other raster images since SVG is text. It can be adapted same optimization as HTML such as minimize and gzip. SVGO is optimizer to delete redundant such as editor metadata, and comments, hidden elements.
Web Font
Loading web font seems simple but developers should be aware of time-to-paint-text. If you import font from css, time-to-paint-text will be delay. Fetching fonts from CDN takes time as well. Therefore, the best practice is downloading from your server (same origin) and preload it.
CDN
A CDN's mission is to virtually shorten that physical distance, the goal being to improve site rendering speed and performance.