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

Big increase of date-fns package size between v2.29.2 and v2.29.3 #3208

Closed
KapowraLL opened this issue Oct 7, 2022 · 20 comments
Closed

Big increase of date-fns package size between v2.29.2 and v2.29.3 #3208

KapowraLL opened this issue Oct 7, 2022 · 20 comments

Comments

@KapowraLL
Copy link

KapowraLL commented Oct 7, 2022

Hello, is there a reason for the increased build size in v2.29.3 ?
I don't think #3167 alone explains this increase https://bundlephobia.com/package/date-fns@2.29.3 (i mean IE support is not worth the bundle size increase)

@wojtekmaj
Copy link

I think it does. The only other change was Ukrainian grammar fixes...

v2.29.2...v2.29.3

@danieldiekmeier
Copy link

I personally think the large increase in bundle size is a problem and the changes should be rolled back. I don't think the additional compatibility for a browser that is no longer maintained/supported is worth this steep increase in bundle size:

image

Link: https://bundlephobia.com/package/date-fns@2.29.3

I think that if teams still need to support IE 11, they should be responsible to run their dependencies through Babel themselves. In my work and on my personal projects, we don't support IE 11 anymore, but now we'll have to accept the bundle size increase if we want to stay up to date with date-fns.

@kashifshamaz21
Copy link

A discussion for this size bump was started here, but I think we can use this to continue the conversation.

One way this could be handled is by having two different distribution outputs - one which doesn't have IE-11 compat support (same as previous v2.29.2) and another which has IE-11 support.
The consumers of date-fns who need to support IE-11 can import the IE-11 compat output, rest can continue using the default version. This way, we don't penalise those who aren't in need of supporting IE-11.

@leshakoss @tan75 @muruvetri Thoughts?

@wojtekmaj
Copy link

wojtekmaj commented Oct 25, 2022

Given that IE11 is essentially dead, with Microsoft itself not supporting it anymore, I don't think any effort towards improving IE11 compatibility is worth it.

Those who require legacy browser compatibility should be reminded that nothing's stopping them from parsing the all or selected packages they use with Babel via babel-loader or whatever other tool they're using. This is the approach nanoid suggested in v3.0.0.

Not only this approach does not bloat the libraries like date-fns for other folks, but also decreases bundle size for them, because instead of inlined polyfills they can have polyfills from their version of core-js injected to the modules requiring them.

If you're dealing with IE11 support, parsing node_modules is what you should be doing anyway, as I'm sure there are other packages that won't work without doing so, and the number of such packages is going to only increase.

@adidahiya
Copy link

I think #3167 should be reverted and date-fns' browser support "guarantees" should be adjusted to reflect the reality that IE11 is not a priority. I agree with @wojtekmaj that IE11 is not worth supporting for a library like date-fns. It's clear from #3155 (comment) that date-fns is not getting tested in IE11 anyway.

date-fns' supported browsers aren't documented anywhere as part of the API contract (see #1227), so IMO dropping IE11 support wouldn't even be considered a breaking change.

In the meantime, we'll have to pin date-fns to v2.29.2 in our projects to avoid the 25% bundle size regression in v2.29.3.

@kossnocorp
Copy link
Member

Let's drop IE 🫠

@boubou158
Copy link

Any news on that? There is no point migrating from moment to date-fns in our angular application using 2.29.3. Bundled tree shaked date-fns.js is bigger than moment.

Thank you

@wojtekmaj
Copy link

Just pin at 2.29.2.

@adidahiya
Copy link

@leshakoss this continues to be a problem for various libraries that depend on date-fns. Packages outside of my control are bumping their date-fns dependency to ^2.29.3 and the only solution to this issue is to force Yarn or PNPM to resolve date-fns down to 2.29.2, which is undesirable. I am once again, please, asking for a revert of #3167.

Side note, has there been a change in the status of this project? I see there have been no commits on main or v2 branches for 6 months. Is date-fns still maintained?

@kossnocorp
Copy link
Member

Side note, has there been a change in the status of this project? I see there have been no commits on main or v2 branches for 6 months. Is date-fns still maintained?

It's maintained, I'm currently focused on v3 documentation generation and the website,

Re the new version with the IE stuff rolled out, I'm sure we can ship a version very soon. It slipped through the cracks.

@kossnocorp
Copy link
Member

TO EVERYONE WHO COMMENTED OR FOUND THE ISSUE:

Please comment if you actually saw the bundle size increase in your app or if Bundlephobia was your only concern. This is important if you are interested in seeing it addressed.

Also, please check if v2.29.2, v2.29.3, and v2.30.0 affect the actual build size. I have a suspicion that. Bundlephobia reports the wrong size, and I want to investigate.

Ok, here's the update on the upcoming version, which removed explicit IE support via #3289:

Pre

date-fns on  v2 [$] npx size-limit tmp/package/index.js

  Package size: 30.91 KB
  With all dependencies, minified and gzipped

date-fns on  v2 [$] npx size-limit tmp/package/addDays/index.js 

  Package size: 598 B
  With all dependencies, minified and gzipped

date-fns on  v2 [$] npx size-limit tmp/package/locale/en-US/index.js 

  Package size: 2.29 KB
  With all dependencies, minified and gzipped

npx size-limit tmp/package/format/index.js 

  Package size: 6.53 KB
  With all dependencies, minified and gzipped

After

date-fns on  boot-too-big [$] npx size-limit tmp/package/index.js

  Package size: 27.71 KB
  With all dependencies, minified and gzipped

date-fns on  boot-too-big [$] npx size-limit tmp/package/addDays/index.js 

  Package size: 529 B
  With all dependencies, minified and gzipped

date-fns on  boot-too-big [$] npx size-limit tmp/package/locale/en-US/index.js 

  Package size: 2.31 KB
  With all dependencies, minified and gzipped

date-fns on  boot-too-big [$] npx size-limit tmp/package/format/index.js       

  Package size: 6.51 KB
  With all dependencies, minified and gzipped

Even though dropping IE shaved off a few bytes, it doesn't appear to have a 30% decrease shown on the Bundlephobia.

Rolling back to v2.29.2 also doesn't show a significant change in size:

v2.29.2

date-fns [$] npx size-limit tmp/package/index.js              

  Package size: 27.7 KB
  With all dependencies, minified and gzipped

date-fns [$] npx size-limit tmp/package/addDays/index.js

  Package size: 529 B
  With all dependencies, minified and gzipped

date-fns [$] npx size-limit tmp/package/locale/en-US/index.js 

  Package size: 2.29 KB
  With all dependencies, minified and gzipped

date-fns [$] npx size-limit tmp/package/format/index.js

  Package size: 6.45 KB
  With all dependencies, minified and gzipped

I will still release v2.30.0 and see how it reflects on Bundlephobia.

@wojtekmaj
Copy link

Hmmm. It looks like indeed, something appears to be off on Bundlephobia's side, and @kossnocorp analysis appear to be more correct. Looking at the raw code:

https://www.npmjs.com/package/date-fns/v/2.29.2?activeTab=code
https://www.npmjs.com/package/date-fns?activeTab=code

and executing the following code I wrote to quickly (and probably not very well) sum all sizes listed:

$$('.af65e767').reduce((sum, el) => {
    if (!el.textContent) return sum;
    const [value, unit] = el.textContent.split(' ');
    const valueNum = parseFloat(value);

    switch (unit) {
        case 'B': return sum + valueNum;
        case 'kB': return sum + valueNum * 1024;
        case 'MB': return sum + valueNum * 1024 * 1024;
        default: throw new Error(`Invalid unit: ${unit}`);
    }
}, 0);

reports 6858898.12 on 2.29.2 and 7132218.52 on 2.29.3, or roughly 3.9% increase.

Additionally, Bundlephobia's own Exports Analysis reports no or negligible increase in size of particular exports. For example, daysInWeek is 349 B on both versions, addHours is 702 and 775 B respectively.

There are particular exports, however, that got noticeably larger, to the point of affecting the entire Export Analysis chart's X scale. isMatch jumped from 9.0 to 13.8 kB, parse from 8.9 to 13.7 kB. npm reports no difference between sizes of isMatch directory, and an increase from 103 to 222 kB of parse directory. Since isMatch depends on parse, parse appears to be the biggest offender.

Looking deeper, it seems like pretty much every file in /parse/_lib/parsers/ got significantly larger, raising from 61397.24 to whopping 176128 B.

I picked one of the files at random, TimestampMillisecondsParser.js, and this reveals what's the root cause: transpilation of ES6 classes. The amount of code added in each (!) file to just "create a class", multiplied by a large number of files, is significant.

If we are to reduce package size while keeping the already-added IE support, we can consider adding @babel/runtime dependency and @babel/transform-runtime Babel plugin to be able to "lift" all this code into a single module referenced in every parser.

Here's an example how to do this:

wojtekmaj/react-pdf@78acd05

Alternatively, we could get rid of classes in parsers, but that would be way more work, of questionable purpose.

@kossnocorp
Copy link
Member

@wojtekmaj thank you so much for investing time into research. I thankfully didn't manage to push v2.30.0 and will look into the proposed solution. It sounds fair to me to extract runtime.

In v3 I'm definitely aiming to drop IE, but if we can keep the module size low and preserve IE compatibility so we don't cause more chaos now, for me it's a worthy trade-off.

@jdelStrother
Copy link

Looks like wojtekmaj's already on top of it, but FWIW we saw ~ 4.4KB increase in minified gzipped size between 2.29.2 & 2.29.3. And yep, looks like almost all of that increase is from importing date-fns/parse.

@adidahiya
Copy link

adidahiya commented Apr 26, 2023

Thanks for your bundle size investigation @wojtekmaj.

@kossnocorp Why is IE11 support being considered for date-fns v2? Has anyone even tested it in IE11? As I mentioned above:

It's clear from #3155 (comment) that date-fns is not getting tested in IE11 anyway.

date-fns' supported browsers aren't documented anywhere as part of the API contract (see #1227), so IMO dropping IE11 support wouldn't even be considered a breaking change.

Edit: I agree that if "we can keep the module size low and preserve IE compatibility", that's a reasonable goal. I just hope this doesn't push the issue resolution out further (this issue has been open for 6 months).

@kossnocorp
Copy link
Member

@adidahiya it is considered because we already pushed a version that fixes the compatibility, and releasing a new version that breaks it will bring more havoc and similar discussion by tone just in another issue. We're talking about a 3Kb total difference. It's not as dramatic as Bundlephobia shows, so finding a middle ground, if possible, is the right decision. What really concerns me is how Bundlephobia is off with their estimate.

Just a side note, double downing on maintainer guilt ("this issue has been open for 6 months") is counter-productive.

@wojtekmaj
Copy link

I believe Bundlephobia shows "what if you imported EVERYTHING that is there, from a package you're asking about" - and in this case, considering my investigation above, the increase is very plausible.

@kossnocorp
Copy link
Member

Ok, so I've finished the investigation.

First of all, the size shown on Bundlephobia is the minified non-gzipped size, which confused me and many others.

While knowing the relative unpacked size is relevant to understanding how fast the code will parse by the browser, showing it next to (and comparing it with) gzipped size is irrelevant and misleading.

So I went and investigated different options on how actually to measure the impact of possible solutions and stopped on @ai's latest size-limit version that, in addition to gzipped size, also shows running time, which is a much more appropriate metric.

So when comparing v2.29.3 and v2.29.2 using "running time," the difference was not that dramatic, with ~10% increase (667 vs. 602 ms).

It's still a problem, and I regret that we ever pushed IE compatibility because now we have a choice of either breaking it again and causing bugs or adding the runtime to dependency. Both aren't ideal. In the first case, we would have the optimal size. The second is more stable and reliable but a compromise size-wise.

So given all that bringing the running time from 667 ms to 617 ms and preserving IE compatibility is still a big improvement and when compared to v2.29.2, is just a 2.5% increase in total running time.

So runtime it is. Even though I hate adding a dependency and settling at not the minimal size we can achieve, it's a dub. Plus, in v3, which is coming soon, I'll get rid of the dependency and retired browser support and bring the bundle size to it's minimum.

See the PR that will address the problem: #3402 (kudos to @wojtekmaj and @Andarist).

I'll update and close the issue once v2.30.0 is out. Thanks everyone!


Here are the tables for each file with versions as columns and metrics as rows:

tmp/package/index.js

Metric v2.29.3 v2.29.2 No IE11 Runtime extraction
Size 34.15 kB 30.8 kB 30.13 kB 31.59 kB
Loading time 667 ms 602 ms 589 ms 617 ms
Running time 317 ms 399 ms 316 ms 303 ms
Total time 984 ms 1.1 s 905 ms 920 ms

tmp/package/addDays/index.js

Metric v2.29.3 v2.29.2 No IE11 Runtime extraction
Size 800 B 727 B 732 B 835 B
Loading time 16 ms 15 ms 15 ms 17 ms
Running time 54 ms 81 ms 78 ms 72 ms
Total time 70 ms 95 ms 93 ms 88 ms

tmp/package/format/index.js

Metric v2.29.3 v2.29.2 No IE11 Runtime extraction
Size 6.96 kB 6.89 kB 6.75 kB 6.86 kB
Loading time 136 ms 135 ms 132 ms 134 ms
Running time 75 ms 117 ms 104 ms 100 ms
Total time 211 ms 252 ms 236 ms 234 ms

tmp/package/parse/index.js

Metric v2.29.3 v2.29.2 No IE11 Runtime extraction
Size 14.06 kB 11.02 kB 10.81 kB 12.27 kB
Loading time 275 ms 216 ms 212 ms 240 ms
Running time 201 ms 192 ms 155 ms 168 ms
Total time 476 ms 407 ms 367 ms 408 ms

@kossnocorp
Copy link
Member

Fixed by date-fns@2.30.0

@dackmin
Copy link

dackmin commented Oct 17, 2023

Hey, I know this issue is closed & marked as fixed, but the @babel/runtime requirement seems to be against all recent work from things like SWC to not use babel anymore. Would it be imaginable (consider-able? is this even a word?) to let the 2.x.x branch with IE11 compat, and avoid using babel and getting rid of IE polyfills with a v3.x.x branch?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants