react-async-component
react-async-component copied to clipboard
Preload dependencies during idle time?
Hey, cool to see you have abstracted away the lazy loading handling for large React tree. I found the approach much better than what react-router is suggesting to do! I'm wondering, do you have any plan preloading dependencies on the client side during the idle time?
I have been implemented a naive solution, I'm pretty sure we could improve that. It's preloading everything. If we were collecting some data. For instance, the order of lazing loading, we could even build a prediction model. I have heard that Facebook is using a machine learning algorithm to smartly load dependencies ahead of time.
Hey @oliviertassinari! Thanks!
Yeah, totally a great idea and I think @bradennapier has some alternative ideas around this problem.
It would be great to come up with a simple and flexible solution for this. I'll review your solution when I get a chance and keep this in the back of my mind. Happy to collaborate with you to get something awesome together.
Olivier, I may be misunderstanding your intent - but the fact the async loading is done using import which already returns promises, we shouldn't need to use setTimeout to accomplish nested asynchronous loading.
This method also allows using the defer method to handle pushing to the client for rendering which @ctrlplusb has given us. From my testing it appears to do a good job so far, but I haven't done extensive tests on it as its working for our dev thus far.
I have setup a method of handling routes asynchronously as well as their dependencies.
export default [
{
id: 'Home',
exactly: true,
props: {
title: 'Home'
},
pattern: '/',
component: () => import('./screens/Home')
},
{
id: 'Welcome',
props: {
title: 'Welcome'
},
pattern: '/login/1',
component: () => import('./screens/Welcome')
},
{
id: 'SecurityCenter',
props: {
title: 'Security Center'
},
pattern: '/security-center',
secure: true,
component: () => import('./screens/SecurityCenter')
},
{
id: 'UserProjects',
props: {
title: 'Project Select'
},
pattern: '/project',
component: () => import('./screens/UserProjects')
},
{
id: 'LoginPage',
props: {
title: 'Login'
},
pattern: '/login',
component: () => import('./screens/Login')
}
]
Then when we move deeper into the routes we simply pass new routes that will be also imported asynchronously
import React from 'react'
import Resolver from 'app/resolver'
const routes = [
{
id: 'ProjectSelect',
pattern: '/',
exactly: true,
component: () => import('./screens/ProjectSelect')
},
{
id: 'ProjectDashboard',
pattern: '/dashboard/:projectSlug',
component: () => import('./screens/ProjectDashboard')
}
]
export default props => (<Resolver {...props} routes={routes} />)
Then we have this as a Resolver ( I added a redux push as well for redirecting when accessing secure pages using a layer:
const RoutedResolver = ({ routes, ...props }) => (
<div>
{
routes.map( route => {
if ( ! route.id ) { throw new Error('Route Does not have an ID: ', route) }
const matchProps = {
...route,
key: route.id,
exactly: route.exactly == true,
pattern: route.pattern === '/'
? props.pathname
: props.pathname + route.pattern
}
return <Match {...matchProps} render={ renderProps => {
const appProps = {
...matchProps,
...renderProps,
}
return <Resolver {...props} {...appProps} />
}}
/>
})
}
</div>
)
const Loading = () => (<div>LOADING</div>)
const Resolver = ({
component, routes,
isAuthenticated = false,
defer = false,
secure = false,
...props
}, { store }) => {
if ( secure && ! isAuthenticated ) {
const { location, ...rest } = props
store.dispatch({
type: 'ROUTER_SECURE_REQUESTED',
location: props.location,
props: rest
})
return null
}
const Component = routes
? RoutedResolver
: component
? BuildAsyncComponent(component, secure || defer)
: Loading
if ( routes ) { props.routes = routes }
//console.log('Resolver: ', props.id, props)
return <Component {...props} />
}
Resolver.contextTypes = {
store: PropTypes.object.isRequired
}
export const BuildAsyncComponent = (component, defer) =>
createAsyncComponent({
resolve: component,
defer
})
export default Resolver
Related: https://github.com/ctrlplusb/react-universally/issues/406