Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/react-server/core/ReactServerAgent.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var RLS = require('./util/RequestLocalStorage').getNamespace()
, Q = require("q")
, Cache = require("./ReactServerAgent/Cache")
, Request = require("./ReactServerAgent/Request")
, Plugins = require("./ReactServerAgent/Plugins")
Expand All @@ -10,8 +11,17 @@ function makeRequest (method, url) {
return new Request(method, url, API.cache());
}

// REALLY don't want to accidentally cache data across requests on the server.
// We throw an error if `preloadDataForURL` is called server-side, but it's
// worth being doubly cautious here.
const DATA_BUNDLE_CACHE = SERVER_SIDE?Object.freeze({}):{};
const DATA_BUNDLE_PARAMETER = '_react_server_data_bundle';
const DATA_BUNDLE_OPTS = {[DATA_BUNDLE_PARAMETER]: 1};

var API = {

DATA_BUNDLE_PARAMETER,

get (url, data) {
var req = makeRequest('GET', url);
if (data) req.query(data);
Expand Down Expand Up @@ -97,6 +107,26 @@ var API = {
Plugins.forResponse().add(pluginFunc);
},

preloadDataForURL (url) {
if (SERVER_SIDE) throw new Error("Can't preload server-side");
if (!DATA_BUNDLE_CACHE[url]){
DATA_BUNDLE_CACHE[url] = API._fetchDataBundle(url);
}
return DATA_BUNDLE_CACHE[url];
},

_fetchDataBundle(url) {
return this.get(url, DATA_BUNDLE_OPTS).then(data => JSON.stringify(data.body));
},

_rehydrateDataBundle(url) {
// If we don't have any then we can't use it.
if (!DATA_BUNDLE_CACHE[url]) return Q();

return DATA_BUNDLE_CACHE[url]
.then(data => API.cache().rehydrate(JSON.parse(data)));
},

}


Expand Down
10 changes: 9 additions & 1 deletion packages/react-server/core/context/Navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var EventEmitter = require('events').EventEmitter,
Router = require('routr'),
Q = require('q'),
History = require("../components/History"),
ReactServerAgent = require("../ReactServerAgent"),
PageUtil = require("../util/PageUtil");

var _ = {
Expand Down Expand Up @@ -65,7 +66,14 @@ class Navigator extends EventEmitter {
// The promise returned from `startRoute()` will be rejected
// if we're not going to proceed, so resources will be freed.
//
this.startRoute(route, request, type).then(() => {
this
.startRoute(route, request, type)

// If we've got a preload bundle let's inflate it and avoid
// firing off a bunch of xhr requests during `handleRoute`.
.then(() => ReactServerAgent._rehydrateDataBundle(request.getUrl()))

.then(() => {
if (this._ignoreCurrentNavigation){
// This is a one-time deal.
this._ignoreCurrentNavigation = false;
Expand Down
25 changes: 25 additions & 0 deletions packages/react-server/core/renderMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ function renderPage(req, res, context, start, page) {
lifecycleMethods = fragmentLifecycle();
} else if (PageUtil.PageConfig.get('isRawResponse')){
lifecycleMethods = rawResponseLifecycle();
} else if (req.query[ReactServerAgent.DATA_BUNDLE_PARAMETER]) {
lifecycleMethods = dataBundleLifecycle();
} else {
lifecycleMethods = pageLifecycle();
}
Expand Down Expand Up @@ -250,6 +252,16 @@ function fragmentLifecycle () {
];
}

function dataBundleLifecycle () {
return [
Q(), // NOOP lead-in to prime the reduction
setDataBundleContentType,
writeDataBundle,
handleResponseComplete,
endResponse,
];
}

function pageLifecycle() {
return [
Q(), // This is just a NOOP lead-in to prime the reduction.
Expand All @@ -268,6 +280,10 @@ function setContentType(req, res, context, start, pageObject) {
res.set('Content-Type', pageObject.getContentType());
}

function setDataBundleContentType(req, res) {
res.set('Content-Type', 'application/json');
}

function writeHeader(req, res, context, start, pageObject) {
res.type('html');
res.set('Transfer-Encoding', 'chunked');
Expand Down Expand Up @@ -736,6 +752,15 @@ function writeResponseData(req, res, context, start, page) {
});
}

function writeDataBundle(req, res) {

const cache = ReactServerAgent.cache();

return Q.allSettled(
cache.getPendingRequests().map(v => v.entry.dfd.promise)
).then(() => res.write(JSON.stringify(cache.dehydrate())));
}

function renderElement(res, element, context) {

if (element.containerOpen || element.containerClose){
Expand Down