Meteor 1.5 and lazy loading react components

you could implement this “lazy”-hoc easily with vanilla react, its not bound to react-komposer or flow router!

2 Likes

I tried something similar with recompose and displaying a loading component while the module is beeing transferred:

1 Like

Is there an actual sense of lazy-loading react-components?
Could you provide any insight on savings in such approach?

I imagine if you have some huge component like react-codemirror you might actually want to render the rest of the page first and only load that one component later and have the editor pop in. Just like you might want to load some initial data for a page and then defer some loading to later, you might want to do the same with a component.

2 Likes

Yeah it’s funny how we crave to get back progressive loading of the good old html days (1990’s) while we’re loading and eval’ing vast amounts of client side scripts like it’s 2017 :slight_smile:

In addition to what @sashko wrote: If you use dynamic imports your initial bundle size gets smaller and your pc/mobile needs less time to load and parse your code. If you use that concept in a way @macrozone described at the router level, your app will end up just loading what is needed for the url you’re opening on initial load. For big apps it is awesome news and gives you the freedom of finally merging the static landing page stuff with your meteor app without suffering page load time increases.

4 Likes

I think code splitting is crucial as the app get larger and it’s getting more important due to the demand for a better user experience on mobile. Take a look at the AMP initiative, their entire focus is on the initial load time of web pages on mobile devices.

Ideally you want to ship the very minimum needed for the initial render and then behind the scene you can load the rest of app by traversing the links to the components and cache it at the client. It’s not much different that streaming a movie online, you don’t need to wait the for the whole movie to start playing, load a bit and start playing and while the viewer is watching you load the rest.

It’s funny how the web progressed, it started by rendering everything (data & view) per route on the server which was good for the initial page load but slow on transitions. Then came Ajax which made the experience better by shipping partial pages from the server on demand, this was good on the initial load but was a bit complex to build, and shortly after we got SPA apps (pioneered by Flash and GWT) which shipped all the client code at the start and then load the data per route, this was great for the in-between transitions but slow at the start and it gets even slower as the app grows. But of course we can still do better by loading only what’s needed for the initial render and then load and cache the rest behind the scene (web buffering), and dynamic import is first step toward this direction.

4 Likes

Great example @alawi :slight_smile:

3 Likes

You would create two different app for client and admin ?

Depending on resources/time availability I certainly considered it… It could not only affect loading speeds, but also improve security - there won’t be any methods within the app to affect any admin-related activities, so less chances that anything might go wrong… Will have to check 1.5 and lazy loading, maybe it might work in a similar way. With different apps though one could even have additional password protected access on meteor application or even domain level… :slight_smile: Am I too paranoid?

2 Likes

I am just as paranoid as you. I do create two different apps because it bugs me too much to know that a regular user loads all the admin template and api. Looking forward for 1.5!

1 Like

This is great. Hopefully by the time 1.5 comes out we can have a few examples for using dynamic imports with common patterns. Lazy-loading React components is going to make a big difference, especially for things like datepickers, forms, etc. where a single component might end up depending on a large number of libraries.

2 Likes

I have been playing with this for a few hours and this is one of the solutions I came up with, wondering what other people are thinking since this seems a good place to talk about it: https://gist.github.com/Kestanous/ebc39ea1b24ba079bf2a68a1e9fa05f4

I always use the class syntax and really wanted something easy like a class method for this. I found two major downsides. For one, you have to specify an exact import path. The other issue is it is if you want more then one component per import things are going to get tricky, especially if you want to use the Name as OtherName syntax.

1 Like

I think react-mounter will pull a bunch of React dependencies into the main bundle. It may be better to load that in a route-handler module, rather than in the main place where you define your routes. Basically, move the contents of your route’s action function to another module, and then import that function dynamically from the other file/module.

1 Like

You can’t use variables for import(…),
meteor has to know which modules you want to download, so it parses import(…) statements afaik.

you have to use string literals in import(…)

That code worked perfectly in 1.5-beta.9. As I understand it, variables with imports is the point of the dynamic import: https://github.com/tc39/proposal-dynamic-import#proposed-solution

It works as long as you have defined the import(string literal) before so:

var a = "mymodule";
import(a);

would fail

but this would work

function notCalled(){
  import("mymodule");
}
var a = "mymodule";
import(a);
1 Like

its not the point with meteor, because the current implementation needs to know which modules you are going to fetch.

it only works with variables if you used a import “…” or import("…") somewhere before as @tcastelli pointed out.

I would currently advice against using import(…) with variables, because it can lead to unexpected behaviour

1 Like

Interesting, shame but thanks for the heads up. Back to square one :slight_smile:

it may help to think about import("…") as a fixed expression. It’s value is a promise, so you can pass it around as you want.

so instead of

const pathToImport = "/path/to/file.js";
// ...
// somewhere in your lazy-load-helper/component/whateve
import(pathToImport).then( ... ); // bad :-( only works if this module has already been imported 

always do this:

const importedThingPromise = import("/path/to/file.js");
// ...
// somewhere in your lazy-load-helper/component/whateve
importedThingPromise.then( ... ); // good :-) 

6 Likes

Yeah, I definitely understand why Meteor would have that requirement but now I really worry about MDG’s choice in naming this feature “dynamic import”, given that they are only implementing part of the specification. It really is only lazy loading and not true dynamic import. I hope they make that clear when they release Meteor 1.5. Regardless it is a great addition and I am looking forward to it.