Skip to content

Commit c037650

Browse files
committed
Preps 1.0.0-alpha.2
1 parent cec03b4 commit c037650

8 files changed

+923
-6
lines changed

.gitignore

-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ npm-debug.log
1111
# Jest
1212
coverage
1313

14-
# Build output
15-
umd
16-
commonjs
17-
build
18-
1914
# Flow
2015
flow-coverage
2116
flow-typed

commonjs/AsyncComponentProvider.js

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8+
9+
var _react = require('react');
10+
11+
var _react2 = _interopRequireDefault(_react);
12+
13+
var _createAsyncContext = require('./createAsyncContext');
14+
15+
var _createAsyncContext2 = _interopRequireDefault(_createAsyncContext);
16+
17+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18+
19+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20+
21+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
22+
23+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
24+
25+
var AsyncComponentProvider = function (_React$Component) {
26+
_inherits(AsyncComponentProvider, _React$Component);
27+
28+
function AsyncComponentProvider() {
29+
_classCallCheck(this, AsyncComponentProvider);
30+
31+
return _possibleConstructorReturn(this, (AsyncComponentProvider.__proto__ || Object.getPrototypeOf(AsyncComponentProvider)).apply(this, arguments));
32+
}
33+
34+
_createClass(AsyncComponentProvider, [{
35+
key: 'componentWillMount',
36+
value: function componentWillMount() {
37+
this.asyncContext = this.props.asyncContext || (0, _createAsyncContext2.default)();
38+
this.rehydrateState = this.props.rehydrateState;
39+
}
40+
}, {
41+
key: 'getChildContext',
42+
value: function getChildContext() {
43+
var _this2 = this;
44+
45+
return {
46+
asyncComponents: {
47+
getNextId: this.asyncContext.getNextId,
48+
resolved: this.asyncContext.resolved,
49+
shouldRehydrate: function shouldRehydrate(id) {
50+
var resolved = _this2.rehydrateState.resolved[id];
51+
delete _this2.rehydrateState.resolved[id];
52+
return resolved;
53+
}
54+
}
55+
};
56+
}
57+
}, {
58+
key: 'render',
59+
value: function render() {
60+
return _react2.default.Children.only(this.props.children);
61+
}
62+
}]);
63+
64+
return AsyncComponentProvider;
65+
}(_react2.default.Component);
66+
67+
AsyncComponentProvider.propTypes = {
68+
children: _react2.default.PropTypes.node.isRequired,
69+
asyncContext: _react2.default.PropTypes.shape({
70+
getNextId: _react2.default.PropTypes.func.isRequired,
71+
resolved: _react2.default.PropTypes.func.isRequired,
72+
getState: _react2.default.PropTypes.func.isRequired
73+
}),
74+
rehydrateState: _react2.default.PropTypes.shape({
75+
resolved: _react2.default.PropTypes.object
76+
})
77+
};
78+
79+
AsyncComponentProvider.defaultProps = {
80+
asyncContext: undefined,
81+
rehydrateState: {
82+
resolved: {}
83+
}
84+
};
85+
86+
AsyncComponentProvider.childContextTypes = {
87+
asyncComponents: _react2.default.PropTypes.shape({
88+
getNextId: _react2.default.PropTypes.func.isRequired,
89+
resolved: _react2.default.PropTypes.func.isRequired,
90+
shouldRehydrate: _react2.default.PropTypes.func.isRequired
91+
}).isRequired
92+
};
93+
94+
exports.default = AsyncComponentProvider;

commonjs/asyncComponent.js

+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8+
9+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
10+
11+
var _react = require('react');
12+
13+
var _react2 = _interopRequireDefault(_react);
14+
15+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16+
17+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
18+
19+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
20+
21+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
22+
23+
var validSSRModes = ['render', 'defer', 'boundary'];
24+
25+
function asyncComponent(args) {
26+
var name = args.name,
27+
resolve = args.resolve,
28+
_args$autoResolveES = args.autoResolveES2015Default,
29+
autoResolveES2015Default = _args$autoResolveES === undefined ? true : _args$autoResolveES,
30+
_args$serverMode = args.serverMode,
31+
serverMode = _args$serverMode === undefined ? 'render' : _args$serverMode,
32+
LoadingComponent = args.LoadingComponent,
33+
ErrorComponent = args.ErrorComponent;
34+
35+
36+
if (validSSRModes.indexOf(serverMode) === -1) {
37+
throw new Error('Invalid serverMode provided to asyncComponent');
38+
}
39+
40+
var env = typeof window === 'undefined' ? 'node' : 'browser';
41+
42+
var sharedState = {
43+
// A unique id we will assign to our async component which is especially
44+
// useful when rehydrating server side rendered async components.
45+
id: null,
46+
// This will be use to hold the resolved module allowing sharing across
47+
// instances.
48+
// NOTE: When using React Hot Loader this reference will become null.
49+
module: null,
50+
// If an error occurred during a resolution it will be stored here.
51+
error: null,
52+
// Allows us to share the resolver promise across instances.
53+
resolver: null
54+
};
55+
56+
// Takes the given module and if it has a ".default" the ".default" will
57+
// be returned. i.e. handy when you could be dealing with es6 imports.
58+
var es6Resolve = function es6Resolve(x) {
59+
return autoResolveES2015Default && x != null && (typeof x === 'function' || (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object') && x.default ? x.default : x;
60+
};
61+
62+
var getResolver = function getResolver() {
63+
if (sharedState.resolver == null) {
64+
try {
65+
// Wrap whatever the user returns in Promise.resolve to ensure a Promise
66+
// is always returned.
67+
var resolver = resolve();
68+
sharedState.resolver = Promise.resolve(resolver);
69+
} catch (err) {
70+
sharedState.resolver = Promise.reject(err);
71+
}
72+
}
73+
return sharedState.resolver;
74+
};
75+
76+
var AsyncComponent = function (_React$Component) {
77+
_inherits(AsyncComponent, _React$Component);
78+
79+
function AsyncComponent(props, context) {
80+
_classCallCheck(this, AsyncComponent);
81+
82+
// We have to set the id in the constructor because a RHL seems
83+
// to recycle the module and therefore the id closure will be null.
84+
// We can't put it in componentWillMount as RHL hot swaps the new code
85+
// so the mount call will not happen (but the ctor does).
86+
var _this = _possibleConstructorReturn(this, (AsyncComponent.__proto__ || Object.getPrototypeOf(AsyncComponent)).call(this, props, context));
87+
88+
if (_this.context.asyncComponents && !sharedState.id) {
89+
sharedState.id = _this.context.asyncComponents.getNextId();
90+
}
91+
return _this;
92+
}
93+
94+
_createClass(AsyncComponent, [{
95+
key: 'getChildContext',
96+
value: function getChildContext() {
97+
if (!this.context.asyncComponents) {
98+
return undefined;
99+
}
100+
101+
return {
102+
asyncComponentsAncestor: {
103+
isBoundary: serverMode === 'boundary'
104+
}
105+
};
106+
}
107+
}, {
108+
key: 'componentWillMount',
109+
value: function componentWillMount() {
110+
this.setState({ module: sharedState.module });
111+
if (sharedState.error) {
112+
this.registerErrorState(sharedState.error);
113+
}
114+
}
115+
}, {
116+
key: 'componentDidMount',
117+
value: function componentDidMount() {
118+
if (!this.state.module) {
119+
this.resolveModule();
120+
}
121+
}
122+
123+
// @see react-async-bootstrapper
124+
125+
}, {
126+
key: 'asyncBootstrap',
127+
value: function asyncBootstrap() {
128+
var _this2 = this;
129+
130+
var _context = this.context,
131+
asyncComponents = _context.asyncComponents,
132+
asyncComponentsAncestor = _context.asyncComponentsAncestor;
133+
var shouldRehydrate = asyncComponents.shouldRehydrate;
134+
135+
136+
var doResolve = function doResolve() {
137+
return _this2.resolveModule().then(function (module) {
138+
return module !== undefined;
139+
});
140+
};
141+
142+
if (typeof window !== 'undefined') {
143+
// BROWSER BASED LOGIC
144+
return shouldRehydrate(sharedState.id) ? doResolve() : false;
145+
}
146+
147+
// SERVER BASED LOGIC
148+
var isChildOfBoundary = asyncComponentsAncestor && asyncComponentsAncestor.isBoundary;
149+
return serverMode === 'defer' || isChildOfBoundary ? false : doResolve();
150+
}
151+
}, {
152+
key: 'resolveModule',
153+
value: function resolveModule() {
154+
var _this3 = this;
155+
156+
this.resolving = true;
157+
158+
return getResolver().then(function (module) {
159+
if (_this3.unmounted) {
160+
return undefined;
161+
}
162+
if (_this3.context.asyncComponents) {
163+
_this3.context.asyncComponents.resolved(sharedState.id);
164+
}
165+
sharedState.module = module;
166+
if (env === 'browser') {
167+
_this3.setState({ module: module });
168+
}
169+
_this3.resolving = false;
170+
return module;
171+
}).catch(function (error) {
172+
if (_this3.unmounted) {
173+
return undefined;
174+
}
175+
if (env === 'node' || !ErrorComponent) {
176+
// We will at least log the error so that user isn't completely
177+
// unaware of an error occurring.
178+
// eslint-disable-next-line no-console
179+
// console.warn('Failed to resolve asyncComponent')
180+
// eslint-disable-next-line no-console
181+
// console.warn(error)
182+
}
183+
sharedState.error = error;
184+
_this3.registerErrorState(error);
185+
_this3.resolving = false;
186+
return undefined;
187+
});
188+
}
189+
}, {
190+
key: 'componentWillUnmount',
191+
value: function componentWillUnmount() {
192+
this.unmounted = true;
193+
}
194+
}, {
195+
key: 'registerErrorState',
196+
value: function registerErrorState(error) {
197+
var _this4 = this;
198+
199+
if (env === 'browser') {
200+
setTimeout(function () {
201+
if (!_this4.unmounted) {
202+
_this4.setState({ error: error });
203+
}
204+
}, 16);
205+
}
206+
}
207+
}, {
208+
key: 'render',
209+
value: function render() {
210+
var _state = this.state,
211+
module = _state.module,
212+
error = _state.error;
213+
214+
// This is as workaround for React Hot Loader support. When using
215+
// RHL the local component reference will be killed by any change
216+
// to the component, this will be our signal to know that we need to
217+
// re-resolve it.
218+
219+
if (sharedState.module == null && !this.resolving && typeof window !== 'undefined') {
220+
this.resolveModule();
221+
}
222+
223+
if (error) {
224+
return ErrorComponent ? _react2.default.createElement(ErrorComponent, { error: error }) : null;
225+
}
226+
227+
var Component = es6Resolve(module);
228+
// eslint-disable-next-line no-nested-ternary
229+
return Component ? _react2.default.createElement(Component, this.props) : LoadingComponent ? _react2.default.createElement(LoadingComponent, this.props) : null;
230+
}
231+
}]);
232+
233+
return AsyncComponent;
234+
}(_react2.default.Component);
235+
236+
AsyncComponent.childContextTypes = {
237+
asyncComponentsAncestor: _react2.default.PropTypes.shape({
238+
isBoundary: _react2.default.PropTypes.bool
239+
})
240+
};
241+
242+
AsyncComponent.contextTypes = {
243+
asyncComponentsAncestor: _react2.default.PropTypes.shape({
244+
isBoundary: _react2.default.PropTypes.bool
245+
}),
246+
asyncComponents: _react2.default.PropTypes.shape({
247+
getNextId: _react2.default.PropTypes.func.isRequired,
248+
resolved: _react2.default.PropTypes.func.isRequired,
249+
shouldRehydrate: _react2.default.PropTypes.func.isRequired
250+
})
251+
};
252+
253+
AsyncComponent.displayName = name || 'AsyncComponent';
254+
255+
return AsyncComponent;
256+
}
257+
258+
exports.default = asyncComponent;

commonjs/createAsyncContext.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = createAsyncContext;
7+
8+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9+
10+
function createAsyncContext() {
11+
var idPointer = 0;
12+
var registry = {};
13+
return {
14+
getNextId: function getNextId() {
15+
idPointer += 1;
16+
return idPointer;
17+
},
18+
resolved: function resolved(id) {
19+
registry[id] = true;
20+
},
21+
getState: function getState() {
22+
return {
23+
resolved: Object.keys(registry).reduce(function (acc, cur) {
24+
return Object.assign(acc, _defineProperty({}, cur, true));
25+
}, {})
26+
};
27+
}
28+
};
29+
}

0 commit comments

Comments
 (0)