bowser-js / bowser

a browser detector
Other
5.5k stars 487 forks source link

v2.0 big bundle size #259

Open fraserxu opened 6 years ago

fraserxu commented 6 years ago

Trying to use this package in our project, but after checking the bundle size with bundlephobia, the new v2 bundle is almost 3 times the total size of v1.

https://bundlephobia.com/result?p=bowser@2.0.0-beta.3

screen shot 2018-10-12 at 2 26 32 pm

Maybe there's some issue with the build script?

Upvote & Fund

Fund with Polar

lancedikson commented 6 years ago

Hi, @fraserxu, thanks for the question and bringing my attention to it. Yes, it became bigger since I drastically rewrote the structure of the project. However, it may contain something that might be not useful for everyone, but for some, like the docs folder. We could get it away, I think. Also, you're free to have a closer look at what's happening with the package and propose any changes to discuss. I'm open for such valuable help πŸ‘ Would you mind making a PR with a fix? :)

fraserxu commented 6 years ago

I just had a build locally and get the following result:

➜  bowser git:(master) βœ— npm run build

> bowser@2.0.0-beta.3 build /Users/fraserxu/projects/bowser
> webpack --config webpack.config.js

Hash: b7d0ad10519da335d568
Version: webpack 4.15.1
Time: 2842ms
Built at: 13/10/2018 12:59:54 pm
     Asset      Size  Chunks             Chunk Names
    es5.js  19.9 KiB       0  [emitted]  es5
bundled.js   108 KiB    1, 0  [emitted]  bundled

So I believe bundlephobia is not counting the docs folder but what is defined in package.json "main": "es5.js".

To avoid pushing docs to npm, you can add files to package.json and only include what will be published. https://docs.npmjs.com/files/package.json#files

In this repo, maybe just files: ['es5.js', 'bundled.js'].

audiolion commented 5 years ago

I also am concerned with the dramatic increase in bundle size, @fraserxu if I understand you correctly the size reported by bundlephobia is off because the author is publishing extra stuff and a webpack build will ignore all that?

lancedikson commented 5 years ago

I guess, we have to take a more precise look at the output of the build, so there might be some extra-scripts included by webpack into the final build of the main files (es5.js, bundled.js). I just don't have enough time to take care of this. If you guys have time and would like to participate, please, you're always welcome. I really appreciate any help with the package. Just ping me if you find any redundant code in the final build and we could investigate where it comes from and how we could get rid of one to make the bundle less πŸ™

nicgirault commented 5 years ago

My only reason to use bowser is to get info about the browser. I would love to be able to write something like

import parse from 'bowser/parse'
parse(window.navigator.userAgent)

to avoid loading the whole bundle. After checking bundlephobia I give up upgrading to v2...

hipstersmoothie commented 5 years ago

Count me as another person who has to downgrade due to bundle size.

After upgrading to v2 my components bundle size increased by 16.56 kB.

Looking at the code for bowser@v2 it seem like it will be quite the challenge to get it back down at all. The code is about 2000 lines long and it seems like almost all of it is used during a run of any of the functions.

lancedikson commented 5 years ago

Hi, @hipstersmoothie and all! I have good news. I tried to dig into the issue. First thought was to ensure that all the modules are legit and there's nothing extra taking into the build. I used webpack-bundle-analyzer and saw that the es5.js build includes only the modules of the project and nothing else.

Then, with the next step, I researched the build itself and its expressions. In a few minutes, I've figured out, that we were having not the most optimized settings for Babel. So, I experimented with changing the modules system it uses in the build (changed umd→auto) and also tried loose mode to avoid explicit property declarations.

Thus, I managed to reduce the build size by 20% from the latest build (2.5.0) β€” 27.5 kB β†’ 22 kB, the reduce of a gzipped file will be around 0.5 kB, I think. I’ll be able to publish 2.5.1 tomorrow with bundle size reduced.

But, the main reason for the problem is that the 2.x version brings a lot of new functionality and API, which makes bowser better and more convenient, but also a heavier tool. There always will be two different groups of users β€” the ones who concerned with the bundle size and the others who interested in rich API and more features from the box.

Nowadays, the 2.x is something in between for those two groups β€” it does its thing good and has some fancy API for itself. But, I think, we could think of having some modular system that would make it possible to avoid useless functionality in the build easily. It would require some refactoring and solid architectural approach, and quite some time, but it’s doable. I'm not sure if I will be able to develop it on my own this year, but, let's see.

One more point here:

The code is about 2000 lines long and it seems like almost all of it is used during a run of any of the functions.

No, it's not. Bowser's Parser is built so, that it would run only needed parsing functions depending on what you asked for. Thus, it doesn't parse OS and platform if you asked just for browser (getBrowser()). But, it obviously doesn't help to reduce the build size, only saves some milliseconds during runtime execution.

And thanks for your message. It's essential for me to know what exactly matters for the users.

audiolion commented 5 years ago

@lancedikson thanks for the work here to reduce the bundle size. I would add that if the imports are tree-shakeable then even if the bundle size is larger, people will only be adding to their bundle the bits that they are actually using. E.g. if you could somehow import { getBrowser } from 'bowser'; and getBowser is a 2kb fn then that is all that gets added to the bundle size.

lancedikson commented 5 years ago

Right, good point, @audiolion. I will try to look at the current module's structure from that perspective first. Maybe a little refactoring would solve the problem for most of the library users.

lancedikson commented 5 years ago

Btw, the 2.5.1 is published. It's a lot less, then 2.5.0, but not much less compared to 2.0.0, which was the first 2.x release without many extra-functionality that came later.

image