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
Tree shaking doesn't work with Typescript barrel files #12557
Comments
|
Feel free to investigate and solve |
|
Same happening with jsx also. |
|
Has anyone been able to solve this? In one of our projects we seem to be getting no tree shaking at all for any TS application code, only for third party library code. Alternatively, could any of the maintainers provide some hints as to how one would best go about investigating and solving such an issue? EDIT: For posterity, the problem in our case was that the bundle analyzer's output is harder to interpret correctly than it appears, which we failed to do initially. It seems that tree shaking was not the problem. |
@seeekr We actually ended up just removing our barrel files. I did a simple experiment with Webpack and a couple of JavaScript modules + a barrel file (no Next, or Typescript) and the same behaviour was present with limited options to enable tree shaking to occur. If you have no side effects in your code then you may be able to look into the Webpack side effects setting to allow this to work for you, but as soon as you're importing a module classed as a side effect, you may start to notice issues. For us, our polyfill imports stopped working along with a whole host of other stuff. I'm not sure this is something Next can/should solve though, as it seems to be inherent to Webpack |
|
@stevethatcodes @majelbstoat Tree shaking seems to work for me as long as I specify side effects in package.json: "sideEffects": [
"./src/some-side-effectful-file.js"
]This is according to the Webpack docs linked above. I think you would just have to determine where your polyfills and other side effects are happening and add those files to the side effects list. |
|
@VWSCoronaDashboard8 Yeah, that's an approach we tried, though still had issues with the polyfills not loading. In fairness, we took the approach to remove barrel files as the path of least resistance, as they didn't add much value and we didn't need to do anything else to our Next/Webpack setup to bring back tree-shaking. |
|
@sphilee I don't actually think it works / resolves the issue, I've installed Webpack 5 on my current Next.js projects but it doesn't have any positive impact on the bundle size, at least for barrel files structured as the issue example by @majelbstoat. |
|
@RobbyUitbeijerse @sphilee I have concluded the same. Webpack 5 didn't solve this issue for me. |
|
Based on the following issue webpack/webpack#11821 , Webpack 5 should actually eliminate dead code with the minimize option being enabled (which is the case by default for What I'm concerned about is that it might actually work for the shared bundle which is loaded for all pages, but doesn't actually consider the page by page chunks, meaning that while dead code is actually eliminated from the shared bundle - you are still left with a single bundle containing everything instead for smaller chunks per page that only contain what you need for that page. Quite unsure whenever it's possible to actually resolve that or that changing the imports is the only way to go. |
|
@timneutkens Webpack is not my strong suit, but do you have any clue if my comment above makes any sense in terms of what we are seeing? |
|
I had similar issues in the past when using In the past we also had issues with babel when it came to exporting types. Since then we started exporting types explicitly using |
|
I actually started doing the same recently: But it turns out, no luck: What I did find tho, that when I put all of the components in an external library and build that library using Rollup while preserving the modules, tree shaking of the same components seems to work properly, meaning that it should be possible to get it all working one way or the other. [edit] Same result with webpack 5 |
Same experience here. I was pulling my hair out trying to figure this out. I have a monorepo, and in the I can make a repro in a monorepo this weekend. I'm using Next |
|
This has been open for over a year. Has anyone found a solution yet? Using a barrel file results in my bundle reaching 12mb whereas without I'm less than 1mb |
|
@JoeyFenny |
|
I am running into simular problems in a non next.js project. Upgrading from webpack 4 to webpack 5 did not fix it, sideEffects: "false" in the package.json does enable tree shaking but the barrel pattern still fails. I think this is a webpack problem, maybe we should move the dicussion there? Important edit: It seems I was wrong that tree shaking wasn't fully working in my webpack project because of the barrel pattern. The barrel pattern (vs direct importing) made a lot more code be processed which increased the chance of tree shaking not being applied because of sideEffects within that code. I don't know OP's exact case or next.js's handling when it comes to tree shaking vs webpack 5 but I did came accross a blog post that goes more in-depth on tree shaking that I would recommend reading: https://dev.to/livechat/tree-shaking-for-javascript-library-authors-4lb0 In the end I had to add Again, I don't know if OP has the same issue, or there is some config issue or if it is next.js that is failing, but what I did found out is that webpack 5 does support the barrel pattern. |
|
settings sideEffects to false and adding |
|
We dont have any news or ideas about this? I am really struggling to fix this since its having a big impact in our page load. |
|
For tree-shaking to work with a barrel file you need
|
sideEffects: false, makes tree shaking work with barrels files vercel/next.js#12557 Mapping only needed data from posts Change first render tweet info date
@sokra I want to have barrel files as the |
|
I have spent days trying basically everything I can think of to get Tree Shaking to work with the app router and barrel files, including all the suggested answers here, and have hit a dead end. Half my pages use the Pages Router, and half use the App Router. The Pages Router pages seem to perform tree shaking on the barrel files properly, but the App Router pages are all double the kB of the Pages Router pages as soon as I import a single component. Here's what I've tried so far:
The only thing that works is bypassing the barrel files and importing components one by one... but I love barrel files and this seems like a (very time-consuming) step backwards. I think Babel Direct Import Plugin may have worked, but I couldn't get it to work. I am pretty amazed that it doesn't just work out of the box as it seems like such a common thing to do and the whole point of NextJS is things are supposed to work out of the box. |
|
An update on the above: I couldn't wait for a fix so I spent a day refactoring out my beloved barrel files so all my files now have tons of separate imports. My App Router routes dropped from ~640kB to ~80kB first load JS. |
@JEGardner would it be possible to point the rest of us mortals on how to optimize these bundles? I'm at a loss on how to optimize my Thank you 🙏🏽 |
|
+1 here, using a |
+1 |
|
Is this issue now fixed with Optimized Package Imports? #54695 |
|
@cseas in my project this option did NOT affect the bundle size. I listed about 10 new libraries along with And total bundle size with Next 13.5 actually increased by 2kb 🤦♂️ |
|
I'm sorry but I can't believe that this issue has been opened for more than 3 years now and that there is still no solution 🤷♂️ |
I have to agree. All these micro-optimisations and then you have this which would probably save 100s of kb being sent on every route on most nextjs apps. Don't get it. |
|
@leerob - any ETA on a solution for this? |
|
I'm so happy I decided to make the changes early even if it took me some time to do it. It would have taken me more time today. Crazy to see this is still not resolved. Next step might be to move the project to Astro 🤔 |
|
Randomly stumbled upon this, but I highly recommend ESLint rule that restricts use of barrel files https://github.com/gajus/eslint-plugin-canonical#no-barrel-import It is auto-fixable so you don't need to do much to leverage it and it will prevent bloat of your bundle size. |
Yeah, seems like it helps. I`ve tested with @nextui-org/react and many of internal packages was gone |
|
For those who have hypothesized that it's a Webpack issue, I cannot reproduce the issue in Webpack alone, treeshaking barrel files seems to work fine there: https://replit.com/@JorenBroekema/barrel-treeshaking In fact, I've also tested this in Rollup and esbuild and they can also treeshake it just fine. Parcel/Browserify not so much So seems like a NextJS specific problem. |



Bug report
I originally raised this as a discussion, but now I think it's a bug.
Describe the bug
When using a barrel file to re-export components from a single location, tree-shaking does not function correctly.
To Reproduce
I'm using Next 9.3.6 and I've arranged my components like:
Each component file exports a single component, like this:
index.ts is a barrel file that re-exports from each individual component file:
I then use a couple of components in _app.tsx like:
There's about 100 components defined, and only a couple are used in _app.tsx. But when I analyze the bundle I have a very large chunk, shared by all pages, and it contains all my components, resulting in an inflated app page size:
I use a similar import strategy within pages, and every one of them appears to contain every component.
my tsconfig.json is:
and I'm using next's native support for the baseUrl field. I haven't changed the module or the target.
When I change the _app.tsx imports to:
the common bundle and app page size drops dramatically, as I would expect it to:
Expected behavior
The app page size should be the same using both import strategies.
System information
The text was updated successfully, but these errors were encountered: