First, static and dynamic import
By default, all modules that we statically import are added to the initial bundle. Modules imported using the default ES2015 import syntax will be imported statically.
import module from 'module'
In fact, we can dynamically import the components that are displayed when needed.
import("b.vue").then() //动态导入,在打包时会自动chunk
As shown above, the emoji-picker component is loaded only when the emoji is clicked.
Dynamic routing and dynamic components automatically split bundles.
2. Visibility import
In addition to user interaction, we often have components that are not visible on the initial page. A good example is lazy loading images that are not directly visible in the viewport, but only load after the user scrolls down.
3. Import during interaction (lazy loading)
Lazy loading of non-critical resources when the user interacts with the UI that needs it
Your page may contain code or data for components or resources that are not immediately necessary. For example, users cannot see parts of the user interface unless they click or scroll through certain parts of the page. Examples include modals, detail pages for lists, video players or chat widgets, third-party resources, and more
Instead of loading these resources immediately, load them at a more opportune moment, for example:
- When the user first clicks to interact with the component
- Scroll the component into view
- Or delay the loading of this component until the browser is idle (via the requestIdleCallback API).
The different methods of loading resources are summarized as follows:
- Load the resource immediately (the normal way to load a script)
- Lazy (Routes) - Loaded when the user navigates to a route or component
- Lazy (while interacting) - loads when the user clicks the UI (e.g. to show a chat)
- Lazy (in the viewport) - loads when the user scrolls to the component
- Prefetch - prefetch
- Preload - preload
Such as: third-party UI
Such as: video player embedded
e.g. certification
eg: chat widget
eg: help page
Fourth, route-based splitting
Dynamically load components based on the current route
{
path: "/home",
component: () => import(/* webpackChunkName: "home"*/ "@/components/layout/Index.vue"),
children: [
//todo
],
},
Five, bundling and splitting
Split code into reusable chunks
When building a modern web application, a bundler such as Webpack or rollup takes the source code of the application and packages it into one or more bundles,
When a user visits a website, the bundle is requested and loaded in order to display data to the user's screen.
The larger the bundle, the longer it takes for the browser engine to reach the line where the first render call is made. Until then, the user has to stare at a blank screen for quite a while, which can be... very frustrating!
We want to show the data to the user as soon as possible. Larger bundles lead to increased load time, processing time, and execution time. It would be great if we could reduce the size of this bundle in order to speed things up.
6. Interrupter Mode
Optimize initial load by pre-caching, lazy loading, and minimizing round trips
When we want to visit a website, we first have to make a request to the server to get these resources. The file pointed to by the entry point is returned from the server, which is usually the initial HTML file for our application! The browser's HTML parser starts parsing this data as soon as it starts receiving this data from the server. If the parser finds that more resources (like stylesheets or scripts) are needed, it sends another HTTP request to the server to get those resources!
Interrupter mode focuses on four main performance considerations:
- Push critical resources efficiently, minimizing round-trips to the server and reducing load times.
- Render the initial route as soon as possible to improve user experience
- Pre-cache resources in the background for frequently accessed routes to minimize requests to the server and enable a better offline experience
- Lazily load routes or resources that are not frequently requested
7. Tree Shaking
Reduce bundle size by eliminating dead code
We may add code to our bundle that is not used anywhere in the application. This dead code can be eliminated to reduce bundle size and prevent unnecessary loading of more data! The process of eliminating dead code before adding it to our bundle is called tree-shaking
Eight, Preload
Notify the browser before discovering key resources (meaning that after the key resources are loaded, the preloaded resources will be loaded.)
<link rel="preload"> way
webpackPreload: true way (Webpack 4.6.0+)
const EmojiPicker = import(/* webpackPreload: true */ "./EmojiPicker");
9. Prefetch
Acquire and cache resources that may be requested soon (meaning that after the key resources are loaded, the prefetched resources may not be loaded, and may not be loaded until specific needs)
<link rel="prefetch"> method
webpackPrefetch: true way
const EmojiPicker = import(/* webpackPrefetch: true */ "./EmojiPicker");
10. Virtual List
This is the idea of rendering only visible content rows instead of the entire list in a dynamic list. The rendered row is only a small part of the full list, and when the user scrolls, the visible content (window) moves. This can improve rendering performance.
11. Compression script
Reduce the time it takes to transfer scripts over the network
- 1. Gzip and Brotli are the two most commonly used compression js methods supported by current browsers (need to be used with nginx configuration)
- 2. Brotli provides better compression ratios at similar compression levels (but requires https, while gzip works under http)
- 3. If you use webpack to package your code, you can use CompressionPlugin to compress to gzip or use BrotliWebpackPlugin to compress to brotli, if you use rollup, use rollup-plugin-gzip plugin
- 4. Switch Gzip compression to Brotli compression, and the file size will be reduced by about 15%-25%.
- 5. compress(a + b) <= compress(a) + compress(b) - a single large bundle will provide better compression than multiple smaller bundles
HTTP data compression can be classified in different ways. One of them is lossy vs lossless.
Lossy compression means that a compression-decompression cycle causes the document to change slightly while maintaining its usability. End users are mostly unaware of this change. The most common example of lossy compression is JPEG compression of images.
Using lossless compression, the data recovered after compression and subsequent decompression will exactly match the original data. PNG images are an example of lossless compression. Lossless compression is related to text transmission and should be applied to text-based formats such as HTML, CSS, and JavaScript.
There are several tools available for minifying HTML, CSS and JS resources. Terser is a popular JavaScript minification tool in ES6+, and by default Webpack includes a plugin for this library to create minified build files.
You can also use esbuild compression, which is a faster compression method than terser. Can be 10-100 times faster
Static and dynamic compression
Minification helps reduce file size significantly, but compressing JS can provide a more significant gain. Server-side compression can be achieved in two ways.
Static Compression: Static compression can be used to pre-compress assets and save them ahead of time during the build process. Often used for compression when packing. For example, when webpack or rollup is packaged, it is compressed into gzip in advance, and then placed on nginx, and gzip_static:on is configured; in this way, when an http request is made, the gzip file will be obtained, and then the browser will decompress it and display the page.
On-the-fly compression: Through this process, compression happens dynamically when a resource is requested by the browser. It is often used for data compression in interfaces. When the interface is requested, the server compresses the data dynamically and then returns it to the browser.
Gzip and Brotli algorithms
The Gzip compression format has been around for nearly 30 years and is a lossless algorithm based on the Deflate algorithm. The Deflate algorithm itself uses a combination of the LZ77 algorithm and Huffman coding.
The LZ77 algorithm identifies duplicate strings and replaces them with a backreference, which is a pointer to where it previously appeared, followed by the length of the string. Subsequently, Huffman coding identifies frequently used citations and replaces them with citations with shorter bit sequences. Longer bit sequences are used to represent infrequently used references.
All major browsers support Gzip.
Brotli
In 2015, Google introduced the Brotli algorithm and the Brotli compressed data format. Like GZip, Brotli is a lossless algorithm based on the LZ77 algorithm and Huffman coding. Additionally, it uses second-order context modeling to produce denser compression at a similar rate. Context modeling is a feature that allows the use of multiple Huffman trees for the same alphabet in the same block. Brotli also supports larger window sizes for backreferences and has static dictionaries. These features help improve its efficiency as a compression algorithm.
Brotli is currently supported by all major servers and browsers and is growing in popularity.
Comparing gzip and brotli
The table below shows a benchmark comparison of Brotli and Gzip compression ratios and speeds for different compression levels.
enable compression
webpack configuration
module.exports = {
//...
plugins: [
//...
new CompressionPlugin()
]
}
Enable it on HTTP proxies like Nginx
server {
listen 8080;
server_name localhost;
# 需要http_gzip_static_module 模块
gzip_static on;
location / {
alias html
index index.html index.htm;
try_files $uri $uri/ /html/index.html;
}
}
The browser communicates the compression algorithms it supports via the Accept-Encoding HTTP header in the request, which indicates that the browser supports Gzip and brotli
Accept-Encoding: gzip, br
The server will return the Content-Encoding HTTP response header to indicate the compression algorithm used in the response. E.g,
Content-Encoding: br
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。