webpack如何做性能优化

日益复杂的业务,越来越庞大的项目,用户体验要求也越来越高,性能问题是必须要考虑的。 今天主要考虑webpack中能做的性能优化有哪些

# 构建速度优化

# 使用新版本

这个是个万能策略,webpack新版本的发布,必定会带来性能提升。

# 优化搜索文件

Webpack 的打包范围很大程度上会影响它的性能。可以使用Webpack提供的配置项来缩小打包范围。排除 Webpack 不需要解析的模块,即使用 loader 的时候,在尽量少的模块中去使用。

例如,可以使用 include、exclude 等选项来控制哪些模块需要打包,哪些模块不需要打包。 这样可以减少不必要的文件的解析和编译,从而提高Webpack的性能。

module.exports = {
  //...
    module: {
        rules: [
            {
                test: /\.js|jsx$/,
                exclude: /node_modules/,
                include: path.resolve(__dirname, '../src'),
                use: ['babel-loader']
            },
            // ...
        ]
    },
};

# 缩小文件检索范围

合理使用resolve alias(减少查找过程) extensions(给定文件扩展中搜索) modules(给定目录中搜索)优化文件检索范围;

module.exports = {
  //...
    resolve: {
        // ...
        alias: {
            react: path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
            @alias: path.resolve(__dirname, '../src/alias'),
        },
    },
};

# 对匹配文件分析转化

使用module.noParse 指定不需要解析的文件,用来排除非模块化文件的解析 ;

防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。

module.exports = {
  //...
  module: {
    noParse: /jquery|lodash/,
  },
};

# 通过DllPlugin避免重复编译第三方库

预先编译资源模块,在打包的时候,一般来说第三方模块是不会变化的,所以我们想只要在第一次打包的时候去打包一下第三方模块,并将第三方模块打包到一个特定的文件中, 当第二次 webpack 进行打包的时候,就不需要去 node_modules 中去引入第三方模块,而是直接使用我们第一次打包的第三方模块的文件就行。

具体用法如下:

// 配置文件目录 config 下新建一个 webpack.dll.js,此文件用于将我们的第三方包文件打包到 dll 文件夹中去:
// config/webpack.dll.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
  mode: 'production', // 环境
  entry: {
    vendors: ['lodash'], // 将 lodash 打包到 vendors.js 下
  },
  output: {
    filename: '[name].dll.js', // 输出的名字
    path: path.resolve(__dirname, '../dll'), // 输出的文件目录
    library: '[name]' // 将我们打包出来的文件以全部变量的形式暴露,可以在浏览器变量的名字进行访问
  },
  plugins: [
    // 对生成的库文件进行分析,生成库文件与业务文件的映射关系,将结果放在 mainfest.json 文件中
    new webpack.DllPlugin({
      name: '[name]', // 和上面的 library 输出的名字要相同
      path: path.resolve(__dirname, '../dll/[name].manifest.json'),
    })
  ]
}

同时我们需要使用 webpack 自带的 DllReferencePlugin 插件对 mainfest.json 映射文件进行分析。

module.exports = {
    plugins: [
        new webpack.DllReferencePlugin({
            manifest: require(path.resolve(__dirname, '../dll/vendors.dll.mainfest.json'))
        }),
    ],
}

# 使用thread-loader开启多进程loader转换

webpack 官方推出的一个多进程方案,用来替代 HappyPack。 每次 webapck 解析一个模块,HappyPack 会将它及它的依赖分配给 worker 线程中。处理完成之后,再将处理好的资源返回给 HappyPack 的主进程,从而加快打包速度。

module.exports = {
  //...
    module: {
        rules: [{
            test: /\.jsx?$/,
            use: [
                {
                    loader: 'thread-loader',
                    options: {
                        workers: 3, // 开启几个 worker 进程来处理打包,默认是 os.cpus().length - 1
                    }
                },
                'babel-loader'
            ]
        }]
    },
};

# 优化输出代码

# 压缩资源

# js压缩

webpack4.0 默认是使用 terser-webpack-plugin 这个压缩插件,在此之前是使用 uglifyjs-webpack-plugin, 区别是uglifyjs-webpack-plugin对 ES6 的压缩不是很好,同时我们可以开启 parallel 参数,使用多进程压缩,加快压缩。

// config/webpack.common.js
const TerserPlugin = require('terser-webpack-plugin');
const commonConfig = {
  // ...
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: 4, // 开启几个进程来处理压缩,默认是 os.cpus().length - 1
      }),
    ],
  },
  // ...
}

# css压缩

我们可以借助 optimize-css-assets-webpack-plugin 插件来压缩 css,其默认使用的压缩引擎是 cssnano。

使用 PurgeCSS 来完成对无用 css 的擦除,它需要和 mini-css-extract-plugin 配合使用。

# 图片压缩

我们就可以借助 image-webpack-loader 帮助我们来实现。它是基于 imagemin 这个 Node 库来实现图片压缩的。

# Tree Shaking去除无用代码

使用 ES6 Modules 语法,以保证 Tree-Shaking 起作用 ;因为 tree-shaking 只对 ES6 Modules 静态引入生效,对于类似于 CommonJs 的动态引入方式是无效的

# 代码分割,按需加载

Webpack提供了Code Splitting机制,可以将代码拆分成多个包,以便更快地加载和处理代码。可以使用以下方法开启Code Splitting: 使用SplitChunksPlugin将公共的代码提取成一个独立的文件,避免代码重复加载。

// 使用 SplitChunksPlugin 将公共代码提取成一个单独的文件
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all' // 可取 all,async 和 initial,默认值async
    }
  }
};

# 分离第三方库,使用cdn加载资源

module.exports = {
  //...
  externals: {
    lodash: '_'
  }
};

需要注意的是,如果你使用externals,则必须确保在打包后能够正确地获取这些模块。可以配合html-webpack-externals-plugin来自动插入script标签

# gzip压缩

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

module.exports = {
    plugins: [
        new CompressionPlugin(),
    ],
};

# 使用动态导入来延迟加载代码

import(/* webpackChunkName: "my-chunk" */ './my-module').then((module) => {
  // do something with module
});

# 合理配置 chunk 的哈希值来利用缓存

在生产环境打包,一定要配置文件的 hash,这样有助于浏览器缓存我们的文件,当我们的代码文件没变化的时候,用户就只需要读取浏览器缓存的文件即可。 一般来说

  1. javascript 文件使用 [chunkhash]
  2. css 文件使用 [contenthash]
  3. 其他资源(例如图片、字体等)使用 [hash]

# 合理使用 sourceMap

生成 sourceMap 的时候,如果信息越详细,打包速度就会越慢

最近更新
01
echarts扇形模拟镜头焦距与可视化角度示意图
03-10
02
vite插件钩子
03-02
03
vite的依赖预构建
02-13
更多文章>