Skip to content

react-scripts v2 webpack 4 splitChunks name setting should use the default #4769

Closed
@TLadd

Description

Is this a bug report?

No

(Disclaimer: not a Webpack 4 expert. Learned as much as I could about splitChunks today for filing this issue, but definitely still have some gaps in knowledge)

I pulled down the latest react-scripts v2 beta release (2.0.0-next.3e165448), which contains the Webpack 4 upgrade (#4077). One of the features included in Webpack 4 is automatically splitting out a vendor bundle for you. As the tweet referenced in the react-scripts webpack config says, all that is necessary to enable this behavior is setting optimization.splitChunks.chunks: "all".

The react-scripts config does this, but it also sets optimization.splitChunks.name to "vendors", which I think is a mistake with unintended consequences. The webpack docs actually have a warning that I believe warns about doing this:

When assigning equal names to different split chunks, all vendor modules are placed into a single shared chunk, though it's not recommend since it can result in more code downloaded.

The problem I'm seeing with the current splitChunks config, is that all node_modules are placed into the vendors bundle even if I dynamically import them. This is problematic for cases where you have a large dependency that is only needed on one or two pages that may not be visited very frequently. It ends up in the vendors bundle, but it would be better if it were split off into its own bundle, loaded whenever the pages are visited, and cached separately. Removing name: 'vendors', from the splitChunks config, seems to give the more desirable output.

I experimented with the different values for the splitChunks name field in this repo. Here's a basic summary of what I found:

Code being run through webpack

// index.js
import "react-dom";
import "./a";
import "./b";
import "./c";

// a.js
import "react";
import "moment";
import "lodash";

// b.js
import "react";
import(/* webpackChunkName: "zxcvbn" */ "zxcvbn");

// c.js
import "react";
import "moment";
import(/* webpackChunkName: "highcharts" */ "highcharts");

So the basic idea here is that react, react-dom, moment, and lodash are all dependencies that are used commonly throughout the application and are well-suited for being in the main vendors.js bundle. highcharts and zxcvbn are large dependencies that are only used once, and so we're dynamically importing them to try and avoid loading them immediately.

With optimization.splitChunks.name: "vendors" (same as react-script), the output is

     Asset      Size  Chunks                    Chunk Names
vendors.js  1.36 MiB       0  [emitted]  [big]  vendors
   main.js  4.89 KiB       1  [emitted]         main

highcharts and zxcvbn both end up in vendors.js.

With optimization.splitChunks.name: true (webpack's default), the output is

                Asset      Size  Chunks                    Chunk Names
vendors~highcharts.js   201 KiB       0  [emitted]         vendors~highcharts
    vendors~zxcvbn.js   799 KiB       1  [emitted]  [big]  vendors~zxcvbn
      vendors~main.js   389 KiB       2  [emitted]  [big]  vendors~main
              main.js  5.62 KiB       3  [emitted]         main

The second output seems like what we would want. So I think it would be best if the name: "vendors" line were removed and instead use the default.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions