Author: afterrhyme of

What is a LazyLoading Chunk?

We can use lazy loading to import modules, such as importing modules through import when a condition is triggered. This can lead to better project performance.

Here’s an example:

The loDash module is introduced when we click on the page, where import() returns a promise

async function getComponent() {
  const {default: _} = await import(/* webpackChunkName:"lodash" */'lodash')
  const element = document.createElement('div')
  element.innerHTML = _.join(['y', 'kk'], '-');
  return element;
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element)
  })
})
Copy the code

The same meaning of route lazy loading means that when we listen for route changes, we will introduce the corresponding page module.

So you know, what is Chunk? Package to generate several JS files, namely several chunks

Shimming

Shimming: Sometimes in the packaging process, code compatibility is required. This compatibility is not limited to high and low browser versions.

For example

Each file is a module, and each module should introduce its own dependency in order to use that dependency.

import $ from 'jquery'
export function setBackground(){
  $('body').css('background','red')
}
Copy the code

But in this case, every document has to be written

import $ from 'jquery'
Copy the code

Therefore, it can be configured automatically by means of gaskets

plugins:[
    new webpack.ProvidePlugin({
      $:'jquery',
      _join:['lodash','join']
    })
]
Copy the code

When we configure the above, it means we see it when we run the code

  • The $sign automatically introduces jquery to node_modules. It works by automatically adding the import step for us.
  • When you see _JOIN, you automatically find the join method in LoDash

So we can use a file module directly

export function setBackground(){
  $('body').css('background', _join(['green'], ''))
}
Copy the code

Webpack and Browser Caching

When we pack it up, we generate

index.html
main.js
vendors.js
Copy the code

The client gets two JS files from the server and saves them in the browser. After the client refreshes, the browser retrieves it from the cache first. When the developer modified the code, repackaged it, and generated the above three files with the same name, the user refreshed the original code and did not update it. So how do you solve this?

1. Package the file and add contentHash

Development environment is hot update, so local debugging can not be added, production environment is changed in output

output: {
    filename: '[name].[contentHash].js',
    chunkFilename: '[name].[contentHash].js'
}
Copy the code

ContentHash indicates that the hash value generated by contentHash does not change as long as the content of the source code is not changed. If the code is split into chunks and a chunk is not modified, the file name of that chunk, contentHash, will not be modified

At the same time did the code split parameters had better be configured

optimization.splitChunks.cacheGroup.vendors.filename = 'vendors.[contentHash].js'
Copy the code

2. Compatibility with older versions

The contentHash value may change even if the content is not changed in older versions, which can be configured

optimization: {
    runtimeChunk:{
      name:'runtime'
    }
}
Copy the code

The runtimeChunk will be added to the runtimeChunk file in the new version without any problem, and a runtime.xxxxxxx.js file will be added to the package

What’s going on here?

Since there was an association between Main.js (business logic) and vendor.js (vendor library) in the old Webpack version, this part of the processing code is put in Mainfest, although the code is not changed, However, in older versions of WebPack, the relationship between mainfest and the package may change with each package. When we configured runtimeChunk, we removed the mainfest relationship and put it in Runtime.js

So this solves the problem of compatibility with older versions.

Split CSS code

The main. Js file will be packaged together with the CSS. How to split the CSS code?

1. Use a plugin: Mini-CSS-extract-plugin

However, this plugin has a disadvantage, currently does not support hot updates, so it is suitable for online environment packaging

Configuration Mode Installation dependency

yarn add mini-css-extract-plugin
Copy the code

Webpack.config.js configuration in the production environment

const MiniCssExtractPlugin = require('mini-css-extract-plugin') module:{ rules:[ { test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 2 } }, 'sass-loader', 'postcss-loader' ] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' ] } ] }, plugins: [ new MiniCssExtractPlugin({ filename: "[name].css", //index.html directly imported file chunkFilename: "id.css" // indirectly referenced file})]Copy the code

Note that if tree shaking is used, look at the sideEffects configuration in package.json. If false then the CSS code is unsplit. CSS Tree shaking needs to be excluded. Modified as follows:

 "sideEffects": [
    "*.css"
  ],
Copy the code

2. Next compress the combined CSS code

Install dependencies

yarn add optimize-css-assets-webpack-plugin -D
Copy the code

The production environment

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

optimization:{
    minimizer:[new OptimizeCSSAssetsPlugin({})]
}
Copy the code

Packaging analysis

Generate webPack package analysis JSON

webpack --profile --json > stats.json --config ./build/webpack.dev.js
Copy the code

The generated stats.json is then put into the relevant analysis site to see the visualized data. Of course, you can also configure the Analyzer

Install dependencies

npm install webpack-bundle-analyzer --save-dev
Copy the code

In webpack. Config. Js configuration

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { ... configureWebpack: { plugins: [new BundleAnalyzerPlugin({// Can be 'server', 'static' or 'disabled'. // In 'server' mode, analyzer will start the HTTP server to display the package report. // In 'static' mode, // In 'disabled' mode, you can use this plugin to set 'generateStatsFile' to 'true' to generate a Webpack Stats JSON file. AnalyzerHost: '127.0.0.1', // Start the HTTP server on the port used in 'server' mode. 8888, // path binding, the report file that will be generated in 'static' mode. 'report.html', // the module size is displayed in the report by default. // It should be one of 'stat ',' parsed 'or' gzip '. 'parsed', // automatically opens the report openAnalyzer: true in the default browser, // If true, the Webpack Stats JSON file will generate generateStatsFile in the bundle output directory: False, // If 'generateStatsFile' is' true ', the Webpack Stats JSON file name will be generated. Json ', // stats.tojson () method option. // For example, you can exclude the source of modules in the statistics file using the 'source: false' option.  //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21 statsOptions: null, logLevel: 'info' / / log level. Can be a 'information', 'warning', 'mistakes' or' silent '.}})],... };Copy the code

Use with –report at package or startup time

npm run serve --report
npm run build --report
Copy the code

prefetching && preloading

Focus on code utilization: don’t load code that won’t execute at first, load it when you interact.

Webpack wants to use asynchronous loading modes as much as possible to improve performance on the first load, while synchronous loading is a second load with limited performance gains from increased caching.

document.addEventListener('click', () => {
  import('./click.js').then(({default:func}) => {
    func()
  })
})
Copy the code

Note that there may be a slight delay in downloading the code until the user clicks on the interaction. How to solve this problem?

The solution is preloading/prefetching

  • Prefetching will wait until the code shown by the core is loaded and until broadband is free to download.

Just add the following to the code:

document.addEventListener('click', () => {
  import(/* webpackPrefetch:true */'./click.js').then(({default:func}) => {
    func()
  })
})
Copy the code

When the user clicks, the click.js file will still be downloaded, but it will be used for a very short time because it has already been downloaded and cached.

  • Preloading is loaded at the same time as the main code.
document.addEventListener('click', () => {
  import(/* webpackPreload:true */'./click.js').then(({default:func}) => {
    func()
  })
})
Copy the code

Therefore, performance optimization is best to consider higher code usage.