自定义 webpack 配置2:缓存配置

802 阅读3分钟

参考 webpack教程、create-react-app(eject后)配置,自定义一个适合的、可维护的webpack配置

  1. 使用 webpack 来打包我们的模块化后的应用程序,会生成一个可部署的 /dist 目录,打包后的内容放置在此目录中。只要 /dist 目录中的内容部署到服务器上,客户端(通常是浏览器)就能够访问网站此服务器的网站及其资源。

  2. 浏览器使用一种名为缓存的技术。可以通过命中缓存,以降低网络流量,使网站加载速度更快。在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。

  3. 通过必要的配置,以确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。

1. 资源缓存

1.1 修改 webpack.base.js 中 file-loader 配置

{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  use: [
    {
      loader: "file-loader",
      options: {
        name: "static/media/[name].[hash:8].[ext]",
      },
    },
  ],
}

1.2 修改 webpack.base.js 中 url-loader 配置

{
  test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
  use: [
    {
      loader: "url-loader",
      options: {
        limit: 51200, //50k
        name: "static/media/[name].[hash:8].[ext]",
      },
    },
  ],
}

1.3 构建成功后可以看到 图片和字体文件出现在dist/static/media文件夹中

big.efb37eb0.png
font.d55bf3f0.ttf

2. JavaScript 缓存

2.1 修改 webpack.base.js 中 output 配置

  output: {
    filename: "static/js/[name].[contenthash:8].js",
  },

1.2 构建成功后可以看到 JavaScript 文件出现在dist/static/js文件夹中

main.5532aaad.js

3. CSS 缓存

3.1 抽取 CSS

3.1.1 安装插件

yarn add mini-css-extract-plugin -D

3.1.2 修改 webpack.base.js 文件

const pathsUtil = require("./pathsUtil");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  //指定入口文件
  entry: pathsUtil.appIndexJs,
  output: {
    filename: "static/js/[name].[contenthash:8].js",
  },
  module: {
    rules: [
      {
        test: /\.(js|mjs|jsx|ts|tsx)$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["@babel/preset-env"], "@babel/preset-react"],
          },
        },
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: { publicPath: "../../" },
          },
          "css-loader",
        ],
      },
      {
        test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 51200, //50k
              name: "static/media/[name].[hash:8].[ext]",
            },
          },
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "static/media/[name].[hash:8].[ext]",
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: pathsUtil.appHtml,
      inject: true,
    }),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[contenthash:8].css",
      chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
    }),
  ],
};

3.1.3 构建成功后可以看到 CSS 文件出现在dist/static/css文件夹中

main.52aa0dde.css
.color {
  color: rebeccapurple;
}
@font-face {
  font-family: myFirstFont;
  src: url(static/media/font.d55bf3f0.ttf);
}
.font {
  font-family: myFirstFont;
}


3.2 压缩 CSS

3.2.1 安装插件

yarn add optimize-css-assets-webpack-plugin -D

3.2.2 修改 webpack.prod.js 文件

开发环境不需要压缩

const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = merge(baseConfig, {
  mode: "production",
  plugins: [new OptimizeCssAssetsPlugin()],
});

3.2.3 构建成功后可以看到 CSS 文件出现在dist/static/css文件夹中

main.52aa0dde.css
.color{color:#639}@font-face{font-family:myFirstFont;src:url(static/media/font.d55bf3f0.ttf)}.font{font-family:myFirstFont}

4. bundle 分析

在进行 提取引导模板防止重复 之前先安装 bundle 分析 工具。

4.1 安装依赖

yarn add -D webpack-bundle-analyzer

4.2 编辑 webpack.prode.js 文件

const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const ImageminPlugin = require("imagemin-webpack-plugin").default;
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
module.exports = smp.wrap(
  merge(baseConfig, {
    mode: "production",
    devtool: "source-map",
    plugins: [
      new CleanWebpackPlugin(),
      new OptimizeCssAssetsPlugin(),
      new BundleAnalyzerPlugin({ analyzerMode: "static" }),
      // 暂时屏蔽,太耗时
      //Make sure that the plugin is after any plugins that add images
      // new ImageminPlugin({
      //   pngquant: {
      //     quality: "95-100",
      //   },
      // }),
    ],
  })
);

4.3 重新构建

在 dist 目录下生成 report.html 文件

index.html 0.35K
static/css/main.ad7a61d4.css 0.23K
static/js/main.8ba15055.js 191.13K
static/js/main.8ba15055.js.map 373.05K
static/media/big.efb37eb0.png 4303.18K
static/media/font.d55bf3f0.ttf 77.86K

5. 提取引导模板

5.1 编辑 webpack.prode.js 文件

const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const ImageminPlugin = require("imagemin-webpack-plugin").default;
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
module.exports = smp.wrap(
  merge(baseConfig, {
    mode: "production",
    devtool: "source-map",
    plugins: [
      new CleanWebpackPlugin(),
      new OptimizeCssAssetsPlugin(),
      new BundleAnalyzerPlugin({ analyzerMode: "static" }),
      // 暂时屏蔽,太耗时
      //Make sure that the plugin is after any plugins that add images
      // new ImageminPlugin({
      //   pngquant: {
      //     quality: "95-100",
      //   },
      // }),
    ],
    optimization: {
      runtimeChunk: "single",
    },
  })
);

5.2 重新构建

在 dist 目录下生成 report.html 文件

static/css/main.ad7a61d4.chunk.css 0.23K
static/js/main.a4b90f3e.js 190.30K
static/js/main.a4b90f3e.js.map 367.78K
static/js/runtime.1ee16c22.js 1.50K
static/js/runtime.1ee16c22.js.map 8.07K
static/media/big.efb37eb0.png 4303.18K
static/media/font.d55bf3f0.ttf 77.86K

6. 防止重复导入

6.1 添加新的入口文件

6.1.1 编辑 webpack.base.js 文件

  entry: {
    index: pathsUtil.appIndexJs,
    index2: pathsUtil.appIndex2Js,//复制粘贴 index.js 内容
  },

6.1.2 重新构建

在 dist 目录下生成 report.html 文件

index.html 0.53K
static/css/index.ad7a61d4.chunk.css 0.23K
static/css/index2.ad7a61d4.chunk.css 0.23K
static/js/index.f769b13e.js 190.39K
static/js/index.f769b13e.js.map 367.79K
static/js/index2.354d10c2.js 190.39K
static/js/index2.354d10c2.js.map 367.79K
static/js/runtime.f00dbe9b.js 1.50K
static/js/runtime.f00dbe9b.js.map 8.07K
static/media/big.efb37eb0.png 4303.18K
static/media/font.d55bf3f0.ttf 77.86K

可以看出,index 和 index2 均为 190.39K, node_modules 中的文件被重复打包,需要抽取公共包

6.2 编辑 webpack.prod.js 文件

    optimization: {
      runtimeChunk: "single",
      splitChunks: {
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: "vendors",
            chunks: "all",
          },
        },
      },
    },

6.3 重新构建

在 dist 目录下生成 report.html 文件

static/css/index.ad7a61d4.chunk.css 0.23K
static/css/index2.ad7a61d4.chunk.css 0.23K
static/js/index.58fc8036.js 63.90K
static/js/index.58fc8036.js.map 62.87K
static/js/index2.829aa779.js 63.91K
static/js/index2.829aa779.js.map 62.87K
static/js/runtime.f00dbe9b.js 1.50K
static/js/runtime.f00dbe9b.js.map 8.07K
static/js/vendors.eea1f403.js 126.60K
static/js/vendors.eea1f403.js.map 305.04K
static/media/big.efb37eb0.png 4303.18K
static/media/font.d55bf3f0.ttf 77.86K

可以看出 index 和 index2 均为 63.90K ,node_modules 中的文件被抽取公共包 vendors 。


代码仓库

参考链接