Last active
October 12, 2017 03:54
-
-
Save jaysoo/aa0c50ef05b4454feea3f4837997e9b0 to your computer and use it in GitHub Desktop.
examples showing how ssr + lazy components might work better
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is just a scratch of ideas I've been thinking about when it comes | |
* to lazy-loaded components/modules, and how that can work with rendering a react | |
* application in a single pass. | |
* | |
* Note: Don't take any of these ideas too seriously. I have implemented some of them in experiments, | |
* but much more thinking is needed. | |
*/ | |
/* | |
* components/Button.js | |
*/ | |
import styled from 'styled-component' | |
const Button = styled.button` | |
/* ... */ | |
` | |
/* | |
* components/Text.js | |
*/ | |
import styled from 'styled-component' | |
const Text = styled.span` | |
/* ... */ | |
` | |
/* | |
* components/index.js | |
*/ | |
import { lazy, concat } from '???' | |
// Each `lazy` call makes a loadable "module". | |
const Button = lazy(() => import('./Button')) | |
const Text = lazy(() => import('./Text')) | |
export { Button, Text } | |
// Use a combinator to concat both "modules" | |
export default concat(Button, Text) | |
/* | |
* index.js | |
*/ | |
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import { load } from '???' | |
import cmps, { Button, Text } from './components' | |
// Wait to resolve module(s) before rendering the application. | |
load(cmps).then(m => { | |
// Maybe we should explicitly pull components out of module? | |
// This can be pretty verbose... but HOCs, etc. may be a ble to help. | |
const [Btn, Txt] = m.get(Button, Text) | |
ReactDOM.render( | |
<div> | |
{/* But maybe it's better/easier to synchonously resolve component function once it has been loaded. */} | |
<Button>Button 1</Button> | |
<Txt>Hello</Txt> | |
<Btn>Button 2</Btn> | |
</div>, | |
document.getElementById('root') | |
) | |
}) | |
/* | |
* ------------------------------------------------------------------* | |
* Using these "modules", you can compose the entire app the same way. | |
*/ | |
/* | |
* foo/index.js | |
*/ | |
import { lazy, concat } from '???' | |
const A = lazy(() => import('./A')) | |
const B = lazy(() => import('./B')) | |
const C = lazy(() => import('./C')) | |
export { A,B,C } | |
export default concat(A, B, C) | |
/* | |
* bar/index.js | |
*/ | |
import { lazy, concat } from '???' | |
const D = lazy(() => import('./D')) | |
export { D } | |
export default D | |
/* | |
* quux/index.js | |
*/ | |
import { concat } from '???' | |
import foo from '../foo' | |
import bar, { D as E } from '../bar' | |
export { E } // re-export stuff if we want to | |
export default concat(foo, bar) | |
/* | |
* index2.js | |
*/ | |
import quux, { E } from './quux' | |
import { A, B, C } from './foo' | |
load(quux).then(() => { | |
// Can render synchronously since modules have been resolved already. | |
ReactDOM.render( | |
<div> | |
<A/> | |
<B/> | |
<C/> | |
<D/> | |
<E/> | |
</div>, | |
document.getElementById('root') | |
) | |
}) | |
/* | |
* ------------------------------------------------------------------* | |
* Other thoughts... | |
* | |
* - Knowing which modules are loaded is very much a routing concern (IMO). I think all the required modules | |
* can known during application bootup, so there should just be one promise resolution before rendering. | |
* | |
* - I'm debating whether having "smart" components that has side-effects (i.e. `import()`) is the way to go. | |
* Perhaps it's better to reify the module concept, and keep components dumb. This reduces the number of areas | |
* in which side-effects can occur, and also keeps testing components simple. | |
* | |
* - It's possible to use higher-order functions or some other mapping means to spy on what modules are loaded | |
* given a route. This means that we can easily record a list of entry-point modules to include on the page | |
* using <script> elements. This speeds up the initial render time. | |
* | |
* - Where to handle errors? Can be at a component-level or a module-level, or both. The granularity depends | |
* on the domain, but error cases should always be considered (even something like unreliable network). | |
* | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment