• externals
  • dll
  • gzip
  • CDN


externals

Applicable scenario

Considering that some third-party libraries will not change frequently in the short term, there is no need to package them every time, just through JS.

Configuration (location: module.exports->externals)

After eject exposes the webpack configuration, the externals configuration item does not exist under module.exports. You need to manually add the externals configuration item.

webpack.config.prod.js

externals: {
	jquery: 'jQuery',
	axios: 'axios',
	moment: 'moment'
}Copy the code

This configuration takes some third-party dependent libraries in the code, such as jquery, Axios and moment, and does not package them. Instead, it manually introduces the corresponding CDN JS into the HTML, as follows:

<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="# 000000"> <! -- manifest.json provides metadata used when your web app is added to the homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <! -- Notice the use of %PUBLIC_URL%inthe tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public`  folder can be referenced from the HTML. Unlike"/favicon.ico" or "favicon.ico"."%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>Gearbest Influencer Program</title>
    <link rel="stylesheet" href="//at.alicdn.com/t/font_975949_zge2u562xp.css">
    <script src="//at.alicdn.com/t/font_975949_zge2u562xp.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
    <script src="https://cdn.bootcss.com/moment.js/2.24.0/moment.min.js"></script>
</head>
<body>
<noscript>
    You need to enable JavaScript to run this app.
</noscript>
<div id="main"></div> <! -- This HTML file is a template. If you open it directlyin the browser, you will see an empty page.

  You can add webfonts, meta tags, or analytics to this file.
  The build step will place the bundled scripts into the <body> tag.

  To begin the development, run `npm start` or `yarn start`.
  To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>Copy the code

Among them

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.bootcss.com/moment.js/2.24.0/moment.min.js"></script>Copy the code

These three lines of code introduce jquery, Axios and Moment, respectively. Links to CDN JS for third-party libraries like these can be found at www.bootcdn.cn/. However, not all third-party dependent libraries can be successfully introduced in the way of CDN JS. It is necessary to verify which third-party dependent libraries can be introduced in the way of CDN JS through practice.

contrast

Package diagram without externals configuration (original)





The package plan configured on externals is used





It is obvious from the figure that jquery is not packed after the externals configuration is introduced, and the size of the main package is reduced from 902.68KB to 822.95KB, a reduction of 8.83%.

dll

Applicable scenario

Considering that some third-party dependent libraries will not change frequently in the short term, there is no need to package each time, but can be introduced separately through DLLS (similar to the concept of dynamic link libraries in C/C++ language). This is another implementation of externals.

Configuration (location: module.exports->plugins)

Create the webpack.dll.config.js file under the config directory as follows:

// webpack_dll.config.js
const paths = require('./paths');
const DllPlugin = require('webpack/lib/DllPlugin'); Module.exports = {entry: {// react: ['react'.'react-dom'.'react-redux'.'redux-saga'.'react-router'.'video-react'.'jquery'.'axios'.'bizcharts'],
		react: ['react'.'react-dom'.'redux-saga'.'video-react'],
		// polyfill: ['core-js/fn/promise'.'whatwg-fetch']
	},
	output: {
		filename: '[name].dll.js'DLL. Js path: paths.appPublic,// Generate the target path for the DLL file. This project is stored in the public directory library:'_dll_[name]'}, plugins: [new DllPlugin({name:'_dll_[name]', // DLL global variable name path: paths.apppublic +'/[name].manifest.json',// Describe the generated manifest file, also stored in the public directory})]};Copy the code

The above configuration can save the generated DLL file (react.dll. Js) and the corresponding manifest.json file (react.manifest.json) to the public directory, so that the file can be directly packaged into an HTML file during the entire project build.

Add DLL commands to package.json

"scripts": {
  "start": "set PORT=3001 && node scripts/start.js"."build": "node scripts/build.js"."test": "node scripts/test.js --env=jsdom"."lint": "eslint --ext .jsx --ext .js src --fix"."dll": "webpack --config config/webpack.dll.config.js"// DLL package command, --config parameter is DLL configuration file path}Copy the code

Type the YARN DLL on the console to generate the DLL file (react.dll.js).



Manually import the DLL file (react.dl.js) to the end of the body tag of the corresponding HTML file

<! DOCTYPE html> <html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="# 000000"> <! -- manifest.json provides metadata used when your web app is added to the homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <! -- Notice the use of %PUBLIC_URL%inthe tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public`  folder can be referenced from the HTML. Unlike"/favicon.ico" or "favicon.ico"."%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>Gearbest Influencer Program</title>
    <link rel="stylesheet" href="//at.alicdn.com/t/font_975949_zge2u562xp.css">
    <script src="//at.alicdn.com/t/font_975949_zge2u562xp.js"></script>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div> <! -- This HTML file is a template. If you open it directlyin the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
    <script src="%PUBLIC_URL%/react.dll.js"></script>
  </body>
</html>Copy the code

PUBLIC_URL is the public directory.

After YARN Build, the directory structure of the packaged file is as follows:

Build ├─ Manifest.json ├─ Favicon.ico ├─ index.html ├─ login. HTML ├─ main.html ├─ Manifest.json ├─ react.dll The react. The manifest. Json ├ ─ register. HTML ├ ─ service - worker. Js └ ─ static ├ ─ CSS │ ├ ─ index. 7 dc833cb. CSS │ ├ ─ Index.7dc833cb.css.map │ ├─ Login.2FF64C8e.css │ ├─ Login.2FF64c8e.cs.map │ ├─ Main.c8e56e47.css │ ├─ Login.2FF64C8e.css │ ├─ Login.2FF64c8e.cs.map │ ├─ Login.c8e56e47.css │ ├─ Main. C8e56e47. CSS. The map │ ├ ─ register. E54b83db. CSS │ └ ─ register. E54b83db. CSS. The map ├ ─ js │ ├ ─ index. E6968086. Js │ ├ ─ Index.e6968086.js.map │ ├─ Login.67bdfb3a.js │ ├─ Login.67bdfb3a.js.js │ ├─ Main.4a5C410c.js │ ├ ─ register. 5 d9dd95a. Js │ └ ─ register. 5 d9dd95a. Js. Map └ ─ media ├ ─ GB_bg. C4c2913b. PNG ├ ─ iconfont. 26 b4e298. The eot ├ ─ Iconfont. 3 e355800. SVG ├ ─ iconfont. 5cd├─ img08.22d05748.png ├─ img08.22d05748.png ├─ login_bg.165CC596.jpgCopy the code

The react.dll. Js and react.manifest.json files are copied directly from the public folder without being packaged.

contrast

Package diagram using DLL configuration





As can be seen from the packaging diagram, the original two third-party dependency libraries react-DOM and video-react are not packaged, and the size of the index package is reduced from 460.75KB to 408.67KB, a reduction of 11.3%.

Some thoughts on externals and DLL optimization

The original intention of webpack optimization using externals and DLLS is to extract some common third-party dependency packages and introduce them into the project independently by CDN or in the form of dynamic link libraries, so that they do not need to be packed into the main package (build/dist folder) every time. However, it still needs to be manually introduced in the HTML file. When the page is loaded and rendered, not only the main CSS and main JS should be downloaded, but also the corresponding CDN JS or the corresponding DLL JS, which undoubtedly may make the page white screen longer.

gzip

It can be found that the above two methods are both attempts to optimize the performance of the first screen of the page from the perspective of the client (separation of front-end third-party dependent libraries), but gZIP (and the CDN method to be introduced next) is a solution to optimize the first screen of the page from the perspective of the server. Gzip focuses on configuration optimization of Nginx. The following will take my nginx as an example to introduce this solution in detail.

Nginx master configuration file



nginx.conf



Nginx configuration file node_react.conf in /etc/nginx/vhost, we include the nginx configuration file. This method is easier to manage and maintain and reduces configuration pollution. Go to the directory.



In this directory, I focus on node_react.conf and gzip.conf, where the former is my nginx configuration file and the latter is gzip configuration file.

My front-end project nginx configuration file

node_react.conf



Take a closer look at the Gzip configuration file

Gzip configuration file

gzip.conf



# open gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
# gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";

# GZIP cache for file filtering of different formats
location ~* ^.+\.(ico|gif|jpg|jpeg|png|webp)$ { 
	access_log   off; 
	expires      30d;
}	

location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
	access_log   off;
	expires      24h;
}	

location ~* ^.+\.(html|htm)$ {
	expires      1h;
}
# open gzipCopy the code

Determines whether the gzip method is enabled

Open Customize Control DevTools, switch to Network, and find the Content-Encoding column.



If the Content-Encoding column is not found, follow the steps shown below



The following figure shows a screenshot of DevTools with Gzip disabled



The following figure shows a screenshot of DevTools with Gzip enabled



In the content-Encoding column in DevTools->Network, gzip is enabled on the server.

Determines whether the caching method is enabled



How to determine the page first screen time and page white screen time

Perhaps the reader will have a question! By what means can we accurately get the data of page first screen time and page white screen time? How do you determine when the first screen of a page ends? In fact, I had these questions at first, but after consulting materials and studying Customize Control DevTools in Google’s browser, I came up with a simple and feasible method to recommend to everyone.

  • Open Google Chrome, Ctrl+Shift+Delete clear cache (Clear the cache before recording the first screen time and white screen time), click F12 to entercustomize control DevToolsOn the Performance panel, click the bookmark saved in advance to open the web page or enter the url, and click at the same timeDevToolsThe gray circular button on the upper left of the interface will then turn into red and flash, and start to record the page loading time. At this time, loading will appear in the title of the page.



  • When the loading circle at title of the page ends and the favicon icon appears, click the bright red circular button at the upper left of DevTools interface to stop recording the page loading time and the time chart appears at the bottom. Move the left time cursor to the far right and the right time cursor to the far right. Observe the time Range at the bottom to get the time on the first screen of the page.



  • Then move the time cursor on the right to the green vertical line in the middle and observe the time Range at the bottom to obtain the blank screen time.



Here, a wave of page top (white) screen time tour officially announced the end, DO you know how to learn? Of course, we can also use specific tools to analyze the performance of our web pages. Here are some recommended Google plugins:

  • PageSpeed Insights (with PNaCl)

  • app.telemetry Page Speed Monitor

  • SEO Analysis & Website Review by WooRank



To save space, I won’t go into the details of each plug-in here, so you can do your own research.

Scheme comparison

After the test, we found that when the client requests static resources (CSS, JS, images) at the front end of the server, gZIP can be compressed with high quality, which greatly reduces the bandwidth pressure and thus greatly reduces the page blank screen time. This conclusion will be verified from a set of data below. Before providing the test data and charts, brief description of scheme 1, Scheme 2, Scheme 3, Scheme 4, Scheme 5, Scheme 6, Scheme 7-1, scheme 7-2 and Scheme 8 mentioned below is required.

  • Scenario 1: Raw Webpack (after eject, no processing) + gzip not enabled

  • Scenario 2: Raw Webpack (after eject, nothing is done) + open gzip

  • Solution 3: the original webpack (eject, do not make any processing) + failed to open the gzip + GB_bg. PNG/img07 PNG/img08 PNG replacement for CDN address + [for the index after packaged. Js CDN address to replace 】

  • Solution 4: original webpack (eject, do not make any processing) + open gzip + to GB_bg. PNG/img07 PNG/img08 PNG replacement for CDN address + [for the index after packaged. Js CDN address to replace 】

  • Solution 5: the original webpack (eject, do not make any processing) + open gzip + to GB_bg. PNG/img07 PNG/img08 PNG replacement for CDN address + [index after the wrong packaging. Js CDN address to replace 】

  • Solution 6: Original WebPack (after eject, no processing) + Enable gzip+ IMG07 / IMG08 Image lazy loading

  • Solution 7-1: Original WebPack (no processing after eject) + Enable gzip+ IMG07 / IMG08 Image lazy loading +GB_bg.png-> gb_bg.jpg
  • Solution 7-2: Original WebPack (with no processing after eject) + Enable gzip+ IMG07 / IMG08 Image lazy loading +GB_bg.png-> gb_bg.webp

  • Solution 8: Original Webpack (with no processing after eject) + Gzip +img07/img08 Image lazy loading +GB_bg. PNG -> gb_bg. webp Replace the CDN address

Yet to gzip








Open the gzip







The above data conducted a GZIP performance comparison test on the two pictures and the main CSS file in my front-end project. The device was my laptop and the network was my residence WIFI.

From the data, it can be seen that compared with not enabling Gzip, the optimization of gzip is significantly reduced the time of downloading static resources. The download time of index.css decreased by 87.88% and the download time of index.js decreased by 59.41%. The file size of index.css decreased from 175KB to 33KB, which is 81.14% smaller. The file size of index.js decreased from 1536KB to 525KB. A 65.82% weight loss.

Furthermore, we only pay attention to the first screen time and the white screen time of this group of data. It can be seen that the index data of the former decreases from 25.208 seconds to 18.253 seconds, a decrease of 27.59%, and that of the latter decreases from 14.454 seconds to 6.02 seconds, a decrease of 58.35%. In particular, the decline of the page white screen time has been a very good result.

Analysis of the

We already know that the server-side GZIP solution can significantly reduce the time to white screen and greatly optimize the performance of the first screen, so why can achieve such performance optimization? Before answering this question, let’s first think about what causes the slow loading of the front screen? If you think about it carefully, before loading the first screen, the browser will first go to the server to download the main CSS, the main JS file, any of these two file download speed is slow will cause the page blocking, resulting in the page first screen loading slow. The server side GZIP just can solve this problem, it uses efficient compression algorithm (should also have a part of the cache, this part will not be explored), can greatly reduce the speed (or volume) of static resources to the client side, play the role of acceleration (or slimmer).

CDN

What is the CDN

The full name of CDN is Content Delivery Network, i.e
Content delivery network. CDN is an intelligent virtual network built on the basis of the existing network. It relies on the edge servers deployed in various places, through the central platform of load balancing, content distribution, scheduling and other functional modules, users can get the content nearby, reduce network congestion, and improve user access response speed and hit ratio. The key technologies of CDN mainly include content storage and distribution. — from Baidu

Application scenarios of CDN in the front-end domain

CDN is applied in the front-end field, mainly to accelerate the process of downloading static resources, so as to achieve the effect of optimizing the first screen. Generally, with the support of CDN, the downloading process of static resources will be greatly accelerated, so as to optimize the performance of the first screen. Combined with the actual situation, we can choose to accelerate the global CDN of the whole front-end project, or accelerate the local CDN of some JS files or pictures.

Scheme comparison and data analysis

A set of test data is given below. The test device is my laptop and the test network is my residence WIFI.

Not enabling GZIP + CDN (Reserving abnormal data)







Gzip + CDN not enabled (remove abnormal data)







It can be seen from the above test data that although CDN scheme can achieve ideal performance optimization effect (after the removal of abnormal data, compared with scheme 1, the first screen time of the page is reduced by 50.02% and the white screen time of the page is reduced by 61.94%), it is not stable enough. There are two data anomalies in 12 tests, and the anomaly rate is as high as 16.67%. There was even a time when the first screen didn’t load for 3 minutes.

In order to achieve the maximum performance optimization effect, we can combine GZIP and CDN into our front-end project. A set of test data of this combination is given below.

Enabling GZIP + CDN (Reserving Abnormal Data)







Enable GZIP + CDN (Remove abnormal data)







Although this scheme can achieve large optimization results, its stability still needs to be improved (the anomaly rate is as high as 23.08%), which depends on the stability of THE CDN network. If the stability of the CDN network reaches an ideal degree, the optimization effect of the first screen can be improved by more than 50% at least. In order to compromise stability and optimize performance, scheme 5 is presented here, that is, “After the original Webpack (eject, Do not make any processing) + open gzip + to GB_bg. PNG/img07 PNG/img08 PNG replacement for CDN address + [index after the wrong packaging. Js CDN address to replace 】 “local CDN solution, the test data of the scheme are as follows.

Enable gZIP + local CDN







First round performance comparison

Based on the above five schemes, the first round performance comparison is given.





Can be seen from the bar chart, plan 4 although performance improvement is the largest, but less stable (depending on the stability of the CDN network), plan 4 5 second only to the margin of performance improvement, and relatively stable, a good compromise between the stability and performance improvements in two aspects, the CDN network to enhance the reality of application scenarios, can yet be regarded as an ideal solution.

Lazy loading of images

If some images on the first screen do not need to be displayed immediately in the viewable area, we can reduce the loading time of the first screen by using image lazy loading. Img07 and IMG08 in this project, there are two images img07 and IMG08 that don’t need to be displayed immediately in the viewable area of the first screen. They can be loaded lazyly by sliding the mouse into the area where the image is. Img07 and IMG08 are lazy loading based on lazy loading images and videos. The first screen performance is tested as follows:







As can be seen from the data, compared with scheme 2, the first screen time of the page in this scheme is reduced by 1.033 seconds, a decrease of 5.66%, which is the time saved by lazy image loading.

Convert image format

By converting images to a format with higher encoding performance and smaller size, the loading time of the first screen can also be effectively reduced. For example, after converting PNG format to JPEG format or webP format, the file will become smaller. There are a few ways to convert PNG images to JPEG or webP, but I recommend a Google extension called Convertio, which makes it easy to convert multiple image formats. Using this tool, I specially converted one of the largest background images in the first screen of this project, GB_bg.png, into JPEG format and webP format, as shown below



As can be seen from the figure, compared with the original image in PNG format, the compression rate of the JPEG format conversion image reaches 39.22%, and the compression rate of the webP format conversion image reaches an astonishing 88.12%.

Further, based on lazy loading of IMG07 and IMG08, we applied the JPEG and webP transformation graphs to the project and got a group of test data.

Jpeg conversion chart







WebP transition diagram







It can be seen that, when the transformed JPEG format images and webP format images are applied to the project, compared with scheme 2, the download time of images with the same content is reduced by 49.12% and 92.65% respectively, and the time of the first screen of the page is finally improved by 14.1% and 42.5%. This strongly supports the conclusion that converting images to a format with higher encoding performance and smaller size can effectively reduce the first screen load time.

WebP format image CDN

Let’s go ahead and replace the converted webP image with a CDN address for a set of performance tests on the front screen.







Unfortunately, we see that after replacing the converted webP images with CDN addresses, the time on the first screen of the page does not decrease, but slightly increases, indicating that not all resources are suitable for CDN. After careful analysis, the converted webP images are only 84.8KB, and the speed of downloading directly from the local server may not be slower than that of downloading from the CDN server, which leads to the phenomenon that the time of the first screen of the page increases instead of decreasing.

Ultimate Performance comparison

Ok, so much said, given so many solutions, in order to be able to more macro analysis of the overall performance of the solution, we carried out the final performance comparison of the above eight solutions.



From the final performance comparison figure, we can see that the performance of the first screen of the page in scheme 4 is the most obvious improvement, which only takes 9.656 seconds on average to complete the first screen loading. However, this scheme is not stable enough. However, if the CDN network is stable enough, the performance of the first screen of the page still has a large space for improvement. The performance improvement of the first screen of the page of scheme 7-2 is second only to that of Scheme 4, and has strong stability. This scheme has strong competitiveness in the application scenarios with limited CDN network performance. Of course, the specific choice of what plan, need to be specific to the application scenario and the status of the specific problem of specific analysis, benevolence and wisdom, there is never the best plan, only a better plan.

Refer to the article

“Performance Optimized” first screen time from 12.67s to 1.06s, how did I do it?

Taobao home page performance optimization practice

Master Webpack performance optimization in 30 minutes

Webpack optimization

Accelerated Nginx: Enable gzip and caching