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

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

Closed
kazazor opened this issue Apr 4, 2017 · 79 comments
Closed
Assignees

Comments

@kazazor
Copy link

kazazor commented Apr 4, 2017

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?

@ghost
Copy link

ghost commented Apr 17, 2017

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

@jbwyme
Copy link
Contributor

jbwyme commented Apr 17, 2017

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 :)

@ghost
Copy link

ghost commented Apr 17, 2017

@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.

@kazazor
Copy link
Author

kazazor commented Apr 18, 2017

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? :)

@ghost
Copy link

ghost commented Apr 18, 2017

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 :)

@rubencodes
Copy link

rubencodes commented Apr 28, 2017

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

@tdumitrescu
Copy link
Member

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.

@OllieJennings
Copy link

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

@ghost
Copy link

ghost commented Aug 7, 2017

@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?

@tdumitrescu
Copy link
Member

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).

@matthewoates
Copy link

matthewoates commented Sep 8, 2017

@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.

@tdumitrescu
Copy link
Member

@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.

@fabiomcosta
Copy link
Contributor

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.

@fabiomcosta
Copy link
Contributor

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

@fabiomcosta
Copy link
Contributor

fabiomcosta commented Sep 21, 2017

Another nice thing to have, size badges:

#144

@bradleyayers
Copy link

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?

@fabiomcosta
Copy link
Contributor

@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

@therajumandapati
Copy link

Any update here would be highly appreciated

@tdumitrescu
Copy link
Member

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.

@therajumandapati
Copy link

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

@hackuun
Copy link

hackuun commented Feb 4, 2018

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

@Swaagie
Copy link

Swaagie commented Mar 23, 2018

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.

@tdumitrescu
Copy link
Member

@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.

@DullReferenceException
Copy link

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

@Ranatchai
Copy link

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

@dedan
Copy link

dedan commented Sep 13, 2018

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

@nicgirault
Copy link

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

@mikehans9
Copy link

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.

@kazazor
Copy link
Author

kazazor commented Jan 27, 2019

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 :/

@enapupe
Copy link

enapupe commented Dec 8, 2020

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 ;)

@bradgreens
Copy link

bradgreens commented Mar 12, 2021

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.

@dawsbot
Copy link

dawsbot commented May 6, 2021

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.

@benjamincombes
Copy link

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...!

@bradgreens
Copy link

bradgreens commented Jun 22, 2021

@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.

@dawsbot
Copy link

dawsbot commented Jun 22, 2021

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

The lightest bundle size option out there 😜

@matthewoates
Copy link

matthewoates commented Oct 25, 2021

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

@bradgreens
Copy link

bradgreens commented Oct 26, 2021

@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.

@jbwyme
Copy link
Contributor

jbwyme commented Oct 26, 2021

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.

@jbwyme
Copy link
Contributor

jbwyme commented Oct 26, 2021

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.

@jbwyme jbwyme self-assigned this Oct 26, 2021
@odedsolutions
Copy link

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

Thanks!

@tdumitrescu
Copy link
Member

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

@odedsolutions
Copy link

odedsolutions commented Feb 7, 2022 via email

@venky216
Copy link

venky216 commented Feb 9, 2022

is this released?

@michael-wallace-bv
Copy link

@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.

@tdumitrescu
Copy link
Member

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

@kazazor kazazor closed this as completed Feb 19, 2022
@mpereira
Copy link

mpereira commented Feb 1, 2023

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

image

@zrthomas
Copy link

zrthomas commented Mar 6, 2023

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

@bradgreens
Copy link

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.

@lbittner-pdftron
Copy link

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

@asp3
Copy link

asp3 commented Jul 10, 2023

bumping, as of july 2023, still 18kb gzipped size.

image

@dragoon
Copy link

dragoon commented Jul 27, 2023

5 years with zero progress, I will use mixpanel-lite as well...

@victorcarvalhosp
Copy link

same problem with big size here

@Ryanjso
Copy link

Ryanjso commented Feb 20, 2024

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

This works well for us, it removes mixpanel-browser from the pages/_app chunk that is part of the first load js shared by all through dynamically importing it.

import Router from 'next/router';

const isProd = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production';

type MixpanelImport = typeof import('mixpanel-browser');
type Mixpanel = MixpanelImport['default'];
type Dict = Parameters<Mixpanel['track']>[1];

let mixpanel: null | Mixpanel;

const loadMixpanel = async (): Promise<Mixpanel> => {
  if (mixpanel) return mixpanel;

  mixpanel = (await import('mixpanel-browser')).default;
  mixpanel.init('proj_id');

  return mixpanel;
};

export const trackEvent = async (
  eventName: string,
  properties?: Dict
) => {
  const { pathname, query } = Router;

  const mp = await loadMixpanel();

  mp.track(eventName, {
    page: pathname,
    title: document.title,
    ...query,
    ...properties,
    environment: isProd ? 'prod' : 'dev',
  });
};

@dmyur
Copy link

dmyur commented Feb 22, 2024

Why is the issue closed? The weight is still too big ☹️

@rmiyazaki6499
Copy link

November 2024, This is the bundle size I'm seeing...

Image

@odedsolutions
Copy link

odedsolutions commented Nov 18, 2024 via email

@bondarenkovladislav
Copy link

Still, 50kb gzipped is a relatively huge, is there any workaround?

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