sequence

Recently encountered project packaging, write about it. To share, to gain.

The premise

There are two premises, which need your approval:

  1. The strongest combination of framework and UI component library is Vue-element-admin + Element UI! (low low ◡)

  2. The core feature of WebPack4 is splitChunks, and the core configuration of splitChunks is cacheGroups!

Based on these two premises, let’s proceed to the next step.

Analysis tools

Webpack analysis is all you need: Webpack-bundle-Analyzer

  • The installation
npm install --save-dev webpack-bundle-analyzer
Copy the code
  • Configuration: Because vue-element-admin is based on vueCli4, it is set in vue.config.js chainWebpack
config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin).tap(() => [ { rel: 'BundleAnalyzerPlugin', analyzerMode: 'server', // 'server': start port service; 'static': generate report.html; 'disabled': GenerateStatsFile: false, // whether to generate stats. Json file analyzerHost: '127.0.0.1', analyzerPort: '8877', reportFilename: 'report.html', defaultSizes: 'parsed', openAnalyzer: false, statsFilename: 'stats.json', statsOptions: null, excludeAssets: null }Copy the code

The setting of analyzerMode is important.

  • Run:
NPM run dev or NPM run buildCopy the code
  • Access:
http://127.0.0.1:8877
Copy the code

Status quo of the problem

Take a look at our packaging diagram:

It’s not hard to get a subcontract like the one above. Vue-element-admin comes with these configurations.

config.optimization.splitChunks({ chunks: 'all', cacheGroups: { libs: { name: 'chunk-libs', test: /[\\/]node_modules[\\/]/, priority: 10, chunks: 'initial' // only package third parties that are initially dependent }, elementUI: { name: 'chunk-elementUI', // split elementUI into a single package priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app test: /[\\/]node_modules[\\/]_? element-ui(.*)/ // in order to adapt to cnpm }, commons: { name: 'chunk-commons', test: resolve('src/components'), // can customize your rules minChunks: 3, // minimum common number priority: 5, reuseExistingChunk: true } } })Copy the code

If you still don’t understand these configuration items, don’t worry, they will be described later.

You just need to know first: it takes apart the third-party packages that were initially loaded, it takes apart the Element UI library, and it takes apart the SRC/Components.

Everything seems to be ok, but we are not satisfied.

In fact, if we run NPM run build:test, we’ll also get a warning.

So what points can we continue to optimize? Combined with the above diagram and test Warning, it is clear that we need to think about:

  1. The size of Echarts cannot be ignored, how to deal with it? Is home page loading or asynchronous loading? Do you want to bring it in on demand?
  2. Vue. Js and other libraries can be dismantled again?
  3. Can the packages on which Entrypoints on the home page depend be optimized?
  4. What range should the package volume be controlled in? The package is too big and loading will be too slow! The packet is too small and consumes the HTTP request connection! More: Does Merging HTTP Requests Really Make Sense?
  5. More……

Dubious! Pack and stuff. Just type a few more times. Ten times not on a hundred times, a hundred times not on a thousand times, a thousand times not on……

Results of optimization

After looking, the following packing analysis diagram is obtained:

We successfully changed the package size from 3.1MB to 2.36MB and the number of files from 68 to 43!! , which implements both unpacking (unpacking common libraries) and merging (merging tiny packages).

While this won’t be the end of the story, Ben can start with one conclusion:

Configuring cacheGroups to weigh unpacking and merging is the ultimate in WebPack subcontracting!

Here is the cacheGroups configuration:

config.optimization.splitChunks({ chunks: 'all', cacheGroups: { vue: { name: 'chunk-vuejs', test: /[\\/]node_modules[\\/]_? vue(.*)/, priority: 20 }, elementUI: { name: 'chunk-elementUI', // split elementUI into a single package priority: 30, // the weight needs to be larger than libs and app or it will be packaged into libs or app test: /[\\/]node_modules[\\/]_? element-ui(.*)/ // in order to adapt to cnpm }, commons: { // split async commons chunk name: 'chunk-async-commons', minChunks: 2, priority: 40, chunks: 'async' }, echarts: { // split echarts libs name: 'chunk-echarts', test: /[\\/]node_modules[\\/]_? echarts(.*)/, priority: 50, chunks: 'async' }, zrender: { // split zrender libs name: 'chunk-zrender', test: /[\\/]node_modules[\\/]_? zrender(.*)/, priority: 55, chunks: 'async' }, 'manage-sendMsg': { // resolve src name: 'chunk-manage-sendMsg', test: resolve('src/views/manage/sendMsg'), priority: 80, chunks: 'async' }, 'manage-packageLink': { // resolve src name: 'the chunk - manage - packageLink' test: resolve (' SRC/views/manage/packageLink '), priority: 80, chunks: 'async'},... })Copy the code

In fact, we do optimization separately from the configuration, but the space is not large. We should also look back at the details of our code from the packaging analysis results, and tuning the business code to optimize the packaging results is perhaps one of the most direct and effective optimization ideas. Including: How to integrate or decouple businesses? How do you do componentization? How is the component introduced? How do plugins lead? Lead? . Each point can be operated again!

  • Especially pay attention to
CommonJs(require) ES6(import)
The output is a copy of the value The output is a reference to the value
Runtime loading Output interface at compile time

cacheGroups

Let’s take a look at the most critical cacheGroups configurations:

“Important”

  • name

File name of chunk

  • test

Filters modules, default to all modules, matching the path of the module or the name of the chunk. When the name of a chunk is matched, all modules introduced in that chunk are selected.

  • priority

Weight. A larger number indicates a higher priority. A Module may match the regex of multiple cacheGroups. Which cache group is applied to that module depends on the priority;

  • Chunks are very, very, very important

There are three values: all, async and initial.

Here is some sample code to see what the package differences are for setting up different chunks:

//app.js
import "my-statis-module";

if(some_condition_is_true){
  import ("my-dynamic-module")
}
console.log("My app is running")
Copy the code

asyn : (default)

Two packages are generated:

  1. Bundle.js (including app.js + my-statis-module)
  2. Chunk.js (my-dynamic-module only)

initial :

Three packages are generated:

  1. App.js (only app.js)
  2. Bundle.js (my-static-module only)
  3. Chunk.js (my-dynamic-module only)

all :

Two packages are generated:

  1. App.js (only app.js)
  2. Bundle.js (my-static-module + my-dynamic-module)

Setting the “all” size will be the smallest, the difference between using these three, is the core of the core.


  • minSize

The minimum size of the bundle to be split before splitting. Only bundles >= minSize will be split.

  • maxSize

The default value is 0, indicating that there is no upper limit on the volume of the bundle before splitting. If maxSize is set to a non-zero value, the value cannot be smaller than minSize.

  • minChunks

Represents the minimum number of chunks that can be shared before splitting

  • reuseExistingChunk

True indicates whether to use the existing chunk. True indicates that if the modules contained in the current chunk have been extracted, the new module will not be generated, that is, several chunks will reuse a split module.

bonus

Code level: This way, user.png will be printed as a separate package. Package out 148B, true no need!

<img v-show="imageUrl" :src="imageUrl" class="sort-img"> <img v-show="! imageUrl" src="~@/assets/user.png" class="sort-img">Copy the code

If this is done, it will no longer be packaged separately.

<img :src="imageUrl? imageUrl:'~@/assets/user.png'" class="sort-img">Copy the code

Looking back at the rest of the code, we see that all the files introduced in the condition are individually packaged. However, some of them can be written in an adjustable way, and there’s really no need to package a few KB files into a few B’s.

Checking the code from the result of packaging is also a good optimization!

Strategy summary

Based on this subcontract, we will simply summarize the strategies:

  1. The public library must be dismantled as far as possible.
  2. Public libraries should be loaded as much as possible on demand, which is also important to optimize for first-screen loading.
  3. Subcontracting should not be too fine. 0KB to 10KB packages are very small packages and should be considered for consolidation. Packets between 10 KB and 100 KB are small and are more appropriate. Packages between 100 KB and 200KB should be the most important ones to focus on. Packages larger than 200KB should be considered for unpacking. Of course, some special circumstances cannot be ruled out.
Packet size strategy
0 KB to 10 KB Consolidation package
10 KB to 100 KB The size of the appropriate
100 KB to 200 KB Core package, focus
More than 200 KB Considering the unpacking
A special case Special handling

That’s all for this time. Packing is endless. May there be no packing siege lions in the world.

Follow the public number [nuggets Anthony], your three company, my power!!