Reactjs 未使用的JS数量巨大,即使代码拆分并使用react.lazy

Reactjs 未使用的JS数量巨大,即使代码拆分并使用react.lazy,reactjs,performance,webpack,single-page-application,lighthouse,Reactjs,Performance,Webpack,Single Page Application,Lighthouse,我不知道如何解决这个问题。如果你有什么想法,请告诉我。 如图所示,这些是来自主应用程序和供应商js文件的捆绑包。 它们都显示了大量未使用的js。他们大多是第三方供应商之类的,但我不知道如何删除未使用的部分 有什么不对劲吗?看看我能改进什么。 我正在我的应用程序中执行以下操作 代码拆分,并使用React.Lazy 这是我的基本网页包文件: const path = require('path'); const webpack = require('webpack'); const MiniCss

我不知道如何解决这个问题。如果你有什么想法,请告诉我。 如图所示,这些是来自主应用程序和供应商js文件的捆绑包。 它们都显示了大量未使用的js。他们大多是第三方供应商之类的,但我不知道如何删除未使用的部分

有什么不对劲吗?看看我能改进什么。

我正在我的应用程序中执行以下操作

  • 代码拆分,并使用React.Lazy
  • 这是我的基本网页包文件:

    const path = require('path');
    const webpack = require('webpack');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    const AsyncStylesheetWebpackPlugin = require('async-stylesheet-webpack-plugin');
    const ScriptExtHtmlWebPackPlugin = require('script-ext-html-webpack-plugin');
    const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
    const ProgressBarPlugin = require('progress-bar-webpack-plugin');
    const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
    const TerserPlugin = require('terser-webpack-plugin');
    const { getConfigFileByEnv } = require('./src/utils/getConfigFileByEnv');
    const imageWebpackQuery = require('./imageWebpackQuery');
    const vendor = require('./vendor');
    
    const configFile = getConfigFileByEnv();
    const publicPath = process.env.CLIENT_HOST || '';
    const assetsPath = `${process.env.PROTOCOL}://${publicPath}/assets/`;
    
    module.exports = {
      mode: 'production',
      entry: {
        vendor,
        app: './src/index.js'
      },
      output: {
        filename: '[name].[chunkhash].js',
        chunkFilename: '[name].[chunkhash].chunk.js',
        publicPath: assetsPath,
        path: path.resolve(__dirname, 'build', 'public'), // string
      },
      devtool: 'source-map',
      module: {
        rules: [
          {
            test: /\.js?$/,
            include: [/src/],
            use: ['babel-loader'],
          },
          {
            test: /\.s?css$/,
            include: [
              path.resolve(__dirname, 'src/styles'),
            ],
            use: [
              MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'resolve-url-loader', 'sass-loader'
            ],
          },
          {
            test: /\.s?css$/,
            exclude: [
              path.resolve(__dirname, 'src/styles'),
            ],
            use: [
              MiniCssExtractPlugin.loader,
              {
                loader: 'css-loader',
                query: {
                  modules: {
                    localIdentName: '[hash:base64]',
                  },
                  importLoaders: true,
                  sourceMap: true,
                },
              },
              'postcss-loader',
              'sass-loader',
            ],
          },
          {
            test: /\.(eot|otf|ttf|woff|woff2)$/,
            use: 'file-loader?name=[name]_[hash:base64:5].[ext]',
          },
          {
            test: /\.(jpg|png|gif|svg)$/,
            use: [
              {
                loader: 'file-loader',
                query: {
                  name: '[name]_[contenthash].[ext]',
                  publicPath: assetsPath,
                },
              },
              {
                loader: 'image-webpack-loader',
                options: imageWebpackQuery,
              },
            ],
          },
          {
            test: /\.(mp4)$/,
            loader: 'file-loader',
            query: {
              name: '[name]_[contenthash].[ext]',
              publicPath: assetsPath,
            },
          }
        ],
      },
      resolve: {
        modules: ['src', 'node_modules'],
        alias: {
          config: path.resolve(__dirname, `src/config/`)
        }
      },
      optimization: {
        minimizer: [
          new TerserPlugin({
            sourceMap: true,
            terserOptions: {
              warnings: false,
              ie8: true,
            },
          }),
        ],
        splitChunks: {
          cacheGroups: {
            vendors: {
              name: 'vendor',
              // chunks: 'all',
              reuseExistingChunk: true,
              priority: -10,
              test(module, chunks) {
                const name = module.nameForCondition && module.nameForCondition();
                return chunks.some((chunk) => chunk.name === 'app' && /[\\/]node_modules[\\/]/.test(name));
              }
            },
            appStyles: {
               name: 'appStyles',
               test: (m, chunks) => {
                 return m.constructor.name === 'CssModule' && !m.issuer.rawRequest.includes('vendor.main.scss') && chunks.some((chunk) => chunk.name === 'app');
               },
               chunks: 'all',
               enforce: true,
             },
             vendorStyles: {
               name: 'vendorStyles',
               test: (m) => {
                 return m.constructor.name === 'CssModule' && m.issuer.rawRequest.includes('vendor.main.scss');
               },
               chunks: 'all',
               enforce: true,
             },
            default: {
              priority: -20,
              reuseExistingChunk: true
            },
          },
        },
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.browser': JSON.stringify(true),
          __CONFIG__: JSON.stringify(configFile)
        }),
        new ProgressBarPlugin(),
        new webpack.ContextReplacementPlugin(/\.\/locale$/, 'empty-module', false, /js$/),
        new MiniCssExtractPlugin({
          filename: '[name]-[contenthash].min.css',
          ignoreOrder: true,
        }),
        new OptimizeCssAssetsPlugin({}),
        new HtmlWebpackPlugin({
          template: './src/document/index.html',
          chunks: ['vendorStyles', 'appStyles', 'app', 'vendor'],
          chunksSortMode: 'manual',
          config: configFile
        }),
        new AsyncStylesheetWebpackPlugin({
          preloadPolyfill: true,
        }),
        new ScriptExtHtmlWebPackPlugin({
          defaultAttribute: 'async'
        }),
        new MomentLocalesPlugin(),
        new InlineManifestWebpackPlugin(),
        new webpack.NamedModulesPlugin(),
        new webpack.LoaderOptionsPlugin({
          minimize: true,
          debug: false,
        }),
        new FaviconsWebpackPlugin({}),
      ],
    };
    
    
    

    当使用第三方代码时,简单的答案是,如果不花费大量的时间,你不能做很多事情

    代码拆分实际上并不会改变未使用代码的数量,它只是意味着您稍后将交付非必要的代码(这对初始页面呈现等很有好处)

    所以您有两个选择。

    第一个是检查代码中“未使用”的每个函数并将其删除。显然,这是充满危险的,因为您可以很容易地删除一些在初始页面加载时可能不使用但以后需要的内容

    第二个是完全使用不同的库,或者更好的是从头开始编写

    正如你可能知道的,这里没有好的选择

    因此,我的建议是看看是否有任何快速的成功(即,您是否加载整个库只是为了延迟加载可以用几行JS完成的图像)。如果是这样的话,找一个较小的库,或者只编写自己的实现,而不需要所有可能不需要的额外特性

    然后,不用担心,集中精力发送最少数量的JS,以呈现“高于折叠”的内容,并使站点最初可用。只要网站不感到迟钝,初始(感知)页面加载速度比总加载速度更重要

    我不得不承认,超过4兆字节的JS是多余的,但我不知道这是一个需要它的复杂应用程序,还是你只是选择了“错误的工作工具”(这总是一个真正的痛苦,取决于你离项目有多远!)

    你还需要权衡时间和回报。我发现以下问题很有用:-

  • 我/公司是否在营销上花费了大量资金。这是一个需要良好排名的页面/站点。如果两个答案都是肯定的,那么速度很重要,你必须通过更好的转化率、排名等来权衡大量页面减重与潜在利润增加所需的时间
  • 如果站点不需要很好的排名,那么我使用的库(库)的开发速度是否足以证明站点速度较慢
  • 网站是否需要快速,如果它是一个销售工具,那么答案是肯定的(因为每秒钟的加载时间会减少7%-10%的转化率)。如果是软件即服务(SaaS),那么初始加载速度就不那么重要,只要它不是很慢。显然,缓存所有内容后的加载速度对于避免挫折很重要,但这更容易修复
  • 我是否修复了所有其他问题,但该网站的得分仍然很低?如果没有,则首先修复其他位。你必须考虑的是,50分实际上意味着站点的性能是第二十五个百分点,如果这是一个SaaS应用程序,这可能是足够的(或好的)。李>