This repository has been archived by the owner on Jan 22, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 130
/
client.js
136 lines (113 loc) · 5.37 KB
/
client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*-------------------------------------------------------------------------------------------------------------------*\
| Copyright (C) 2017 PayPal |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance |
| with the License. |
| |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed |
| on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for |
| the specific language governing permissions and limitations under the License. |
\*-------------------------------------------------------------------------------------------------------------------*/
'use strict';
var Config = require('./config.json');
var ReactDOM = require('react-dom');
var assign = require('lodash/assign');
var isFunction = require('lodash/isFunction');
// declaring like this helps in unit test
// dependency injection using `rewire` module
var _window;
var _document;
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
_window = window;
_document = document;
}
// returns the data/state that was
// injected by server during rendering
var data = exports.data = function data() {
// this file needs to be a external js file
var element = document.getElementById(Config.client.markupId);
// grab the contents from the script element
var jsonString = element.textContent || element.innerText;
// parse the text contents to JSON
return JSON.parse(jsonString);
};
// the client side boot function
exports.boot = function boot(options, callback) {
var React = require('react');
var Router;
var RouterComponent;
var match;
var browserHistory;
try {
Router = require('react-router');
RouterComponent = Router.Router;
match = Router.match;
// compatibility for both `react-router` v2 and v1
browserHistory = Router.browserHistory || require('history').createHistory();
} catch (err) {
if (!Router && options.routes) {
throw new Error('asking to use react router for rendering, but no routes are provided');
}
}
var router;
var history;
var location;
var viewResolver = options.viewResolver;
// pick up the state that was injected by server during rendering
var props = data();
var useRouter = (props.__meta.view === null);
var mountNode = options.mountNode || _document;
// wrap component with react-redux Proivder if redux is required
var wrap = function(component) {
if (options.reduxStoreInitiator && isFunction(options.reduxStoreInitiator)) {
var initStore = options.reduxStoreInitiator;
if (initStore.default) {
initStore = initStore.default;
}
var store = initStore(props);
var Provider = require('react-redux').Provider;
return React.createElement(Provider, { store: store }, component);
} else {
return component;
}
};
var renderMethod = ReactDOM.hydrate || ReactDOM.render;
if (useRouter) {
history = options.history || browserHistory;
location = _window.location.pathname +
_window.location.search + _window.location.hash;
if (options.routes.default) {
options.routes = options.routes.default;
}
// Wrap the 'render' function within a call to 'match'. This is a workaround to support
// users using code splitting functionality
match({ routes: options.routes, location: location }, function() {
// for any component created by react-router, merge model data with the routerProps
// NOTE: This may be imposing too large of an opinion?
var routerComponent = React.createElement(RouterComponent, {
createElement: function(Component, routerProps) {
return React.createElement(Component, assign({}, props, routerProps));
},
routes: options.routes,
history: history
});
// wrap routerComponent with redux provider
renderMethod(wrap(routerComponent), mountNode);
});
} else {
// get the file from viewResolver supplying it with a view name
var view = viewResolver(props.__meta.view);
// create a react view factory
var viewFactory = React.createFactory(view);
// render the factory on the client
// doing this, sets up the event
// listeners and stuff aka mounting views.
renderMethod(wrap(viewFactory(props)), mountNode);
}
// call the callback with the data that was used for rendering
return callback && callback(props, history);
};