{"_id":"@ackee/redux-worker","_rev":"6-484863b83f70c2d2462fca039ced006d","name":"@ackee/redux-worker","dist-tags":{"latest":"0.0.1-alpha.2"},"versions":{"0.0.1-alpha.2":{"name":"@ackee/redux-worker","version":"0.0.1-alpha.2","author":{"name":"Jiří Čermák","email":"jiri.cermak@ackee.cz"},"license":"MIT","_id":"@ackee/redux-worker@0.0.1-alpha.2","maintainers":[{"name":"borecekbaji","email":"jakub.baierl@ackee.cz"},{"name":"horaklukas","email":"horaklukas@centrum.cz"},{"name":"ackeecz","email":"ackeedevelopment@gmail.com"}],"homepage":"https://github.com/AckeeCZ/redux-worker#readme","bugs":{"url":"https://github.com/AckeeCZ/redux-worker/issues"},"dist":{"shasum":"e758ce5a8f449769550e2db380cc6ad55331d913","tarball":"https://registry.npmjs.org/@ackee/redux-worker/-/redux-worker-0.0.1-alpha.2.tgz","fileCount":121,"integrity":"sha512-LA+Dq8h/FK5Qchu00CiH5eWxdkLByn0z0DtoP1Cr/loDywatZ4v9ZqQe1REccRWxadoKLDLFMc9dtxq0H3n5wA==","signatures":[{"sig":"MEQCIBq3iqq4a2APvqW9rbAz4uPc8FwnZYpn04g1HAWaXnNWAiAbWhE5K7k6ODGTOS764/RFwSFVw2QMZW9SzO7AoiZyEQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":132127,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcSyUZCRA9TVsSAnZWagAA15YP/R1VQybA1WuNpzLaXfI1\nU5ouasHMb96Tsmp+XKghrOgOKBTlex0O8m6fWK45pNB5zV6pbyh+mgl33s2e\nBPY/JezsOiTnIvQ9xgdBddjYqrQG1MaZJsQVieOukga4ZRusJ/TaJFaX6GgR\nxYHIweWGy+5niRtkL5Bsr9fT73OiT7yXQEj47a6TLAKW1A9omkOAoh+c6mts\nQx96v1+Iv8HNF4YacvQIlUaOTEkLT9/bpSxcy5d5snQtsR6Adek2IUQgrDob\nOhiIYxxp2T6tSvdET/Rh1GUP+RhcR/Mf0JKYh042bs3DffG64FmtgmnZk98I\ngZZ3veEVByF6h0g8QibVL/BBU4XVozxL9TOyY7qwIIls4ZnGpPFIeHwvMwF6\nvAO1b/VBf89ib7uMz7NXpVKroHKz2IPIWhtD204ziHg9HlNul4kU2swVBDvF\npcfFn9eygxg/r+6oUQx2/RdeZOQ2HcblFGhVHLAauM3WKvi6uknPTLJNHa7c\nW7Fqg26jpt1pvY/W/tE7mjyUfMEjjeM/Dbmfpx92S0YYXSthSWsrK8x1EYzQ\n/BbIZ0ULLYmGEzpXJFrLsfhxx+gJ9QnknUguJXvfSZKIPizOcj+9eESy+90V\nmP1k+PtOIlk+WhhRE42LRkPDdhFkszEzJ8ABuRV/ECNWJSKBlL7iirrv9Y5K\nj3Yk\r\n=cfRo\r\n-----END PGP SIGNATURE-----\r\n"},"main":"lib/index.js","husky":{"hooks":{"pre-commit":"lint-staged"}},"module":"es/index.js","gitHead":"9d5a1dd3a75d3f252fa971fb0da6f77b34b14598","scripts":{"lint":"eslint 'src/**/*.{js,jsx}'","build":"yarn run build:es & npm run build:lib","start":"yarn install && yarn run build:es && onchange 'src/**/*.{js,jsx}' -- yarn onChange","prepare":"npm run build","build:es":"rm -rf ./es && cross-env BABEL_ENV=es babel src --out-dir es","onChange":"yarn run build && yalc push","prettier":"prettier --config ./prettier.config.js --write './src/**/*.{js,jsx}'","build:lib":"rm -rf ./lib && cross-env BABEL_ENV=lib babel src --out-dir lib"},"_npmUser":{"name":"ackeecz","email":"ackeedevelopment@gmail.com"},"repository":{"url":"git+https://github.com/AckeeCZ/redux-worker.git","type":"git"},"_npmVersion":"6.5.0","description":"![ackee|redux-worker](https://img.ack.ee/ackee/image/github/js)","directories":{},"lint-staged":{"*.{js,jsx,json,scss,less,css,md}":["prettier --config ./prettier.config.js --write && yarn lint","git add"]},"_nodeVersion":"8.12.0","browserslist":["last 2 version","> 1%","maintained node versions","not dead","IE > 11"],"dependencies":{"redux":"4.x.x","@babel/runtime":"^7.2.0","lodash.isequal":"^4.5.0","react-display-name":"^0.2.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"^1.3.1","react":"^16.7.0","eslint":"^5.12.0","onchange":"^5.2.0","prettier":"^1.15.3","cross-env":"^5.2.0","@babel/cli":"^7.2.3","@babel/core":"^7.2.2","lint-staged":"^8.1.0","babel-eslint":"^10.0.1","@babel/preset-env":"^7.2.3","@babel/preset-react":"^7.0.0","eslint-config-ackee":"^0.9.1","prettier-config-ackee":"0.0.12","eslint-config-prettier":"^3.4.0","@babel/plugin-transform-runtime":"^7.2.0","@babel/plugin-proposal-class-properties":"^7.2.3","@babel/plugin-proposal-object-rest-spread":"^7.2.0","@babel/plugin-proposal-export-namespace-from":"^7.2.0"},"peerDependencies":{"react":"16.x","redux-saga":"0.x.x"},"_npmOperationalInternal":{"tmp":"tmp/redux-worker_0.0.1-alpha.2_1548428569249_0.5315230860076736","host":"s3://npm-registry-packages"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."}},"time":{"created":"2019-01-25T15:02:49.065Z","modified":"2024-09-16T08:07:04.618Z","0.0.1-alpha.2":"2019-01-25T15:02:49.432Z"},"bugs":{"url":"https://github.com/AckeeCZ/redux-worker/issues"},"author":{"name":"Jiří Čermák","email":"jiri.cermak@ackee.cz"},"license":"MIT","homepage":"https://github.com/AckeeCZ/redux-worker#readme","repository":{"url":"git+https://github.com/AckeeCZ/redux-worker.git","type":"git"},"description":"![ackee|redux-worker](https://img.ack.ee/ackee/image/github/js)","maintainers":[{"name":"ackeecz","email":"ackeedevelopment@gmail.com"},{"name":"borecekbaji","email":"jakub.baierl@ackee.cz"},{"name":"davidbilik","email":"david.bilik@ackee.cz"},{"name":"grissius","email":"grissius@gmail.com"},{"name":"hofp37","email":"hoffmann.p37@gmail.com"},{"name":"horaklukas","email":"horaklukas@centrum.cz"},{"name":"pivl","email":"s.pavel66@gmail.com"}],"readme":"![ackee|redux-worker](https://img.ack.ee/ackee/image/github/js)\n\n# [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/AckeeCZ/redux-worker/blob/master/LICENSE) [![CI Status](https://img.shields.io/travis/com/AckeeCZ/redux-worker.svg?style=flat)](https://travis-ci.com/AckeeCZ/redux-worker) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request) [![Dependency Status](https://img.shields.io/david/AckeeCZ/redux-worker.svg?style=flat-square)](https://david-dm.org/AckeeCZ/redux-worker)\n\n# [WIP] redux-worker\n\nReact bindings for Redux, where Redux is placed at Web Worker.\n\n### Main features\n\n-   #### ⚡️ Always responsive UI\n\n    All business logic (reducers, sagas, selectors) is placed at worker thread, so the main thread isn't blocked by those opererations and is freed for UI.\n\n-   #### ⏲ Handling of long-runnning tasks\n\n    If worker thread isn't responding to the main thread for certain amount time, the `TASK_DURATION_TIMEOUT` event is fired. The worker thread can be then terminated or rebooted. **No need for page reload**.\n\n-   #### 🐌 At least limited access to the `window` object in worker context\n    If you need access the window object in worker thread, you can use [`executeInWindow`](#api-worker-executeInWindow) async. method, e.g.:<br>\n    `const innerHeight = await executeInWindow('innerHeight')`;\n\n---\n\n> ### Knowledge requirements\n>\n> You should known [React](https://reactjs.org/) and [Redux](https://redux.js.org/introduction/getting-started). But you don't need to know anything about Web Workers.\n\n---\n\n> ### Current Limitations\n>\n> -   Import files (container selectors in our case) with `require.context` is really easy, but really slow. Particularly, when we need to search for those files also in `node_modules`. This may be solved with a Webpack plugin.\n\n---\n\n## Table of contents\n\n-   [Installing](#installing)\n-   [Core Concepts](#core-concepts)\n-   [Usage](#usage)\n-   API\n    -   [Window context](#api-window)\n        -   [initialize](#api-window-initialize)\n        -   [connectWorker](#api-window-connectWorker)\n    -   [Worker context](#api-worker)\n        -   [configureStoreWorker](#api-worker-confifureStoreWorker)\n        -   [registerSelector](#api-worker-registerSelector)\n        -   [executeInWindow](#api-worker-executeInWindow)\n    -   [Common](#api)\n        -   [uniqueId](#api-uniqueId)\n\n---\n\n## <a name=\"installing\"></a>Installing\n\nUsing yarn:\n\n```bash\n$ yarn add @ackee/redux-worker\n```\n\nUsing npm:\n\n```bash\n$ npm i -S @ackee/redux-worker\n```\n\n---\n\n## <a name=\"core-concepts\"></a>Core Concepts\n\n> TODO\n\n## <a name=\"usage\"></a>Usage\n\n### Implement `redux-worker` to your project\n\n-   Add [`worker-plugin`](https://github.com/GoogleChromeLabs/worker-plugin) to your Webpack configuration.\n\n-   Create filed called `getSelectors.js` with the code below:\n\n    ```js\n    export default function getContainerSelectors() {\n        // import all files that match the regex pattern (e.g. 'Counter.selector.js')\n        // The path must also include node_modules (if any of them uses `connectWorker` HOC)\n\n        // require.context(pathToRoot, deepLookUp, regexPattern)\n        return require.context('../../../', true, /\\.selector\\.js$/);\n    }\n    ```\n\n-   Create file called `configureStore.js` with function that returns the Redux Store:\n\n    ```js\n    import { createStore } from 'redux';\n\n    const rootReducer = (state, action) => state;\n\n    export default function configureStore() {\n        // The simplest Redux store.\n        return createStore(rootReducer);\n    }\n    ```\n\n-   Create file called `Store.worker.js` with the code below:\n\n    ```js\n    import { configureStoreWorker } from '@ackee/redux-worker/worker';\n\n    import configureStore from './createStore';\n    import getSelectors from './getSelectors';\n\n    configureStoreWorker({\n        configureStore,\n        getSelectors,\n    });\n    ```\n\n-   Create file called `configureReduxWorker.js` with the code below:\n\n    ```js\n    import * as ReduxWorker from '@ackee/redux-worker/main';\n\n    const createStoreWorker = () => {\n        // NOTE: Path to the web worker we've created earlier.\n        return new Worker('./Store.worker.js', {\n            type: 'module',\n            name: 'Store.worker', // optional, for easier debugging\n        });\n    };\n\n    ReduxWorker.initialize(createStoreWorker);\n    ```\n\n## Examples\n\n### Connecting to Redux Store with `connectWorker` HOC\n\n1. Create new bridge ID for this container:\n\n    ```js\n    // ---------------------------------------\n    //  modules/counter/constants/index.js\n    // ---------------------------------------\n    import { uniqueId } from '@ackee/redux-worker';\n\n    export const bridgeIds = {\n        COUNTER_BRIDGE: uniqueId('COUNTER_BRIDGE'),\n    };\n    ```\n\n2. Create container component with that ID:\n\n    ```js\n    // ---------------------------------------\n    //  modules/counter/containers/Counter.js\n    // ---------------------------------------\n    import { connectWorker } from '@ackee/redux-worker/main';\n\n    import { bridgeIds } from '../constants';\n    import Counter from '../components/Counter';\n\n    const mapDispatchToProps = dispatch => ({\n        // ...\n    });\n\n    export default connectWorker(bridgeIds.COUNTER_BRIDGE, mapDispatchToProps)(Counter);\n    ```\n\n3. Create special file for `mapStateToProps` and use that ID:\n\n    ```js\n    // ---------------------------------------\n    //  containers/Counter.selector.js\n    // ---------------------------------------\n    import { registerSelector } from '@ackee/redux-worker/worker';\n    import { bridgeIds } from '../constants';\n\n    const mapStateToProps = state => {\n        return {\n            // ...\n        };\n    };\n\n    registerSelector(bridgeIds.COUNTER_BRIDGE, mapStateToProps);\n    ```\n\n### Rebooting unresponding store worker\n\n```js\n// ---------------------------------------\n//  config/redux-worker/index.js\n// ---------------------------------------\nimport * as ReduxWorker from '@ackee/redux-worker/main';\n\nconst createStoreWorker = () => {\n    return new Worker('./Store.worker.js', {\n        type: 'module',\n        name: 'Store.worker',\n    });\n};\n\nReduxWorker.on(ReduxWorker.eventTypes.TASK_DURATION_TIMEOUT, async () => {\n    // worker is terminated, then immediately booted again, new redux store is created\n    await ReduxWorker.storeWorker.reboot();\n});\n\nReduxWorker.initialize(createStoreWorker, {\n    taskDurationWatcher: {\n        enabled: true,\n    },\n});\n```\n\n---\n\n## <a name=\"api-window\"></a>API - Window context\n\n### <a name=\"api-window-initialize\"></a>`async initialize(createStoreWorker, [config]): void`\n\nWhat does it do:\n\n-   Store worker is booted (Redux Store is created).\n-   An configuration object is created and sent to the worker.\n-   The task duration watcher is started.\n-   The window bridge is initialized (see [`executeInWindow`](#api-worker-executeInWindow) section).\n\n#### Parameters\n\n-   `createStoreWorker: Function` - Function that returns new store worker.\n-   `config: Object` - Optional, with following defaults:\n\n    ```js\n    {\n        /*\n            const logLevelEnum = {\n                development: logLevels.INFO,\n                production: logLevels.SILENT,\n                [undefined]: logLevels.ERROR,\n            };\n        */\n        logLevel: logLevelEnum[process.env.NODE],\n\n        taskDurationWatcher: {\n            enabled: process.env.NODE_ENV !== 'development',\n\n            /* If the store worker doesn't report itself\n               in 4s to the main thread, then the worker is considered to be non-responding and the ReduxWorker.eventTypes.TASK_DURATION_TIMEOUT event is fired. */\n            unrespondingTimeout: 1000 * 4, // ms\n\n            /* How often should the store worker report itself to the tasksDurationWatcher module. Note that each report resets the unrespondingTimeout.\n            So reportStatusInPeriod + messageHopDelay <  unrespondingTimeout.\n            */\n            reportStatusInPeriod: 1000 * 3, // ms\n        }\n    }\n    ```\n\n#### Example\n\n```js\n// ...\n\nReduxWorker.initialize(createStoreWorker).then(() => {\n    console.log('Store worker is ready');\n});\n```\n\n#### Notes\n\n-   This method can be called only once, otherwise an error is thrown.\n-   The `connectWorker` HOC can be safely used before this method is called. But since the store worker isn't ready at that moment, nothing will be rendered and all incoming messages to the worker are going to be queued.\n\n---\n\n### <a name=\"api-window-connectWorker\"></a>`connectWorker(bridgeId, mapDispatchToProps?, ownPropsSelector?): (ConnectedComponent, Loader?): React.Component`\n\nWhat does it do:\n\n-   It connects to Redux store which is placed at a Web Worker. This happens on `componentDidMount`.\n-   It disconnects from Redux store on `componentWillUnmount`.\n\n#### Parameters\n\n-   `bridgeId: String` - An unique ID among other instances of `connectWorker`. See helper utility [`uniqueId`](#api-uniqueId)\n-   `mapDispatchToProps: Function|Object`\n    -   `Function`: 1st argument is dispatch method that send Redux actions to the store worker. 2nd argument is `ownProps` object which is returned from `ownPropSelector`.\n    -   `Object`: Properties are Redux action creators.\n-   `ownPropsSelector: Function` - Function that receives all component props and returns props that are only required in the `mapDispatchToProps` and `mapStateToProps` (e.g. `userId`).\n\n### Returns\n\nA React component wrapped by `connectWorker` HOC.\n\n#### Example\n\n```js\n// --------------------\n// Foo.js (main thread context)\n// --------------------\nimport { connectWorker } from '@ackee/redux-worker/main';\nimport Foo from '../components/Foo';\n\nconst mapDispatchToProps = (dispatch, selectedOwnProps) => ({\n    // ...\n});\n\nconst ownPropSelector = componentProps => ({\n    // ...\n});\n\n// The mapStateToProps selector is placed at `Foo.selector.js` file\nexport default connectWorker('FOO_BRIDGE', mapDispatchToProps, ownPropsSelector)(Foo);\n```\n\n```js\n// --------------------\n// Foo.selector.js (worker context)\n// --------------------\nimport { registerSelector } from '@ackee/redux-worker/worker';\n\nconst mapStateToProps = (state, selectedOwnProps) => ({\n    // ...\n});\n\nregisterSelector('FOO_BRIDGE', mapStateToProps);\n```\n\n## API - Worker context\n\n### <a name=\"api-worker-registerSelector\"></a>`registerSelector(bridgeId: String, mapStateToProps: Function): void`\n\nAdd a container selector to global selectors register.\n\n```js\nimport { registerSelector } from '@ackee/redux-worker';\n\nconst mapStateToProps = state => ({\n    // ...\n});\n\nregisterSelector('BRIDGE_ID', mapStateToProps);\n```\n\n### <a name=\"api-worker-executeInWindow\"></a>`async executeInWindow(pathToProperty: String, args:Array?): any`\n\n```js\nimport { executeInWindow } from '@ackee/redux-worker/worker';\n\nasync function accessWindowObjectInWorker() {\n    const innerWidth = await executeInWindow('innerWidth');\n    console.log(innerWidth);\n}\n\nasync function goBack() {\n    await executeInWindow('history.back');\n}\n\nasync function storeToSessionStorage() {\n    await executeInWindow('sessionStorage.setItem', ['message', 'hello world']);\n\n    const message = await executeInWindow('sessionStorage.getItem', ['message']);\n    console.log(message); // > 'hello world'\n}\n```\n\n## API - shared context\n\n### <a name=\"api-uniqueId\"></a>`unqiueId(prefix?): String`\n\nGet unique string ID, optionally with custom prefix. The uniqueness is guaranteed under the same context.\n\n> The purpose of this utility is to generate bridge IDs for `connectWorker` HOC and `registerSelector` method.\n\n#### Example\n\n```js\nimport { uniqueId } from '@ackee/redux-worker';\n\nuniqueId(); // > 'rs'\nuniqueId('COUNTER_BRIDGE'); // > 'COUNTER_BRIDGE_rt'\nuniqueId('COUNTER_BRIDGE'); // > 'COUNTER_BRIDGE_ru'\n```\n","readmeFilename":"README.md"}