Very low meteor performance in production

Hi @dr.dimitru , Can you share some examples in blaze also?

1 Like

Also an example with a react router.
I created and used a collection exactly as follows :

Importing File Collection :

import EditorImg from "../../../../Collections/Files/Editor/EditorImg.js";

EditorImg Collection :

import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';

const EditorImg = new FilesCollection({
    collectionName: 'EditorImg',
    storagePath : 'assets/uploads/editor/img/',
    allowClientCode: true, // Disallow remove files from Client
    onBeforeUpload(file) {
      // Allow upload files under 10MB, and only in png/jpg/jpeg formats
      if (file.size <= 1697400 && /png|jpg|jpeg/i.test(file.extension)) {
        return true;
      }
      return `please upload image, with size equal or less than 1MB ,,, ${file.size} `;
    }
});
export default EditorImg;

Now exactly how can I load this package lazy, of course I use a react router

I need an example and a full explanation about lazy.
How is it used in different packages?
How exactly should I start?
An example and explanation that can clarify the issue.

@mixmatric demo-app is entirely made of Blaze

1 Like

lazy is only for Atmosphere Package.
Iā€™m curious how we can make NPM package lazy? :thinking:

For your own code use dynamic import().

What should be the idle size of the bundle?

In the matter of import dynamics and lazy packages, there are really few documents and I am confused

From what Iā€™ve read so far it seems that people are getting relaxed with around 1.4-1.5MB and less, but there is no established hard limit.

Also mind that there is a related problem in Meteor, the bundled css. All css/scss that is not explicitly imported gets compiled into the css bundle, meaning that if you donā€™t import any, all of your css/scss get compiled into this bundle. It is then referenced in your main.html's <head> section via a <link> tag.

The problem with that is that such a css reference represents a blocking resource, which will ultimately delay the client appā€™s startup, thus adding to the time until FCP, First Contentful Paint, and, maybe even more importantly the LCP, Largest Contentful Paint. This is bad for SEO and should be taken very seriously since the introduction of Googleā€™s Web Vitals.

Also see e.g.

LCP (largest contentful paint): The amount of time to render the largest content element visible in the viewport, from when the user requests the URL. The largest element is typically an image or video, or perhaps a large block-level text element. This is important because it tells the reader that the URL is actually loading.

LCP thresholds

  • <=2.5s: Good
  • <=4s Needs Improvement
  • >4s Poor
1 Like

Thanks for the information shared,

Attaching two Screenshots,

Can you please suggest the following things

  1. How can we improve Speed Index
  2. Currently the website is on Heroku, which comes with a machine having 512 MB ram, but not sure which parameter will get improvement in case I would change the RAM of the machine, please let me know if this would many any difference
  3. Regarding Reduce initial load time, here I observed that all the package we have in packages (inside the .meteor folder) combines and give us one single file. Is there any approach we can decide whether we want a particular package on a page?
1 Like

@mixmatric
The strategy of increasing RAM and CPU does not work.
I tried many times, it does not have much effect.
Of course I use prerender and nginx proxies it.
Iā€™m not exactly sure if prerender might not work well.

I am also not sure how does exactly prerender works but what I observed is Reduce initial server response time reduces if the RAM and CPU increases of a machine. @peterfkruger would be great if you can confirm

The only way is that
First, solve the ssr problem to reduce the serverā€™s initial response time and eliminate the need to use a prerender.
Secondly, it provides a comprehensive solution for code spliting, packages and components. This issue is very difficult and ambiguous at the moment

Prerendering is a great concept, but only if done correctly ā€“ but itā€™s rather difficult to get there. Once that is achieved, it reduces initial server response time, and also both FCP and LCP. Also, it only requires minimal server resources (CPU and RAM).

On-demand prerendering

On-demand prerendering is the natural choice, but itā€™s the wrong way. It involves a middleware that makes a request to a prerendering service to produce an html snapshot of the page referred to by the initial request. The snapshot is cached in redis for subsequent requests, and of course it is delivered to the client.

Problems

There are multiple problems with this approach:

  • It takes too long for a page that is not cached yet or if the redis TTL for that page is already expired
  • while the page is still cached in redis, potential changes in the database arenā€™t reflected
  • prerender deletes all <script> tags from html, and that equally destroys JSON-LD encoded schema.org definitions, and also any dehydration data embedded into a <script> tag. This can only be circumvented by renaming the <script> tags during rendering, and then by re-renaming the tags in the final html snapshot. I know, it sounds crazy.

The proper way of doing the prerendering is actually an even more crazy thing, brace for impact!

Welcome to pre-prerendering

You need to set up your system in such a way that it automatically triggers prerendering for:

  • new pages (if your app creates pages dynamically)
  • updated pages

ā€¦and if a dynamically created page becomes obsolete, the corresponding prerendered snapshot also needs to be deleted from redis.

This whole thing also coincides with your site.xml for search engines, which you need to update anyway, if the site content changes.

As hinted previously, youā€™ll need to render your pages during prerendering in such that you also add a <script> tag for client side hydration. This is to prevent the much dreaded flickering effect upon client start.

Redis TTL for pre-prerendered pages: If you do all of the above right, you donā€™t even need to set an expiration for your pages.

Give a small example, how to implement the second mode.
With code

Please provide some kind of tutorials, there is too much information to digest for. We donā€™t have that much appetite :sweat_smile:

1 Like

FWIW Iā€™ve gone with an approach that is fairly common but wonā€™t answer your question directly: donā€™t use Meteor for your marketing site. Meteor is a powerful application framework but itā€™s heavy and honestly getting it to act as a performant marketing site is difficult and requires tons of optimizations.

So for example my setup looks like this:

  • www.myapp.com
    • My marketing site. I use Webflow to make mine but you can use anything that lets you build a lightweight marketing page, whether it be by hand with your front end framework of choice or with a tool like Webflow.
    • All backlinks point to www.myapp.com so this is the basis of all of our SEO.
    • Itā€™s hosted out of an S3 bucket w/Cloudflare as a CDN so it loads blazingly fast anywhere
    • Itā€™s just a static website for marketing purposes. Itā€™s not making any API calls or anything and each page is its own .html file so thereā€™s no dealing with code splitting, dynamic imports, or anything else when worrying about the bundle size. It just loads really fast.
  • app.myapp.com
    • My Meteor app
    • www.myapp.com sends users here to sign up/sign in
    • I donā€™t need to worry too much about page load speeds because all SEO efforts point to the marketing website, so the Meteor app loading slowly doesnā€™t give our domain a huge penalty for SEO

Tons of sites do this to separate the marketing site from the application itself, it has lots of benefits. For example it looks like Meteor.com does this.

7 Likes

Weā€™re using the same approach and I can confirm that this is blazing (pun intended) fast and IMO the best way forward with Meteor apps in Production.

This is the Lighthouse result for our landing page: Your DNA family and the results (not optimized for a while, hence results went down a bit

Screenshot 2021-02-22 at 02.05.43

Oh and if you think we achieve this by basically going with a naked landing page, nope, our page is actually quite long and has a YouTube video referenced and several images including one big, hero image:

1 Like

Iā€™ll chime in here and say itā€™s still possible to create quite a very landing page in Meteor if you use dynamic/lazy imports in the right places. Attached performance results for submithub.com.

1 Like

Excellent results, Jason!

It is very causal. Maybe this is the first time I see this with a meteor.
And until now I thought it was impossible.

Please help us.
How exactly can we load packages and components dynamically and lazily?

No matter how hard I tried, I could only dynamically import my root components that I called in the router.
Also by npdev-react-loadable.

Iā€™m really confused and I do not know exactly how to dynamically import the sub-branches and sub-components. For example, components that are in the same route and in the same mother component.
ex : HomeComponent -> HeaderComponent , FooterComponent

On the other hand, I really do not know how to load a package as Tenible.
Like
react - bootstrap,
alanning:roles,
ostrio:files,
SunEditor,
sweetalert2,
framer-motion