genji-core
Version:
The core lightweight library for genji, based on redux and redux-saga.
332 lines (274 loc) • 9.82 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.create = create;
var _getIterator2 = _interopRequireDefault(require("@babel/runtime/core-js/get-iterator"));
var _keys = _interopRequireDefault(require("@babel/runtime/core-js/object/keys"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
var _invariant = _interopRequireDefault(require("invariant"));
var _checkModel = _interopRequireDefault(require("./checkModel"));
var _prefixNamespace = _interopRequireDefault(require("./prefixNamespace"));
var _Plugin = _interopRequireWildcard(require("./Plugin"));
var _createStore = _interopRequireDefault(require("./createStore"));
var _getAction = _interopRequireDefault(require("./getAction"));
var _getMutation = _interopRequireDefault(require("./getMutation"));
var _createAsyncMiddleware = _interopRequireDefault(require("./createAsyncMiddleware"));
var _createImmerReducer = _interopRequireWildcard(require("./createImmerReducer"));
var _subscription = require("./subscription");
var _utils = require("./utils");
// Internal model to update global state when do unmodel
var genjiModel = {
namespace: '@@genji',
state: 0,
mutations: {
UPDATE: function UPDATE(state) {
state += 1;
}
}
};
/**
* Create dva-core instance.
*
* @param hooksAndOpts
* @param createOpts
*/
function create() {
var hooksAndOpts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var createOpts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var initialReducer = createOpts.initialReducer,
_createOpts$setupApp = createOpts.setupApp,
setupApp = _createOpts$setupApp === void 0 ? _utils.noop : _createOpts$setupApp;
var plugin = new _Plugin.default();
plugin.use((0, _Plugin.filterHooks)(hooksAndOpts));
var app = {
_models: [(0, _prefixNamespace.default)((0, _objectSpread2.default)({}, genjiModel))],
_store: null,
_plugin: plugin,
use: plugin.use.bind(plugin),
model: model,
start: start
};
return app;
/**
* Register model before app is started.
*
* @param m {Object} model to register
*/
function model(m) {
if (process.env.NODE_ENV !== 'production') {
(0, _checkModel.default)(m, app._models);
}
var prefixedModel = (0, _prefixNamespace.default)((0, _objectSpread2.default)({}, m));
app._models.push(prefixedModel);
return prefixedModel;
}
/**
* Inject model after app is started.
*
* @param createReducer
* @param onError
* @param unlisteners
* @param m
*/
function injectModel(createReducer, actions, onError, unlisteners, m) {
m = model(m);
var store = app._store;
var onMutation = plugin.get('onMutation');
store.asyncReducers[m.namespace] = {
mutations: (0, _getMutation.default)(m.mutations, onMutation, m),
state: m.state
};
store.replaceReducer(createReducer(store.asyncReducers));
if (m.actions) {
actions[m.namespace] = app._getAction(m.actions, m, onError, plugin.get('onAction'));
store.runAction(actions);
}
if (m.subscriptions) {
unlisteners[m.namespace] = (0, _subscription.run)(m.subscriptions, m, app, onError);
}
}
/**
* Unregister model.
*
* @param createReducer
* @param reducers
* @param unlisteners
* @param namespace
*
* Unexpected key warn problem:
* https://github.com/reactjs/redux/issues/1636
*/
function unmodel(createReducer, reducers, actions, unlisteners, namespace) {
var store = app._store; // Delete reducers
delete store.asyncReducers[namespace];
delete reducers[namespace];
delete actions[namespace];
store.replaceReducer(createReducer());
store.dispatch({
type: '@@genji/UPDATE'
}); //reload actions
store.runAction(actions); // Unlisten subscrioptions
(0, _subscription.unlisten)(unlisteners, namespace); // Delete model from app._models
app._models = app._models.filter(function (model) {
return model.namespace !== namespace;
});
}
/**
* Start the app.
*
* @returns void
*/
function start() {
// Global error handler
var onError = function onError(err, extension) {
if (err) {
if (typeof err === 'string') err = new Error(err);
err.preventDefault = function () {
err._dontReject = true;
};
plugin.apply('onError', function (err) {
throw new Error(err.stack || err);
})(err, app._store.dispatch, extension);
}
};
var extraModels = plugin.get('extraModels');
extraModels.forEach(function (model) {
app.model(model);
});
var asyncMiddleware = (0, _createAsyncMiddleware.default)();
app._getAction = _getAction.default.bind(null);
var actions = {};
var onMutation = plugin.get('onMutation');
var reducers = {};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator2.default)(app._models), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var m = _step.value;
reducers[m.namespace] = {
mutations: (0, _getMutation.default)(m.mutations, onMutation, m),
state: m.state
};
actions[m.namespace] = app._getAction(m.actions, m, onError, plugin.get('onAction'));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var extraReducers = (0, _objectSpread2.default)({}, initialReducer, plugin.get('extraReducers'));
(0, _invariant.default)((0, _keys.default)(extraReducers).every(function (key) {
return !(key in reducers);
}), "[app.start] extraReducers is conflict with other reducers, reducers list: ".concat((0, _keys.default)(reducers).join(', '))); // Create store
var store = app._store = (0, _createStore.default)({
// eslint-disable-line
reducers: createReducer(),
initialState: hooksAndOpts.initialState || {},
plugin: plugin,
createOpts: createOpts,
asyncMiddleware: asyncMiddleware
}); // Extend store
store.runAction = asyncMiddleware.run;
store.asyncReducers = {}; // Execute listeners when state is changed
var listeners = plugin.get('onStateChange');
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
var _loop = function _loop() {
var listener = _step2.value;
store.subscribe(function () {
listener(store.getState());
});
};
for (var _iterator2 = (0, _getIterator2.default)(listeners), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
_loop();
} // Run sagas
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
asyncMiddleware.run(actions); // Setup app
setupApp(app); // Run subscriptions
var unlisteners = {};
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = (0, _getIterator2.default)(this._models), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _model = _step3.value;
if (_model.subscriptions) {
unlisteners[_model.namespace] = (0, _subscription.run)(_model.subscriptions, _model, app, onError);
}
} // Setup app.model and app.unmodel
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
app.model = injectModel.bind(app, createReducer, actions, onError, unlisteners);
app.unmodel = unmodel.bind(app, createReducer, reducers, actions, unlisteners);
/**
* Create global reducer for redux.
*
* @returns {Object}
*/
function createReducer() {
var normalReducers;
if ((0, _keys.default)(extraReducers).length != 0) {
normalReducers = (0, _createImmerReducer.combineReducers)(extraReducers);
} else {
normalReducers = function normalReducers(state, action) {
return state;
};
}
var mutations = (0, _createImmerReducer.default)(reducers);
var asyncMutations;
if (app._store) {
asyncMutations = (0, _createImmerReducer.default)(app._store.asyncReducers);
} else {
asyncMutations = function asyncMutations(state, action) {
return state;
};
}
return function (state, action) {
state = normalReducers(state, action);
state = mutations(state, action);
state = asyncMutations(state, action);
return state;
};
}
}
}