├── .babelrc
├── .eslintrc
├── .gitignore
├── .npmignore
├── .npmrc
├── CHANGELOG.md
├── DEV_ONLY
├── App.js
├── index.js
└── store.js
├── LICENSE
├── README.md
├── package.json
├── src
├── actions
│ ├── index.js
│ ├── localActions.js
│ └── sessionActions.js
├── constants.js
├── index.js
├── reducers
│ ├── index.js
│ ├── localReducer.js
│ └── sessionReducer.js
└── utils.js
├── test
├── actions
│ ├── index.js
│ ├── localActions.js
│ └── sessionActions.js
├── helpers
│ └── setup-browser-env.js
├── index.js
├── reducers
│ ├── index.js
│ ├── localReducer.js
│ └── sessionReducer.js
└── utils.js
├── webpack
├── webpack.config.dev.js
├── webpack.config.js
└── webpack.config.minified.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "lib": {
4 | "presets": [
5 | [
6 | "@babel/preset-env",
7 | {
8 | "loose": true
9 | }
10 | ]
11 | ]
12 | },
13 | "test": {
14 | "presets": [
15 | [
16 | "@babel/preset-env",
17 | {
18 | "loose": true
19 | }
20 | ]
21 | ]
22 | }
23 | },
24 | "presets": [
25 | [
26 | "@babel/preset-env",
27 | {
28 | "loose": true,
29 | "modules": false
30 | }
31 | ]
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["rapid7/browser", "rapid7/react"],
3 | "parser": "babel-eslint",
4 | "rules": {}
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .nyc_output
3 | coverage
4 | lib
5 | dist
6 | es
7 | node_modules
8 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .git
2 | .idea
3 | .nyc_output
4 | DEV_ONLY
5 | node_modules
6 | src
7 | test
8 | webpack
9 | .babelrc
10 | .eslintrc
11 | .gitignore
12 | .npmignore
13 | webpack.config.js
14 | webpack.config.minified.js
15 | webpack.config.dev.js
16 | yarn.lock
17 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | scripts-prepend-node-path=true
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # redux-browser-storage CHANGELOG
2 |
3 | ## 1.1.0
4 |
5 | - Activate tree-shaking with `module` build
6 | - Replace `kari` with `unchanged`
7 | - Fix security issue with old version of `webpack-dev-server`
8 |
9 | ## 1.0.1
10 |
11 | - Update `kari` version to fix issue
12 |
13 | ## 1.0.0
14 |
15 | - Initial release
16 |
--------------------------------------------------------------------------------
/DEV_ONLY/App.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import PropTypes from 'prop-types';
3 | import React, {PureComponent} from 'react';
4 | import {connect} from 'react-redux';
5 |
6 | // actions
7 | import {
8 | localActions,
9 | sessionActions,
10 | } from '../src';
11 |
12 | const createOnClickClearValues = (instance, type) => () => {
13 | const {clearLocalValues, clearSessionValues} = instance.props;
14 |
15 | const action = type === 'local' ? clearLocalValues : clearSessionValues;
16 |
17 | action();
18 | };
19 |
20 | const createOnClickDeleteValue = (instance, type) => (event) => {
21 | const {deleteLocalValues, deleteSessionValues} = instance.props;
22 |
23 | const key = event.currentTarget.dataset.key;
24 | const action = type === 'local' ? deleteLocalValues : deleteSessionValues;
25 |
26 | action(key);
27 | };
28 |
29 | const createOnClickSetValue = (instance, type) => () => {
30 | const {setLocalValues, setSessionValues} = instance.props;
31 |
32 | const keyElement = instance[`${type}KeyElement`];
33 | const valueElement = instance[`${type}ValueElement`];
34 | const action = type === 'local' ? setLocalValues : setSessionValues;
35 |
36 | action({
37 | [keyElement.value]: valueElement.value,
38 | });
39 |
40 | keyElement.value = '';
41 | valueElement.value = '';
42 |
43 | keyElement.focus();
44 | };
45 |
46 | const createSetRef = (instance, name) => (element) => {
47 | instance[name] = element;
48 | };
49 |
50 | const DELETE_BUTTON_STYLE = {
51 | marginLeft: 5,
52 | };
53 |
54 | const SECTION_CONTAINER_STYLE = {
55 | display: 'inline-block',
56 | verticalAlign: 'top',
57 | width: '50%',
58 | };
59 |
60 | const SPACING_STYLE = {
61 | marginTop: 15,
62 | };
63 |
64 | class App extends PureComponent {
65 | static propTypes = {
66 | local: PropTypes.object.isRequired,
67 | session: PropTypes.object.isRequired,
68 | };
69 |
70 | // instance values
71 | localKeyElement = null;
72 | localValueElement = null;
73 | sessionKeyElement = null;
74 | sessionValueElement = null;
75 |
76 | // instance methods
77 | onClickClearLocalValues = createOnClickClearValues(this, 'local');
78 | onClickClearSessionValues = createOnClickClearValues(this, 'session');
79 | onClickDeleteValueInLocal = createOnClickDeleteValue(this, 'local');
80 | onClickDeleteValueInSession = createOnClickDeleteValue(this, 'session');
81 | onClickSetValueInLocal = createOnClickSetValue(this, 'local');
82 | onClickSetValueInSession = createOnClickSetValue(this, 'session');
83 | setLocalKeyElementRef = createSetRef(this, 'localKeyElement');
84 | setLocalValueElementRef = createSetRef(this, 'localValueElement');
85 | setSessionKeyElementRef = createSetRef(this, 'sessionKeyElement');
86 | setSessionValueElementRef = createSetRef(this, 'sessionValueElement');
87 |
88 | render() {
89 | const {local, session} = this.props;
90 |
91 | return (
92 |
93 |
App
94 |
95 |
96 |
102 |
103 |
109 |
110 |
111 |
112 |
Set in local
113 |
114 |
115 |
119 |
120 |
121 |
122 |
126 |
127 |
128 |
129 |
135 |
136 |
137 |
138 | {Object.keys(local).map((key) => (
139 |
140 | {key}: {JSON.stringify(local[key])}
141 |
149 |
150 | ))}
151 |
152 |
153 |
154 |
155 |
Set in session
156 |
157 |
158 |
162 |
163 |
164 |
165 |
169 |
170 |
171 |
172 |
178 |
179 |
180 |
181 | {Object.keys(session).map((key) => (
182 |
183 | {key}: {JSON.stringify(session[key])}
184 |
192 |
193 | ))}
194 |
195 |
196 |
197 | );
198 | }
199 | }
200 |
201 | const mapStateToProps = ({local, session}) => {
202 | console.log('local', local);
203 | console.log('session', session);
204 |
205 | return {
206 | local,
207 | session,
208 | };
209 | };
210 |
211 | const mapDispatchToProps = {
212 | ...localActions,
213 | ...sessionActions,
214 | };
215 |
216 | export default connect(
217 | mapStateToProps,
218 | mapDispatchToProps
219 | )(App);
220 |
--------------------------------------------------------------------------------
/DEV_ONLY/index.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import React from 'react';
3 | import {render} from 'react-dom';
4 | import {Provider} from 'react-redux';
5 |
6 | // app
7 | import App from './App';
8 |
9 | // store
10 | import store from './store';
11 |
12 | const div = document.createElement('div');
13 |
14 | render(
15 |
16 |
17 | ,
18 | div
19 | );
20 |
21 | document.body.appendChild(div);
22 |
--------------------------------------------------------------------------------
/DEV_ONLY/store.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import {
3 | combineReducers,
4 | createStore,
5 | } from 'redux';
6 |
7 | // reducers
8 | import {
9 | localReducer,
10 | sessionReducer,
11 | } from '../src';
12 |
13 | const reducers = combineReducers({
14 | local: localReducer,
15 | session: sessionReducer,
16 | });
17 |
18 | export default createStore(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Tony Quetano
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 | # redux-browser-storage
2 |
3 | Use redux to manage specific data saved in either localStorage or sessionStorage
4 |
5 | ## Table of contents
6 | * [Installation](#installation)
7 | * [Usage](#usage)
8 | * [API](#api)
9 | * [localActions](#localactions)
10 | * [clearLocalValues](#clearlocalvalues)
11 | * [deleteLocalValues](#deletelocalvalues)
12 | * [setLocalValues](#setlocalvalues)
13 | * [sessionActions](#sessionactions)
14 | * [clearSessionValues](#clearsessionvalues)
15 | * [deleteSessionValues](#deletesessionvalues)
16 | * [setSessionValues](#setsessionvalues)
17 | * [localReducer](#localreducer)
18 | * [sessionReducer](#sessionreducer)
19 | * [Development](#development)
20 |
21 | ## Installation
22 |
23 | ```
24 | $ npm i redux-browser-storage --save
25 | ```
26 |
27 | ## Usage
28 |
29 | Include the storage type(s) you want into your standard store creation, assigning to any name you would like.
30 |
31 | ```javascript
32 | import {
33 | combineReducers,
34 | createStore
35 | } from 'redux';
36 | import {
37 | localReducer
38 | } from 'redux-browser-storage';
39 |
40 | const reducers = combineReducers({
41 | ...otherReducers,
42 | local: localReducer // or whatever key you want
43 | });
44 |
45 | export default createStore(reducers);
46 | ```
47 |
48 | Connect your component to redux, and when you want to update the values use the provided redux actions.
49 |
50 | ```javascript
51 | import React, {
52 | PureComponent
53 | } from 'react';
54 | import {
55 | localActions
56 | } from 'redux-browser-storage';
57 | import {
58 | connect
59 | } from 'redux-react';
60 |
61 | const mapStateToProps = ({local}) => {
62 | return {
63 | local
64 | };
65 | };
66 |
67 | const mapDispatchToProps = {
68 | ...localActions
69 | };
70 |
71 | @connect(mapStateToProps, mapDispatchToProps)
72 | class App extends PureComponent {
73 | onClickButton = () => {
74 | this.props.setLocalValues({
75 | count: this.props.local.count + 1
76 | });
77 | };
78 |
79 | render() {
80 | return (
81 |
87 | )
88 | }
89 | }
90 | ```
91 |
92 | All data values in your reducer are automatically synced to their respective browser storage, and the reducer's initial state is based off of existing values in that storage, so all saved values are automatically rehydrated on page load.
93 |
94 | ## API
95 |
96 | ### localActions
97 |
98 | #### clearLocalValues
99 |
100 | `clearLocalValues()`
101 |
102 | Clears the values in `localStorage` that were stored via `redux-browser-storage`.
103 |
104 | ```javascript
105 | onClickClear = () => {
106 | this.props.clearLocalValues();
107 | };
108 | ```
109 |
110 | #### deleteLocalValues
111 |
112 | `deleteLocalValues(keys: (Array|string))`
113 |
114 | Deletes the value(s) at the location of `keys` in `localStorage`. Nested values are allowed by use of dot or bracket notation.
115 |
116 | ```javascript
117 | // standard
118 | deleteLocalValues('foo');
119 |
120 | // Nested
121 | deleteLocalValues('foo.bar[0].baz');
122 |
123 | // multiple
124 | deleteLocalValues(['foo', 'bar[0].baz']);
125 | ```
126 |
127 | #### setLocalValues
128 |
129 | `setLocalValues(values: Object)`
130 |
131 | Sets the value(s) in `localStorage` based on the keys of the object passed. Nested values are allowed by use of dot or bracket notation.
132 |
133 | ```javascript
134 | // standard
135 | setLocalValues({
136 | foo: 'bar'
137 | });
138 |
139 | // Nested
140 | setLocalValues({
141 | 'foo.bar[0]': 'baz'
142 | });
143 |
144 | // multiple
145 | setLocalvalues({
146 | foo: 'bar',
147 | 'bar[0]': 'baz'
148 | });
149 | ```
150 |
151 | ### sessionActions
152 |
153 | #### clearSessionValues
154 |
155 | `clearSessionValues()`
156 |
157 | Clears the values in `sessionStorage` that were stored via `redux-browser-storage`.
158 |
159 | ```javascript
160 | clearSessionValues();
161 | ```
162 |
163 | #### deleteSessionValues
164 |
165 | `deleteSessionValues(keys: (Array|string))`
166 |
167 | Deletes the value(s) at the location of `keys` in `sessionStorage`. Nested values are allowed by use of dot or bracket notation.
168 |
169 | ```javascript
170 | // standard
171 | deleteSessionValues('foo');
172 |
173 | // Nested
174 | deleteSessionValues('foo.bar[0].baz');
175 |
176 | // multiple
177 | deleteSessionValues(['foo', 'bar[0].baz']);
178 | ```
179 |
180 | #### setSessionValues
181 |
182 | `setSessionValues(values: Object)`
183 |
184 | Sets the value(s) in `sessionStorage` based on the keys of the object passed. Nested values are allowed by use of dot or bracket notation.
185 |
186 | ```javascript
187 | // standard
188 | setSessionValues({
189 | foo: 'bar'
190 | });
191 |
192 | // Nested
193 | setSessionValues({
194 | 'foo.bar[0]': 'baz'
195 | });
196 |
197 | // multiple
198 | setSessionValues({
199 | foo: 'bar',
200 | 'bar[0]': 'baz'
201 | });
202 | ```
203 |
204 | ### localReducer
205 |
206 | Handles storage of items in `localStorage`. This can be assigned to any key you'd like when using `combineReducers`, it is not prescriptive.
207 |
208 | ```javascript
209 | combineReducers({
210 | permanentCache: localReducer
211 | });
212 | ```
213 |
214 | ### sessionReducer
215 |
216 | Handles storage of items in `sessionStorage`. This can be assigned to any key you'd like when using `combineReducers`, it is not prescriptive.
217 |
218 | ```javascript
219 | combineReducers({
220 | temporaryCache: sessionReducer
221 | });
222 | ```
223 |
224 | ## Development
225 |
226 | Standard stuff, clone the repo and `npm i` to get the dependencies. npm scripts available:
227 | * `build` => builds the distributed JS with `NODE_ENV=development` and with sourcemaps
228 | * `build:minified` => builds the distributed JS with `NODE_ENV=production` and minified
229 | * `clean` => removes `lib` and `dist` folders
230 | * `dev` => runs the webpack dev server for the playground
231 | * `lint` => runs ESLint against files in the `src` folder
232 | * `lint:fix` => runs ESLint against files in the `src` folder and fixes any fixable issues discovered
233 | * `prepublish` => if in publish, runs `prepublish:compile`
234 | * `prepublish:compile` => runs the `lint`, `test:coverage`, `clean`, `transpile`, `build`, and `build:minified` scripts
235 | * `test` => run `ava` with NODE_ENV=test
236 | * `test:coverage` => run `ava` with `nyc` to calculate code coverage
237 | * `test:watch` => runs `test` but with persistent watcher
238 | * `transpile` => runs Babel against files in `src` to files in `lib`
239 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "tony.quetano@planttheidea.com",
3 | "ava": {
4 | "failFast": true,
5 | "files": [
6 | "test/**/*.js"
7 | ],
8 | "require": [
9 | "@babel/register",
10 | "test/helpers/setup-browser-env.js"
11 | ],
12 | "sources": [
13 | "src/**/*.js"
14 | ],
15 | "verbose": true
16 | },
17 | "bugs": {
18 | "url": "https://github.com/planttheidea/redux-browser-storage/issues"
19 | },
20 | "dependencies": {
21 | "namespace-constants": "^0.5.0",
22 | "redux-actions": "^2.0.3",
23 | "unchanged": "^1.5.2"
24 | },
25 | "description": "Use redux to manage localStorage and sessionStorage data",
26 | "devDependencies": {
27 | "@babel/cli": "^7.0.0",
28 | "@babel/core": "^7.0.0",
29 | "@babel/plugin-proposal-class-properties": "^7.0.0",
30 | "@babel/plugin-proposal-decorators": "^7.0.0",
31 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
32 | "@babel/plugin-proposal-function-sent": "^7.0.0",
33 | "@babel/plugin-proposal-json-strings": "^7.0.0",
34 | "@babel/plugin-proposal-numeric-separator": "^7.0.0",
35 | "@babel/plugin-proposal-throw-expressions": "^7.0.0",
36 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
37 | "@babel/plugin-syntax-import-meta": "^7.0.0",
38 | "@babel/preset-env": "^7.0.0",
39 | "@babel/preset-react": "^7.0.0",
40 | "@babel/register": "^7.0.0",
41 | "ava": "^1.0.1",
42 | "babel-eslint": "^10.0.1",
43 | "babel-loader": "^8.0.0",
44 | "browser-env": "^3.2.5",
45 | "eslint": "^5.12.0",
46 | "eslint-config-rapid7": "^3.1.0",
47 | "eslint-friendly-formatter": "^4.0.1",
48 | "eslint-loader": "^2.1.1",
49 | "html-webpack-plugin": "^3.2.0",
50 | "in-publish": "^2.0.0",
51 | "ink-docstrap": "^1.3.0",
52 | "jsdoc": "^3.4.3",
53 | "jsdoc-babel": "^0.5.0",
54 | "lodash": "^4.17.11",
55 | "nyc": "^13.1.0",
56 | "optimize-js-plugin": "^0.0.4",
57 | "prop-types": "^15.5.10",
58 | "react": "^16.7.0",
59 | "react-dom": "^16.7.0",
60 | "react-redux": "^6.0.0",
61 | "redux": "^3.6.0",
62 | "rimraf": "^2.6.1",
63 | "sinon": "^7.2.2",
64 | "webpack": "^4.28.3",
65 | "webpack-cli": "^3.2.0",
66 | "webpack-dev-server": "^3.1.14"
67 | },
68 | "homepage": "https://github.com/planttheidea/redux-browser-storage#readme",
69 | "keywords": [
70 | "redux",
71 | "localStorage",
72 | "sessionStorage"
73 | ],
74 | "license": "MIT",
75 | "main": "lib/index.js",
76 | "module": "es/index.js",
77 | "name": "redux-browser-storage",
78 | "peerDependencies": {
79 | "redux": "^3.6.0"
80 | },
81 | "repository": {
82 | "type": "git",
83 | "url": "git+https://github.com/planttheidea/redux-browser-storage.git"
84 | },
85 | "scripts": {
86 | "build": "NODE_ENV=development webpack --progress --colors --config=webpack/webpack.config.js",
87 | "build:minified": "NODE_ENV=production webpack --progress --colors --config=webpack/webpack.config.minified.js",
88 | "clean": "rimraf lib && rimraf es && rimraf dist",
89 | "dev": "NODE_ENV=development webpack-dev-server --progress --config=webpack/webpack.config.dev.js",
90 | "lint": "NODE_ENV=test eslint src",
91 | "lint:fix": "NODE_ENV=test eslint src --fix",
92 | "prepublish": "in-publish && npm run prepublish:compile || echo",
93 | "prepublish:compile": "npm run lint && npm run test:coverage && npm run clean && npm run transpile:lib && npm run transpile:es && npm run build && npm run build:minified",
94 | "start": "npm run dev",
95 | "test": "NODE_PATH=. NODE_ENV=test ava",
96 | "test:coverage": "nyc npm test",
97 | "test:watch": "NODE_PATH=. NODE_ENV=test ava --watch",
98 | "transpile:es": "BABEL_ENV=es babel src --out-dir es",
99 | "transpile:lib": "BABEL_ENV=lib babel src --out-dir lib"
100 | },
101 | "version": "1.1.0"
102 | }
103 |
--------------------------------------------------------------------------------
/src/actions/index.js:
--------------------------------------------------------------------------------
1 | // actions
2 | import {
3 | clearLocalValues,
4 | deleteLocalValues,
5 | setLocalValues,
6 | } from './localActions';
7 | import {
8 | clearSessionValues,
9 | deleteSessionValues,
10 | setSessionValues,
11 | } from './sessionActions';
12 |
13 | export {clearLocalValues};
14 | export {deleteLocalValues};
15 | export {setLocalValues};
16 |
17 | const localActions = {
18 | clearLocalValues,
19 | deleteLocalValues,
20 | setLocalValues,
21 | };
22 |
23 | export {localActions};
24 |
25 | export {clearSessionValues};
26 | export {deleteSessionValues};
27 | export {setSessionValues};
28 |
29 | const sessionActions = {
30 | clearSessionValues,
31 | deleteSessionValues,
32 | setSessionValues,
33 | };
34 |
35 | export {sessionActions};
36 |
37 | export default {
38 | localActions,
39 | sessionActions,
40 | };
41 |
--------------------------------------------------------------------------------
/src/actions/localActions.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import createConstants from 'namespace-constants';
3 | import createAction from 'redux-actions/lib/createAction';
4 |
5 | // constants
6 | import {LOCAL_STORAGE_KEY} from '../constants';
7 |
8 | export const ACTION_TYPES = createConstants(LOCAL_STORAGE_KEY, [
9 | 'CLEAR_LOCAL_VALUES',
10 | 'DELETE_LOCAL_VALUES',
11 | 'SET_LOCAL_VALUES',
12 | ]);
13 |
14 | export const clearLocalValues = createAction(ACTION_TYPES.CLEAR_LOCAL_VALUES);
15 | export const deleteLocalValues = createAction(ACTION_TYPES.DELETE_LOCAL_VALUES);
16 | export const setLocalValues = createAction(ACTION_TYPES.SET_LOCAL_VALUES);
17 |
--------------------------------------------------------------------------------
/src/actions/sessionActions.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import createConstants from 'namespace-constants';
3 | import createAction from 'redux-actions/lib/createAction';
4 |
5 | // constants
6 | import {SESSION_STORAGE_KEY} from '../constants';
7 |
8 | export const ACTION_TYPES = createConstants(SESSION_STORAGE_KEY, [
9 | 'CLEAR_SESSION_VALUES',
10 | 'DELETE_SESSION_VALUES',
11 | 'SET_SESSION_VALUES',
12 | ]);
13 |
14 | export const clearSessionValues = createAction(ACTION_TYPES.CLEAR_SESSION_VALUES);
15 | export const deleteSessionValues = createAction(ACTION_TYPES.DELETE_SESSION_VALUES);
16 | export const setSessionValues = createAction(ACTION_TYPES.SET_SESSION_VALUES);
17 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @constant {string} LOCAL_STORAGE_KEY
3 | * @default
4 | */
5 | export const LOCAL_STORAGE_KEY = 'REDUX_BROWSER_STORAGE:LOCAL';
6 |
7 | /**
8 | * @constant {string} SESSION_STORAGE_KEY
9 | * @default
10 | */
11 | export const SESSION_STORAGE_KEY = 'REDUX_BROWSER_STORAGE:SESSION';
12 |
13 | /**
14 | * @constant {string} LOCAL_STORAGE_TYPE
15 | * @default
16 | */
17 | export const LOCAL_STORAGE_TYPE = 'localStorage';
18 |
19 | /**
20 | * @constant {string} SESSION_STORAGE_TYPE
21 | * @default
22 | */
23 | export const SESSION_STORAGE_TYPE = 'sessionStorage';
24 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // actions
2 | import {
3 | clearLocalValues,
4 | clearSessionValues,
5 | deleteLocalValues,
6 | deleteSessionValues,
7 | localActions,
8 | sessionActions,
9 | setLocalValues,
10 | setSessionValues,
11 | } from './actions';
12 |
13 | // reducers
14 | import {
15 | localReducer,
16 | sessionReducer,
17 | } from './reducers';
18 |
19 | export {clearLocalValues};
20 | export {clearSessionValues};
21 | export {deleteLocalValues};
22 | export {deleteSessionValues};
23 | export {setLocalValues};
24 | export {setSessionValues};
25 |
26 | export {localActions};
27 | export {sessionActions};
28 |
29 | export {localReducer};
30 | export {sessionReducer};
31 |
32 | export default {
33 | clearLocalValues,
34 | clearSessionValues,
35 | deleteLocalValues,
36 | deleteSessionValues,
37 | localActions,
38 | localReducer,
39 | sessionActions,
40 | sessionReducer,
41 | setLocalValues,
42 | setSessionValues,
43 | };
44 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | // reducers
2 | import localReducer from './localReducer';
3 | import sessionReducer from './sessionReducer';
4 |
5 | export {localReducer};
6 | export {sessionReducer};
7 |
8 | export default {
9 | localReducer,
10 | sessionReducer,
11 | };
12 |
--------------------------------------------------------------------------------
/src/reducers/localReducer.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import handleActions from 'redux-actions/lib/handleActions';
3 |
4 | // actions
5 | import {ACTION_TYPES} from '../actions/localActions';
6 |
7 | // constants
8 | import {
9 | LOCAL_STORAGE_KEY,
10 | LOCAL_STORAGE_TYPE,
11 | } from '../constants';
12 |
13 | // utils
14 | import {
15 | createHandleClearValues,
16 | createHandleDeleteValues,
17 | createHandleSetValues,
18 | getLocalStorage,
19 | } from '../utils';
20 |
21 | export const INITIAL_STATE = getLocalStorage();
22 |
23 | export default handleActions(
24 | {
25 | [ACTION_TYPES.CLEAR_LOCAL_VALUES]: createHandleClearValues(LOCAL_STORAGE_KEY, LOCAL_STORAGE_TYPE),
26 | [ACTION_TYPES.DELETE_LOCAL_VALUES]: createHandleDeleteValues(LOCAL_STORAGE_KEY, LOCAL_STORAGE_TYPE),
27 | [ACTION_TYPES.SET_LOCAL_VALUES]: createHandleSetValues(LOCAL_STORAGE_KEY, LOCAL_STORAGE_TYPE),
28 | },
29 | INITIAL_STATE
30 | );
31 |
--------------------------------------------------------------------------------
/src/reducers/sessionReducer.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import handleActions from 'redux-actions/lib/handleActions';
3 |
4 | // actions
5 | import {ACTION_TYPES} from '../actions/sessionActions';
6 |
7 | // constants
8 | import {
9 | SESSION_STORAGE_KEY,
10 | SESSION_STORAGE_TYPE,
11 | } from '../constants';
12 |
13 | // utils
14 | import {
15 | createHandleClearValues,
16 | createHandleDeleteValues,
17 | createHandleSetValues,
18 | getSessionStorage,
19 | } from '../utils';
20 |
21 | export const INITIAL_STATE = getSessionStorage();
22 |
23 | export default handleActions(
24 | {
25 | [ACTION_TYPES.CLEAR_SESSION_VALUES]: createHandleClearValues(SESSION_STORAGE_KEY, SESSION_STORAGE_TYPE),
26 | [ACTION_TYPES.DELETE_SESSION_VALUES]: createHandleDeleteValues(SESSION_STORAGE_KEY, SESSION_STORAGE_TYPE),
27 | [ACTION_TYPES.SET_SESSION_VALUES]: createHandleSetValues(SESSION_STORAGE_KEY, SESSION_STORAGE_TYPE),
28 | },
29 | INITIAL_STATE
30 | );
31 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import {
3 | remove,
4 | set,
5 | } from 'unchanged';
6 |
7 | // constants
8 | import {
9 | LOCAL_STORAGE_KEY,
10 | LOCAL_STORAGE_TYPE,
11 | SESSION_STORAGE_KEY,
12 | SESSION_STORAGE_TYPE,
13 | } from './constants';
14 |
15 | /**
16 | * @function createGetStorage
17 | *
18 | * @description
19 | * create a method that will retrieve the storage type requested
20 | *
21 | * @param {string} storageType the type of storage to retrieve
22 | * @param {string} storageKey the key used in local storage
23 | * @returns {function(): Object} the method that will retrieve the value in storage
24 | */
25 | export const createGetStorage = (storageType, storageKey) => () => {
26 | try {
27 | const storageJson = window[storageType].getItem(storageKey);
28 |
29 | return storageJson ? JSON.parse(storageJson) : {};
30 | } catch (error) {
31 | return {};
32 | }
33 | };
34 |
35 | /**
36 | * @function setStateInStorage
37 | *
38 | * @description
39 | * set the newState in the storage type requested
40 | *
41 | * @param {string} storageType the type of storage to retrieve
42 | * @param {string} storageKey the key used in local storage
43 | * @param {Object} newState the new state value to storewindow
44 | */
45 | export const setStateInStorage = (storageType, storageKey, newState) =>
46 | window[storageType].setItem(storageKey, JSON.stringify(newState));
47 |
48 | /**
49 | * @function createHandleClearValues
50 | *
51 | * @description
52 | * create the handler for clearing of values in storage
53 | *
54 | * @param {string} storageKey the key used in local storage
55 | * @param {string} storageType the type of storage to retrieve
56 | * @returns {function(): Object} the clear values handler
57 | */
58 | export const createHandleClearValues = (storageKey, storageType) => () => {
59 | const newState = {};
60 |
61 | setStateInStorage(storageType, storageKey, newState);
62 |
63 | return newState;
64 | };
65 |
66 | /**
67 | * @function createHandleDeleteValues
68 | *
69 | * @description
70 | * create the handler for deleting specific keys in state
71 | *
72 | * @param {string} storageKey the key used in local storage
73 | * @param {string} storageType the type of storage to retrieve
74 | * @returns {function(): Object} the delete values handler
75 | */
76 | export const createHandleDeleteValues = (storageKey, storageType) => {
77 | const handleDeleteValues = (state, {payload: key}) => {
78 | if (Array.isArray(key)) {
79 | return key.reduce((newState, keyToRemove) => handleDeleteValues(newState, {payload: keyToRemove}), state);
80 | }
81 |
82 | const newState = remove(key, state);
83 |
84 | setStateInStorage(storageType, storageKey, newState);
85 |
86 | return newState;
87 | };
88 |
89 | return handleDeleteValues;
90 | };
91 |
92 | /**
93 | * @function createHandleSetValues
94 | *
95 | * @description
96 | * create the handler for setting specific keys in state
97 | *
98 | * @param {string} storageKey the key used in local storage
99 | * @param {string} storageType the type of storage to retrieve
100 | * @returns {function(): Object} the set values handler
101 | */
102 | export const createHandleSetValues = (storageKey, storageType) => (state, {payload}) => {
103 | const newState = Object.keys(payload).reduce((newState, path) => set(path, payload[path], newState), state);
104 |
105 | setStateInStorage(storageType, storageKey, newState);
106 |
107 | return newState;
108 | };
109 |
110 | export const getLocalStorage = createGetStorage(LOCAL_STORAGE_TYPE, LOCAL_STORAGE_KEY);
111 | export const getSessionStorage = createGetStorage(SESSION_STORAGE_TYPE, SESSION_STORAGE_KEY);
112 |
--------------------------------------------------------------------------------
/test/actions/index.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 | import _ from 'lodash';
4 |
5 | // src
6 | import * as actions from 'src/actions/index';
7 | import * as localActionsExports from 'src/actions/localActions';
8 | import * as sessionActionsExports from 'src/actions/sessionActions';
9 |
10 | test('if every localActions import that is an action has a corresponding export', (t) => {
11 | const {__esModule: moduleDeclarationIgnored, ACTION_TYPES: actionTypesIgnored, ...localActions} = localActionsExports;
12 |
13 | Object.keys(localActions).forEach((key) => {
14 | t.true(_.isFunction(actions[key]));
15 | });
16 | });
17 |
18 | test('if every sessionActions import that is an action has a corresponding export', (t) => {
19 | const {
20 | __esModule: moduleDeclarationIgnored,
21 | ACTION_TYPES: actionTypesIgnored,
22 | ...sessionActions
23 | } = sessionActionsExports;
24 |
25 | Object.keys(sessionActions).forEach((key) => {
26 | t.true(_.isFunction(actions[key]));
27 | });
28 | });
29 |
30 | test('if the default export has all the actions namespaced', (t) => {
31 | const {
32 | __esModule: localModuleDeclarationIgnored,
33 | ACTION_TYPES: localActionTypesIgnored,
34 | ...localActions
35 | } = localActionsExports;
36 | const {
37 | __esModule: sessionModuleDeclarationIgnored,
38 | ACTION_TYPES: sessionActionTypesIgnored,
39 | ...sessionActions
40 | } = sessionActionsExports;
41 |
42 | t.deepEqual(actions.default, {
43 | localActions,
44 | sessionActions,
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/test/actions/localActions.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 | import _ from 'lodash';
4 |
5 | // src
6 | import * as actions from 'src/actions/localActions';
7 |
8 | test('if every constant has a corresponding camelCase action', (t) => {
9 | Object.keys(actions.ACTION_TYPES).forEach((key) => {
10 | t.true(_.isFunction(actions[_.camelCase(key)]));
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/actions/sessionActions.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 | import _ from 'lodash';
4 |
5 | // src
6 | import * as actions from 'src/actions/sessionActions';
7 |
8 | test('if every constant has a corresponding camelCase action', (t) => {
9 | Object.keys(actions.ACTION_TYPES).forEach((key) => {
10 | t.true(_.isFunction(actions[_.camelCase(key)]));
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/helpers/setup-browser-env.js:
--------------------------------------------------------------------------------
1 | // external dependencies
2 | import browserEnv from 'browser-env';
3 |
4 | browserEnv();
5 |
6 | const createMockStorage = () => {
7 | let values = {};
8 |
9 | return {
10 | clear() {
11 | values = {};
12 | },
13 | getItem(key) {
14 | return values[key];
15 | },
16 | setItem(key, value) {
17 | values[key] = value;
18 | },
19 | };
20 | };
21 |
22 | window.localStorage = createMockStorage();
23 | window.sessionStorage = createMockStorage();
24 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 | import _ from 'lodash';
4 |
5 | // src
6 | import * as index from 'src/index';
7 | import * as actionsExports from 'src/actions';
8 | import * as reducersExports from 'src/reducers';
9 |
10 | test('if each actions import has a reflective export', (t) => {
11 | const {
12 | __esModule: moduleDeclarationIgnored,
13 | default: defaultIgnored,
14 | localActions,
15 | localReducer: localReducerIgnored,
16 | sessionActions,
17 | sessionReducer: sessionReducerIgnored,
18 | ...actions
19 | } = actionsExports;
20 |
21 | Object.keys(actions).forEach((key) => {
22 | t.true(_.isFunction(index[key]));
23 | });
24 |
25 | Object.keys(localActions).forEach((key) => {
26 | t.true(_.isFunction(localActions[key]));
27 | });
28 |
29 | Object.keys(sessionActions).forEach((key) => {
30 | t.true(_.isFunction(sessionActions[key]));
31 | });
32 | });
33 |
34 | test('if each reducers import has a reflective export', (t) => {
35 | const {localReducer, sessionReducer} = reducersExports;
36 |
37 | t.is(index.localReducer, localReducer);
38 | t.is(index.sessionReducer, sessionReducer);
39 | });
40 |
--------------------------------------------------------------------------------
/test/reducers/index.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 |
4 | // src
5 | import * as reducers from 'src/reducers/index';
6 | import localReducer from 'src/reducers/localReducer';
7 | import sessionReducer from 'src/reducers/sessionReducer';
8 |
9 | test('if all reducers have a corresponding export', (t) => {
10 | t.is(reducers.localReducer, localReducer);
11 | t.is(reducers.sessionReducer, sessionReducer);
12 | });
13 |
14 | test('if the default export has all the reducers', (t) => {
15 | t.deepEqual(reducers.default, {
16 | localReducer,
17 | sessionReducer,
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/test/reducers/localReducer.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 |
4 | // src
5 | import reducer, {INITIAL_STATE} from 'src/reducers/localReducer';
6 |
7 | test('if INITIAL_STATE is returned when no matching actions are found', (t) => {
8 | const result = reducer(undefined, {});
9 |
10 | t.is(result, INITIAL_STATE);
11 | });
12 |
--------------------------------------------------------------------------------
/test/reducers/sessionReducer.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 |
4 | // src
5 | import reducer, {INITIAL_STATE} from 'src/reducers/sessionReducer';
6 |
7 | test('if INITIAL_STATE is returned when no matching actions are found', (t) => {
8 | const result = reducer(undefined, {});
9 |
10 | t.is(result, INITIAL_STATE);
11 | });
12 |
--------------------------------------------------------------------------------
/test/utils.js:
--------------------------------------------------------------------------------
1 | // test
2 | import test from 'ava';
3 | import _ from 'lodash';
4 | import sinon from 'sinon';
5 |
6 | // src
7 | import * as utils from 'src/utils';
8 | import * as constants from 'src/constants';
9 |
10 | test('if createGetStorage will return the value in state if the key exists', (t) => {
11 | const object = {
12 | foo: 'bar',
13 | };
14 | const storageKey = constants.LOCAL_STORAGE_KEY;
15 | const storageType = constants.LOCAL_STORAGE_TYPE;
16 |
17 | const getStorage = utils.createGetStorage(storageType, storageKey);
18 |
19 | t.true(_.isFunction(getStorage));
20 |
21 | const stub = sinon.stub(window[storageType], 'getItem').returns(JSON.stringify(object));
22 |
23 | const result = getStorage();
24 |
25 | t.true(stub.calledOnce);
26 | t.true(stub.calledWith(storageKey));
27 |
28 | t.deepEqual(result, object);
29 |
30 | stub.restore();
31 | });
32 |
33 | test('if createGetStorage will return an empty object if the key does not exist', (t) => {
34 | const storageKey = constants.LOCAL_STORAGE_KEY;
35 | const storageType = constants.LOCAL_STORAGE_TYPE;
36 |
37 | const getStorage = utils.createGetStorage(storageType, storageKey);
38 |
39 | t.true(_.isFunction(getStorage));
40 |
41 | const stub = sinon.stub(window[storageType], 'getItem').returns(null);
42 |
43 | const result = getStorage();
44 |
45 | t.true(stub.calledOnce);
46 | t.true(stub.calledWith(storageKey));
47 |
48 | t.deepEqual(result, {});
49 |
50 | stub.restore();
51 | });
52 |
53 | test('if createGetStorage will return an empty object if parsing the result throws an error', (t) => {
54 | const storageKey = constants.LOCAL_STORAGE_KEY;
55 | const storageType = constants.LOCAL_STORAGE_TYPE;
56 |
57 | const getStorage = utils.createGetStorage(storageType, storageKey);
58 |
59 | t.true(_.isFunction(getStorage));
60 |
61 | const stub = sinon.stub(window[storageType], 'getItem').returns({});
62 |
63 | const result = getStorage();
64 |
65 | t.true(stub.calledOnce);
66 | t.true(stub.calledWith(storageKey));
67 |
68 | t.deepEqual(result, {});
69 |
70 | stub.restore();
71 | });
72 |
73 | test('if setStateInStorage will set the state in the storage specified', (t) => {
74 | const object = {
75 | foo: 'bar',
76 | };
77 | const storageKey = constants.LOCAL_STORAGE_KEY;
78 | const storageType = constants.LOCAL_STORAGE_TYPE;
79 |
80 | const stub = sinon.stub(window[storageType], 'setItem');
81 |
82 | utils.setStateInStorage(storageType, storageKey, object);
83 |
84 | t.true(stub.calledOnce);
85 |
86 | const args = stub.firstCall.args;
87 |
88 | t.is(args.length, 2);
89 |
90 | const [key, value] = args;
91 |
92 | t.is(key, storageKey);
93 | t.is(value, JSON.stringify(object));
94 |
95 | stub.restore();
96 | });
97 |
98 | test('if createHandleClearValues will set the initial state passed both in the reducer and in storage', (t) => {
99 | const storageKey = constants.LOCAL_STORAGE_KEY;
100 | const storageType = constants.LOCAL_STORAGE_TYPE;
101 |
102 | const handleClearValues = utils.createHandleClearValues(storageKey, storageType);
103 |
104 | t.true(_.isFunction(handleClearValues));
105 |
106 | const stub = sinon.stub(window[storageType], 'setItem');
107 |
108 | const result = handleClearValues();
109 |
110 | t.true(stub.called);
111 |
112 | const args = stub.firstCall.args;
113 |
114 | t.is(args.length, 2);
115 |
116 | const [key, value] = args;
117 |
118 | t.is(key, storageKey);
119 | t.is(value, JSON.stringify({}));
120 |
121 | t.deepEqual(result, {});
122 |
123 | stub.restore();
124 | });
125 |
126 | test('if createHandleDeleteValues creates a reducer that will remove the key from the state passed and return it', (t) => {
127 | const storageKey = constants.LOCAL_STORAGE_KEY;
128 | const storageType = constants.LOCAL_STORAGE_TYPE;
129 |
130 | const handleDeleteValues = utils.createHandleDeleteValues(storageKey, storageType);
131 |
132 | t.true(_.isFunction(handleDeleteValues));
133 |
134 | const currentState = {
135 | foo: {
136 | bar: 'baz',
137 | },
138 | };
139 | const action = {
140 | payload: 'foo.bar',
141 | };
142 |
143 | const stub = sinon.stub(window[storageType], 'setItem');
144 |
145 | const result = handleDeleteValues(currentState, action);
146 | const expectedResult = {
147 | foo: {},
148 | };
149 |
150 | t.true(stub.calledOnce);
151 |
152 | const args = stub.firstCall.args;
153 |
154 | t.is(args.length, 2);
155 | t.deepEqual(args, [storageKey, JSON.stringify(expectedResult)]);
156 |
157 | stub.restore();
158 |
159 | t.deepEqual(result, expectedResult);
160 | });
161 |
162 | test('if createHandleDeleteValues creates a reducer that will remove the keys from the state passed and return it', (t) => {
163 | const storageKey = constants.LOCAL_STORAGE_KEY;
164 | const storageType = constants.LOCAL_STORAGE_TYPE;
165 |
166 | const handleDeleteValues = utils.createHandleDeleteValues(storageKey, storageType);
167 |
168 | t.true(_.isFunction(handleDeleteValues));
169 |
170 | const currentState = {
171 | bar: 'bar',
172 | foo: 'foo',
173 | };
174 | const action = {
175 | payload: ['foo', 'bar'],
176 | };
177 |
178 | const stub = sinon.stub(window[storageType], 'setItem');
179 |
180 | const result = handleDeleteValues(currentState, action);
181 |
182 | t.true(stub.calledTwice);
183 |
184 | const firstArgs = stub.firstCall.args;
185 |
186 | t.is(firstArgs.length, 2);
187 | t.deepEqual(firstArgs, [
188 | storageKey,
189 | JSON.stringify({
190 | bar: 'bar',
191 | }),
192 | ]);
193 |
194 | const secondArgs = stub.secondCall.args;
195 |
196 | t.is(secondArgs.length, 2);
197 | t.deepEqual(secondArgs, [storageKey, JSON.stringify({})]);
198 |
199 | stub.restore();
200 |
201 | t.deepEqual(result, {});
202 | });
203 |
204 | test('if createHandleSetValues creates a reducer that will add the items in state passed and return it', (t) => {
205 | const storageKey = constants.LOCAL_STORAGE_KEY;
206 | const storageType = constants.LOCAL_STORAGE_TYPE;
207 |
208 | const handlSetValues = utils.createHandleSetValues(storageKey, storageType);
209 |
210 | t.true(_.isFunction(handlSetValues));
211 |
212 | const currentState = {
213 | foo: 'foo',
214 | };
215 | const action = {
216 | payload: {
217 | bar: 'bar',
218 | },
219 | };
220 |
221 | const stub = sinon.stub(window[storageType], 'setItem');
222 |
223 | const result = handlSetValues(currentState, action);
224 | const expectedResult = {
225 | ...currentState,
226 | ...action.payload,
227 | };
228 |
229 | t.true(stub.calledOnce);
230 |
231 | const args = stub.firstCall.args;
232 |
233 | t.is(args.length, 2);
234 | t.deepEqual(args, [storageKey, JSON.stringify(expectedResult)]);
235 |
236 | stub.restore();
237 |
238 | t.deepEqual(result, expectedResult);
239 | });
240 |
--------------------------------------------------------------------------------
/webpack/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const HtmlWebpackPlugin = require('html-webpack-plugin');
5 |
6 | const defaultConfig = require('./webpack.config');
7 |
8 | const PORT = 3000;
9 | const ROOT = path.join(__dirname, '..');
10 |
11 | module.exports = Object.assign({}, defaultConfig, {
12 | cache: true,
13 |
14 | devServer: {
15 | contentBase: './dist',
16 | host: 'localhost',
17 | inline: true,
18 | lazy: false,
19 | noInfo: false,
20 | port: PORT,
21 | quiet: false,
22 | stats: {
23 | colors: true,
24 | progress: true,
25 | },
26 | watchOptions: {
27 | ignored: /node_modules/,
28 | },
29 | },
30 |
31 | entry: [path.join(ROOT, 'DEV_ONLY', 'index.js')],
32 |
33 | module: Object.assign({}, defaultConfig.module, {
34 | rules: defaultConfig.module.rules.map((rule) => {
35 | if (rule.loader !== 'babel-loader') {
36 | return rule;
37 | }
38 |
39 | return Object.assign({}, rule, {
40 | include: rule.include.concat([path.join(ROOT, 'DEV_ONLY')]),
41 | options: {
42 | plugins: ['@babel/plugin-proposal-class-properties'],
43 | presets: ['@babel/react'],
44 | },
45 | });
46 | }),
47 | }),
48 |
49 | output: Object.assign({}, defaultConfig.output, {
50 | publicPath: `http://localhost:${PORT}/`,
51 | }),
52 |
53 | plugins: defaultConfig.plugins.concat([new HtmlWebpackPlugin()]),
54 | });
55 |
--------------------------------------------------------------------------------
/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const eslintFriendlyFormatter = require('eslint-friendly-formatter');
4 | const path = require('path');
5 | const webpack = require('webpack');
6 |
7 | const ROOT = path.join(__dirname, '..');
8 |
9 | module.exports = {
10 | devtool: '#source-map',
11 |
12 | entry: [path.resolve(ROOT, 'src', 'index.js')],
13 |
14 | mode: 'development',
15 |
16 | module: {
17 | rules: [
18 | {
19 | enforce: 'pre',
20 | include: [path.resolve(ROOT, 'src')],
21 | loader: 'eslint-loader',
22 | options: {
23 | configFile: '.eslintrc',
24 | failOnError: true,
25 | failOnWarning: false,
26 | formatter: require('eslint-friendly-formatter'),
27 | },
28 | test: /\.js$/,
29 | },
30 | {
31 | include: [path.resolve(ROOT, 'src'), path.resolve(ROOT, 'DEV_ONLY')],
32 | loader: 'babel-loader',
33 | test: /\.js$/,
34 | },
35 | ],
36 | },
37 |
38 | output: {
39 | filename: 'redux-browser-storage.js',
40 | library: 'ReduxBrowserStorage',
41 | libraryTarget: 'umd',
42 | path: path.join(ROOT, 'dist'),
43 | umdNamedDefine: true,
44 | },
45 |
46 | plugins: [new webpack.EnvironmentPlugin(['NODE_ENV'])],
47 | };
48 |
--------------------------------------------------------------------------------
/webpack/webpack.config.minified.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const webpack = require('webpack');
4 | const OptimizeJsPlugin = require('optimize-js-plugin');
5 |
6 | const defaultConfig = require('./webpack.config');
7 |
8 | module.exports = Object.assign({}, defaultConfig, {
9 | devtool: undefined,
10 |
11 | mode: 'production',
12 |
13 | output: Object.assign({}, defaultConfig.output, {
14 | filename: 'redux-browser-storage.min.js',
15 | }),
16 |
17 | plugins: defaultConfig.plugins.concat([
18 | new webpack.LoaderOptionsPlugin({
19 | debug: false,
20 | minimize: true,
21 | }),
22 | new OptimizeJsPlugin({
23 | sourceMap: false,
24 | }),
25 | ]),
26 | });
27 |
--------------------------------------------------------------------------------