Introduction: In real projects, we may rarely need to configure a Webpack project from scratch, especially after the release of Webpack 4.0, zero configuration to start a project has become a standard configuration. Because zero-configuration WebPack has optimized the “packaging” and “compression” capabilities provided by the project itself, in practice we can focus more on the business level and not be distracted from optimizing the project build. However, from the learner’s point of view, we need to know what optimizations webPack has made in project construction, packaging and compression, and what performance improvements can be made over the existing default configuration. Recently, after completing the single-page application of Vue, I came up with the idea of abandoning the vuE-CLI construction configuration and optimizing webpack from scratch. I shared my thoughts and experience in the process in this article. The initial configuration of WebPack in another article I wrote earlier that taught you from scratch in WebPack 4.0, the following does not go into too much detail on the basic Configuration of WebPack.

First, the direction of optimization

1.1 Project Development

For developers, we want webPack to be a smooth development experience. For example, when changing code, we want the changes to inform the browser to refresh the page, rather than manually refreshing the page. Further, we hope that code changes will result in a partial replacement of a module, rather than an entire page refresh. This saves us a lot of time waiting for a refresh and greatly improves the efficiency of page development.

1.2 Project Deployment

When the project was deployed online, performance optimization was the focus of our consideration, and there were two directions that could be considered as the core point. One was to reduce HTTP requests. We knew that downloading a 100KB image was faster than downloading two 50KB images under the same Internet speed. We require WebPack to package multiple files into one or a small number of files; Another focus of optimization is to reduce the time of a single request, that is, to minimize the size of the request file. The performance optimization efforts in WebPack also revolve around these two broad directions. In addition, we want to continuously improve the efficiency of our build projects.

Second, improve development efficiency

2.1 Volume reduction

In the development environment, we still have certain requirements on the size of the code. A smaller size can make the loading speed faster, the development efficiency higher, and of course, the configuration is relatively simple.

Module. exports = {devServer: {contentBase: path.join(__dirname,'dist'),
        port: 9000,
        compress: true// code compression},}Copy the code

2.2 Module Hot Update (HMR)

During development, we wanted to make changes to the code in real time without having to manually refresh the page. Therefore, the use of HRM and HMR not only avoids frequent manual page refresh, but also reduces the wait for page refresh, greatly improving the development efficiency.

// webpack.dev.js
module.exports = {
  devServer: {
    compress: true,
    hot: true/ / open configuration}, plugins: [new webpack. NamedModulesPlugin (), new webpack. HotModuleReplacementPlugin (),],}Copy the code

Third, build volume optimization

3.1 SourcemAP mode in production

Webpack provides no fewer than seven sourcemap modes for builds, of which the Eval mode can improve the build efficiency, but the script after the build is too large to be suitable for production. Source-map mode can reduce the size of the script file by tracking the location of the script file through the generated.map file. This is preferred in production mode, and in production mode, we need to hide the specific script information, so we can use cheap and Module modes to do this. In summary, in the production of the Webpack devtool option, we use a cheap-module-source-map configuration

Module. exports = {mode: // webpack.pro.js exports webpack configuration script module.exports = {mode:'production',
  devtool: 'cheap-module-source-map',}Copy the code

3.2 Independent CSS Files

In terms of single-entry files, it is common to package all static resources of a page into a SINGLE JS file. This has been implemented in the optimization section of 1.2, which combines code into a single static resource and reduces HTTP requests.

Before the separation of

Webpack4.0 provides a plug-in for extracting CSS files, the mini-css-extract-plugin, which requires a simple configuration to separate CSS files

const MiniCssExtractPlugin = require('mini-css-extract-plugin'Module.exports = {··· plugins: [new MiniCssExtractPlugin({filename:"[name].[contenthash].css",
            chunkFilename: "[name].[contenthash].css"
        })
    ],
    module: {
        rules: {
            test: /\.(css|scss)$/,
            use: [process.env.NODE_ENV == 'production' ? MiniCssExtractPlugin.loader : 'style-loader', {
              loader: 'css-loader',
              options: {
                sourceMap: true}},"sass-loader"]}} ···}Copy the code
After the separation

3.3 Compress JS, HTML, CSS files

To optimize the post-build size and reduce the static resource file size, we wanted WebPack to help us reduce the file size as much as possible. For js script files, webpack4.0 starts compression by default when mode is set to ‘production’. In addition, we need to manually compress the HTML and CSS. For HTML compression, only the htmL-webpack-plugin needs to be configured.

// webpack.base.js 

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
          title: 'minHTML',
          filename: 'index.html',
          template: path.resolve(__dirname, '.. /index.html'// Collapse HTML configuration collapseWhitespace:true,
            removeComments: true,
            useShortDoctype: true]}}}),Copy the code

For CSS compression, Webpack 4.0 uses optimization-csS-assets-webpack-plugin to compress individual CSS files.

const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
    plugins: [
        new OptimizeCSSAssetsPlugin()
    ],
}
Copy the code

optimize-css-assets-webpack-plugin

3.4. Merge compressed images

After dealing with the three front-end chunks of JS, HTML and CSS, the next thing you can think of is dealing with images. As mentioned earlier, an important condition to improve performance is to reduce the number of HTTP requests, and there are often large and small images in the application to deal with, for small ICONS in the application, CSS Sprite is the first choice, all kinds of ICONS into a large picture can be very good to reduce the number of network requests. But for the image that needs to be opened independently, and the size is within a reasonable range, we can convert the image to Base64 bit encoding, embedded in CSS, can also reduce the request.

3.4.1 track base64 conversion

When processing image resources, Webpack provides two loaders file-loader and URl-loader to choose from. File-loader and URl-loader can be used to resolve the URL import problem of image files in projects. The difference between the two is that urL-loader can convert files smaller than the specified byte to DataURL, while files larger than the specified byte will still be parsed by file-loader

// webpack.base.js
module.exports = {
    module: {
        rules: [{
            test: /\.(png|jpe? g|gif|svg|ttf|woff2|woff)(\? . *)? $/, use: [{ loader:'url-loader',
              options: {
                limit: 10000, // limit size}},]},}Copy the code
3.4.2 Compress images

After processing the Base64 conversion of Sprite images and small images, Webpack can also compress large images. It is recommended to use image-webpack-Loader. The plug-in provides various forms of compression, for details, please refer to the official website documents

// webpack.base.js
module.exports = {
    module: {
        rules: [
            {
              loader: 'image-webpack-loader'Optipng: {// Use imagemin-optipng to compress PNG,enable: falseFor the closed enabled:true}, pngquant: {// Use imagemin-pngquant to compress PNG images.'65-90',
                  speed: 4
                },
              }
            }
        ]
    }
}
Copy the code

The effect comparison is as follows:

3.5 Separation of dependent libraries

In a medium – to large-sized application, third-party dependencies are terrifyingly large, accounting for more than half of the packaged files. However, these dependency modules are resources that rarely change. Similar to the logic of CSS code separation, separating third-party dependency libraries can better utilize the browser cache and improve application performance. Therefore, separating dependent modules from business code is an important part of performance optimization. In webpack4.0, the separation of dependency libraries can only be configured through optimization.splitchunks.

// webpack.pro.js
module.exports = {
    optimization: {
       splitChunks: {
          cacheGroups: {
            vendor: {
              chunks: "initial".test: path.resolve(__dirname, ".. /node_modules"),
              name: "vendor"// Use the vendor entry as the public part.true,},},},},}Copy the code

The result of the separation of common libraries

3.6 Dependency Analysis

As mentioned earlier, the third party libraries for node_modules are the ones that actually have the biggest impact on the volume of optimization analysis, and optimization in this part can greatly reduce the volume after packaging. Here, we use the latest webpack-bundle-Analyzer plug-in to analyze the packaged modules. It can bundle the packaged content into a convenient interactive tree. Through this, we can know which modules are roughly composed of a project, which modules occupy a large volume, and whether they are replaceable.

We can think about it in a couple of directions

  • 1. Determine whether dependencies are indispensable and underused in the project. In the project, we may use a huge library for a certain operation or function, which occupies a large volume but uses fewer functions. At this point we can look for a smaller, functional replacement library, or manually implement some dependent functionality to replace it.
  • 2. Whether the volume of large libraries can be reduced by customizing functions. An obvious example is Echart, echart full version of the dependence after compression also has hundreds of K, which is unacceptable. In real projects, we may only need a small amount or part of echart functions. In this case, we can make charts and download the functions used in the charts to achieve volume optimization.
  • 3. Whether some large libraries that cannot be optimized can reduce file size through external references. For example, third-party libraries that cannot be optimized, such as Bootstrap and Vue, can not only reduce the file volume, but also improve the loading speed of the website through free and open source CDN service, which is also a method to optimize the performance

3.7 Loading on Demand

In the direction of dependency analysis mentioned earlier, if the large library is indispensable and the usage is not low, we can use the form of load on demand. In this way, your code leaves at some logical breakpoint, and then references, or is about to reference, new blocks of code as soon as you have done something in those blocks. This speeds up the initial loading of the application and reduces its overall size, since some code blocks may never be loaded.

Require. Ensure () is used in Webpack to realize on-demand loading. Without on-demand loading, all scripts will be loaded at the same time during the first screen loading, which often slows down the first screen display time and brings bad user experience. For example. When a project needs to use a large diagram class library and the home page doesn’t, loading on demand is often a much better user experience than loading simultaneously.

When loading on demand is not required, our code might look like this:

import test from './components/test.vue'
import test2 from './components/test2.vue'
Copy the code

When loading on demand is turned on, our code is changed to:

const test = r => require.ensure([], () => r(require('./components/test.vue')), 'chunk1')
const test2 = r => require.ensure([], () => r(require('./components/test2.vue')), 'chunk2')
Copy the code

The Webpack configuration is changed to

Output: {... chunkFilename:'[name].[hash].js'
}
Copy the code

Instead of just one file, the compiled file becomes multiple smaller files. Each route loads a different resource. Especially in the first screen of resources to further optimize the experience of the application.

However, in practice, we need to measure the availability of on-demand according to the needs of the project. Despite the great improvement in the optimization of the first screen, on-demand splits large files into many smaller files, increasing the number of HTTP requests. This again defeats the foundation of performance optimization. So in practice, there is a trade-off, but also a trade-off.

3.8 Deleting redundant Code

At this point in code volume optimization, most of the areas that can be optimized have been optimized. Then you can grab some details and do more fine-tuning. For example, you can remove code in a project whose context is not referenced. This is called Tree Shaking optimization. In WebPack 4.0, Mode starts this optimization by default for Production. However, if you use Babel in your project, you need to turn off Babel’s parsing of the syntax. Only need to

// .babelrc

{
  "presets": [["env", { "modules": false}}]]Copy the code

Fourth, construction speed optimization

Having said how to reduce the size of a project after it is built, let’s briefly talk about how to speed up builds. In fact, webPack builds much faster with a simple configuration change. The common Settings are as follows.

4.1 Babel-Loader Construction Takes a Long time

4.1.1 Limit the scope of loader

Since babel-Loader needs to convert the syntax, which takes a long time, the first step is to limit the scope of babel-Loader so that the search and conversion of babel-Loader can locate the specified module accurately. Significantly increase build speed. Such as:

// webpack.base.js
module.exports = {
    module:{
        rules: [
            {
                test: /\.js$/,
                include: [resolve('src')],// use: {loader:'babel-loader',},},]}}Copy the code
4.1.2 Cache loader execution results

Because babel-Loader takes too long to parse the transformation, we want to cache the results of each execution. CacheDirectory (false by default) is available in the Webpack loader. When enabled, cached execution results are used.

// webpack.base.js
module.exports = {
    module: {
        rules: [
            {
            test: /\.js$/,
            include: [resolve('src')],
            use: {
              loader: 'babel-loader? cacheDirectory',},},]}}Copy the code

4.2 Resolve Resolve optimization

Webpack’s Resolve can also be configured to speed up projects. For details, see the following configuration:

  • When import ‘react’ is neither absolute nor relative in a project, specify a search path to avoid excessive queries
  • Use resolve. Alias as little as possible to set path aliases, as it will affect tree Shaking optimization
  • Suffixes auto-complete as little as possible. Reduce path query work
  • When using a third-party library that is too large and does not include a call to import Require define. You can use noParse to keep the library from being parsed by loaders
// webpack.base.js
module.exports = {
    resolve: {
      modules: [
        path.resolve(__dirname, 'node_modules'),
      ],

      extensions: [".js"], // Avoid creating new default files, use detailed file paths when coding, the code is easier to read, also helps speed up the build'index'],}, module: {noParse:function(content){
            return /jquery/.test(content)
        }
    }
}

Copy the code

Five, the concluding

The bottleneck of Webpack performance optimization is still focused on build time and build volume. As the hegemony of the build tool industry, WebPack has been constantly optimizing the build packaging process. You can also gain a deeper understanding of the Webpack tool and the knowledge of performance tuning by optimizing old projects.

Please indicate the source of reprint