Vue - Project compilation speed, performance optimization, packaging volume optimization

GitHub Demo address
online preview

webpack Chinese documentation

Article:
Project optimization methods and advantages and disadvantages
HardSourceWebpackPlugin configuration and other optimization solutions
Vue project performance optimization solution sharing What
vue-cli projects can do to optimize
Vue first review loading speed and white screen time optimization detailed explanation

What are the differences between webpack5 and webpack4?
Webpack5 upgrade guide (with a complete package performance optimization guide)

sequence

Personally, I think it’s good to choose the appropriate optimization plan. It’s not necessary to use all of them. You can spend more time on optimizing the business code.
The project environment is based on webpack4x, some may be outdated, please judge by yourself
下面的方法只有部分使用,更多的是一种记录!!!

Check webpack version npm list webpack
Or you can find the webpack/package.json file under the node_modules directory and check the version in the file, as shown below

Insert image description here

1. Compilation speed optimization

Articles on optimizing compilation:
Vue project compilation and running are too slow. How to improve the speed of compilation (compilation includes running compilation and package compilation).
During the development process, vue projects are saved and compiled slowly. Optimization method
webpack5. Configure multi-threading and caching to speed up the build.

1. Use cache

  • In order to improve the build speed in webpack3, we often use the DllPlugin and DllReferencePlugin plug-ins, but the configuration is complicated, and updating files requires manual regeneration of the dll, which is more cumbersome. There is another kind of autodll-webpack-plugin that will be better
  • It can be used after webpack 4. HardSourceWebpackPluginIt improves the compilation and loading speed by setting a cache in the disk. The first time it is compiled and cached normally, and the second time it is cached, it can reduce the time by 80%-90%. Need to install and use
  • Webpack5 built-in cacheconfiguration.

1.1. Cache plug-in-HardSourceWebpackPlugin

hard-source-webpack-plugin plug-in GitHub address

HardSourceWebpackPlugin is a plugin for webpack that provides an intermediate caching step for modules. In order to see the results, you need to run webpack twice with this plugin: the first build will take the normal time. The second build will be significantly faster.
The speed is improved by about 80%-90%

tips:

Default cache location: nodemodules/.cache. If you need to clear the cache, you can delete it and compile again.
HardSourceWebpackPlugin 和 speed-measure-webpack-plugin 不能一起使用 !!!

Install hard-source-webpack-plugin

npm install --save-dev hard-source-webpack-plugin

Configuration

// webpack.config.js 或 vue.config.js
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const path = require('path')

module.exports = {
    
    
  // ...
  plugins: [
     // 默认缓存位置:node_modules/.cache路径下
     new HardSourceWebpackPlugin()
     // new HardSourceWebpackPlugin({
    
    
     //   cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/hard_source_cache')
     // })
  ]
}

1.2. webpack5Configure cache

webpack5Built-in cache caching mechanism. Just configure it directly.
The cache will be set to type: memory in development mode and the cache will be disabled in production mode.

// webpack.config.js 或 vue.config.js
const path = require('path')
module.exports = {
    
    
  transpileDependencies: true,
  configureWebpack: {
    
    
    cache: {
    
    
      type: 'filesystem',
      // cacheDirectory: path.resolve(__dirname, '.webpack_cache') // 设置缓存目录(根路径下)
      cacheDirectory: path.join(__dirname, 'node_modules/.cache/webpack_cache') // 设置缓存目录(node_modules/.cache路径下)
    }
  }
}

1.3. cache-loader plug-in

Similar to the first one, I won’t go into details here.

Comparison before and after installation of hard-source-webpack-plugin

First compilation 36340ms
Insert image description here
Second compilation 3760ms
Insert image description here

2. Proper use of source-map

The role of productionSourceMap is to locate problems. A .map file will be generated during packaging. In the production environment, you can view the specific line of the output information in the browser, but the size of the corresponding package will also increase, which will also affect the build speed. , setting it to false will not generate .map files.
Setting productionSourceMap to false can not only reduce the package size, but also encrypt the source code.

module.exports = {
    
    
  productionSourceMap: false
}

3. Multi-thread packaging

3.1、thread-loader

The article
[Webpack Performance Optimization Series (9) - Multi-process Packaging] greatly improves project packaging and construction speed

Thread-loader is a loader of Webpack. It can put some expensive work into the worker pool and execute it in the worker pool to improve the build speed.
For example, when building a Vue.js project, due to the need to compile .vue single-file components, parse templates and other operations, the build time may be very long, especially for large projects. You can use thread-loader to execute these operations on a worker pool, significantly reducing build time.

When used, this loader needs to be placed before other loaders. Loaders placed after this loader will run in a separate worker pool.
Loaders running in a worker pool are restricted. For example:
these loaders cannot generate new files.
These loaders cannot use custom loader APIs (that is, they cannot be customized through plugins).
These loaders cannot obtain webpack configuration.
Each worker is an independent node.js process, and its overhead is about 600ms. At the same time, cross-process data exchange will be restricted.
Please only use this loader for time-consuming operations!

Note that thread-loader is not suitable for all scenarios. It is only effective for some expensive tasks. If the task itself is very fast and simple, using a thread-loader may be slower than executing directly in the main thread.

Install

 npm install thread-loader --save-dev

The following is an example of thread-loader usage (will be applied to all .js and .vue files, except files in node_modules.):

webpack.config.js

module.exports = {
    
    
  module: {
    
    
    rules: [
      {
    
    
        test: /\.js$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        use: [
          'thread-loader', // 将后续 loader 放在 worker 池中执行
          // 耗时的 loader (例如 babel-loader)
          'babel-loader'
        ]
      }
    ]
  }
}

view.config.js

module.exports = {
    
    
  // ... 
  configureWebpack: {
    
    
    module: {
    
    
      rules: [
        {
    
    
          test: /\.js$/,
          include: path.resolve('src'),
          exclude: /node_modules/,
          use: [
            'thread-loader', // 将后续 loader 放在 worker 池中执行
            // 耗时的 loader (例如 babel-loader)
            'babel-loader'
          ]
        }
      ]
    }
  }
}

options

use: [
  {
    
    
    loader: "thread-loader",
    // 有同样配置的 loader 会共享一个 worker 池
    options: {
    
    
      // 产生的 worker 的数量,默认是 (cpu 核心数 - 1),或者,
      // 在 require('os').cpus() 是 undefined 时回退至 1
      workers: 2,

      // 一个 worker 进程中并行执行工作的数量
      // 默认为 20
      workerParallelJobs: 50,

      // 额外的 node.js 参数
      workerNodeArgs: ['--max-old-space-size=1024'],

      // 允许重新生成一个僵死的 work 池
      // 这个过程会降低整体编译速度
      // 并且开发环境应该设置为 false
      poolRespawn: false,

      // 闲置时定时删除 worker 进程
      // 默认为 500(ms)
      // 可以设置为无穷大,这样在监视模式(--watch)下可以保持 worker 持续存在
      poolTimeout: 2000,

      // 池分配给 worker 的工作数量
      // 默认为 200
      // 降低这个数值会降低总体的效率,但是会提升工作分布更均一
      poolParallelJobs: 50,

      // 池的名称
      // 可以修改名称来创建其余选项都一样的池
      name: "my-pool"
    },
  },
  // 耗时的 loader(例如 babel-loader)
];

3.2、parallel-webpack

parallel-webpack is a plug-in based on Webpack, which can break down the build task into multiple sub-processes to run in parallel to improve the build speed. Compared with other similar plug-ins, the biggest feature of parallel-webpack is that it supports parallel processing of asynchronous and synchronous modules, not just limited to Loader and Plugin.

npm install --save-dev parallel-webpack
// webpack.config.js
const ParallelWebpack = require('parallel-webpack').Plugin

module.exports = {
    
    
  // ...
  plugins: [
    new ParallelWebpack({
    
    
      // 配置选项
    }),
    /* 其他插件 */
  ],
  // ...
}

The above configuration will enable the parallel-webpack plug-in to achieve multi-process packaging. You can configure the plug-in according to your needs in the configuration options.

It should be noted that using multi-threaded packaging may increase the CPU and memory consumption of the system. Therefore, it is recommended to match the number of threads that matches the machine performance and test the multi-threaded packaging effect. You should also observe the build time and the build process. CPU and memory consumption.

3.3、HappyPack

HappyPack is a tool for multi-threaded compilation of Webpack. It can decompose a complex Loader or Plugin task into multiple sub-processes for parallel execution to speed up the build.

npm install happypack --save-dev
const HappyPack = require('happypack');

module.exports = {
    
    
  // ...
  module: {
    
    
    rules: [
      {
    
    
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'happypack/loader?id=js'
      }
    ]
  },
  plugins: [
    new HappyPack({
    
    
      id: 'js',
      threads: 4,
      loaders: ['babel-loader']
    })
  ],
  // ...
};

In the above code, we define a HappyPack instance named js and use 4 threads to compile the JavaScript files processed by babel-loader in parallel.

注:2和3插件相关的代码没有经过实际使用测试效果!!!

4. Enable hot update/hot replacement

webpack Chinese document HMR loading style

The difference between webpack hot loading using module.hot.accept and not using
module hot replacement (HMR)

  • Hot Update: After the code file is modified, new code is automatically compiled and injected into the JavaScript running in the browser. Hot update does not reload the page, but updates some changed content and retains the status information of the page, so the user's operating status can be maintained.
  • Hot Reload: After the code file is modified, recompile, package and refresh the browser window as quickly as possible. Compared with hot update, hot reload not only updates the JavaScript code, but also re-renders the entire page, so there will be a brief splash screen, which is more suitable for UI-related modifications.
  • Hot Module Replacement: Similar to hot update, but only replaces the changed parts and does not reload the entire module or application, so it is faster and has a better experience. Module hot replacement is not only applicable to JavaScript modules, but also can be used to replace CSS, images and other resources.

HotModuleReplacementPluginIt is a plug-in provided by Webpack to enable the hot module replacement (HMR) function. HMR is a development mode that can update only the modified parts without refreshing the entire page, improving development efficiency.

Note:

Only effective for js.
When modifying css, the page will not refresh automatically, only our modified css will be updated.

const webpack = require('webpack');

module.exports =  {
    
    
  // ...
  mode: 'development',
  devtool: 'eval-source-map', // 使用 source-map 方便调试
  devServer: {
    
    
    port: 8080,
    hot: true, // 开启 HMR 功能
    open: true // 自动打开浏览器
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin() // 启用 HMR 功能
  ]
}

Among them, the hot option is set to true, which means the HMR function is enabled; the HotModuleReplacementPlugin plug-in is added to the plugins to enable the HMR function.

Add the following code in the js code:

// js 代码中添加 HMR 相关的代码
if (module.hot) {
    
    
  // 如果支持HMR,告诉 Webpack,当前模块更新不用刷新
  module.hot.accept()
  // 如果支持HMR,告诉 Webpack,当前模块更新时一定要刷新
  // module.hot.decline()
}

Through the above configuration, you can turn on the module hot replacement function of Webpack, so that you can preview the effects of modifications in real time during the development process and improve development efficiency. It should be noted that the HMR feature is only available in development environments and should not be used in production environments.

Insert image description here

5. Use Dll pre-compilation (DllPlugin/autodll-webpack-plugin)

DllPlugin is a plug-in of webpack that can package some infrequently changing codes or third-party libraries into a separate dynamic link library (DLL file), so that there is no need to repackage these codes every time you compile, thereby improving the compilation speed.

Using DllPlugin, you can pre-compile some stable and difficult-to-modify libraries, such as vue, vue-router, vuex, etc., and use the pre-compiled dll library files directly during project compilation through the build tool, thus improving the packaging speed.

It is recommended to use autodll-webpack-plugin

It is more recommended to use it directlyhard-source-webpack-plugin

npm install autodll-webpack-plugin --save-dev

view.config.js

const AutoDllPlugin = require('autodll-webpack-plugin');

module.exports = {
    
    
  // ...
  plugins: [
    new AutoDllPlugin({
    
    
      inject: true,
      debug: true,
      filename: '[name]_[hash].js',
      path: './dll',
      entry: {
    
    
        vendor: [
          'vue',
          'vue-router',
          'vuex'
        ]
      }
    })
  ]
}

In the above configuration, we used the AutoDllPlugin plug-in and passed in the following parameters:

  • inject: true means automatically referencing the generated DLL into HTML;
  • debug: true means output debugging information in the webpack log;
  • filename: '[name]_[hash].js' represents the generated DLL file name, where [name] corresponds to the key in the entry, and [hash] represents the file hash value;
  • path: './dll' indicates the storage path of the generated DLL file;
  • entry represents a list of third-party libraries to be compiled into DLL.

The above configuration will generate a DLL file named vendor_XXXX.js, where XXXX represents the file hash value. This file contains the code of the three libraries vue, vue-router and vuex.

Add the following code in the HTML to reference the generated DLL file, where XXXX should be replaced with the hash of the generated DLL file.

<script src="./dll/vendor_XXXX.js"></script>

If you use webpack-dev-server for development, you need to add the following content to the DevServer configuration:
In this way, after starting DevServer, autodll-webpack-plugin will automatically introduce the generated DLL into HTML, thereby improving the build speed.

const AutoDllPlugin = require('autodll-webpack-plugin');

module.exports = {
    
    
  // ...
  devServer: {
    
    
    // ...
    before(app, server) {
    
    
      AutoDllPlugin({
    
    
        debug: true,
        filename: '[name]_[hash].js',
        path: './dll',
        entry: {
    
    
          vendor: [
            'vue',
            'vue-router',
            'vuex'
          ]
        }
      }).apply(new webpack.Compiler());
    }
  }
}

6. Optimize Loader

Loader is an important part of webpack, and its processing of files may affect the compilation speed. Optimizing Loader configuration can greatly improve compilation speed.

  • Reduce the number of Loaders: Avoid repeated use of Loaders as much as possible, or merge multiple Loaders as much as possible if necessary, thereby reducing the number of Loaders that need to be compiled.

  • Cache the Loader's compilation results: Use Webpack's cache-loader plug-in to cache the Loader's compilation results to the hard disk, which can greatly shorten the Loader's recompilation time without changing the source file.

  • Enable multi-threaded compilation: Using multi-threaded compilation tools, the Webpack construction task can be decomposed into multiple sub-processes for parallel execution, which can take full advantage of the multi-core parallel computing of the CPU and speed up compilation. This can be achieved using tools such as happyPack or thread-loader.

  • Avoid using regular expressions as Loader rules: When defining Loader rules, try to avoid using regular expressions as a rule matching method, as this will slow down the build process. If you must use it, you can also try to limit the matching range of the regular expression to improve matching efficiency.

7、exclude & include

Using exclude and include in Vue projects can help improve compilation speed because they can reduce unnecessary file checking and compilation.

exclude and include are set through the module.rules configuration item of webpack. Among them, exclude means to exclude certain directories or files from being compiled, while include means to include certain directories or files for compilation.

The following takes the Babel compilation of the Vue project as an example to introduce how to use exclude and include.

Install dependencies

npm install --save-dev babel-loader @babel/core @babel/preset-env

Among them, babel-loader is a tool for compiling JavaScript code, @babel/core is the Babel core library, and @babel/preset-env is a preset package that can automatically select conversion plug-ins according to the target environment.

Configure webpack.config.js

In the following configuration, exclude: /node_modules/ means to exclude JavaScript files in the node_modules directory from being compiled to improve compilation speed.

module.exports = {
    
    
  // ...
  module: {
    
    
    rules: [
      {
    
    
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
    
    
          loader: 'babel-loader',
          options: {
    
    
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

Sometimes, if we only need to compile JavaScript files in a certain directory in the project, we can use include to specify the corresponding directory.

For example, we only need to compile the JavaScript files in the src/components directory. We can change the configuration to:

module.exports = {
    
    
  // ...
  module: {
    
    
    rules: [
      {
    
    
        test: /\.js$/,
        include: path.resolve(__dirname, 'src/components'),
        use: {
    
    
          loader: 'babel-loader',
          options: {
    
    
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

In the above configuration, include: path.resolve(__dirname, 'src/components') means that only the JavaScript files in the src/components directory are included for compilation to reduce unnecessary file checking and compilation.

8. Build a differentiated environment

For example, in the development environment, we usually need to enable functions such as source map and hot update, while in the production environment, we need to enable optimization technologies such as code compression and Tree Shaking. Therefore, we can use the following code in Webpack's configuration file to configure different plug-ins and optimizations according to the environment:

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
    
    
  // ...
  plugins: [
    isProd ? new UglifyJSPlugin() : null,
    // ...
  ].filter(Boolean),
};

9. Improve webpack version

Upgrading the Webpack version is an important way to improve build speed, and each new version will bring new optimizations and performance improvements.

Update Webpack to the latest version:
First, you need to determine the version of Webpack currently used and check whether it needs to be updated. You can install the latest version of Webpack through the npm command:

npm install webpack@latest --save-dev

Precautions:

  • Check the versions of Webpack-related plug-ins and loaders:
    When upgrading Webpack, you should also check whether the related plug-ins and loaders need to be updated, and make sure they are compatible with the Webpack version.
  • Remove obsolete plug-ins and loaders:
    Some plug-ins and loaders may have been deprecated with the upgrade, so the corresponding plug-ins and loaders need to be removed.

2. Packaging volume optimization

Analysis pluginwebpack-bundle-analyzer

First, we recommend an analysis plug-in. Using this plug-in can open an analysis page during compilation and packaging, which can help us optimize the file size and performance after packaging.
It can generate a visual report showing the size, dependencies and composition of each module. Through this report, we can clearly understand the size and dependencies of each module, thereby determining which modules contribute more to the size of the packaged results, and then optimize them.

webpack-bundle-analyzer plugin configuration

Install webpack-bundle-analyzerplugin

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

Using plugins in Webpack configuration files

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
    
    
  // ...
  plugins: [
      new BundleAnalyzerPlugin({
    
    
        openAnalyzer: true
      }),
  ]
}

vue cli 生成的项目下面的就不需要了,直接编译打包会打开一个分析页面

Run the Webpack build
Run the Webpack build command, for example:

webpack --config webpack.config.js

View analysis report
After the above command is executed, a report page will be generated and the port number will be printed in the console, for example:

Webpack Bundle Analyzer is started at http://127.0.0.1:8888

Open the corresponding address in your browser to view the analysis report.

It should be noted that if your build configuration is generated based on tools such as Vue CLI or Create React App, you do not need to manually add the webpack-bundle-analyzer plug-in. These tools already include the plug-in by default. You can compile and package it directly or view the analysis report through the corresponding command, for example:

vue-cli-service build --mode production --report

Insert image description here

1. Reference third-party libraries on demand

1.1, element-ui on-demand reference

The complete list of components is subject to components.json (referenced version)

  • Step 1: Install babel-plugin-component plugin:
npm i babel-plugin-component -D
  • Step 2: Configure in babel.config.jsor file:.babelrc
module.exports = {
    
    
  presets: [
    '@vue/cli-plugin-babel/preset',
    ['@babel/preset-env', {
    
     'modules': false }]
  ],
  plugins: [
    [
      'component',
      {
    
    
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ]
  ]
}
  • Step 3: Create element.js

// element-ui 按需引入
// 注:完整组件列表以 components.json (引用版本的)为准
// https://github.com/ElemeFE/element/blob/master/components.json

import {
    
    
  Pagination,
  Dialog,
  Autocomplete,
  Dropdown,
  DropdownMenu,
  DropdownItem,
  Menu,
  Submenu,
  MenuItem,
  MenuItemGroup,
  Input,
  InputNumber,
  Radio,
  RadioGroup,
  RadioButton,
  Checkbox,
  CheckboxButton,
  CheckboxGroup,
  Switch,
  Select,
  Option,
  OptionGroup,
  Button,
  ButtonGroup,
  Table,
  TableColumn,
  DatePicker,
  TimeSelect,
  TimePicker,
  Popover,
  Tooltip,
  Breadcrumb,
  BreadcrumbItem,
  Form,
  FormItem,
  Tabs,
  TabPane,
  Tag,
  Tree,
  Alert,
  Slider,
  Icon,
  Row,
  Col,
  Upload,
  Progress,
  Spinner,
  Badge,
  Card,
  Rate,
  Steps,
  Step,
  Carousel,
  Scrollbar,
  CarouselItem,
  Collapse,
  CollapseItem,
  Cascader,
  ColorPicker,
  Transfer,
  Container,
  Header,
  Aside,
  Main,
  Footer,
  Timeline,
  TimelineItem,
  Link,
  Divider,
  Image,
  Calendar,
  Backtop,
  PageHeader,
  CascaderPanel,
  Avatar,
  Drawer,
  Popconfirm,
  // 单独设置
  Loading,
  MessageBox,
  Message,
  Notification
} from 'element-ui'

const components = [
  Pagination,
  Dialog,
  Autocomplete,
  Dropdown,
  DropdownMenu,
  DropdownItem,
  Menu,
  Submenu,
  MenuItem,
  MenuItemGroup,
  Input,
  InputNumber,
  Radio,
  RadioGroup,
  RadioButton,
  Checkbox,
  CheckboxButton,
  CheckboxGroup,
  Switch,
  Select,
  Option,
  OptionGroup,
  Button,
  ButtonGroup,
  Table,
  TableColumn,
  DatePicker,
  TimeSelect,
  TimePicker,
  Popover,
  Tooltip,
  Breadcrumb,
  BreadcrumbItem,
  Form,
  FormItem,
  Tabs,
  TabPane,
  Tag,
  Tree,
  Alert,
  Slider,
  Icon,
  Row,
  Col,
  Upload,
  Progress,
  Spinner,
  Badge,
  Card,
  Rate,
  Steps,
  Step,
  Carousel,
  Scrollbar,
  CarouselItem,
  Collapse,
  CollapseItem,
  Cascader,
  ColorPicker,
  Transfer,
  Container,
  Header,
  Aside,
  Main,
  Footer,
  Timeline,
  TimelineItem,
  Link,
  Divider,
  Image,
  Calendar,
  Backtop,
  PageHeader,
  CascaderPanel,
  Avatar,
  Drawer,
  Popconfirm
]

const element = {
    
    
  install: (Vue) => {
    
    
    components.forEach(component => {
    
    
      Vue.component(component.name, component)
    })

    // 单独设置
    Vue.use(Loading.directive)
    Vue.prototype.$loading = Loading.service
    Vue.prototype.$msgbox = MessageBox
    Vue.prototype.$alert = MessageBox.alert
    Vue.prototype.$confirm = MessageBox.confirm
    Vue.prototype.$prompt = MessageBox.prompt
    Vue.prototype.$notify = Notification
    Vue.prototype.$message = Message
  }
}
export default element
  • Step 4: main.js reference (the reference method changes from referencing official components to referencing custom element.js)
// import ElementUI from 'element-ui' // 全局引用
import ElementUI from '@/utils/element' // 按需引用
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

You can use it normally after that

1.2. Echart quoted on demand

Create an echart.js file directly here, and then reference it wherever you need to use it. The
reference method changes from referencing official components to referencing custom echarts.js.

// import * as echarts from 'echarts' // 全量引入
import echarts from '@/utils/echarts' // 按需引入

echart.js file

// echarts 按需引入

// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core'

// 引入图表类型,图表后缀都为 Chart
import {
    
     BarChart, LineChart, PieChart } from 'echarts/charts'
// 自定义类型的图表
import {
    
     CustomChart } from 'echarts/charts'

// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
    
    
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  DatasetComponent,
  TransformComponent,
  DataZoomComponent
} from 'echarts/components'

// 标签自动布局、全局过渡动画等特性
import {
    
     LabelLayout, UniversalTransition } from 'echarts/features'
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
// import { CanvasRenderer } from 'echarts/renderers'
import {
    
     SVGRenderer } from 'echarts/renderers'

// 将以上引入的组件使用use()方法注册
echarts.use([
  BarChart,
  LineChart,
  PieChart,
  CustomChart,
  // 提示框,标题,直角坐标系,数据集 等组件
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  DatasetComponent,
  TransformComponent,
  DataZoomComponent,
  // 标签自动布局、全局过渡动画等特性
  LabelLayout,
  UniversalTransition,
  // Canvas 渲染器
  // CanvasRenderer
  SVGRenderer
])

// 导出
export default echarts

1.3. Lodash quoted on demand

Method 1: Use 'lodash-es' instead of 'lodash'

import {
    
     cloneDeep } from 'lodash-es' // 按需引入
import {
    
     throttle, debounce } from 'lodash-es' // 按需引入
// import lodash from 'lodash-es' // 全量引入

Method 2: Pay attention to on-demand references when using 'lodash'

// import cloneDeep from 'lodash/cloneDeep' // 按需引入
// import lodash from 'lodash' // 全量引入

2. Remove console.log in production environment

The development environment requires debugging and adding console logs. If it is also printed in the production environment, it will easily cause data leakage and occupy space.

2.1、 babel-plugin-transform-remove-console

This is a Babel plugin that removes all console.* statements during build.

npm install --save-dev babel-plugin-transform-remove-console

Then, add the following code in the babel.config.jsor file:.babelrc

const plugins = []
// remove console.* in production
if (process.env.NODE_ENV === 'production') {
    
    
  plugins.push('transform-remove-console')
  // plugins.push(['transform-remove-console', { 'exclude': ['error', 'warn'] }])
}

module.exports = {
    
    
  //...
  plugins: plugins
}

2.2、terser-webpack-plugin

This plug-in is used to compress js code. It has a function of deleting console.log. You
webpack4need to download and install terser-webpack-pluginthe plug-in, and the following configuration is required:

npm install terser-webpack-plugin --save-dev
const TerserPlugin = require('terser-webpack-plugin')
 
module.exports = {
    
     
// ...other config
optimization: {
    
    
  minimize: !isDev,
  minimizer: [
    new TerserPlugin({
    
    
      extractComments: false, 
      terserOptions: {
    
     
        compress: {
    
     
          pure_funcs: ['console.log'] 
        }
      }
    }) ]
 }

webpack5It has its own js compression function internally, and it has a built-in terser-webpack-pluginplug-in, so we don’t need to download and install it. And the js compression function will be automatically turned on when mode="production" is set.

If you want to use it in a development environment, use the following:

  // webpack.config.js中
  module.exports = {
    
    
     optimization: {
    
    
       usedExports: true, //只导出被使用的模块
       minimize : true // 启动压缩
     }
  }
 

2.3、 uglifyjs-webpack-plugin

uglifyjs-webpack-plugin is a Webpack plug-in for compressing JavaScript code. It is based on UglifyJS and is used to compress and obfuscate JavaScript code.

npm install --save-dev uglifyjs-webpack-plugin
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
    
    
  // ...
  optimization: {
    
    
    minimize: true,
    minimizer: [
      new UglifyJsPlugin({
    
    
        // 开启并发
        parallel: true,
        // 多进程压缩
        uglifyOptions: {
    
    
          compress: {
    
    },
          output: {
    
    
            comments: false,
          },
        },
      }),
    ],
  }
}

注:2和3插件相关的代码没有经过实际使用测试效果!!!

3. Proper use of source-map

The role of productionSourceMap is to locate problems. A .map file will be generated during packaging. In the production environment, you can view the specific line of the output information in the browser, but the size of the corresponding package will also increase, which will also affect the build speed. , setting it to false will not generate .map files.
Setting productionSourceMap to false can not only reduce the package size, but also encrypt the source code.

module.exports = {
    
    
  productionSourceMap: false
}

4. Code Splitting

Code Splitting is a technology for optimizing the performance of web applications. It splits the application's JavaScript code into multiple smaller parts and loads them on demand, reducing the loading time of the homepage and speeding up response times.

Before the code is subcontracted, the code of the entire project is packaged into one main.js. Then when a certain page is accessed, it will inevitably cause a waste of resources and prolong the loading time of the page.
After the code is subpackaged, each module is packaged separately. After main.js is split, it becomes very small. When the page is loaded, it will also be loaded on demand.

effect:

  • Speed ​​up page loading
    When your application's JavaScript code is split into smaller pieces and loaded on demand, you can reduce page load times and make your website more responsive.

  • Reduce resource waste
    Large Web applications often contain a large amount of JavaScript code, which is not used in every page. Through Code Splitting technology, unnecessary code can be delayed to load, thereby reducing resource waste.

  • Improve user experience
    When using Code Splitting technology, users only need to load the code they actually need, rather than all the code for the entire application. This can improve page response speed and user experience, while reducing application load time and resource utilization.

Here, I split elementUI, echarts, xlsx, and the components used in the project into separate files, such as chunk-echarts.js, chunk-elementUI.js, etc. The others are allocated to different chunk js files according to the configured rules.

view.config.js

module.exports = {
    
    
  // ...
  chainWebpack(config) {
    
    
  
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
    
    
          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: 25, // 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
                },
                echarts: {
    
    
                  name: 'chunk-echarts', // split echarts 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[\\/]_?echarts(.*)/ // in order to adapt to cnpm
                },
                xlsx: {
    
    
                  name: 'chunk-xlsx', // split xlsx 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[\\/](xlsx|file-saver)[\\/]/ // 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
                }
              }
            })
        }
      )

  }
}

5. Tree shaking technology

webpack Chinese website Tree Shaking

Front-end experience optimization tree-shaking
1 minute understanding of Tree-shaking
A brief analysis of Tree Shaking

Use Tree shaking technology to eliminate useless code, reduce packaged file size, and improve page loading speed.
Tree Shaking is a technique used to clean up unused code (dead-code) in JavaScript. It relies on static structure in ES6 module syntax and reduces bundle size by identifying and removing unused parts of the project, thereby improving application performance.

Enabling Tree Shaking in Webpack requires the following configuration:

Use ES6 module syntax:
Tree Shaking relies on the static structure of ES6 module syntax, so you need to ensure that you use ES6 module syntax in your project and avoid using non-static module syntax such as CommonJS/AMD.

Set mode in Webpack's configuration file:

odule.exports = {
    
    
  // ...
  mode: 'production',
  optimization: {
    
    
    usedExports: true, // 开启 Tree shaking
  },
};

Set the sideEffects property in the package.json file:

{
    
    
  "name": "example",
  "sideEffects": [
    "*.css",
    "*.scss",
    "*.jpg",
  ]
}

Add the sideEffects attribute in the package.json file to tell Webpack which modules should not be Tree Shaking, such as CSS/SCSS files and other files with side effects.

Make sure to use the UglifyJSPlugin plug-in:
UglifyJSPlugin is a plug-in built into Webpack, which is used to compress and obfuscate JavaScript code, and can also be used to remove unused code. In Webpack 4, since the TerserWebpackPlugin is automatically used for JavaScript code compression and optimization when the mode is production, there is no need to add UglifyJSPlugin separately.

After enabling Tree Shaking, Webpack will analyze the project code and delete all modules and code blocks that are not referenced. Doing so not only reduces the packaged size, but also improves application performance because invalid code that is not used no longer needs to be parsed and executed.

After setting the above configuration, Webapck will automatically perform Tree shaking and delete unused code.

A simple example is given below:

// index.js
import {
    
     add } from './math.js';
console.log(add(1, 2));
// math.js
export function add(x, y) {
    
    
  return x + y;
}

export function sub(x, y) {
    
    
  return x - y;
}

In the above code, the sub function is not used, so the Tree will be deleted after shaking. The final output code only contains the code of the add function, and the code of the sub function is successfully deleted.

Generally, Tree Shaking needs to be used in conjunction with other optimization technologies, such as code splitting, lazy loading, preloading, etc., to further improve application performance and user experience.

6. Introduction of large module cdn

CDN provider
https://unpkg.com/
https://www.jsdelivr.com/
https://www.bootcdn.cn/
http://www.staticfile.org/

Use unpkg, such as searching for xlsx

Entering in the browser unpkg.com/xlsxwill jump to the latest version of the source code.

Insert image description here

Go back a few spaces and type in the browser. unpkg.com/xlsx/dist/It will jump to the latest version of the dist list.

Insert image description here

article

Using externals correctly, Vue project build performance improves by 67%.
Vue project CDN introduces ElementUI

Disadvantages: Using CDN online may be unstable due to network problems, unless the company has its own CDN library.
However, this is indeed an optimization solution, and the effect is not bad. Its configuration is also very simple, configured as follows in externals:

module.exports = {
    
    
    // 设置通过cdn引入的库,不打包到vendor中(需要去掉导入的相关代码),需要在index.html中引入cdn资源
    externals: {
    
    
      vue: 'Vue', // 使用cdn引用element-ui时,必须设置vue和element-ui为外部依赖。
      'element-ui': 'ELEMENT', // 不去 node_modules 中找,而是去找 全局变量 ELEMENT
      // 'vue-router': 'VueRouter',
      // axios: 'axios',
      echarts: 'echarts'
      // XLSX: 'XLSX'
    }
}

How to know what the corresponding third-party package is key? valueIt keyis package.jsonthe name of the package installed in the package. valueWhen the package is actually registered or the value of the global variable exposed, for example , element-uiwhen the source code is opened and formatted, you can see the registered value as follows. Yes , and it depends on it ; other packages have the same ideavalueELEMENTelememt-uiELEMENTvue

Insert image description here
Introduce CDN in public/index.html

<!-- vue必须在element-ui前面 -->
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script> 
<!-- unpkg element-ui 源 -->
<link href="https://unpkg.com/[email protected]/lib/theme-chalk/index.css" rel="stylesheet">
<script src="https://unpkg.com/[email protected]/lib/index.js"></script>
<!-- bootcdn element-ui 源 -->
<!-- <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/index.min.js"></script> -->
    
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
<!-- <script src="https://unpkg.com/[email protected]/dist/xlsx.full.min.js"></script> -->

If you use the following code in main.js, you can remove it

import ElementUI from 'element-ui'
Vue.use(ElementUI)

Regarding echarts, use the following code

import * as echarts from 'echarts'

7. Compress css, js, and image resources, and delete useless code

8. gzip compression

Gzip is a commonly used file compression algorithm that can compress text files into smaller sizes, improving website loading speed and user experience. In web development, commonly used compression tools include Gzip and Brotli.

To enable Gzip compression, you can use webpack's built-in compression-webpack-pluginplugin. The plug-in will automatically Gzip compress the packaged js and css files and generate corresponding .gz files.

Here are the steps on how to enable Gzip compression in your project:

1. Install the compression-webpack-plugin plug-in.

npm install compression-webpack-plugin --save-dev

Add configuration in vue.config.js and enable it compression-webpack-plugin.

const CompressionWebpackPlugin = require('compression-webpack-plugin');

module.exports = {
    
    
  configureWebpack: {
    
    
    plugins: [
      // 启用 Gzip 压缩
      new CompressionWebpackPlugin({
    
    
        filename: '[path][base].gz',
        algorithm: 'gzip',
        test: /\.(js|css)$/,
        threshold: 10240,
        minRatio: 0.8,
        deleteOriginalAssets: false,
      }),
    ],
  },
}

In the above configuration, the parameters of CompressionWebpackPlugin have the following meanings:

filename: compressed file name, [path] represents the file path, [base] represents the file name.
algorithm: compression algorithm, Gzip is selected here.
test: Matches the file types that need to be compressed.
threshold: The file size will be compressed only if it exceeds this value, the unit is bytes.
minRatio: The ratio of the compressed file size to the original file size. A compressed file will be generated only if it is less than this value.
deleteOriginalAssets: Whether to delete the original files. If true, the original file will be deleted and only the compressed file will be retained.
Execute npm run build to build the production environment code. You can see that a .gz compressed file is generated in the dist directory.

Enable Gzip compression on the server. If you are using Nginx as a web server, you can set it in the nginx.conf file:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
gzip_proxied any;

This enables Gzip compression on the server side, improving website loading speed and user experience.

3. Performance and user experience optimization

3.1. Lazy loading of routes

Lazy loading of routes means loading the corresponding routing modules only when needed, instead of loading all routing modules when the project is initialized. This can reduce initial loading time and resource consumption, and improve page loading speed and user experience. In a Vue project, you can use dynamic import to implement lazy loading of routes.

Here are the steps on how to use lazy loading of routes:

Install @babel/plugin-syntax-dynamic-import plugin

npm install @babel/plugin-syntax-dynamic-import --save-dev

Add plugin in .babelrc file

{
    
    
  "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

When defining routes in routing configuration files (such as router.js), use the import function to lazily load routing components.

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const Home = () => import('./views/Home.vue')

export default new Router({
    
    
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
    
    
      path: '/',
      name: 'home',
      component: Home
    },
  ]
})

In the above code, the component is dynamically loaded using the import function, and the component will be loaded only when the corresponding route is accessed. This implements lazy loading of routes.

3.2. vue-lazyload plug-in, lazy loading of images

vue-lazyloadIt is a Vue.js plug-in used to implement lazy loading of images. It can automatically monitor the scrolling events of the page and load the image when it appears in the user's visible area, thereby reducing page loading pressure, optimizing user experience and speeding up page rendering.

The following are vue-lazyloadthe basic steps to implement lazy loading of images using :

1). Install vue-lazyloadplug-in

npm install vue-lazyload --save

2). Write Vue components and introduce lazy loading images into the template.

<template>
  <div class="container">
    <img v-lazy="imgSrc" alt="图片描述">
  </div>
</template>

<script>
export default {
      
      
  data() {
      
      
    return {
      
      
      imgSrc: 'path/to/image.jpg'
    }
  }
}
</script>

vue-lazyload3). Register the plug-in in Vue

import Vue from 'vue'
import VueLazyLoad from 'vue-lazyload'

Vue.use(VueLazyLoad)

4). Configure vue-lazyloadglobal parameters of

import Vue from 'vue'
import VueLazyLoad from 'vue-lazyload'

Vue.use(VueLazyLoad, {
    
    
  loading: 'loading.gif', // 加载中的占位图
  error: 'error.gif' // 加载失败的占位图
})

Through the above steps, you can implement simple lazy loading of images in Vue applications, improving page performance and user experience.

It should be noted that on mobile browsers, in order to improve the scrolling smoothness and user experience of the page, it is recommended to vue-lazyloadenable listenEventsthe option in and use Touchevents instead scrollof events to monitor page scrolling. At the same time, considering that users may slide the interface quickly during scrolling, it is recommended to turn on adapterthe option, which is to automatically adjust the loading timing and order of lazy-loaded images when the page is scrolling, thereby preventing some images from failing to load due to scrolling too fast. .

3.3. Use cache

Use caching and resource reuse technology to reduce unnecessary repeated requests and renderings, such as using keep-alive components to cache component status.

Caching technology is an effective way to optimize web application performance and user experience. The Vue.js project can also use caching technology to further improve application response speed, reduce server burden and enhance user experience. Here are several common ways to use caching technology to improve user experience in Vue.js projects:

1). Browser cache
Browser cache is a common and easy-to-implement caching technology. By caching resource files (such as images, CSS, JS, etc.) into the client browser, it can reduce the number of server requests and speed up page loading. speed and reduce server load. In Vue.js, you can use keep-alivethe components provided by Vue Router to implement component caching. When a component is cached, it will be loaded from the browser cache every time it is accessed, thereby reducing the number of server requests and improving user experience. .

2). Server-side caching
In Vue.js projects, we usually use AJAX or Axios to send HTTP requests to obtain data. If we have to re-request data from the server for each request, it will consume a lot of time and bandwidth resources and affect users. experience. Therefore, you can use server-side caching technology to cache data, such as using Redis to cache commonly used data or using CDN to store static resource files, thereby reducing the request burden on the server and improving data access speed and response time.

3). Lazy loading.
If a page contains a large number of pictures or other resource files, it will greatly affect the loading speed and user experience of the page. In order to avoid this situation, you can use lazy loading technology, that is, the resource files of a certain area are loaded only when the user needs to browse the area. In Vue.js, you can use vue-lazyloadplugins to implement lazy loading of images.

4). Data caching
In the Vue.js project, you can use Vuex to manage the status of the application. In the application, you often need to obtain the same data, so you can use Vuex's caching technology to cache the requested data and make it available in the next request. Data is obtained directly from the cache, thereby reducing the number of server requests and improving user experience.

3.4、watch & computed

watchand computedare two very commonly used reactive data processing methods in Vue. They can both monitor data changes and perform corresponding operations. In terms of improving the performance and user experience of Vue projects, watchand computedalso have different application scenarios and optimization methods.

1). Optimize watch performance

  • Try to avoid asynchronous operations in watch, because asynchronous operations usually block the JS thread and affect page performance. If asynchronous operations must be performed, you can use vm.$nextTickthe or Promise.thenmethod to defer the asynchronous operations to the next DOM update.
  • When monitoring complex data types such as arrays or objects, try to use deepthe option to listen for changes in its sub-properties instead of using immediatethe option to immediately execute the callback function. Because immediatethe callback function will be executed immediately, the monitored data will be calculated and rendered multiple times, affecting page performance.
  • Avoid performing too many calculation and rendering operations in the watch, and try to computedhandle these operations in attributes.
  1. Optimize computed performance
  • Avoid computedreferencing others in computed, as this will cause redundant calculations and rendering and reduce page performance.
  • For large amounts of data or large calculations computed, you can use lazythe option to set it to lazy calculation, which will only be recalculated when calculations are needed.
  • For some frequently changing responsive data, you can consider using watchto monitor its changes instead of using computedto calculate.

3.5. Anti-shake & throttling

Function throttling (throttle) and function debounce (debounce) are both to limit the execution frequency of the function to optimize the response speed caused by the function trigger frequency being too high to keep up with the trigger frequency, delay, suspended animation or freezing
. Optimization solution for frequently triggered events.

Vue - Anti-shake and throttling using Lodash

3.6. Use of v-if and v-show

v-ifand v-showare two commonly used conditional rendering instructions in Vue. They can both control the display and hiding of elements based on the value of an expression, but there are some differences in specific usage.

1). The function of the v-if
v-ifdirective is to decide whether to render the DOM element based on the true or false value of the bound expression. When the bound expression is true, the element will be rendered to the page; when the bound expression is false, the element will not be rendered to the page, which is equivalent to removing the element from the DOM tree. element and its subelements.
Advantages: When the conditions are not met, the rendering and loading of unnecessary DOM elements can be reduced, thereby improving the loading speed and performance of the page.
Disadvantages: Each time the condition is switched, the corresponding component or element will be recreated and destroyed, so it may be slower than when the program is running v-show.

2). The function of the v-show
v-showdirective is to control the display and hiding of elements based on the true or false value of the bound expression. Unlike v-if, v-showthe element is not removed from the DOM tree, but the display and hiding of the element is controlled by modifying its CSS style.
Advantages: When the condition is not met, the element and its sub-elements will not be removed from the DOM tree. Therefore, when switching conditions, the state and attributes of the element can be retained, improving the smoothness and experience of page switching.
Disadvantages: When the condition is not met, the element will still be loaded into the page, so the rendering and loading time of the page may be increased. Therefore, it is recommended to use it for elements or components that need to be switched frequently v-show.

Guess you like

Origin blog.csdn.net/iotjin/article/details/131050534