├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── index.d.ts ├── index.js ├── package-lock.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test.html -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andy Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hyperapp-redux-devtools 2 | hyperapp HOA (higher order app) to utilize redux-devtools-extension from hyperapp 3 | 4 | ```js 5 | import { h, app } from 'hyperapp'; 6 | import devtools from 'hyperapp-redux-devtools'; 7 | 8 | devtools(app)( 9 | { count: 0 }, 10 | { 11 | increment: () => (state) => Object.assign({}, state, { count: state.count + 1 }) 12 | }, 13 | (state, actions) => { 14 | return ( 15 |
16 | 17 | {state.count} 18 |
19 | ); 20 | }, 21 | document.body 22 | ); 23 | ``` 24 | 25 | ### Dev vs. Prod 26 | 27 | When deploying a Hyperapp with this HOA, it is advised you don't ship the devtools bundle with it: 28 | 29 | #### With Webpack Dynamic Import 30 | 31 | ```js 32 | import { h, app } from 'hyperapp'; 33 | 34 | let main; 35 | 36 | if (process.env.NODE_ENV !== 'production') { 37 | import('hyperapp-redux-devtools') 38 | .then((devtools) => { 39 | main = devtools(app)(...); 40 | }); 41 | } else { 42 | main = app(...); 43 | } 44 | ``` 45 | 46 | #### With Conditional Require (Rollup/Gulp/etc..) 47 | 48 | ```js 49 | import { h, app } from 'hyperapp'; 50 | const devtools = process.env.NODE_ENV !== 'production' 51 | ? require('hyperapp-redux-devtools') 52 | : null; 53 | 54 | let main; 55 | 56 | if (devtools) { 57 | main = devtools(app)(...); 58 | } else { 59 | main = app(...); 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'hyperapp-redux-devtools'; 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var { createStore } = require("redux"); 2 | var { composeWithDevTools } = require("redux-devtools-extension"); 3 | 4 | function reduxReducer(state = {}, action) { 5 | return Object.assign({}, state, action.payload); 6 | } 7 | 8 | function reducAction(name, data) { 9 | return { 10 | type: name, 11 | payload: data 12 | }; 13 | } 14 | 15 | function copy(target, source) { 16 | var obj = {}; 17 | for (var i in target) obj[i] = target[i]; 18 | for (var i in source) obj[i] = source[i]; 19 | return obj; 20 | } 21 | 22 | function set(path, value, source, target) { 23 | if (path.length) { 24 | target[path[0]] = 25 | 1 < path.length ? set(path.slice(1), value, source[path[0]], {}) : value; 26 | return copy(source, target); 27 | } 28 | return value; 29 | } 30 | 31 | function get(path, source) { 32 | for (var i = 0; i < path.length; i++) { 33 | source = source[path[i]]; 34 | } 35 | return source; 36 | } 37 | 38 | module.exports = function devtools(app) { 39 | var composeEnhancers = composeWithDevTools({ action: reducAction }); 40 | var store; 41 | 42 | return function(state, actions, view, container) { 43 | var appActions; 44 | 45 | function wire(path, actions) { 46 | for (var key in actions) { 47 | if (typeof actions[key] === "function") { 48 | (function(key, action) { 49 | actions[key] = function() { 50 | var reducer = action.apply(this, arguments); 51 | return function (slice) { 52 | var data = typeof reducer === "function" 53 | ? reducer(slice, get(path, appActions)) 54 | : reducer; 55 | if (data && !data.then) { 56 | state = set(path, copy(slice, data), state, {}); 57 | store.dispatch(reducAction(key, state)); 58 | } 59 | return data; 60 | }; 61 | }; 62 | })(key, actions[key]); 63 | } else { 64 | wire(path.concat(key), (actions[key] = copy(actions[key]))); 65 | } 66 | } 67 | } 68 | wire([], (actions = copy(actions))); 69 | 70 | actions.replaceState = function(actualState) { 71 | return function (state) { 72 | return actualState; 73 | } 74 | }; 75 | store = createStore(reduxReducer, state, composeEnhancers()); 76 | store.subscribe(function() { 77 | appActions.replaceState(store.getState()); 78 | }); 79 | 80 | appActions = app(state, actions, view, container); 81 | return appActions; 82 | }; 83 | }; 84 | 85 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperapp-redux-devtools", 3 | "version": "1.1.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "js-tokens": { 8 | "version": "3.0.2", 9 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 10 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" 11 | }, 12 | "lodash": { 13 | "version": "4.17.4", 14 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 15 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 16 | }, 17 | "lodash-es": { 18 | "version": "4.17.4", 19 | "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz", 20 | "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=" 21 | }, 22 | "loose-envify": { 23 | "version": "1.3.1", 24 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", 25 | "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", 26 | "requires": { 27 | "js-tokens": "3.0.2" 28 | } 29 | }, 30 | "prettier": { 31 | "version": "1.9.2", 32 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.9.2.tgz", 33 | "integrity": "sha512-piXx9N2WT8hWb7PBbX1glAuJVIkEyUV9F5fMXFINpZ0x3otVOFKKeGmeuiclFJlP/UrgTckyV606VjH2rNK4bw==", 34 | "dev": true 35 | }, 36 | "redux": { 37 | "version": "3.7.2", 38 | "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", 39 | "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", 40 | "requires": { 41 | "lodash": "4.17.4", 42 | "lodash-es": "4.17.4", 43 | "loose-envify": "1.3.1", 44 | "symbol-observable": "1.1.0" 45 | } 46 | }, 47 | "redux-devtools-extension": { 48 | "version": "2.13.2", 49 | "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz", 50 | "integrity": "sha1-4Pmo6N/KfBe+kscSSVijuU6ykR0=" 51 | }, 52 | "symbol-observable": { 53 | "version": "1.1.0", 54 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz", 55 | "integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw==" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperapp-redux-devtools", 3 | "version": "1.1.6", 4 | "description": "hyperapp HOA to utilize redux-devtools-extension for time travel debugging capabilities", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "format": "prettier --write \"./*.js\"" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/andyrj/hyperapp-redux-devtools.git" 13 | }, 14 | "keywords": [ 15 | "hyperapp", 16 | "redux", 17 | "devtools", 18 | "debug", 19 | "time-travel", 20 | "time", 21 | "travel", 22 | "debugging" 23 | ], 24 | "author": "Andy Johnson ", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/andyrj/hyperapp-redux-devtools/issues" 28 | }, 29 | "homepage": "https://github.com/andyrj/hyperapp-redux-devtools#readme", 30 | "dependencies": { 31 | "redux": "^3.7.2", 32 | "redux-devtools-extension": "^2.13.2" 33 | }, 34 | "devDependencies": { 35 | "prettier": "^1.9.2" 36 | }, 37 | "peerDependencies": { 38 | "hyperapp": "^1.0.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | js-tokens@^3.0.0: 6 | version "3.0.1" 7 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" 8 | 9 | lodash-es@^4.2.1: 10 | version "4.17.4" 11 | resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" 12 | 13 | lodash@^4.2.1: 14 | version "4.17.4" 15 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 16 | 17 | loose-envify@^1.1.0: 18 | version "1.3.1" 19 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 20 | dependencies: 21 | js-tokens "^3.0.0" 22 | 23 | prettier@^1.5.2: 24 | version "1.5.2" 25 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.5.2.tgz#7ea0751da27b93bfb6cecfcec509994f52d83bb3" 26 | 27 | redux-devtools-extension@^2.13.2: 28 | version "2.13.2" 29 | resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz#e0f9a8e8dfca7c17be92c7124958a3b94eb2911d" 30 | 31 | redux@^3.7.1: 32 | version "3.7.1" 33 | resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.1.tgz#bfc535c757d3849562ead0af18ac52122cd7268e" 34 | dependencies: 35 | lodash "^4.2.1" 36 | lodash-es "^4.2.1" 37 | loose-envify "^1.1.0" 38 | symbol-observable "^1.0.3" 39 | 40 | symbol-observable@^1.0.3: 41 | version "1.0.4" 42 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" 43 | --------------------------------------------------------------------------------