Skip to content

Instantly share code, notes, and snippets.

@nolanlawson
Last active April 29, 2017 13:05
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nolanlawson/d8541c6e818c8eb6e440d6a25c02987e to your computer and use it in GitHub Desktop.
Save nolanlawson/d8541c6e818c8eb6e440d6a25c02987e to your computer and use it in GitHub Desktop.
Mastodon frontend perf suggestions

Mastodon frontend perf suggestions

I took some time this weekend to analyze Mastodon's frontend performance. I didn't manage to write many fixes (just a config fix and better caching for static assets) so this was mostly just investigation.

The point of this document is to lay out some of my initial thoughts, since it may be helpful for others. There's a lot of technical jargon, so you may want to get some background by looking at my blog post on "The cost of small modules" and my talk on "Solving the web performance crisis" (slides).

Tootstorms

Basic analysis

Reduce JS bundle size

The JS bundle (2.6MB before gzip) is too big, especially for mobile devices. On a Galaxy Nexus running Chrome 47 throttled to 3G, it takes 15 seconds for a full load, and the size of the JavaScript bundle is the biggest cause of this. Sean Larkin of Webpack has proposed a target of <300KB per bundle whereas Addy Osmani proposes <100KB to hit <3 seconds on 3G per RAIL, so 2.6MB is far off that target.

The caching fixes I added will help with second load, but they won't help with first load, nor with the compile/exec time or memory costs.

JS bundle breakdown video and how to do it yourself

  • emojione is roughly 1/3 of the total minified bundle size – this should be either 1) moved to the server side, 2) trigger-loaded, 3) moved to a web worker (to avoid main thread parse costs), or 4) moved to an IndexedDB-based lookup system (to avoid keeping all emoji data in memory at all times). In my ideal world, I would move it to a web worker and use IndexedDB since that not only avoids the parse/exec cost on the main thread but would also remove any UI thread costs from IDB itself.
  • React and associated libraries take up roughly 1/4 - 1/3 of the total size – replacing React with Preact would help.
  • Mastodon core components take up ~1/4 of total size – using Rollup or rollupify could save around 7% of that size while also reducing parse costs.
  • Intl takes up 70kb – not needed for modern browsers, could be conditionally loaded based on feature checking.
  • Babel is probably adding overhead – I can't figure out exactly how much, but this blog post although satirical offers a good fix: split into an ES6 version and an ES5 version and then use a "cut the mustard" test to switch between the two, also see babel-preset-env which can help in case you don't actually need to support old browsers. Another option is to try Babel "loose" mode.
  • Conditional loading, trigger-loading, etc. – In the Webpack world this is called "code-splitting" and uses an API called require.ensure(), pretty sure there's a Browserify equivalent (other than factor-bundle which is not quite the same, more like Webpack's CommonsChunkPlugin) but I'd need to do research.
  • Remove dependencies – It may also be worthwhile to just jettison some larger dependencies if we don't need them. I'm not familiar enough with the codebase to know what's expendible though.

Simplify layout

Layout is the single most expensive thing in Edge and also seems expensive in Firefox and Chrome due to the slowness of resizing browser windows. At the very least there is a call to scrollTop that should be throttled because it costs ~600ms in Edge.

4200 DOM elements is a lot; I'd target 3000 since that's how many GMail has, and arguably GMail is about as complex as Mastodon if not more complex.

Since layout seems more expensive than style my hunch is that reducing the number of DOM elements would help here (as well as with memory usage) but I also need to investigate what layout patterns exactly are so expensive and why.

Conclusion

This is just my first look, and you should probably read all those threads for the full backstory, but I hope it helps! 😊 Note I do plan to do more investigations in the future and hopefully should have some actual PRs once I'm more comfortable with the codebase.

@nolanlawson
Copy link
Author

More research on emojione: https://toot.cafe/@nolan/316181

@Gargron
Copy link

Gargron commented Apr 29, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment