0

Just upgraded webpack 4 to webpack 5 on our react project that only required a few minor tweaks to get it to actually build. After being built and deployed, it appears that the code splitting aspect is working, but it also appears that a main app.js file is still being created and then fetched upon each load/reload of the page.

Here is what I believe is the applicable code in our webpack config:

this.config = {
        devServer: {
            static: ['./public/', './src/'],
            historyApiFallback: true,
            hot: true,
            devMiddleware: {
                publicPath: '/assets/js/',
            },
            port: 2612,
            host: 'localhost'
        },
        cache: false,
        devtool: 'source-map',
        entry: ['babel-polyfill', './index.js'],
        output: {
            path: root('app'),
            publicPath: '',
            filename: 'assets/js/app.js',
            chunkFilename: 'assets/js/[id].[contenthash].chunk.js',
            // Point sourcemap entries to original disk location (format as URL on Windows)
            devtoolModuleFilenameTemplate: (info) =>
                path.relative('src', info.absoluteResourcePath).replace(/\\/g, '/')
        },
        optimization: {
            splitChunks: {
                chunks: 'async',
                minSize: 20000,
                minChunks: 1,
                maxAsyncRequests: 30,
                maxInitialRequests: 30,
                enforceSizeThreshold: 50000,
                cacheGroups: {
                  defaultVendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                    reuseExistingChunk: true,
                  },
                  default: {
                    minChunks: 2,
                    priority: -20,
                    reuseExistingChunk: true,
                  },
                },
            },
            minimize: true,
            minimizer: [
                new TerserPlugin(),
                new CssMinimizerPlugin()
            ]
        },
        resolve: {
            alias: {
                assets: `${this.srcPathAbsolute}/assets/`,
                actions: `${this.srcPathAbsolute}/actions/`,
                components: `${this.srcPathAbsolute}/components/`,
                constants: `${this.srcPathAbsolute}/constants`,
                config: `${this.srcPathAbsolute}/config/${this.env}.js`,
                containers: `${this.srcPathAbsolute}/containers/`,
                reducers: `${this.srcPathAbsolute}/reducers/`,
                app: `${this.srcPathAbsolute}/app/`,
                styles: `${this.srcPathAbsolute}/styles/`,
                themes: `${this.srcPathAbsolute}/themes/`,
                utilities: `${this.srcPathAbsolute}/utilities/`
            },
            extensions: ['.js', '.jsx'],
            modules: [this.srcPathAbsolute, 'node_modules'],
            fallback: {
                "stream": false,
                "zlib": false,
                "assert": false,
                "buffer": require.resolve('buffer/'),
                "process": require.resolve('process/browser'),
                "util": require.resolve('util/'),
                "stream": require.resolve("stream-browserify"),
            }
        },
        module: {
            rules: [
                {
                    enforce: 'pre',
                    test: /\.js?$/,
                    include: this.srcPathAbsolute,
                    use: {
                        loader: 'babel-loader'
                        // options: {
                        //   presets: ['es2015', 'react', 'stage-2']
                        // }
                    }
                },
                {
                    test: /^.((?!cssmodule).)*\.css$/,
                    use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
                },
                {
                    test: /\.(png|jpg|gif|mp4|ogg|svg|woff|woff2|ttf|eot|ico)$/,
                    use: [
                        {
                            loader: 'file-loader',
                            options: {
                                outputPath: 'assets/fonts'
                            }
                        }
                    ]
                },
                {
                    test: /^.((?!cssmodule).)*\.styl$/,
                    use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'stylus-loader' }]
                },
                {
                    test: /\.cssmodule\.(sass|scss)$/,
                    use: [
                        { loader: 'style-loader' },
                        {
                            loader: 'css-loader',
                            options: cssModulesQuery
                        },
                        { loader: 'sass-loader' }
                    ]
                },
                {
                    test: /\.cssmodule\.css$/,
                    use: [
                        { loader: 'style-loader' },
                        {
                            loader: 'css-loader',
                            options: cssModulesQuery
                        }
                    ]
                },
                {
                    test: /\.cssmodule\.less$/,
                    use: [
                        { loader: 'style-loader' },
                        {
                            loader: 'css-loader',
                            options: cssModulesQuery
                        },
                        { loader: 'less-loader' }
                    ]
                },
                {
                    test: /\.cssmodule\.styl$/,
                    use: [
                        { loader: 'style-loader' },
                        {
                            loader: 'css-loader',
                            options: cssModulesQuery
                        },
                        { loader: 'stylus-loader' }
                    ]
                },
                {
                    test: /\.js?$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            extends: path.join(__dirname, '../../.babelrc'),
                            cacheDirectory: true
                        }
                    }
                },
                {
                    test: /^.((?!cssmodule).)*\.(sass|scss)$/,
                    use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }]
                },
                {
                    test: /^.((?!cssmodule).)*\.less$/,
                    use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'less-loader' }]
                }
            ]
        },
    };

This config is creating a TON of small (5-100kb) chunked out files and map files that look something like this: 250.2edde99552a0e46f7950.chunk.js 250.2edde99552a0e46f7950.chunk.js.map

and then what appears to be a main app.js file (1.8MB) and app.js.map...

I guess what I don't understand is why does the app.js need to be fetched each time (or why this file is even being created at all) if we are supposedly code splitting here and only fetching the necessary chunks in real time of what we actually need.

The small chunks are only taking a few milleseconds to fetch for each one, but that initial fetch of the app.js is 2-3 seconds since it is so large so I'd rather avoid that if possible.

Full disclosure is that I am a webpack newbie so I'm sure there is something I am missing in the docs or something along the build process that might be causing this.

EDIT HERE: Maybe if it helps I thought about including a screenshot of the network requests happening over the course of our ridiculously long load time (5+ seconds) on the site with the app.js vs. the individual chunks: app.js and chunk fetch during load

mateotherock
  • 235
  • 5
  • 16

1 Answers1

0

in webpack, minSize: 20000, and enforceSizeThreshold: 50000, are in bytes. That means 20kb and 50kb.

Increase these values to 200000 = 200kb and 500000 = 500kb. Then the number of chunks will get reduced.

Thank you

  • I think my question is more along the lines of why it is taking so long to load the app in general. I'm not as concerned with the size of the chunks persay, but why does it appear to be fetching both the full app.js file as well as the chunks that it needs when as I understand what it SHOULD be doing is only fetching the chunks. – mateotherock Mar 13 '23 at 16:05