Improve performance on a complex infrastructure of apps and packages

We work in a project of apps that are currently using Meteor 1.4.2 version. Our infrastructure is shaped by several applications and also packages that encapsulate logic for favoring modularity and reusability.

An example of how our apps and packages looks could be:

Meteor App #1
   NPM Packages 1
   Meteor Package A
      NPM Packages A
   Meteor Package B
      NPM Package B
      Meteor Package C
         NPM Packages C
Meteor App #2
   NPM Packages 2
   Meteor Package A
      NPM Package A

We have recently wrapped up the features and wanted to go to production env. Our surprise there has been the loss of performance we have experienced on the client. We’ve been looking into the browser profiles and we have noticed that a considerable time is spent into the initial load of our apps.

Diving more into this we noticed the possible causes.

Dependencies eagerly loaded

This is probably the major reason, which contributes the worse performance on our apps.

All our packages dependencies are importing all their contents automatically though the api.mainModule definition. So, that is causing that the apps depending on each package are importing the contents fully on each app, no matter is they ever use it or not.

A possible solution researching over the Internet has been to stop using an api.mainModule to expose our logic modules. So a possible alternative could be to export our package modules lazily using api.addFiles(..., ..., { isAsset: true }) and then referencing them on all apps/packages by meteor/[PACKAGE]/....

Is that a common pattern used in Meteor packages?, What else should I know about how Meteor manages package module exporting?, Is there an option to say Meteor to load dependencies by requiring them instead of on initial load?

NPM dependencies are loaded multiple times

The way meteor packages handle NPM dependencies, is that all of them, whether they are included directly at package.json or using Npm.depends, are bundled on the package itself, which produces increasing our apps in both size and processing. So creating NPM dependencies on the packages, just as I depict on the snippet above, causes our apps to get extra size and time to import all of them since it gets repeated.

I have been researching solutions around this issue. One is to move all NPM dependencies from the packages to the app level. However that produces to move all our package tests to a separate application and running them there, which drive us to lose test package possibilities in the same context. And it also requires a way to handle the requirements on the NPM versions that each package needs, check-npm-version has not resulted to be worth for us, we’ve faced so many issues, feels like quite buggy and abandoned. Do you happen to know other ideas or ways to handle peer NPM dependencies on your projects?

Other solution could be to create our packages as plain NPM modules and have a custom way to build and test (through webpack or other env setup tool). The problem here is that some of our modules need to include meteor package dependencies. So, how do you face this transition?

How is it normally faced this NPM replication problem on big projects?

I wanted to share this with you for checking possible alternatives, or in case you have also got experience on building complex meteor apps, what approaches you have adopted to solve such issues. Or in case I miss other common causes I could check that drive Meteor apps and packages to get bundled and run losing performance significatively.

We would want to know more and discuss about how to address more complex infrastructures on the top of Meteor. Thanks a lot!

1 Like