Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
TLadd opened this issue Jul 16, 2018 · 7 comments
Closed

Comments

@TLadd
Copy link

TLadd commented Jul 16, 2018

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.

@TLadd TLadd changed the title CRA v2 webpack 4 splitChunks name setting should use the default react-scripts v2 webpack 4 splitChunks name setting should use the default Jul 16, 2018
@Timer
Copy link
Contributor

Timer commented Jul 16, 2018

Wow, thanks for the detailed report! It helps explain this: #4633, or at least points us in the general direction.

Does this splitting happen even if you don't manually set chunk names in your code? That's the behavior we want (one vendor-bundle per chunk).

@TLadd
Copy link
Author

TLadd commented Jul 16, 2018

If I don't manually set the chunk names, the output is:

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

So yeah, still splits correctly.

@TLadd
Copy link
Author

TLadd commented Jul 24, 2018

@Timer Anything more I can do on this?

@catchergeese
Copy link

@TLadd Thank you for very detailed and self-evident documentation of the issue.

@Timer I experienced exactly the same problem as @TLadd and I'm also willing to help if there is anything I can do. For code splitting I use react-loadable.

@irrigator
Copy link

Right now the generated bundles for both vendor and splits are named like "1.[hash].js", which makes it hard to see which corresponds to which entry point. Is there any way to name specific bundles after the module name?

@TLadd
Copy link
Author

TLadd commented Oct 8, 2018

@irrigator I haven't tested with CRA 2.0 yet, but I think that specifying webpackChunkName like in my example in the first post in this issue ought to work still.

import(/* webpackChunkName: "highcharts" */ "highcharts");

@jomaxx
Copy link

jomaxx commented Jan 8, 2019

Hello, looks like this doesn't currently work in CRA 2.0. The vendor chunks continue to be numbered (1.hash.chunk.js) instead of named (vendors~main.hash.js).

@lock lock bot locked and limited conversation to collaborators Jan 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants