VueCli Checks the size ratio of the packed files

⚠ ️ vue – cli2 use webpack – bundle – analyzer

// The project built with vue-cli2 already integrates NPM run build --report commandCopy the code

⚠️ Below applies to: VUE-CLI3

1.1 Installation Dependencies

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

1.2 configuration vue. Config. Js

chainWebpack: Plugin (' webpack-bundle-Analyzer '); .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin,[ { analyzerMode: 'server' } ]) } /** analyzerMode? : 'server' | 'static' | 'json' | 'disabled'; * Can be "server", "static" or "disabled". * Defaults to "server". * In "server" mode analyzer will start HTTP server to show bundle report. * In "static" mode single HTML file with bundle report will be generated. * In "json" mode single JSON file with  bundle report will be generated * In "disabled" mode you can use this plugin to just generate Webpack Stats JSON file by setting "generateStatsFile" to true. */Copy the code

1.3 Configuring the package Script Configure the package script in the scripts of package.json

$ "build": "vue-cli-service build --report"
Copy the code

Execute command:

$ npm run build
Copy the code

Open your browser: http://127.0.0.1:8888 and you’ll see a visual representation of the file percentage

❗️ extension: if the terminal displays a warning: (the asset size limit is 244KIB, network performance may be affected).

🧠 Solution: Configure it in vue.config.js

Module.exports = {// webPack configureWebpack: {// disable webpack performance: Performance: {hints:' Warning ', // maxEntrypointSize: MaxAssetSize: 30000000, // Only js file performance prompt assetFilter: function(assetFilename) { return assetFilename.endsWith('.js'); } } }, // vue.config.js // configureWebpack: config => { // config.performance = { // hints: 'warning', // maxEntrypointSize: 50000000, // maxAssetSize: 30000000, // assetFilter: function(assetFilename) { // return assetFilename.endsWith('.js'); //} // /Copy the code

For more details, please refer to the Webpack Documentation – Performance.

2. Remove console

If you are using WebPack V5 or above, you do not need to install this plugin. Webpack V5 comes with the latest Terser-webpack-plugin. If you use Webpack V4, you must install the version of Terser-webpack-Plugin V4.

2.1 Installation Dependencies

$ npm install terser-webpack-plugin -D
Copy the code

2.2 configuration vue. Config. Js

const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
    chainWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
          config.optimization.minimizer([
            new TerserPlugin({
              test: /\.js(\?.*)?$/i,
              terserOptions: {
                compress: {
                  drop_console: true,
                  pure_funcs: ['console.log']
                }
              }
            })
          ])
        } else {
          // disable optimization during tests to speed things up
          config.optimization.minimize(false)
        }
      }
}
Copy the code

For more details, please refer to the WebPack Chinese documentation -TerserWebpackPlugin

❓❓❓ If an error is reported:

Error: optimization.minimizer() no longer supports being passed an array. Either switch to the new syntax (https://github.com/neutrinojs/webpack-chain#config-optimization-minimizers-adding) or downgrade to webpack-chain 4. If using Vue this likely means a Vue plugin has not yet been updated to support Vue CLI 4+.
Copy the code

🧠 Can be reconfigured

if (process.env.NODE_ENV === 'production') { config.optimization.minimizer('js') Resolve ('terser-webpack-plugin'), [{terserOptions: {comments: true, compress: {drop_console: true, drop_debugger: true // pure_funcs: ["console.log"] } } }]) } else { // disable optimization during tests to speed things up config.optimization.minimize(false) }Copy the code

❗️ Extended: Why delete console in production environment?

Console. log: Prints a message to the Web development console, often used for debugging analysis at development time. Sometimes you need to print some object information during development, but forget to remove the console.log statement when publishing, which can cause a memory leak.

Objects passed to console.log cannot be garbage collected ♻️ because the object information needs to be viewable in the development tool after the code is run. So it’s best not to console.log any objects in production.Example code:

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Leaker</title> </head> <body> <input type="button" value="click"> <script> ! function () { function Leaker() { this.init(); }; Leaker.prototype = { init: function () { this.name = '*'.repeat(1e5); console.log("Leaking an object %o: %o", (new Date()), this); // This object cannot be recycled}}; document.querySelector('input').addEventListener('click', function () { new Leaker(); }, false); }() </script> </body> </html>Copy the code

Devtools – >Performance of Chrome to do some analysis, the procedure is as follows:

  1. Enable recording Performance
  2. Execute the CG button to create a baseline guide
  3. Click the [click] button several times to create a new Leaker object
  4. Execute CG button
  5. Stop recording

It can be seen that[JS Heap]The line does not fall back to the base reference line, so there is clearly memory that has not been reclaimed. If the code is modified to

// console.log("Leaking an object %o: %o", (new Date()), this);
Copy the code

Repeat the above steps and the analysis results are as follows:

From the comparative analysis, console.log prints objects that are not collected by the garbage collector. Therefore, it is best not to console.log any objects in the page, including warn, error, etc. This can affect the overall performance of the page, especially in a production environment, these details need special attention.

Three, compress the picture

3.1 Installation Dependencies

$ npm install terser-webpack-plugin -D
Copy the code

3.2 configuration vue. Config. Js

config.module .rule('images') .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/) .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true, disable: process.env.NODE_ENV ! == 'production' });Copy the code

Iv. UI library is loaded on demand

Most systems use a library of UI components, such as Ant Design or Element UI. These components can be imported on demand. If you only use some of these components, you can configure them to be loaded on demand and modify the code in main.js:

import { Pagination, Icon, Tabs, } from 'ant-design-vue' // import 'ant-design-vue/dist/antd. CSS ' .use(Tabs)Copy the code

Then modify babel.config.js as follows:

"plugins": [ ["import", { "libraryName": "ant-design-vue", "libraryDirectory": "es", "style": "css" }], // `style: True 'will load less file]Copy the code

In this way, the component’s JS and CSS files can be loaded on demand.

5. Lazy route loading

For large b-end management system projects, Vue Router is generally used to manage routes. These projects involve a large number of pages. Therefore, in order to prevent the first screen resources from being too large, we need to adopt route slouch loading resources, namely Code Splitting, to separate resources on each page. This can only be configured in router.js:

$Component: () => import('./index.vue')Copy the code

Sixth, moment optimization

6.1 Problem Description

According to the package analysis chart, other language packages of moment mainly occupy a large volume in locale. The default is en, so you can just ignore the locale files and not package them if you don’t need another language.

Before ignoring:

After ignoring:

6.2 The solution uses the IgnorePlugin plug-in of WebPack

// vue.config.js var webpack = require('webpack') module.exports = { // ... Plugin('ignore').use(new webpack.ignoReplugin (/^\.\/locale$/, /moment$/)); // ignore all files in /moment/locale} //... Other configurations omitted here}Copy the code

6.3 Solution – Mechanism During webpack compilation, if the imported file path matches /^./locale$/, the file is ignored and will not be packaged.

  • /^./locale$/, aliasedRequire(‘./locale/’ + name), aliasedRequire(‘./locale/’ + name) The moment SRC source file contains the import… The from ‘. / locale. However, in the package.json file of the moment, main points to the compiled file, not the SRC file, which is strange, so debug IgnorePlugin looks at it.

  • Request is really a./locale, blind or webpack problem? AliasedRequire (‘./locale/’ + name);

  • When webpack compiles an expression such as require(‘./locale/’ + name), webpack looks for files in the directory ‘./locale/’ that match the regular expression /^.*.$/. Since name is unknown at compile time, WebPack introduces each file into the bundle as a module, which is why the compiled file is so large after the moment is introduced.

6.4 What Do I Do If I Need to Set the Locale After Adding IgnorePlugin?

  1. After adding webpack.ignoReplugin, the file size is reduced, but after setting moment.locale(‘zh-cn’), the date after format is still in English and the language is not switched.

Before adding: The size of the file containing momen.js after packagingAfter addition: Contains the file size of momen.js after packaging2. The lack of functionality is definitely unacceptable. What to do? How to do? 3. Moment-locales-webpack-plugin is also provided in the moment documentation

$ npm install --save-dev moment-locales-webpack-plugin
Copy the code
// vue.config.js
new MomentLocalesPlugin({
  localesToKeep: ['zh-cn'],
})

 // const MomentLocalesPlugin = require('moment-locales-webpack-plugin')
        // config.plugin('moment-locales-webpack-plugin').use(
        //     new MomentLocalesPlugin({
        //         localesToKeep: ['zh-cn']
        //     })
        // );
Copy the code
  1. The moment default locale is en, which is bound to be packaged in the moment. If you need to configure other languages, you can use localesToKeep to do so, and other unused language packages will not be packaged in the moment.

Vue.config.js configures the following code

config.plugin('moment-locales-webpack-plugin').use(
            new MomentLocalesPlugin({
                localesToKeep: ['es-us', 'ru', 'cs', 'hi', 'uk']
            })
        );
Copy the code

You can see that when packing, it has been packed and deleted!

6.5 Moment-locales-webpack-plugin principle analysis

  1. IgnorePlugin ignores all language packages (except en) if option is not configured
  2. If option is set, use the ContextReplacementPlugin to set the rules for webPack to find the specified locale at compile time.
. if (localesToKeep.length > 0) { var regExpPatterns = localesToKeep.map(function(localeName) { return localeName + '(\\.js)? '; }); return new ContextReplacementPlugin( /moment[\/\\]locale/, New RegExp (' (' + regExpPatterns. Join (' | ') + ') $') / / configuration webpack compilation phase lookup rules, specifying the language pack); } else { return new IgnorePlugin(/^\.\/locale$/, /moment$/); }...Copy the code

Webpack repeats dependencies of the same name

A recent installation of the webpack-bundle-Analyzer plugin to analyze the package composition found that some packages are repeatedly packaged multiple times, which can make the built packages particularly bloated. This is mainly because we often reference a lot of third-party packages, and many of the libraries of utility classes are indirectly dependent on other packages, which leads to the phenomenon of repeated packaging, such as bn.js in the figure below.

7.1 Solution Add the following configuration to webpack resolve:

Module.exports = {resolve: {alias:{'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js')}}}; // module.exports = {alias:{'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js')}}}; Module. exports = {configureWebpack:{resolve:{alias:{'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js') } } } }; // const path = require('path'); Function resolve(dir){return path.join(__dirname,dir)//path.join(__dirname) set absolute path} module.exports={ ChainWebpack: config =>{config.resolve.alias. set("@", resolve(" SRC "))}}Copy the code

Resolve. Alias is used to add the package alias and specify a unified reference path.

After the optimization

Before the optimization

Use prefetch and preload selectively

prefetch

<link rel="prefetch" ></link>
Copy the code

This code tells the browser that the resource will be used in some future navigation or function, but that the download order weight of the resource is low. That is, Prefetch is usually used to speed up the next navigation, not this one. preload

<link rel="preload" ></link>
Copy the code

Preload is usually used for key resources used in the page, including key JS, fonts, and CSS files. Preload will increase the load order weight of resources, so that key data can be downloaded in advance, optimize the speed of page opening.

In the project generated using Vue Cli, when we configured the route lazy load, by default WebPack will prefetch and preload all lazy load resources during the build, so when you open the home page, you will see a large number of prefetch and preload requests, as shown below:

// Disallow prefetch and preload chainWebpack: (config) => {config.plugins.delete('prefetch') config.plugins.delete('preload')} // Select prefetch and preload config.plugin('prefetch').tap(options => { options[0].fileBlacklist = options[0].fileBlacklist || [] options[0].fileBlacklist.push(/myasyncRoute(.) +? \.js$/) return options })Copy the code

The code above modifies the chainWebpack of vue.config.js to add configuration.

All in all, we have done our best. All in all, we have done our best

Reference links:

  1. Segmentfault.com/a/119000001…
  2. zhuanlan.zhihu.com/p/362547907
  3. www.jianshu.com/p/4f8f36944…
  4. Juejin. Cn/post / 684490…
  5. Blog.csdn.net/u010352770/…