UNPKG

ducks

Version:

🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.

232 lines 8.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Ducks = void 0; /** * Ducks - https://github.com/huan/ducks * * @copyright 2020 Huan LI (李卓桓) <https://github.com/huan> * * 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. * */ const redux_1 = require("redux"); const redux_observable_1 = require("redux-observable"); const config_js_1 = require("../config.js"); const bundle_js_1 = require("../bundle.js"); const combine_duckery_js_1 = require("./combine-duckery.js"); const insert_reducers_js_1 = require("./insert-reducers.js"); const noop_reducer_js_1 = require("./noop-reducer.js"); class Ducks { /** * Construct a `Ducks` manager for managing the Duck(s) * * @param duckery is a `DucksMapObject` which: * 1. key is the reducer key (namespace) * 2. value is a `Duck` instance */ constructor(duckery) { this.duckery = duckery; if (Object.keys(duckery).length <= 0) { throw new Error('You need to provide at least one duck for the duckery'); } this.asyncMiddlewares = {}; const ducksNest = {}; for (const [ns, duck] of Object.entries(duckery)) { ducksNest[ns] = new bundle_js_1.Bundle(duck); /** * Huan(202006): Binding the Ducks to Duck, * so that the Duck can use other Duck modules (if needed) */ if (duck.setDucks) { duck.setDucks(this); } } this.ducksNest = ducksNest; } get store() { return this._store; } get reducer() { return (0, combine_duckery_js_1.combineDuckery)(this.duckery); } get middlewares() { const middlewareList = Object.values(this.duckery) .map(duck => duck.middlewares) .filter(Boolean) .map(middlewares => Object.values(middlewares)) .flat(); return middlewareList; } ducksify(nsOrDuck) { if (!nsOrDuck) { return this.ducksNest; } if (typeof nsOrDuck === 'string') { if (nsOrDuck in this.duckery) { return this.ducksNest[nsOrDuck]; } throw new Error('Ducks can not found the Duck for the namespace: ' + nsOrDuck); } if (typeof nsOrDuck === 'object') { const namespaceList = Object.keys(this.duckery) .filter(ns => this.duckery[ns] === nsOrDuck); if (namespaceList.length <= 0) { throw new Error('Duck not found: ' + nsOrDuck); } const namespace = namespaceList[0]; return this.ducksify(namespace); } throw new Error('unknown param: ' + nsOrDuck); } enhancer() { if (!this.asyncMiddlewares.epicMiddleware && this.getRootEpic()) { this.asyncMiddlewares.epicMiddleware = (0, redux_observable_1.createEpicMiddleware)(); } if (!this.asyncMiddlewares.sagaMiddleware && this.getRootSaga()) { /** * Huan(202109): disable saga * See: https://github.com/huan/ducks/issues/4 */ // this.asyncMiddlewares.sagaMiddleware = require('redux-saga').default() throw new Error('saga is disabled. See: https://github.com/huan/ducks/issues/4'); } const asyncMiddlewareList = Object.values(this.asyncMiddlewares).filter(Boolean); return (0, redux_1.compose)( /** * Huan(202005): * the `this.storeEnhancer()` should be put before applyMiddleware * (to initiate asyncMiddlewares before storeEnhancer) */ this.duckeryEnhancer(), (0, redux_1.applyMiddleware)(...asyncMiddlewareList, ...this.middlewares)); } /** * 1. Add Ducks Reducers to Store * 2. Bind Store to Ducks */ duckeryEnhancer() { const enhancer = next => (reducer, preloadedState) => { const newReducer = (0, insert_reducers_js_1.insertReducers)(reducer, { [config_js_1.DUCKS_NAMESPACE]: this.reducer, // Huan(202005) FIXME: any ? }); // FIXME: any const store = next(newReducer, preloadedState); this.initializeDucks(store); return store; }; return enhancer; } /** * A convenience way to initialize your store with Ducks with default settings. * * `ducks.configureStore()` only supports creating a store with Ducks. * * If you want to create a store that with other `reducer` and `enhances` (or `middlewares`), * please use `createStore()` from `redux` module instead of this one. * * @param preloadedState */ configureStore(preloadedState) { if (this._store) { throw new Error('Ducks can be only configureStore() for once! If you need another store, you can create another Ducks to fullfil your needs.'); } const store = (0, redux_1.createStore)(noop_reducer_js_1.noopReducer, preloadedState, this.enhancer()); return store; } /** * Initialize ducks */ getRootEpic() { const epics = Object.values(this.duckery) .map(duck => duck.epics) .filter(Boolean) .map(epics => Object.values(epics)) .flat(); if (epics.length <= 0) { return undefined; } /** * Load Epics Combinator * * We are using `require` at here because we will only load `redux-observable` module when we need it */ return (0, redux_observable_1.combineEpics)(...epics); } getRootSaga() { const sagas = Object.values(this.duckery) .map(duck => duck.sagas) .filter(Boolean) .map(sagas => Object.values(sagas)) .flat(); if (sagas.length <= 0) { return undefined; } /** * Load Saga Effects * * We are using `require` at here because we will only load `redux-saga` module when we need it */ /** * Huan(202109): disable saga * See: https://github.com/huan/ducks/issues/4 */ // const effects = require('redux-saga/effects') // return function * rootSaga () { // yield effects.all( // sagas.map( // saga => saga() // ) // ) // } as Saga throw new Error('Saga is disabled. See: https://github.com/huan/ducks/issues/4'); } initializeDucks(store) { if (this._store) { throw new Error('store has already initialized'); } this._store = store; /** * Configure Duck */ Object.keys(this.duckery).forEach(namespace => { // console.info('initializeDucks() namespace', namespace) // console.info('initializeDucks() state', this.store.getState()) this.ducksNest[namespace].setStore(store); this.ducksNest[namespace].setNamespaces(config_js_1.DUCKS_NAMESPACE, namespace); }); /** * Run Epic */ const rootEpic = this.getRootEpic(); if (rootEpic) { const epicMiddleware = this.asyncMiddlewares.epicMiddleware; if (!epicMiddleware) { throw new Error('epicMiddleware is required but not found in the this.asyncMiddlewares.'); } epicMiddleware.run(rootEpic); } /** * Run Saga */ const rootSaga = this.getRootSaga(); if (rootSaga) { const sagaMiddleware = this.asyncMiddlewares.sagaMiddleware; if (!sagaMiddleware) { throw new Error('sagaMiddleware is required but not found in the this.asyncMiddlewares.'); } sagaMiddleware.run(rootSaga); } } } exports.Ducks = Ducks; Ducks.VERSION = config_js_1.VERSION; //# sourceMappingURL=ducks.js.map