UNPKG

zus

Version:

> a lightweight front-end framework.

342 lines (276 loc) 11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = create; var _redux = require("redux"); var _reduxSaga = _interopRequireDefault(require("redux-saga")); var _logTips = _interopRequireWildcard(require("log-tips")); var _checkModel = _interopRequireDefault(require("./checkModel")); var _prefixNamespace = _interopRequireDefault(require("./prefixNamespace")); var _Plugin = _interopRequireWildcard(require("./Plugin")); var _createStore = _interopRequireDefault(require("./createStore")); var _getSaga = _interopRequireDefault(require("./getSaga")); var _getReducer = _interopRequireDefault(require("./getReducer")); var _createPromiseMiddleware = _interopRequireDefault(require("./createPromiseMiddleware")); var _subscription = require("./subscription"); var _utils = require("./utils"); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 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; } // Internal model to update global state when do unmodel var zusModel = { namespace: '@zus', state: 0, reducers: { UPDATE: function UPDATE(state) { return state + 1; } } /** * Create zus-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] : {}; // 解析了createOpts => set upApp var _createOpts$setupApp = createOpts.setupApp, setupApp = _createOpts$setupApp === void 0 ? _utils.noop : _createOpts$setupApp; var plugin = new _Plugin["default"](); plugin.use((0, _Plugin.filterHooks)(hooksAndOpts)); // 在定义的hooks中加入全局的配置 var app = { _models: [(0, _prefixNamespace["default"])(_objectSpread({}, zusModel))], _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"])(_objectSpread({}, m)); app._models.push(prefixedModel); return prefixedModel; } /** * Inject model after app is started. * * @param createReducer * @param onError * @param unlisteners * @param m */ function injectModel(createReducer, onError, unlisteners, m) { m = model(m); var store = app._store; store.asyncReducers[m.namespace] = (0, _getReducer["default"])(m.reducers, m.state, plugin._handleActions); store.replaceReducer(createReducer()); if (m.effects) { store.runSaga(app._getSaga(m.effects, m, onError, plugin.get('onEffect'))); } 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, unlisteners, namespace) { var store = app._store; // Delete reducers delete store.asyncReducers[namespace]; delete reducers[namespace]; store.replaceReducer(createReducer()); store.dispatch({ type: '@@zus/UPDATE' }); // Cancel effects store.dispatch({ type: "".concat(namespace, "/@@CANCEL_EFFECTS") }); // Unlisten subscrioptions (0, _subscription.unlisten)(unlisteners, namespace); // Delete model from app._models app._models = app._models.filter(function (_model) { return _model.namespace !== namespace; }); } /** * Replace a model if it exsits, if not, add it to app * Attention: * - Only available after zus.start gets called * - Will not check origin m is strict equal to the new one * Useful for HMR * @param createReducer * @param reducers * @param unlisteners * @param onError * @param m */ function replaceModel(createReducer, reducers, unlisteners, onError, m) { var store = app._store; var namespace = m.namespace; var oldModelIdx = (0, _utils.findIndex)(app._models, function (model) { return model.namespace === namespace; }); if (oldModelIdx !== -1) { // Cancel effects store.dispatch({ type: "".concat(namespace, "/@@CANCEL_EFFECTS") }); // Delete reducers delete store.asyncReducers[namespace]; delete reducers[namespace]; // Unlisten subscrioptions (0, _subscription.unlisten)(unlisteners, namespace); // Delete model from app._models app._models.splice(oldModelIdx, 1); } // add new version model to store app.model(m); store.dispatch({ type: '@@zus/UPDATE' }); } /** * Start the app. * * @returns void */ function start() { 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 sagaMiddleware = (0, _reduxSaga["default"])(); // saga 中间件 var promiseMiddleware = (0, _createPromiseMiddleware["default"])(app); // app._getSaga = _getSaga["default"].bind(null); var sagas = []; var reducers = {}; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = app._models[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var m = _step.value; reducers[m.namespace] = (0, _getReducer["default"])(m.reducers, m.state, plugin._handleActions); if (m.effects) sagas.push(app._getSaga(m.effects, m, onError, plugin.get('onEffect'))); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var reducerEnhancer = plugin.get('onReducer'); var extraReducers = plugin.get('extraReducers'); (0, _logTips["default"])(Object.keys(extraReducers).every(function (key) { return !(key in reducers); }), "[app.start] extraReducers is conflict with other reducers, reducers list: ".concat(Object.keys(reducers).join(', '))); // Create store var store = (0, _createStore["default"])({ reducers: createReducer(), initialState: hooksAndOpts.initialState || {}, plugin: plugin, createOpts: createOpts, sagaMiddleware: sagaMiddleware, promiseMiddleware: promiseMiddleware }); app._store = store; // Extend store store.runSaga = sagaMiddleware.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 = listeners[Symbol.iterator](), _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; } } } sagas.forEach(sagaMiddleware.run); // Setup app => 加入路由改变监听 setupApp(app); // Run subscriptions var unlisteners = {}; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this._models[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var _model2 = _step3.value; if (_model2.subscriptions) { unlisteners[_model2.namespace] = (0, _subscription.run)(_model2.subscriptions, _model2, 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, onError, unlisteners); app.unmodel = unmodel.bind(app, createReducer, reducers, unlisteners); app.replaceModel = replaceModel.bind(app, createReducer, reducers, unlisteners, onError); /** * Create global reducer for redux. * * @returns {Object} */ function createReducer() { return reducerEnhancer((0, _redux.combineReducers)(_objectSpread({}, reducers, extraReducers, app._store ? app._store.asyncReducers : {}))); } } }