webpack优化手段

webpack优化手段

1. Webpack 性能优化手段

1.1. 减小文件体积

1.1.1. 使用 Tree Shaking

通过静态分析代码,移除未使用的代码。

// webpack.config.js
module.exports = {
  // ...
  optimization: {
    usedExports: true,
  },
};

1.1.2. 使用代码分割(Code Splitting)

将代码拆分为多个较小的块,按需加载。

// App.js
import(/* webpackChunkName: "my-chunk" */ './my-module').then((module) => {
  // 使用导入的模块
});

// webpack.config.js
module.exports = {
  // ...
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

1.1.3. 使用动态导入(Dynamic Import)

按需加载模块。

// App.js
import('./my-module').then((module) => {
  // 使用导入的模块
});

1.1.4. 压缩代码

使用 UglifyJS、Terser 等工具压缩 JavaScript 代码。

// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  // ...
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
};

1.1.5. 使用 Css 预处理器

如使用 Sass、Less 等,可以通过编译和压缩减小 CSS 文件体积。

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
    ],
  },
};

1.1.6. 图片优化

使用压缩工具压缩图片,如使用 imagemin-webpack-plugin。

// webpack.config.js
const ImageminPlugin = require('imagemin-webpack-plugin').default;

module.exports = {
  // ...
  plugins: [
    new ImageminPlugin({
      test: /\.(jpe?g|png|gif|svg)$/i,
    }),
  ],
};

1.2. 缓存优化

1.2.1. 使用持久化缓存

使用 webpack-manifest-plugin 生成一个映射清单,将模块 ID 映射到实际的输出文件,以便在构建过程中保持持久化的模块 ID。

// webpack.config.js
const ManifestPlugin = require('webpack-manifest-plugin');

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

1.2.2. 文件名哈希化

通过添加哈希值到文件名中,确保文件内容发生变化时,生成的文件名也会发生变化,从而使浏览器能够正确地缓存新文件。

// webpack.config.js
module.exports = {
  // ...
  output: {
    filename: '[name].[contenthash].js',
  },
};

1.2.3. 使用缓存加载器(cache-loader、hard-source-webpack-plugin)

将中间结果缓存起来,避免重复的工作。

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['cache-loader', 'babel-loader'],
      },
    ],
  },
};

1.3. 并行构建

1.3.1. 使用 Happypack

将任务分解给多个子进程并行处理。

// webpack.config.js
const HappyPack = require('happypack');

module.exports = {
  // ...
  plugins: [
    new HappyPack({
      threads: 4, // 指定线程池的数量
      loaders: ['babel-loader'], // 使用的 Loader
    }),
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'happypack/loader', // 使用 HappyPack 加载器
      },
    ],
  },
};

1.3.2. 使用 Thread-loader

将耗时的 Loader 任务分配给 Worker 线程处理。

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['thread-loader', 'babel-loader'], // 使用 thread-loader 和 babel-loader
      },
    ],
  },
};

1.4. 减少构建时间

1.4.1. 使用 resolve.modules 配置

缩小模块搜索范围,减少模块查找时间。

// webpack.config.js
module.exports = {
  // ...
  resolve: {
    modules: ['src', 'node_modules'], // 指定模块的搜索路径
  },
};

1.4.2. 使用 resolve.extensions 配置

减少模块文件后缀的解析尝试。

// webpack.config.js
module.exports = {
  // ...
  resolve: {
    extensions: ['.js', '.jsx', '.json'], // 指定模块文件后缀的解析尝试顺序
  },
};

1.4.3. 使用 Externals

将一些不需要打包的模块排除在构建之外。

// webpack.config.js
module.exports = {
  // ...
  externals: {
    lodash: '_', // 指定外部引入的模块
  },
};

1.5. 优化输出结果

1.5.1. 使用 DLL(动态链接库)

将基础模块提前编译成静态文件,加快构建速度。

webpack.dll.config.js:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  mode: 'production',
  entry: {
    vendor: ['react', 'react-dom'], // 指定基础模块
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].dll.js',
    library: '[name]_dll', // 输出的全局变量名
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]_dll',
      path: path.resolve(__dirname, 'dist', '[name].manifest.json'),
    }),
  ],
};

webpack.config.js:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  // ...
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./dist/vendor.manifest.json'),
    }),
  ],
};

1.5.2. 使用 Scope Hoisting(作用域提升)

将模块封装成函数作用域,减少模块包裹代码的体积。

// webpack.config.js
module.exports = {
  // ...
  optimization: {
    concatenateModules: true,
  },
};

1.6. 使用优化插件

1.6.1. 使用 webpack.optimize.ModuleConcatenationPlugin

启用模块串联,减少模块封装代码的体积。

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  // ...
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin(),
  ],
};

1.6.2. 使用 webpack.IgnorePlugin

忽略某些特定的模块,在打包过程中不引入它们。

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  // ...
  plugins: [
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale/, // 忽略 moment.js 的 locale 目录
      contextRegExp: /moment/, // 忽略 moment.js 的 context
    }),
  ],
};

1.6.3. 使用 Webpack-bundle-analyzer

可视化地分析构建结果,找出体积较大的模块。

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

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

1.7. 使用 Webpack-merge

合并 webpack 配置的工具,可以用于区分开发环境和生产环境的配置。减少重复代码

npm install webpack-merge --save-dev

然后,我们将创建三个配置文件:webpack.common.js、webpack.dev.js 和 webpack.prod.js。

在 webpack.common.js 中定义通用的配置项,包括入口、输出路径、加载器、插件等:

// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      // 加载器规则
      // ...
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
    // 其他插件
    // ...
  ],
};

我们创建 webpack.dev.js 文件,该文件包含开发环境的特定配置,如开发服务器配置、源映射等:

// webpack.dev.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

module.exports = merge(commonConfig, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
    port: 3000,
  },
  module: {
    rules: [
      // 开发环境的加载器规则
      // ...
    ],
  },
  plugins: [
    // 开发环境的插件
    // ...
  ],
});

我们创建 webpack.prod.js 文件,该文件包含生产环境的特定配置,如压缩代码、提取 CSS、代码分割等:

// webpack.prod.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = merge(commonConfig, {
  mode: 'production',
  devtool: 'source-map',
  module: {
    rules: [
      // 生产环境的加载器规则
      // ...
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
    // 其他插件
    // ...
  ],
  optimization: {
    minimizer: [new TerserPlugin()],
    splitChunks: {
      chunks: 'all',
    },
  },
});

最后,在 package.json 中配置脚本,以便在开发环境和生产环境中使用相应的配置文件:

{
  "scripts": {
    "dev": "webpack-dev-server --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  }
}

留下回复

目录