react-scripts v2 webpack 4 splitChunks name setting should use the default
Created by: TLadd
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 (https://github.com/facebook/create-react-app/pull/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.