Webpack Optimization Practice

Time:2022-5-6

preface

With the continuous iteration of the project, the project volume will become larger and larger, resulting in the project construction speed and the time for the browser to open the page. Therefore, the webpack construction needs to be optimized.

What is webpack

Webpack is a static resource packaging tool, which is responsible for packaging each module in the project into one or more files.

Speed up construction

1、 Narrow the search for files

Optimize loader configuration

Definition: webpack can only directly process code in JavaScript format. Any non JS file must be pre processed and converted into JS code before it can participate in packaging. Loader is such a code converter.
Since the file conversion operation of loader is time-consuming, it is necessary to make as few files as possible processed by loader. We can optimize the loader configuration in the following three aspects: (1) optimize regular matching (2) enable caching through the cachedirectory option (3) reduce the processed files through include and exclude. The practice is as follows:
Original configuration of the project:

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [resolve('src'), resolve('test')]
}

Optimized configuration:

// webpack.base.conf.js
{
  //1. If there is only JS file in the project source code, don't write it as / \ jsx?$/, To improve the performance of regular expressions
  test: /\.js$/,
  //2. Babel loader supports caching the converted results, which can be enabled through the cachedirectory option
  loader: 'babel-loader?cacheDirectory',
  //3. Babel loader is only used for files in SRC directory under the root directory of the project
  include: [resolve('src')],
  exclude: /node_modules/
}
Optimize resolve Modules configuration

resolve. Modules is used to configure which directories webpack goes to find third-party modules. resolve. The default value of modules is [node modules], which means to go to the / node modules directory of the current directory to find the module we want. If we don’t find it, go to the upper directory/ Find it in node modules. If you don’t have any more, go to.. // Find in node modules, and so on, which is the same as node The module search mechanism of JS is very similar. When the installed third-party modules are placed in the root directory of the project/ In the node modules directory, there is no need to search layer by layer in the default way. You can specify the absolute path to store the third-party modules to reduce the search.
Optimized configuration:

// webpack.base.conf.js
resolve: {
//Use the absolute path to indicate the storage location of the third-party module to reduce the search steps
modules: [resolve('src'), resolve('node_modules')]
},
function resolve (dir) {
   return path.join(__dirname, '..', dir)
}
Optimize resolve Alias configuration

resolve. The alias configuration item maps the original import path to a new import path through an alias.
Optimized configuration:

alias: {
  '@': resolve('src'),
},
//Through the above configuration, reference the common. Under Src JS file, you can write it directly
import common from '@/common.js';
Optimize resolve Extensions configuration

When there is no file suffix in the import statement, webpack will try to ask whether the file exists after automatically adding the suffix. The default is: Extensions: [‘. JS’,’. JSON ‘]. In other words, when encountering import statements such as import (‘. / data’), webpack will look for them first/ data . JS file. If the file does not exist, look for it/ data. JSON file. If you still can’t find it, an error will be reported. The longer the list or the later the correct suffix, the more attempts will be made, so resolve The configuration of extensions will also affect the performance of the build.
Optimization measures:

  • The suffix attempt list should be as small as possible. Do not write the impossible situations in the project into the suffix attempt list.
  • The file suffix with the highest frequency should be put first, so as to exit the search process as soon as possible.
  • When writing import statements in the source code, you should bring suffixes as much as possible, so as to avoid the search process. For example, in the case of determination, write require (‘. / data’) as require (‘. / data. JSON’)
Optimize resolve Noparse configuration

The noparse configuration item allows webpack to ignore the recursive parsing and processing of some files that are not modular. The advantage of this is to improve the construction performance. The reason is that some libraries such as jQuery and lodash are huge and do not adopt modular standards. It is time-consuming and meaningless for webpack to parse these files.
Noparse is an optional configuration item. The type should be one of regexp, [regexp] and function. For example, if you want to ignore jQuery and chartjs, the optimized configuration is as follows:

// webpack.base.conf.js
    module: {
        Noparse: '/ jquery|lodash /', // do not parse the third-party library
        rules: []
    }

2、 Use happypack multi process to parse and process files

Because there are a large number of files that need to be parsed and processed, construction is a file reading, writing and computing intensive operation. Especially when the number of files becomes more and more, the problem of slow construction of webpack will become more serious. Run on node The webpack above is a single thread model, that is to say, the webpack needs to process tasks one by one, and cannot process multiple tasks at the same time. Happy Pack (https://github.com/amireh/happypack)Webpack can do this. It decomposes the task to multiple sub processes for concurrent execution, and then sends the results to the main process after the sub processes are processed.
Configuration used by happypack in the project:

(1) Happypack plug-in installation:
    $ npm i -D happypack
(2)webpack. base. Conf.js file is not valid for module Configure rules
    module: {
     rules: [
      {
        test: /\.js$/,
        //Will be right The processing of JS file is transferred to the happypack instance with ID Babel
          use:['happypack/loader?id=babel'],
          include: [resolve('src'), resolve('test'),   
            resolve('node_modules/webpack-dev-server/client')],
        //Exclude third-party plug-ins
          exclude:path.resolve(__dirname,'node_modules'),
        },
        {
          test: /\.vue$/,
          use: ['happypack/loader?id=vue'],
        },
      ]
    },
(3)webpack. Prod.conf.js file for configuration   
    const HappyPack = require('happypack');
    //Construct a shared process pool, which contains 5 sub processes
    const HappyPackThreadPool = HappyPack.ThreadPool({size:5});
    plugins: [
       new HappyPack({
         //Using a unique identifier ID to represent the current happypack is used to process a specific type of file
         id:'vue',
         loaders:[
           {
             loader:'vue-loader',
             options: vueLoaderConfig
           }
         ],
         threadPool: HappyPackThreadPool,
       }),

       new HappyPack({
         //Using a unique identifier ID to represent the current happypack is used to process a specific type of file
         id:'babel',
         //How to deal with it JS file, the usage is the same as that in loader configuration
         loaders:['babel-loader?cacheDirectory'],
         threadPool: HappyPackThreadPool,
       }),
    ]

3、 Compress code files using paralleluglifyplugin multiprocess

When compressing JavaScript code, you need to parse the code into an ast syntax tree abstracted by object, and then apply various rules to analyze and process ast. Therefore, this process has a huge amount of calculation and time-consuming. When webpack has multiple JavaScript files that need to be output and compressed, uglifyjs was originally used to compress and then output one by one, but paralleluglifyplugin will start multiple sub processes and allocate the compression of multiple files to multiple sub processes. In fact, each sub process compresses the code through uglifyjs, but it becomes parallel execution. Therefore, paralleluglify plugin can compress multiple files faster.
Paralleluglifyplugin usage configuration in the project:

(1) Paralleluglifyplugin plug-in installation:
     $ npm i -D webpack-parallel-uglify-plugin
(2)webpack. Prod.conf.js file for configuration
    const ParallelUglifyPlugin =require('webpack-parallel-uglify-plugin');
    plugins: [
    new ParallelUglifyPlugin({
      cacheDir: '.cache/',
      uglifyJs:{
        compress: {
          warnings: false
        },
        sourceMap: true
      }
     }),
    ]

4、 Use auto refresh

With the help of automatic means, when monitoring the change of local source code file, automatically rebuild the runnable code and then control the browser refresh. Webpack has built-in these functions and provides a variety of options for us to choose from.
Configuration of automatic refresh in the project:

// webpack.dev.config.js
module: {},
devServer: {
  watchOptions: {
    //Do not listen to files or folders, support regular matching
    ignored: /node_modules/,
    //After monitoring the change, wait 300ms to execute the action
    aggregateTimeout: 300,
    //The default is 1000 queries per second
    poll: 1000
  }
}

**Relevant optimization measures:**
(1) The configuration ignores some files that do not listen, such as node_ modules。
(2)watchOptions. The higher the value of aggregatetirneout, the better the performance, because it can reduce the frequency of reconstruction.
(3) watchOptions. The smaller the value of poll, the better, because it can reduce the frequency of inspection.

5、 Open module hot replacement

Devserver also supports a technology called hot module replacement, which can achieve ultra sensitive real-time preview without refreshing the whole web page. The principle is that when a source code changes, you only need to recompile the changed module, and then replace the corresponding old module in the browser with the new output module. Module hot replacement technology improves the development efficiency and experience to a great extent.
Configuration of module hot replacement in the project:

// webpack.dev.config.js
devServer: {
  hot: true,
},
plugins: [
  new webpack.HotModuleReplacementPlugin(),
//Displays the name of the replaced module
  new webpack.NamedModulesPlugin(), // HMR shows correct file names
]

6、 Extract public code

If the third-party library and public module of each page are not extracted in the project, the project will have the following problems:

  • The same resources are loaded repeatedly, wasting user traffic and server cost.
  • Each page needs to load too many resources, resulting in slow loading of the first screen of the web page and affecting the user experience.

Therefore, we need to separate the public code of multiple pages into separate files to optimize the above problems. Webpack has built-in plug-in Commons chunkplugin, which is specially used to extract the common parts of multiple chunks. The configuration of Commons chunkplugin in our project is as follows:

// webpack.prod.config.js
//All in package The packages that JSON relies on will be packaged into the vendor JS in this file.
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function(module, count) {
    return (
      module.resource &&
      /\.js$/.test(module.resource) &&
      module.resource.indexOf(
        path.join(__dirname, '../node_modules')
      ) === 0
    );
  }
}),
//Extract the mapping relationship of code modules
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

7、 Resource compression

Resource compression includes image, HTML, JS and CSS file compression. Its function is to reduce the packaging volume, load faster, and optimize the first screen loading speed and page switching speed.

  • Image compression plug-in: image webpack loader
  • HTML compression plug-in: HTML webpack plugin
  • JS compression plug-in: uglifyjs webpack plugin
  • CSS compression plug-in: optimize CSS assets webpack plugin

(1) First install image webpack loader

npm install image-webpack-loader --save-dev

(2) Then in webpack base. Conf.js

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}

8、 Optimize sourcemap

Simply put, a source map is an information file that stores location information. That is, each position of the converted code corresponds to the position before conversion.
With it, when an error occurs, the error tool will directly display the original code instead of the converted code. This undoubtedly brings great convenience to developers.
In the development mode of webpack, the source map will be automatically opened. It will accurately capture the number of files and lines where the error code is located. This is the most important role of source map, which is automatically closed in the production environment
Sourcemap will display all the business codes. There will be security problems, so the production environment needs to be shut down.

After the project is packaged, we will package the codes of multiple files under development into one file. After compression, removing redundant spaces and Babel compilation, the compiled code will eventually be used in the online environment. Then the processed code will be very different from the source code. When there are bugs, we can only locate the compressed code, not the code in the development environment, For development, it is difficult to locate the mode, so sourcemap appears to solve the problem of bad mode code.
The optional values of sourcemap are as follows (+ more signs mean faster speed, – more signs mean slower speed, and O means medium speed)

Webpack Optimization Practice

Recommended development environment: soap module Eval source map
Recommended production environment: soap module source map
The reasons are as follows:

  • Soap: the column information in the source code has no effect, so our packaged file does not want to contain column related information. Only the row information can establish the dependency before and after packaging. Therefore, no matter in the development environment or production environment, we want to add the basic type of soap to ignore the column information before and after packaging;
  • Module: whether it is a development environment or a formal environment, we hope to locate the specific location of the bug’s source code. For example, if a Vue file reports an error, we hope to locate the specific Vue file. Therefore, we also need module configuration;
  • Soure map: source map will generate an independent soucemap file for each packaged module, so we need to add the source map attribute;
  • Eval source map: the speed of Eval packaging code is very fast, because it does not generate a map file, but it can be combined with eval. Using Eval source map will store the map file in the packaged JS file in the form of dataurl. Don’t use Eval source map in the formal environment because it will increase the file size, but in the development environment, you can try it because they pack quickly.

9、 Output analysis of construction results

The readability of the code output from webpack is very poor, and the file is very large, which gives us a headache. In order to analyze the output results more simply and intuitively, many visual analysis tools have appeared in the community. These tools show the results more intuitively in a graphical way, so that we can quickly understand the problem. Next, I will explain the analysis tool used in Vue project: webpack bundle analyzer.

First install the plugin in the project

npm install --save-dev webpack-bundle-analyzer

On webpack Add in prod.conf.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = { 
  plugins: [
     new BundleAnalyzerPlugin()
  ]
};

Finally, execute NPM run build — report to generate the analysis report as follows:

Webpack Optimization Practice

In this tree image, there will be the following contents:

  • What content does each packaged bundle file really contain? Which corresponding bundle file is the module, JS, component, HTML, CSS and img of the project finally put into.
  • Each bundle file lists the specific size of each module, component and JS, as well as the size of start size, parsed size and gzip size for optimization.

Start size: the size of the original file that has not been minify processed
Parse size: for example, uglify is used in the webpack plugin, which is the file size after minified
Gzip size: the size of the compressed file

Based on the information given above, you can intuitively see in the picture which public libraries are repeatedly packaged into different bundle files, or which one has too much impact, etc; So you can optimize your webpack packaging.

Recommended Today

Vue: treechart tree

1、 Lateral 1. Effect   2. Code 1) , treechart components {{treeData.name}} {{treeData.name}} export default { name: “TreeChart”, props: [“json”], data() { return { treeData: {} } }, watch: { json: { handler: function(Props){ let extendKey = function(jsonData){ jsonData.extend = (jsonData.extend===void 0 ? true: !!jsonData.extend); if(Array.isArray(jsonData.children)){ jsonData.children.forEach(c => { extendKey(c) }) } return jsonData; } […]