mixpanel / mixpanel-js

Official Mixpanel JavaScript Client Library

Home Page:https://mixpanel.com/help/reference/javascript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

mixpanel-browser is huge! Maybe support tree shaking? What can be done?

kazazor opened this issue · comments

According to webpack-bundle-analyzer mixpanel-browser is huge!
screen shot 2017-04-04 at 10 06 41 pm

This is the one of the biggest vendor packages we have and it doesn't make any sense to me.
To put it into perspective, this is moment.js:
screen shot 2017-04-04 at 10 09 39 pm

This is even bigger tan moment, and moment is big!

I'm opening a discussion here with Mixpanel guys, how can we make it smaller?
can we support ES6 modules style in order to leverage tree shaking?
Any other ideas?

@jbwyme @ilyakamens @tdumitrescu any thoughts on the size of the package? is there any way we can decrease the size in the build step?

Totally in support of making the package size smaller. The mixpanel js library comes bundled with support for a number of different features like in-app notifications which bloats out the size. However, we should be able to restructure it a bit so that you can do more granular imports when using mixpanel-browser. I'll take a look at the work required to see if we can get some easy wins but as always PRs are welcome :)

@jbwyme awesome, thank you! It would be great to have a core package for mixpanel, and then extras like in-app notifications could be separate packages. i like the way lodash does this, where a single helper function is packaged.

Thanks everyone for looking at doing that!

@baldwmic I actually disagree with the packages approach. This approach is kind of outdated and was replaced even in lodash.

In lodash instead of installing a specific package per function you can go ahead and do:

import get from 'lodash/get';
import remove from 'lodash/remove';
import isPlainObject from 'lodash/isPlainObject';

This way you don't need to go ahead and install each package and get your package.json so big.
More than that, doing that you actually able to share the different functions from different packages that uses lodash itself, which is very common. By doing so you're actually reducing the total size of your website. If you'll use individual packages, you'll make my life as a developer a little bit harder then just doing something like:

import X from 'mixpanel-browser/X';

I would suggest going with that option.

Tree shaking

In today's js frontend world, support for tree shaking is a must.
So instead of doing:

import X from 'mixpanel-browser/X';
import Y from 'mixpanel-browser/Y';
import Z from 'mixpanel-browser/Z';

I could do:

import { X, Y, Z } from 'mixpanel-browser';

tree shaking is really easy to have along side with commonjs support and it's just some babel configurations to add. You can take a look at lodash-es & react-router/es for reference..

IMO having both es support (tree shaking) along with commonjs in the same package (link react-router does) would be the best option. The other option like lodash-es does makes it harder to share common packages so I wouldn't go with that option.

WDYT? :)

ooh @kazazor i do like the idea of installing only one package and then just modifying the import statements, good point! that does seem much easier from a developer perspective.

i also agree that tree-shaking would be awesome! removing code that is not used will definitely help decrease the size of developer builds :)

So I was curious about this myself, but mostly because my gzip size comes out to 42kb (double what's loaded from the CDN, or what the OP has). Looks like our "stat size" is the same so not sure what might cause this...

screen shot 2017-04-28 at 4 08 15 pm

Note that if your main concern is just reducing download size on pageload, then the CommonJS and other bundled/synchronous versions of the lib will never be as efficient as the standard snippet-loaded version (where you just add the embed code to your page). In that version, just the small minified embed code runs initially, and the rest of the lib is downloaded asynchronously without blocking, and will also be more cacheable than if it is included in the main bundle of an application.

@tdumitrescu How about the idea of a mixpanel-lite package, which only contains say the code for tracking events, or something along those lines?

@tdumitrescu the problem with "installing" a package by embedding a script tag in html is that it's not very maintainable for our application. My team, and I'd be willing to bet many others, prefer to use npm / yarn to manage our dependencies. Is it not possible to create a liter version of the package like @OllieJennings suggested?

Yes, there would definitely be advantages to improving the modularization of the lib and building separate versions with different parts included. Until we find the time to implement it (or shepherd through an acceptable pull request), I was suggesting the embed code as a way to remove the pageload impact of the extra 40K gzipped bundle.

@baldwmic you can totally use npm/yarn to install mixpanel-browser and still use the embed code to load the lib asynchronously. The instructions are basically the same as for "Using Bower to load the entire library": point a script tag at the embed code downloaded with the npm package, and use the MIXPANEL_CUSTOM_LIB_URL var to point at the npm-downloaded lib src (at whichever URL your asset pipeline ends up making it available).

commented

@tdumitrescu To elaborate on your earlier message:

Note that if your main concern is just reducing download size on pageload, then the CommonJS and other bundled/synchronous versions of the lib will never be as efficient as the standard snippet-loaded version (where you just add the embed code to your page). In that version, just the small minified embed code runs initially, and the rest of the lib is downloaded asynchronously without blocking, and will also be more cacheable than if it is included in the main bundle of an application.

Our main concern is JS execution time. Larger JS payloads, even if they're cached by the browser, impart a pretty significant first-pass performance penalty. (V8 can't do any optimizations on the first pass + parsing + JIT compilation)

see https://medium.com/reloading/javascript-start-up-performance-69200f43b201 for more info.

@matthewoates sure, parsing a larger blob of js will take more time before the Mixpanel lib starts firing off events, no doubt about that. My point about using the embed code is that parsing the lib in that case does not block pageload (it loads the lib asynchronously, and any mixpanel.track etc calls that you make until the lib loads are simply queued), and shouldn't measurably affect your page's startup time.

I think one good first step is defining what browsers should this library support.
Do we already have that?
With that in hand we might be able to do a nice cleanup on the utils.js module.

Created a PR to decrease its size #143
There is still a lot to be improved though, this is just the utils module.

Another nice thing to have, size badges:

#144

I use this library solely for sending events, and paying 70kB for that is hard to swallow. Is there any progress on repackaging using a more modular structure?

@bradleyayers I created a branch that is intended for logging only (we also use it only for logging).
I can't give you any guarantees that will work perfectly for you, but take a look, I hope it helps.
It currently has around 50% less code than the full library. (you can see that on the README badges). Feel free to branch it out and apply your own changes.
https://github.com/fabiomcosta/mixpanel-js/tree/mixpanel-logging-only

Any update here would be highly appreciated

Unfortunately, the only update at the moment is that this ask hasn't reached high priority in our product backlog. If you simply need to avoid blocking pageload with your JS loading, then the script tag embed code loader is the way to go (i.e. the "standard" mixpanel-js installation). For static bundles including mixpanel-browser via require/import, the amount of effort relative to the gains (your bundle will be a few kb smaller gzipped) simply hasn't yet justified prioritizing this over other engineering projects.

@tdumitrescu Totally fair, we switched to using the js library instead. Thank you.

The size is really frustrating. I still hope there will be updates.

Also could a non-build source file be exposed from the package.json? E.g. a browser or module property that points to ./src/[entry-file]. That would help whatever builder immensely with deduping common modules and thus reducing overall bundle size. I'd rather not be limited to whatever is pre-built but allow a builder to simple include the minimum set of modules required.

Similarly I don't see any reason for having inline styles being included with a library that is suppose to just track users. If these could be part of a special build just for when they are needed that would make a lot more sense.

@Swaagie which builder are you looking to support, or more to the point what exact entry would you like in package.json? We can add it easily. FWIW if you just want to make a PR, the entrypoint file you want is src/loader-module.js. There's an in-repo example of importing from it at

import mixpanel from '../../src/loader-module';

There is a plan to support alternative builds so you can drop modules that you don't use, but unfortunately no ETA right now on when we'll be able to work on it.

More granular functionality importing would definitely be nice. Hopefully this can help in migration toward this goal. It also introduces a no-notifications bundle as a stop-gap measure:

#172

I think using dynamic import help this

I made the util of the dynamic load of the mixpanel and util components for React user here
https://gist.github.com/Ranatchai/6112c5c952299c6ac67bba7dff11c49c

It uses dynamic-import syntax, that is in a ECMAScript proposal and not currently part of the language standard. if you use babel you need
https://yarnpkg.com/en/package/babel-plugin-syntax-dynamic-import

Any progress here? 40k is way too huge for simply tracking

Any news? Mixpanel lib is almost the same size than react-dom... seriously? We are on our way to stop mixpanel because of this

any updates?

The purpose of mixpanel is to ultimately enhance user experience. Long initial loading times directly contribute to worse UX. It follows that decreasing bundle size should be mixpanels #1 priority imo.

It has been almost 2 years since I opened this issue. I'm afraid it seems to not be Mixpanel's priority at all even that this issue has a LOT of people interesting in.

Seems like if anyone would like it to be reduced the only way it's going to be is by using something else than Mixpanel :/

Any progress?

Any progress?

What's the current status? Any improvements?

I assume they have 0 interest in this, might end just ripping apart their library to create a tiny version for tracking only when l get a chance

Would be really appreciated to see progress on this.

@valentinkostadinov first cut is done, it has track, identify and alias with ability for bulk sending events. Give me a week to fully test it, then will put it on NPM. It sits at around 13KB Gzipped and 39KB minified only

Hi @OllieJennings, any news on this? Thanks!

@jpreynat yes, apologies, just came back from holiday, going to re-test the module and push to NPM this week

@OllieJennings Friendly ping, are there any updates?

Also very interested for this update! Would be amazing

Came here to complain about bundle size as well. Any progress from devs on this issue?

I created a lightweight version that also supports offline mode mixpanel-lite 5.2k (2.2k gzipped).

I've only included the core features, PR's welcome!

// setup mixpanel
mixpanel.init('your-token-here'); // pass { mute: true } to mute by default

// assign all future events to a user
mixpanel.identify('user@email.com');

// assign user info
mixpanel.people.set({
    $email: 'user@email.com' // only special properties need the $
});

// track an event
mixpanel.track('Your Event Name' {
    firstName: 'Optional event property 1',
    lastName: 'Optional event property 2'
});

// clear current identity
mixpanel.reset();

// stop sending data to mixpanel (calls to track, identify etc are ignored)
mixpanel.mute();

// resume sending data to mixpanel
mixpanel.unmute();

// check if mixpanel is muted
if (mixpanel.muted) {
    console.log('Mixpanel is disabled');
}

Also throwing down a friendly ping, I like @john-doherty 's lightweight implementation, any chance at getting something like this into the mixpanel-js repo?

Is there anybody working on this?

Guys - this is really insane!!! So many complaints already and you are ignoring it for 3 years? What have you done? Am a customer for 1 year and haven't seen much else. Really wants to make me churn!

It's really been a while. Can somebody from the team react to this, please? Thank you very much 🙂

Are there any plans to look into that?

I've been following this issue since a couple years ago and it's quite clear to me this company doesn't give a dam. Just move to another solution, there are dozens of solutions like mixpanel out there. It's a shame they let random developers create a minimal version of this from their own pocket. Mixpanel is not a free product/solution. We have stopped using and the only big deal about it was the large payload we stopped serving ;)

I just signed our startup with Mixpanel (correction, we haven't switched to the paid plan yet). We implemented Mixpanel tracking, and then afterwards observed how much the JS bundle size increased. It's extremely ironic that the largest factor to increasing conversions and product performance is...... ..... PAGE LOAD TIME.

This is disappointing. We are reviewing the 'lite' package to see if it feels safe to use. @john-doherty thank you for that, we are betting the future of our product on these analytics... so we will need to vet it a bit. I intend to notify Mixpanel about this as well.

mixpanel-lite does not work with Next.js because it requires document to exist. The lite solution is a good start, but it does not function in the same server + client environment that this package does.

Although we are only calling Mixpanel on the client-side in our application, it still is bundled server-side where it does this check for document. It's too bad a team that creates a web product does not prioritize web performance.

Same for me, it's 23% of my app size while I just use basic parts of the SDK... After 4 years, any plans to fix this fast??? We will have to drop Mixpanel otherwise, please do something...!

@dawsbot I'm using next.js, whether or not you use Mixpanel's Library, or the lighter library, you need to load it dynamically client side. My technique was to assign the script's loaded event to a redux/react state, then initialize Mixpanel inside of useEffect (which has access to the DOM) after the scripts loaded event is set.

@bradgreens No worries, I fully removed mixpanel last month.

The lightest bundle size option out there 😜

commented

Agreed. The response time for this issue is unacceptable. I've moved over to amplitude. (edit: and not just for this reason)

@matthewoates Not gonna lie, it's kind of painful to see Atlassian on Amplitude's homepage. But that said, alternative options are very much in play. We harvested some great metrics, but the developer confidence just isn't available on this project.

Hey folks, I just wanted to let you all know that this library will be much smaller in Q1 2022. With the deprecation of messaging, we will be able to remove some sizable portions of the code base. If the size at that point is still an issue to you, we will work with you to get to a good solution.

I am assigning this issue to myself right now to make sure it is, at long last, resolved. I'm embarrassed it's taken this long and promise you we'll fix it.

Hey! Still on track? Is it out maybe and can share a link here?

Thanks!

@odedsolutions the release removing the in-app notifications code will be publicly available likely this coming week.

is this released?

@odedsolutions the release removing the in-app notifications code will be publicly available likely this coming week.

Hi @tdumitrescu, is there a a new timeline for releasing this? It's been nearly 2 weeks.

The new release (v2.45.0) is now available everywhere.

I'm still seeing +60KB minified bundle sizes using version 2.45.0... anyone else?

image

given the size of this bundle is there a recommended pattern for lazy loading in Next.js applications?

Last I recall they chipped at the size, but if it’s still an issue just load it like any other bullshit script way after your primary UX loads.

+1 this issue is not resolved, v2.45.0 is still 60kb+. Quite a shame