The sea is wide by diving, the sky is high as birds fly. Hey how are you! I’m Ed Qin. πŸ˜„

The previous article introduced the basic configuration of WebPack (portal πŸš€πŸš€πŸš€). Now let’s talk about how we can improve our project build performance by optimizing configuration items.

What should be optimized?

From the actual project perspective, we are more concerned about from project development to release online. Therefore, optimization items can be divided into the following dimensions:

  • The development environment
    • Optimize the performance of code execution
    • Optimized code debugging
  • Production environment optimization
    • Optimize code packaging build speed
    • Optimize the performance of code execution

Optimize the performance of code execution (development environment)

Development server devServer

In the development environment, the main reason is for the code to be friendly to run and easy to debug, so we need to use devServer to start a local service, let the code run.

DevServer is used for project automation (auto-compile, auto-open browser, auto-refresh browser, etc.). The build package will only be compiled in memory and will not be exported. Instead, the build package will be stored in memory and deleted automatically after closing.

You need to download the package to start the development server devServer

npm i -D webpack-dev-server
Copy the code

Write the base server configuration items

DevServer: {// contentBase: resolve(__dirname, 'dist'), // port: 3000, // open: true,},Copy the code

After the configuration is complete, I can start the project. My Webpack is installed in the project dimension, so I use NPX to run it

NPX webpack will output the packing result. In the dist folder, NPX webpack-dev-server will only compile the packing in memory, with no outputCopy the code

HMR (Module hot replacement)

HMR: Hot module replacement, responsive to file changes in a timely manner to the page, freeing F5 manual refresh.

Simply set hot to true in devServer to automatically enable HMR

DevServer: {// enable HMR hot: true}Copy the code

HMR Support files:

  • Style files: You can use the HMR function. Style-loader implements the hot module replacement function by default

  • Js file: HMR function cannot be used by default

    If you modify a JS module, all JS modules will be refreshed, which obviously leads to inefficient hot replacement. We need to modify the entry JS file code so that one module changes and only that module is rebuilt, not all of them.

If (module.hot) {// If module.hot is true, HMR is enabled. Module.hot.accept ('./print.js', function() {// the method listens for changes in the print.js file. If changes occur, only this module will be repackaged. Print (); print(); }); }Copy the code
  • HTML files: the HMR function is disabled by default

Note: HTML files cannot be hot-replaced using HMR. You can modify the entry entry to introduce HTML files

entry: ['./src/index.js', './src/index.html']
Copy the code

Optimized code debugging (development environment)

Extract CSS into a separate file

The CSS-loader integrates CSS files into JS files, causing the following impacts:

1: JS file size will be large

2: you need to load JS first and then dynamically create style tags, style rendering speed is slow

Solution: use MiniCssExtractPlugin. Alternative style – loader loader, extraction of js CSS into a single file

The mini-CSS-extract-plugin needs to be introduced

npm i -D mini-css-extract-plugin
Copy the code
// webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

{
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../'
            }
          },
        ],
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/main.css'
    }),
  ]
}
Copy the code

CSS Compatibility

During development, we were writing some advanced styles that were not supported in older browsers, so we needed to introduce some loaders to help us solve this problem.

Postcss-loader postCSs-preset -env needs to be imported

npm i -D postcss-loader postcss-preset-env
Copy the code
// webpack.config.js
{
  loader: 'postcss-loader',
  options: {
    ident: 'postcss',
    plugins: () => [
      require('postcss-preset-env')(),
    ],
  },
},
Copy the code

After importing the loader, you also need to define browserslist in package.json

// package.json "browserslist": { [// Based on specific business scenarios, Match different browsers "last 1 Chrome version", "last 1 Firefox version", "last 1 Safari version"], // Production environment "production": [// compatible with most browsers ">0.2%", "not dead", "not op_mini all"]},Copy the code

Js Compatibility processing

In order to be compatible with older generation browsers, js also needs to be compatible.

Need to introduce babel-loader @babel/preset-env core-js@babel /core

{ test: /\.js$/, exclude: /node_modules/, use:[ { loader: 'babel-loader', options: { presets: [['@babel/preset-env', {// Load useBuiltIns as needed: 'usage', // Specify core-JS version corejs:{version: Targets :{Chrome: '60', Firefox: '60', IE: '9', Safari: '10', edge: '17' } } ] ], cacheDirectory:true } } ], },Copy the code

source-map

Source-map: a technique that provides a map of the source code to the code after it is built (if something goes wrong after it is built, the map can trace the source code errors)

Parameters: [the inline – | hidden – | eval -] [nosources -] [being – [module -]] source – the map

 devtool: 'eval-source-map'
Copy the code

The parameters listed above can be combined arbitrarily, and each combination is different. There can be seven common combinations

With all these patterns, what’s the right combination?

Finally, the best two solutions

1: Eval-source-map (high integrity, fast)

2: eval-cheap-module-souce-map (error ignores columns but contains other information, fast)

Configure esLint code style checking

Team development, specification is essential. Personally, I think ESLint is too strict and recommend that teams write a set of ESLint rules based on their own situation.

Here is a popular JS style Airbnb portal πŸš€πŸš€πŸš€

Eslint-loader esLint needs to be imported

// webpack.config.js {test: /\.js$/, exclude: /node_modules/, // Ignore node_modules loader: 'eslint-loader', options: {fix: true, // automatic fix},}Copy the code

After importing the Loader, you also need to write the configuration in eslintConfig of package.json

// package.json "eslintConfig": {"extends": "airbnb-base", // Airbnb style specification "env": {"browser": True // Global variables can be used in the browser (window does not give an error)}}Copy the code

Optimize code packaging build speed (production environment)

oneOf

OneOf: no backward matching is performed on the loader to optimize the packaging and construction speed of the production environment

Babel cache

Babel cache: Cache the resources after Babel processing, so that the second package build only changes the content, other unchanged content out of the cache. Therefore, the construction speed is improved

// Enable Babel cache cacheDirectory:trueCopy the code

There is a problem: files with the same name are cached when the file name has not changed. The modified content may be inconsistent with the actual displayed content.

Solution: Use hash names and change file names to determine which files need to be updated.

The hash value is classified into hash, chunkhash, and contenthash. Contenthash is appropriate

Hash: A unique hash value is generated each time a wepack is packed.

Chunkhash: Hash value generated by the module. The hash values for the same module are the same

Contenthash: Generates hash values based on the contents of files to ensure the uniqueness of hash values for different files

Multi-process packaging

Thread-loader enables multi-process packaging for the subsequent loaders.

The thread-loader needs to be imported

Starting thread-Loader is expensive and is not recommended for common projects

npm i -D thread-loader
Copy the code
{loader: 'thread-loader', options: {workers: 2 // Enable 2 processes}},Copy the code

externals

Externals allows certain third-party libraries to be unpackaged

externals: {
  jquery: 'jQuery'
}
Copy the code

Optimize the performance of code run (production environment)

The compressed file

  • Compressed style file

    Optimize – CSS -assets-webpack-plugin needs to be introduced

      npm i -D optimize-css-assets-webpack-plugin
    Copy the code
      const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
      plugins: [
        new OptimizeCssAssetsWebpackPlugin(),
      ]
    Copy the code
  • Compressed HTML

    The HTML-webpack-plugin needs to be introduced

    The HTML-webpack-plugin automatically brings in individually packaged style files via the Link tag

      npm i -D html-webpack-plugin
    Copy the code
    const HtmlWebpackPlugin = require('html-webpack-plugin') plugins: [ new HtmlWebpackPlugin({ template: / SRC /index.html', minify: {// collapseWhitespace: true, // remove comment removeComments: true}}),]Copy the code
  • Js code is automatically compressed in production

Tree shaking

If you think of a program as a tree, the useful code or third-party library we’re using represents the green leaf. The dead code, the dead code represents the withered leaves. Tree shaking is like a big invisible hand shaking the tree down dead leaves (useless code).

Tree shaking

1: must use ES6 modularization 2: Start production environment

Under both conditions, WebPack automatically removes our useless code

You can write configuration items in package.json to control the tree swing range

// Not shaking "sideEffects": [".css", ".less"]Copy the code

The code segment

Webpack packs js code into a build.js file, which can be fatal for large projects. The build.js file is too large, resulting in long page loading times, a small change in the code to download the entire file, and many other problems.

Code splitting splits a large bundle.js file packed with output into smaller files so that multiple files can be loaded in parallel faster than loading a single file.

There are three ways to implement code splitting:

1: multi-entry split (entry entry uses multiple entry files)

entry: {
  index: './src/js/index.js',
  test: './src/js/test.js'
},
output: {
  filename: 'js/[name].[contenthash:10].js',
  path: resolve(__dirname, 'build')
},
Copy the code

2: Configuration optimization

optimization: {
  splitChunks: {
    chunks: 'all'
  }
},
Copy the code

3: import Dynamic import syntax

Import ('/test '). Then (({a, b}) = > {/ / file loading successful ~}). The catch (() = > {/ / file loading failure ~});Copy the code

Lazy loading

Lazy loading: files are loaded when they are needed

Preload: Load in advance before use

Lazy loading and preloading can be realized through dynamic import

// webpackPrefetch: true enables preloading import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(() => { ... });Copy the code

So much for webPack optimization. This summary may not be comprehensive, but it is sufficient for most projects. Encourage together, good good study, day day up.

Scatter flowers 🌸🌸🌸🌸 disk 🌸🌸

Click like πŸ‘ to see again, has become a habit! This series is constantly updated, and your one-key three-link is the biggest motivation for me to continue writing. If you have any comments and suggestions on this blog, welcome to leave a message! Welcome to disturb! 😜 😝

I am Qin Aide, a programmer in the Internet to survive!