diff --git a/README.md b/README.md index 00de9bc..71c63d3 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,33 @@ export default function serverRender(req, res) => { `) ``` +> NOTE: this requires that the bundling and rendering happen within the same context. The module, react-universal-component/server holds a global cache of all the universal components that are rendered and makes them available via `flushChunkNames` + +If you build step and your render step are separate (i.e. using a static site generator like `react-static`) we can use a Provider type component to locate the components that should be included on the client. This is not the recommended use of locating chunk names and only should be used when absolutely necessary. It uses React's context functionality to pass the `report` function to react-universal-component. + +```js +import { ReportChunks } from 'react-universal-component' +import flushChunks from 'webpack-flush-chunks' +import ReactDOM from 'react-dom/server' + +function renderToHtml () => { + let chunkNames = [] + const appHtml = + ReactDOM.renderToString( + chunkNames.push(chunkName)}> + + , + ), + ) + + const { scripts } = flushChunks(webpackStats, { + chunkNames, + }) + + return appHtml +} +``` + ## Preload diff --git a/server.js b/server.js index 9019049..150b005 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ module.exports = { flushModuleIds: require('./dist/requireUniversalModule').flushModuleIds, flushChunkNames: require('./dist/requireUniversalModule').flushChunkNames, - clearChunks: require('./dist/requireUniversalModule').clearChunks + clearChunks: require('./dist/requireUniversalModule').clearChunks, + ReportChunks: require('./dist/report-chunks').default } diff --git a/src/flowTypes.js b/src/flowTypes.js index db787a2..a1e03ad 100644 --- a/src/flowTypes.js +++ b/src/flowTypes.js @@ -77,7 +77,7 @@ export type OnError = (error: Object, info: { isServer: boolean }) => void export type RequireAsync = (props: Object, context: Object) => Promise export type RequireSync = (props: Object, context: Object) => ?any -export type AddModule = (props: Object) => void +export type AddModule = (props: Object) => ?string export type Mod = Object | Function export type Tools = { requireAsync: RequireAsync, diff --git a/src/index.js b/src/index.js index 721d8e7..e1edaba 100644 --- a/src/index.js +++ b/src/index.js @@ -16,6 +16,7 @@ import type { import { DefaultLoading, DefaultError, isServer, createElement } from './utils' export { CHUNK_NAMES, MODULE_IDS } from './requireUniversalModule' +export { default as ReportChunks } from './report-chunks' let hasBabelPlugin = false @@ -75,7 +76,8 @@ export default function universal( } static contextTypes = { - store: PropTypes.object + store: PropTypes.object, + report: PropTypes.func } constructor(props: Props, context: {}) { @@ -102,7 +104,11 @@ export default function universal( } this._asyncOnly = asyncOnly - addModule(this.props) // record the module for SSR flushing :) + const chunkName = addModule(this.props) // record the module for SSR flushing :) + + if (this.context.report) { + this.context.report(chunkName) + } if (Component || isServer) { this.handleBefore(true, true, isServer) diff --git a/src/report-chunks.js b/src/report-chunks.js new file mode 100644 index 0000000..66dfda1 --- /dev/null +++ b/src/report-chunks.js @@ -0,0 +1,29 @@ +// @flow + +import React from 'react' +import PropTypes from 'prop-types' + +type Props = { + report: Function, + children: Object +} + +export default class ReportChunks extends React.Component { + static propTypes = { + report: PropTypes.func.isRequired + } + + static childContextTypes = { + report: PropTypes.func.isRequired + } + + getChildContext() { + return { + report: this.props.report + } + } + + render() { + return React.Children.only(this.props.children) + } +} diff --git a/src/requireUniversalModule.js b/src/requireUniversalModule.js index 6e70037..e757a80 100644 --- a/src/requireUniversalModule.js +++ b/src/requireUniversalModule.js @@ -133,21 +133,24 @@ export default function requireUniversalModule( return prom } - const addModule = (props: Object): void => { + const addModule = (props: Object): ?string => { if (isServer || isTest) { if (chunkName) { const name = callForString(chunkName, props) if (name) CHUNK_NAMES.add(name) - if (!isTest) return // makes tests way smaller to run both kinds + if (!isTest) return name // makes tests way smaller to run both kinds } if (isWebpack()) { const weakId = callForString(resolve, props) if (weakId) MODULE_IDS.add(weakId) + return weakId } - else if (!isWebpack()) { + + if (!isWebpack()) { const modulePath = callForString(path, props) if (modulePath) MODULE_IDS.add(modulePath) + return modulePath } } }