React @loadable/component SSR with Redux Router
Asked by Koda Odom onAnswer by Briar Lowe
I am trying to use @loadable/component library with React at the app that uses SSR, Redux and Router.,Could you please tell me, how I could use store and StaticRouter with renderRoutes(...) and this @loadable/component so that my SSR work?,The docs gives an example application code, but it's without Router and Redux (no need to pass state and render routes). The file src/server/main.js from the example contains such lines:
Answer by Hayden Leal
For Loadable ready components, inside your App components, you can wrap your required component with Providers of your own choice:
import { loadableReady } from '@loadable/component'
loadableReady(() => {
const root = document.getElementById('main')
hydrate(<App />, root)
})
For Chunks:
import { renderToString } from 'react-dom/server'
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server'
const statsFile = path.resolve('../dist/loadable-stats.json')
const extractor = new ChunkExtractor({ statsFile })
const html = renderToString(
<ChunkExtractorManager extractor={extractor}>
<YourApp />
</ChunkExtractorManager>,
)
const scriptTags = extractor.getScriptTags()
Answer by Henry Sutton
To make it work, we use the getLoadableState method provided by loadable-components. It allows us to make a pre-rendering of the application (including asynchronous calls), and extract the references of the chunks needed to render the requested page. We also have to make the express route asynchronous (with async and await).,(This example comes from the blog post Introducing loadable-components),a first asynchronous pre-rendering that launches the sagas (this is what we are already doing with const loadableState = await getLoadableState(appWithRouter) used to make the code splitting work in SSR),
// in package.json
"dependencies": {
"date-fns": "^1.28.5",
"lodash.debounce": "^4.0.8",
"material-ui": "^1.0.0-alpha.21",
"material-ui-icons": "^1.0.0-alpha.19",
"prop-types": "^15.5.10",
"query-string": "^4.3.4",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router-dom": "^4.1.1",
"typeface-roboto": "0.0.31"
},
Answer by Heidi Wiggins
I try to make React Router 4 + React 16 + Redux + Loadable Components + Webpack 4 to work together but fail.,Here is a repo https://github.com/lauterry/perfect-react-app which illustrate how loadable-components works with React 16 + React router 4 + Redux + Webpack 4 + Babel 7 + SSR + React-inl,Can't use ReactDOM.hydrate in [React 16 + React router 4 + Redux + Webpack 4 + Babel 7 + SSR + React-inl] project? When I changed render to hydrate, it logged warning : "Warning: Expected server HTML to contain a matching .. "
const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats })
const { default: App } = nodeExtractor.requireEntrypoint()
const webExtractor = new ChunkExtractor({ statsFile: webStats })
const jsx = webExtractor.collectChunks(<App />)
const html = renderToString(jsx)
Answer by Otis Bonilla
When server receives a request, it runs react on server-side. The fetch function is defined in react component. Fetch data by rendered component.,Get the js file name by react-loadable.json (source code),defined fetch function (source code)
Install
yarn add react-loadable
Webpack Plugin (source code)
plugins: [new ReactLoadablePlugin({filename: path.resolve(__dirname, 'dist', 'react-loadable.json')})]
Define Async React Component (source code)
const AsyncHome = Loadable({ loader: () => import('../components/Home'), loading: Loading});
On server side, We can get the rendered async react components at first.
// moduleName is the rendered async react componentReactDOMServer.renderToString( <Loadable.Capture report={moduleName => modules.push(moduleName)} > <Router location={req.url}> <Routes /> </Router> </Loadable.Capture>);
Get the js file name by react-loadable.json (source code)
const styles = bundles.filter( bundle => bundle.file.endsWith('.css')); const components = bundles.filter(bundle => bundle.file.endsWith('.js'));
Inject these js paths into HTML (source code)
res.send(`<!doctype html> <html lang="en"> <head> <body> ${components.map(script => `<script src="/dist/${script.file}"></script>`).join('\n')} </body> </html> `);
actions and reducer (source code)
export const queryAdoptions = () => async (dispatch) => { dispatch({type: 'ADOPTIONS_REQUEST'}); const res = await fetch(`http://asms.coa.gov.tw/Asms/api/ViewNowAnimal? pageSize=30¤tPage=${~~(Math.random() * 10) + 1}`); const adoptions = await res.json(); dispatch({ type: ADOPTIONS_SUCCESS, adoptions: Object.values(adoptions)});};
defined fetch function (source code)
import fetchData from 'hocs/fetchData';import { queryAdoptions } from 'reducers/adoptions';const fetchAdoptions = ({ dispatch }) => { return dispatch(queryAdoptions());};@fetchData(fetchAdoptions)class FetchAdoptionsComponent extends Component { ...}
Client: while first rendering, we don’t have to run fetch functions. So we use a flag isDataFetchEnabled to disabled it (source code).
if (__SERVER__) { push(fetch({ dispatch })); } else if (isDataFetchEnabled){ fetch({ dispatch }); }
yarn analytics
Answer by Zane Griffin
Loadable-Components is a library to solve the React code-splitting client-side and server-side.,So If you want to do code-splitting in a server-rendered app you may want to go with Loadable-Components which is also react’s suggested way since the React.lazy and Suspense is not yet available for server-side rendering.
Answer by Violette Logan
Making React and Redux and React router dom easy to use and make with ARS react,Fork of loadable-components.,Various codemods related to @loadable/components for easier migration/ugprades.
Answer by Kye Harrington
Answer by Capri Rodgers
We will use React in the examples below, but the same techniques can be used with other view frameworks that can render on the server.,and then pass the state along to the client.,To send the data down to the client, we need to:
npm install express react-redux
Answer by Hadlee Solomon
Boilerplate for quick start using React + Redux + React Router + React Helmet + React Google Analytics + SSR + Code Split + Dynamic Route Imports + Long Term Caching + Styled Components + Jest + Enzyme + HMR + BrowserSync + ESLint + Prettier + Webpack Dashboard + Friendly Errors + HTTP2,stefanlazarevic / isomorphic-react-boilerplateBoilerplate for quick start using React + Redux + React Router + React Helmet + React Google Analytics + SSR + Code Split + Dynamic Route Imports + Long Term Caching + Styled Components + Jest + Enzyme + HMR + BrowserSync + ESLint + Prettier + Webpack Dashboard + Friendly Errors + HTTP2reactreduxreact-routerreact-helmetreact-gassrnodejscode-splittingreact-loadablecachingstyled-componentsstefanlazarevicjavascriptenzymeLanguage:JavaScript Stargazers:11Updated 4 months ago,ReactJS starter progressive web app template with cool features such as hot-reload, async import for code splitting, browser history router with react-router-dom, and custom webpack config without eject using react-app-rewired.