如何对Webpack的供应商代码块进行代码分离?

3

我有一个webpack的main.bundle.js,由于代码拆分,大小为287kb,但我的vendor.js5mb。当用户第一次访问网站时,他将不得不下载5.2mb,这太大了。

如何正确地拆分供应商,使用户只下载运行页面所需的包,然后webpack在后台预取所有剩余的包?

我正在使用webpack 4(在支持Storybook之前,我正在等待webpack 5的支持。如果W5中有新的方法,请告诉我)。

以下是我的配置:

/* eslint-env node */
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const Dotenv = require("dotenv-webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const isProductionMode = (mode) => mode === "production";

module.exports = () => {
  const env = require("dotenv").config({ path: __dirname + "/.env" });
  const nodeEnv = env.parsed.NODE_ENV;
  return {
    mode: "development",
    entry: "./src/index.tsx",
    output: {
      path: path.join(__dirname, "./dist"),
      filename: "[name].[hash].bundle.js",
      publicPath: "/",
    },
    resolve: {
      extensions: [".ts", ".tsx", ".js", "jsx", ".json"],
    },
    module: {
      rules: [
        {
          test: /\.(ts|js)x?$/,
          exclude: /node_modules/,
          use: { loader: "babel-loader" },
        },
        { test: /\.css$/, use: ["style-loader", "css-loader"] },
        { test: /\.(png|jpg|jpeg|gif)$/, use: ["file-loader"] },
        {
          test: /\.svg$/,
          use: [
            {
              loader: "babel-loader",
            },
            {
              loader: "react-svg-loader",
              options: {
                jsx: true,
              },
            },
          ],
        },
      ],
    },
    devServer: {
      historyApiFallback: true,
      port: 3000,
      inline: true,
      hot: true,
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: "./src/index.html",
      }),
      new Dotenv(),
    ],
    optimization: {
      minimize: isProductionMode(nodeEnv),
      minimizer: isProductionMode(nodeEnv) ? [new TerserPlugin()] : [],
      splitChunks: { chunks: "all" },
    },
  };
};


我觉得你可能想使用 'webpack-bundle-analyzer'(https://www.npmjs.com/package/webpack-bundle-analyzer)来查看哪个模块增加了文件大小。之后,你可以使用代码分割技术来延迟导入较大的模块。另一种应用的技术是树摇动。 - dongnhan
2个回答

6
这对我在拆分供应商捆绑包方面非常有帮助。
来源:https://gist.github.com/davidgilbertson/c9af3e583f95de03439adced007b47f1
splitChunks: {
  chunks: 'all',
  enforce: true,
  cacheGroups: {
    vendor: {
      test: /[\\/]node_modules[\\/]/,
      name(module) {
        // get the name. E.g. node_modules/packageName/not/this/part.js
        // or node_modules/packageName
        const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

        // npm package names are URL-safe, but some servers don't like @ symbols
        return `npm.${packageName.replace('@', '')}`;
      },
    },
  },
},

0

这个https://github.com/facebook/create-react-app/discussions/9161讨论包含一些配置(Webpack 5,不需要太多调整即可与Webpack 4一起使用),如果您想学习和重用单个分块策略,则可以给您一个很好的默认值。

如果您喜欢简单的东西,可以在config.optimization.splitChunks下添加1-2个自定义cacheGroups,看起来可能像这样:

     firebase: { // Internal identifier, just any unique name.
        test: /@firebase|redux-fire/, // This will match any file path containing @firebase or redux-fire (base and store) which is massive.
        name: "firebase", // Add a name to easily spot this chunk among outputs, or remove the `name` property to get a number instead which seems to be best-practice.
        priority: 10, // Higher prio = gets processed earlier. Defaults are on below 0.
      },

以上据我所见兼容Webpack 4和5: https://v4.webpack.js.org/plugins/split-chunks-plugin/ 如果你想要更多的控制,你也可以取消默认分组:
    cacheGroups: {
      firebase: {
        test: /@firebase|redux-fire/,
        name: "firebase",
        priority: 20,
      },
      defaultVendors: false,
      default: false,
      // Add more groups here
    },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接