This article was originally published at github.com/bigo-fronte… Welcome attention, reprint.

What we did

Bigo Front-end Group Computing platform Front-end Group is based on the Amis framework, see the previous article github.com/bigo-fronte… , has a good improvement in research and development efficiency, but the construction speed is very slow, and it needs to be optimized. After optimization, we achieved a result of increasing webPack build speed by about 80%. Here is the comparison before and after optimization 👇

30965 ms ➡ ️ 6545 ms

The team did three things to achieve this effect:

  1. split-chunksPerform common module optimization 👇
    optimization: {
        splitChunks: {
            chunks: "all",
            cacheGroups: {
                vendorsa: {
                    chunks: 'all',
                    test: /(mobx-state-tree|react-color|react-dom-router|sortablejs|mobx-react)/,
                    priority: 100,
                    name: 'vendors-react-mobx',
                },
                venodrb: {
                    test: /lodash/,
                    priority: 100,
                    name: 'vendor-lodash',
                    chunks: 'all'
                },
            }
        }
    },
    Copy the code
  2. externalAvoid packaging large third-party dependencies into bundles 👇
    webpack.config.js: externals: [ { 'react': 'React', 'react-dom': 'ReactDOM', 'moment': 'moment', 'mobx': 'mobx', 'monaco-editor': 'monaco', 'echarts': 'echarts', 'jquery': 'jQuery', 'hls.js': 'hls', 'flv.js': 'flv', }, function (context, request, callback) { if (/^moment\/.+$/.test(request)) { return callback(null, 'root ' + 'moment'); } if (/^tinymce\/.+$/.test(request)){ return callback(null, 'root ' + 'tinymce'); } if (/^froala-editor\/.+$/.test(request)){ return callback(null, 'root ' + 'froala'); } if (/^echarts\/.+$/.test(request)){ return callback(null, Callback ();},] index.html: < script SRC = "https://unpkg.com/[email protected]/umd/react.production.min.js" > < / script > < script SRC = "https://unpkg.com/[email protected]/umd/react-dom.production.min.js" > < / script > < script SRC = "https://unpkg.com/[email protected]/min/moment.min.js" > < / script > < script SRC = "https://unpkg.com/[email protected]/min/locales.min.js" > < / script > < script SRC = "https://unpkg.com/[email protected]/lib/mobx.umd.min.js" > < / script >Copy the code
  3. rightts-loaderThe optimization of the:
    { test: /\.tsx? $/, use: [ { loader: 'ts-loader', options: { transpileOnly: true } } ], exclude: /node_modules/ }, ... plugins: [ new ForkTsCheckerWebpackPlugin(), ]Copy the code

Based on this optimization to do homework, look at some information, to see what can be optimized.

What is the webpack

Definition of website:

webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.

Webpack is a static module packaging tool for modern JavaScript applications. It starts from the entry, finds all the dependencies of the entry file, and generates a bundle file that the browser can use. The advent of WebPack makes front-end engineering even richer. Since the first release of WebPack in 2013 (V1.0.0-Beta2), it has been 8 or 9 years. It is a fairly mature tool and its ecology is relatively complete, so the front end uses Webpack very widely.

version

Try to use newer versions, which have some performance improvements and optimizations over previous versions, including Node and Webpack. Note that node.js v8.9.10-V9.11.1 ES6 Set and Map will have performance rollback issues. The LTS Node is already V14.16.0, so assume that the Node version is new and uses WP4(Webpack4). Currently, it is not recommended to immediately upgrade to WP5 for stable or already large projects. For one thing, not all plug-ins in the WebPack ecosystem can keep up with the latest version, which may cause compatibility problems. Second, webPack5 has not been widely used, and it will take some time to stabilize and mature the new version. In order to avoid unnecessary bugs, it is recommended to use WebPack4 temporarily.

Why optimize

For developers, each build does not want to take a long time, optimize the build speed can reduce development costs; For users, optimizing the number and size of bundle files can reduce user churn and improve user experience. So webPack performance optimization is a very key technical means.

Optimization means

Two measuring tools

  • speed-measure-webpack-plugin(SMPTo optimize webPack build speed, you need to know what to optimize for, and the plug-in is a tool to help you check what needs to be further optimized.
  • webpack-bundle-analyzer, although Webpack has an official versionAnalysis tools, there are many other tools available to the community, but through information, technology sharing, and project experience,webpack-bundle-analyzerIt’s a great way to show the bundle as an interactive, scalable tree, which is very easy to use.

Three optimizable phases

Webpack construction can be divided into three phases: Loader parsing -> dependency search -> packaging. We will elaborate on how to optimize the three phases respectively.

Loader resolution:

  • Include /exclude: It is not necessary for loader to convert all files in the project. Loader should be applied to the minimum number of necessary modules.

    {
        ...,
        exclude: /node_modules/
    },
    Copy the code
  • Be careful if your project uses TS-Loader, as the build speed can be time consuming if you don’t do extra configuration. The reason is that ts-Loader does type checking on all files every time it builds, and as the project gets bigger and bigger, the build speed becomes slower and slower. Set transpileOnly: true to speed up the build. This configuration only handles compilation without type checking. While type checking is the original purpose of using TypeScript, you can use the fork-ts-checker-webpack-plugin to do type checking in a separate process. It covers both performance and type checks.

  • If you are using a Babel-Loader, you can set its cache-related options such as cacheDirectory, cacheCompression, and so on.

  • Cache-loader: Uses the modifier time of the file to check whether the file has been updated, and if not, uses the contents of the cache, which is a lightweight comparison. The characteristic is that the first build is slow, and later builds are much faster. However, it should also be used with special attention, it is best used in the performance of more expensive places, otherwise it has little effect. This loader has been archived by the author, as WebPack5 has built-in cache configuration and will not be needed for future upgrades. When using cache-Loader, place it before other loaders.

  • Thread-loader: This is also used where it is more expensive. It can be used to divide the packaging task into multiple node processes and assign modules to each process at a time for multi-process build. Like cache-loader, it also needs to be placed before other loaders.

    {... }, use: ['thread-loader', // equal-size loader],},Copy the code
  • Finally, use tools as little as possible, as each Loader /plugin has its own startup time, so there will be no performance problems if you don’t use them.

Dependent search:

  • Reduce the number of entries in resolve.modules, resolve.extensions, etc., because IO operations are performance consuming;

  • Modules is set to node_modules, which tells WebPack to search the node_modules directory when parsing modules. The default value of resolve-. Extensions is [‘.wasm’, ‘.mjs’, ‘.js’, ‘.json’]. If you are using TypeScript, you still need to configure this.

    import File from '.. /path/to/file';Copy the code

Packaging: Smaller = Faster

  • SplitChunks, in line with the “small is fast” principle, make chunk packages as small as possible. Before WebPack4, you could use the CommonsChunkPlugin to avoid recurring dependencies between modules. Webpack4 had built-in optimisation.splitchunks and was available out of the box. SplitChunks have their default behavior, which is adjusted differently for different projects according to their needs. You can set different CacheGroups, the minimum number of chunks a module must share before splitting, and so on, to maximize the problem of duplicate dependencies. A simple 🌰 :

    splitChunks: {
      chunks: "all",
      cacheGroups: {
        lodash: {
          test: /lodash/,
          priority: 1,
        },
      }
    }
    Copy the code
  • Externals, which prevents certain import packages from being packaged into bundles, and instead obtains these extended dependencies externally at run time. Such as:

    externals: [
        {
            'moment': 'moment',
        }
        ...
    ]
    Copy the code

Many environmental

Production environment: Production environment focuses on compressed bundles and lightweight source maps. It is recommended that different environments write different configurations. Of course, there can be shared configurations, which can be realized by using Webpack-merge. For devTools, source-map is recommended as it performs better than inline-source-map and eval-cheap-modole-source-map. For code compression, the Terser-Webpack-Plugin is built into WP5. Now, to use WP4, you need to install the plugin. This plugin is very powerful. With no path configuration, path-info contains comments for module information in the bundle, but in large projects, this causes poor GC performance and should be turned off.

Development environment: Similarly, some production configurations are not applicable to development environments. For example, the TerserPlugin is not required because it makes no sense to compress code in a development environment; The best practice for devTools is eval-cheap-mode-source-map. My current project is relatively lightweight, but you can see the comparison:

'inline-source-map' : 5205ms VS 'eval-count-modole-source-map' : 4744msCopy the code

Although the difference is less than 1000ms, fly meat is also meat is not? And the gap will become even more pronounced as the code grows larger.

There are other ways to optimize, such as using the ES Module to make better use of WebPack’s Tree Shaking functionality; Dll, which generates separate compilation results for code that changes infrequently, but is a complicated process to configure; And the compression of pictures and so on. The above is the basic configuration for WebPack4 performance optimization, looking forward to webPack5 mature and stable day.

reference:

  • Webpack.docschina.org/guides/buil…
  • Developers.google.com/web/fundame…

Welcome to leave a message and discuss, I wish a smooth work, happy life!

I’m bigo front end, see you next time.