Optimizing initial page loads and overall performance

Here’s what I’m currently doing to make initial page loads fast:

My app’s minified JS payload is now 1.1MB. Consequently, loading times are rather high on mobile web. I’m considering taking the following steps to improve performance.

  • moving appropriate code defined in shared contexts to server-side only, so it won’t be minified and packaged in JS.

What other ways have you been able to improve your app’s performance?

Hey peter!

You’ve mentioned client-side code size performance, but server-side is IMO more important, client download size only really affects initial pageload and should be cached in later requests. For server-side there’s lots of stuff

  • this.unblock() in methods (or publications with the meteorhacks:unblock package) to prevent blocking incoming ddp requests
  • Meteor.defer() to run code in methods that doesn’t need to be completed before the result is sent back in a deferred callback
  • proper data modeling can play a big role in reducing db stress and read operations. ddp and mergebox only diff top-level fields so if you have deep nested fields changing it’ll send down the whole document, keeping changes in the top-level fields makes a big difference in how much data is sent down the wire
  • reusing observers in publications is really important, Meteor is smart enough to only hit the db for the initial cursor and fetch it from memory for others so if you can reuse observers you relieve a lot of db reads
  • using the meteorhacks:cluster package to get multi-core support
  • using the meteorhacks:cluster package to split code up into microservices. lots of meteor projects promote the monolith approach, which I don’t really think is the right way to scale
  • using a profiler like the kadira-profiler package, or any other one you like, to get server CPU profiles to find what’s hanging up your responses
  • using streams when appropriate to avoid the db layer entirely. for example in a chat app you can get away with mostly using streams, look at the RocketChat codebase for good examples, they use them extensively
  • field filtering and server-side transforms of data in publications or methods to reduce the amount of data sent down the wire
  • I’ve been playing around with operational transforms via sharejs lately for truly realtime collaborative stuff and it’s really great. I’ve moved from writing all changes to mongodb and sending changes to clients to using sharejs to handle perpetuating changes and conflict resolution and it’s awesome. It’s definitely only useful for specific use cases and isn’t just a mongo/publication replacement, but if you want lots of ppl collaborating on something in realtime simultaneously the OT approach is the way to go

For client-side performance

  • I’ve been using react with SSR which is really performant. No SSR for blaze is a dealbreaker for me.
  • CPU profiles can also be just as helpful on the client to find what’s taking up time on initial pageload and what’s blocking the event loop, Chrome has awesome profiling tools.
  • I haven’t used it yet personally but I’ve been keeping my eye on using Webpack within Meteor, being able to lazy load dependencies on demand could potentially make a huge difference in pageload size. Right now the best approach if you have parts of the app that will never be seen by some customers (ie: an admin dashboard) is to make a separate app for it so that the main user client doesn’t download tons of code it won’t ever use. Webpack would help avoid that by letting you only download the code for modules that are actually being used by the user

Client side performance is huge. Compared to server side performance, I would say both are equally important. My app takes about 5-6 seconds to load on mobile. And I get a decent percentage mobile traffic. That’s unacceptable. Who knows how many users today are too impatient for that, and perhaps even drop off? Performance is expected for production apps. Note that my app is snappy once all dependencies are loaded. But for the ‘framework of the future’ to be this slow on initial page load? This has got to get some priority before it only gets slower.

Why can’t Meteor asynchronously load libraries that don’t need to be present on initial page load? Loading everything that could be possibly needed at once is expensive, and it’s inefficent since based off my traffic I know that only a subset of templates are heavily used.

There are hacky solutions I could take, but these issues are fundamentally core issues. They need to be resolved by MDG. The build system has a significant disadvantage of compiling down to a single javascript file. 300+ other people agree with me.

AFAIK webpack is the only option for code splitting/lazy loading atm, these two articles are a good introduction to it. Haven’t tried it myself though. But yeah, I’d agree Meteor really really needs this in core