dash-renderer
Version:
render dash components in react
183 lines (179 loc) • 7.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _ramda = require("ramda");
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _reactRedux = require("react-redux");
var _api = _interopRequireDefault(require("../../actions/api"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
class Reloader extends _react.default.Component {
constructor(props) {
super(props);
if (props.config.hot_reload) {
var _props$config$hot_rel = props.config.hot_reload,
interval = _props$config$hot_rel.interval,
max_retry = _props$config$hot_rel.max_retry;
this.state = {
interval,
disabled: false,
intervalId: null,
packages: null,
max_retry
};
} else {
this.state = {
disabled: true
};
}
this._retry = 0;
this._head = document.querySelector('head');
this.clearInterval = this.clearInterval.bind(this);
}
clearInterval() {
window.clearInterval(this.state.intervalId);
this.setState({
intervalId: null
});
}
static getDerivedStateFromProps(props) {
/*
* Save the non-loading requests in the state in order to compare
* current hashes with previous hashes.
* Note that if there wasn't a "loading" state for the requests,
* then we could simply compare `props` with `prevProps` in
* `componentDidUpdate`.
*/
if (!(0, _ramda.isEmpty)(props.reloadRequest) && props.reloadRequest.status !== 'loading') {
return {
reloadRequest: props.reloadRequest
};
}
return null;
}
componentDidUpdate(prevProps, prevState) {
var reloadRequest = this.state.reloadRequest;
var dispatch = this.props.dispatch;
// In the beginning, reloadRequest won't be defined
if (!reloadRequest) {
return;
}
/*
* When reloadRequest is first defined, prevState won't be defined
* for one render loop.
* The first reloadRequest defines the initial/baseline hash -
* it doesn't require a reload
*/
if (!(0, _ramda.has)('reloadRequest', prevState)) {
return;
}
if (reloadRequest.status === 200 && (0, _ramda.path)(['content', 'reloadHash'], reloadRequest) !== (0, _ramda.path)(['reloadRequest', 'content', 'reloadHash'], prevState)) {
// Check for CSS (!content.hard) or new package assets
if (reloadRequest.content.hard || !(0, _ramda.equals)(reloadRequest.content.packages.length, (0, _ramda.pathOr)([], ['reloadRequest', 'content', 'packages'], prevState).length) || !(0, _ramda.equals)((0, _ramda.sort)((0, _ramda.comparator)(_ramda.lt), reloadRequest.content.packages), (0, _ramda.sort)((0, _ramda.comparator)(_ramda.lt), (0, _ramda.pathOr)([], ['reloadRequest', 'content', 'packages'], prevState)))) {
// Look if it was a css file.
var was_css = false;
// eslint-disable-next-line prefer-const
var _iterator = _createForOfIteratorHelper(reloadRequest.content.files),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var a = _step.value;
if (a.is_css) {
was_css = true;
var nodesToDisable = [];
// Search for the old file by xpath.
var it = document.evaluate("//link[contains(@href, \"".concat(a.url, "\")]"), this._head);
var node = it.iterateNext();
while (node) {
nodesToDisable.push(node);
node = it.iterateNext();
}
(0, _ramda.forEach)(n => n.setAttribute('disabled', 'disabled'), nodesToDisable);
if (a.modified > 0) {
var link = document.createElement('link');
link.href = "".concat(a.url, "?m=").concat(a.modified);
link.type = 'text/css';
link.rel = 'stylesheet';
this._head.appendChild(link);
// Else the file was deleted.
}
} else {
// If there's another kind of file here do a hard reload.
was_css = false;
break;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (!was_css) {
// Assets file have changed
// or a component lib has been added/removed -
// Must do a hard reload
window.location.reload();
}
} else {
// Backend code changed - can do a soft reload in place
dispatch({
type: 'RELOAD'
});
}
} else if (this.state.intervalId !== null && reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
this.clearInterval();
// Integrate with dev tools ui?!
window.alert("Hot reloading is disabled after failing ".concat(this._retry, " times. ") + 'Please check your application for errors, then refresh the page.');
}
this._retry++;
}
}
componentDidMount() {
var _this$props = this.props,
dispatch = _this$props.dispatch,
reloadRequest = _this$props.reloadRequest;
var _this$state = this.state,
disabled = _this$state.disabled,
interval = _this$state.interval;
if (!disabled && !this.state.intervalId) {
var intervalId = window.setInterval(() => {
// Prevent requests from piling up - reloading can take
// many seconds (10-30) and the interval is 3s by default
if (reloadRequest.status !== 'loading') {
dispatch((0, _api.default)('_reload-hash', 'GET', 'reloadRequest'));
}
}, interval);
this.setState({
intervalId
});
}
}
componentWillUnmount() {
if (!this.state.disabled && this.state.intervalId) {
this.clearInterval();
}
}
render() {
return null;
}
}
Reloader.defaultProps = {};
Reloader.propTypes = {
id: _propTypes.default.string,
config: _propTypes.default.object,
reloadRequest: _propTypes.default.object,
dispatch: _propTypes.default.func,
interval: _propTypes.default.number
};
var _default = exports.default = (0, _reactRedux.connect)(state => ({
config: state.config,
reloadRequest: state.reloadRequest
}), dispatch => ({
dispatch
}))(Reloader);