Meteor 1.5 and lazy loading react components

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.

It’s not “MDG’s choice in naming”.

Babel: https://babeljs.io/docs/plugins/syntax-dynamic-import/
Webpack: https://webpack.js.org/guides/code-splitting-import/#dynamic-import

Webpack adds:

Keep in mind that import() path cannot be fully dynamic (e.g., import(Math.random())). Rather either completely static (e.g., import(’./locale/de.json’)) or partially static (e.g., import(’./locale/’ + language + ‘.json’)).

2 Likes

Can you expound on the differences between lazy loading and true dynamic import?

Correct me if I’m wrong but wouldn’t having the option to automatically download the entire app but defer lower-priority modules (but still download them) be superior to this download-and-load-modules if requested approach? That way all parts of the app are ready to be consumed by the user upon request? This is similar to ordering routes in the order of usage (although of course this optimization will probably result in a un-noticeable speed performance improvement).

I think this matters if the additional dynamic import requests are slower than the user will notice, perhaps >1 second. If the dynamic imports are small enough, perhaps they will likely be so fast the load time doesn’t matter (which I’m guessing is the case for most of them). So I’m wondering what the latency + load time of each additional dynamic import request is and will work to measure this once I get a chance to play with dynamic-import more.

It’s definitely possible to build the system you’re talking about on top of this one! That could be a very cool thing to add, and doesn’t sound like it would be very hard. However, as a default I feel like loading on demand is better since some people have data caps etc.

3 Likes

@sashko and @jalligator I did see that kind of approach when I once had the developer console open while loading a Facebook page. FB downloaded about 5 megabytes on initial page load but didn’t stop after that, strongly hinting it was precaching some components.

1 Like

There was a discussion on this here, a good analogy to this approach is online video streaming and the buffering that happens while watching video.

It seems that components buffering technique is the next logical optimization that can be build on top of dynamic imports as sashko hinted. We need to optimize for both initial load time and routes transitions time, the code splitting crucial for large apps initial load time, while the “components buffering” is an optimization that can be built on top of dynamic imports to speed up in the routes transition time.

3 Likes

I haven’t looked into dynamic imports or read through the entire thread.
But think this is relevant.

3 Likes

Highly relevant! Especially like the Lazy load component bit at ~10:00.

I feel like this suggested “bolt ons” on top of dynamic imports make sense to do after some service worker logic is implemented.
I would suggest the following:

  • get dynamic imports ready
  • implement service worker
  • preload (not yet) needed imports via service worker and store in AppCache

That way we could have a quick loading webapp, which only loads the needed imports initially but starts preloading and caching all the other stuff right away.

2 Likes

Agreed @klabauter. And perhaps we can have way to indicate the priority/order of the yet-to-load imports such that those with the highest probability of getting a hit get loaded first.

I now use a solution based on react-loadable

This is my component:

import React from 'react';
import ReactLoadable from 'react-loadable';
import { Loading } from './loading.jsx';

export const Loadable = promise => (
    ReactLoadable({
        loader: () => promise.then(ex => ex.default),
        LoadingComponent: Loading,
    })
);

Where Loading is a loading component.

And I use it in my other components like that:

const Plans = Loadable(import('../containers/plans'));
4 Likes

I’ve gone ahead and done the FlowRouter implementation as in the first post, but… I see all of those files loading in my app.js (in dev), and can also see them (minified) inside my prod js file. Is that right? Or am I missing something? I thought the whole point of this was to keep components from loading if they weren’t needed (eg, admin pages or an obscure part of the website).

FlowRouter.route('/artists', {
    name: 'artists',
    action() {
        mount(Layout, {
            content: <Loader />,
        });
        import('/client/components/artists').then(({ default: Artists }) => {
            mount(Layout, {
                content: <Artists />,
            });
        });
    },
})

And then inside my component:

export default Artists = React.createClass({ 
    render() {
        // code goes here
    }
})

@jasongrishkoff are you putting the files into the imports directory? That was my mistake when I first tried it out.

You’re right. I’m not. I’ve got a simple /client and /server structure, and I should read this closer: https://guide.meteor.com/structure.html

Thank you for the tip!

1 Like

Just to be clear, if you want to be able to use the [import directive] anywhere within Meteor (client or server), we must put the stuff we intend to import somewhere inside a [imports directory] that lives under root?

1 Like

Yes.

This will sooner or later change though and the root of our application will serve as /imports folder. Possibly even in 1.5.

1 Like