-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Single-file bundling is still preventing useful tree-shaking #6608
Comments
Thanks for checking, @billyjanitsch.
It's more than a little frustrating that the limitations of webpack dictate how we structure our modules. My strategy up to this point has been to rely on webpack's minifier (uglify) to eliminate dead code, but, as you say, it's not working very well. I did quite a bit of research into this a few months ago, where I determined that we should be able to build everything into a single file while relying on uglify to strip out all the code we weren't using. It worked fine there (on the 2nd attempt). Not sure why it's not working very well now. I need to dig in again. Quick question: using your repo, how are you determining that tree-shaking isn't working? When I ran |
@billyjanitsch Are you sure the treeshaking isn't working? Using your repository, I checked the bundle composition with webpack-bundle-analyzer and I see the following stats:
According to bundlephobia, the (self-)size of react-router-dom is 2.8kB (~2.4 kB more) and the size of react-router is 6.36kB (~4kB more). Edit: Looks to me like only the history bundle isn't properly tree-shaken. But that should probably be reported on the |
@mjackson I look directly at the output file (dist/main.js), but I realize this is a pain. I made an
@StringEpsilon as you point out, this code is coming from the The problem is that when I hope that makes sense -- it's hard to explain but I tried my best. 😅
@mjackson I understand your point of view, but the way I think about it is that tree-shaking (with FWIW, even if it worked as intended, I feel like modifying source code to make Uglify happier (e.g. #6465, which is detrimental because In any case, thanks again for looking into this! |
Thanks for following up here @billyjanitsch. At this point we have done as much as we can to enable tree-shaking w/out making special concessions for webpack (which doesn't really do tree-shaking). All of Having said that, here are a few points to consider:
// Import directly from history
import { createBrowserHistory } from 'history';
// Import Router directly instead of BrowserRouter
import { Router } from 'react-router-dom';
const history = createBrowserHistory();
<Router history={history}>
// ...
</Router> I actually forked your repo and experimented with this approach in the If you don't like that workaround, you can always switch to using Rollup for bundling your app. Granted, the Rollup ecosystem isn't quite as developed as webpack currently is, but it's getting there. All of this is not to say we don't care about your bundle size; we absolutely do and we are actively working to get our bundle size down. Our initial estimates of the bundled size of version 5 are around 3kb right now. That's smaller than our But for now, I need to ship 4.4 and move on. This issue has been delaying the release for a few weeks now. Hope that helps! |
@mjackson once again, thanks so much for the time you've spent looking into this.
I totally agree that there's no reason for this to block 4.4, and I apologize if I came across as suggesting that 4.4 shouldn't be released until this was resolved. Congratulations on shipping. 🙂 That said, now that 4.4 is out, would you consider re-opening this to continue discussion for future versions?
Unfortunately, this isn't the case. See mjackson/react-router-tree-shaking#1, where I've replaced Webpack with Rollup and still found that tree-shaking doesn't work. This doesn't seem to be an issue of Rollup vs. Webpack, but rather a limitation in static module analysis + DCE when packages are pre-bundled into single files.
Thanks for suggesting. It's a good idea, but this workaround prevents
( That's true, but I'm not sure it's a fair comparison. Tree-shaking mostly benefits libraries which expose multiple, somewhat independent pieces of similar size which aren't all likely to be used, and React is not such a library. Also, the advantages that React buys itself by pre-bundling are larger than those received by libraries which only use Rollup to put everything in one file. To elaborate, the There's also the fact that React uses advanced compile-time tooling (e.g. GCC) to produce a maximally small/performant build, using optimizations that would be very slow or impossible to reproduce in users' bundling setups. This necessitates shipping a single file. This is different from plain Rollup, which, when bundling libraries, roughly just concatenates the modules in the right order. i.e. React gets something from doing this that other libraries don't. |
Version
react-router-dom@4.4.0-beta.7
Test Case
https://github.com/billyjanitsch/react-router-tree-shaking
Steps to reproduce
Clone the repo above, run
npm run build
, then observe the output indist/main.js
.Expected/Actual Behavior
Continuation of #6464.
@mjackson thanks for trying to resolve this. Unfortunately, the same issue as originally described for 4.4.0-beta.6 persists in 4.4.0-beta.7.
I've updated the example repo to show this. The repro instructions are the same as before, and as before, all three
history
types are included in the bundle even though onlyBrowserRouter
is imported.I still think the proper fix is to stop bundling the libraries into single JS files, outlined in #6464 (comment).
To summarize,
{sideEffects: false}
allows Webpack to prune unused files (rather than relying on a minifier to prune unused code paths, which doesn't work very well). But it can only prune entire files, so it only works when code is split between multiple files. That's why{sideEffects: false}
is not useful if the library is bundled into a single file.The text was updated successfully, but these errors were encountered: