Recently, I am working on a cartoon project based on mobile APP for the Indonesian market.

The url is www.mangaya.mobi

After the online, the basic test no problem, open also pretty smooth. But Google Analytics reported an average load of 19 seconds!

So OMG ~ ~ started a series of explorations.

The technology stack is create-react-app,redux, React-Router, WebPack4,babel7.

We know that the loading process of a web page is roughly as follows:

So the most essential way to optimize the loading speed of web pages is to 1. Reduce the number of requests 2. Reduce the request volume size.

Reduce the number of requests

  1. Using Base64 to reduce unnecessary network requests, create-React-app actually does that for us automatically.

  1. Import files using react.lazy

  1. Lazy loading of images, using React-lazyload, is very convenient.

Reduce the request volume size

  1. The images returned in the background are in webP format, reduced in size. However, webP is only supported by Android, so our current solution is to get the user-agent information of the request at the back end. If it is ios, the image in JPG format will be returned, and if it is Android, the image in WebP format will be returned. This is mainly used for banners.

  2. Webpack processing

  • 2.1 Build time remove map files, reduce unnecessary files and prevent being viewed source code

  • 2.2 Compressing CSS and JS. Create-react-app already does this automatically. The Uglify-es used by uglifyjs-webpack-plugin is no longer maintained, replaced by a branch called Terser.

  • 2.3 The default splitChunk is chunks: ‘all’, but this will cause a large vendor file to be generated. This can be changed to separate the node file.

 splitChunks: {
        // chunks: 'all',
        chunks: "all",
        maxInitialRequests: Infinity,
        minSize: 0,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/, name(module) { // get the name. E.g. node_modules/packageName/not/this/part.js // or node_modules/packageName const packageName = module.context.match( /[\\/]node_modules[\\/](.*?) (/ / \ \ | $) /) [1]; // npm package names are URL-safe, but some servers don't like @ symbols return `npm.${packageName.replace("@", "")}`; } } }, name: false },Copy the code

In this way, although the total project size is larger, because vendor files are divided into multiple files, according to http1.1 or HTTP2 protocol, browser resources can be obtained in multiple parallel, with THE CDN, so that resource request is faster.

  • 2.4 Babel Polyfill is loaded on demand. It can be configured directly in package.json> 0.02%In the model. Can bereference
"browserslist": [
    "0.02%" >."not dead"."not ie <= 11"."not op_mini all"
  ]
Copy the code
  1. Gzip Compression If the browser supports gzip compression, the request header is loaded withAccept-Encoding:gzip. Then the server will gzip the original response, and transmit the gzip compressed response to the browser, which then carries out gzip decompression, and finally feeds back to the web page.

Resource CDN acceleration

Change the static server to Indonesian server, obviously DNS and static resources transfer faster. Finally, the CDN accelerated static resources, I put the NPM package JS on the CDN, then can also configure multi-channel CDN and other strategies.

4. Add the static resource cache to the PWA service worker

5. Font Because the font is usually large, use font display: swap. Let the user see the content in the local font first, wait for the font to load, and then replace it.

@font-face {
  font-family: 'Arvo';
  font-display: swap;
  src: local('Arvo'), url(https://fonts.gstatic.com/s/arvo/v9/rC7kKhY-eUDY-ucISTIf5PesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
}
Copy the code

For details, see font-display.

conclusion

After a period of effort, the first load time has been reduced from 19 seconds to under 10 seconds! Still need to go on…