├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── README.md ├── package.json ├── src ├── __test__ │ ├── actions.specs.js │ └── reducer.specs.js ├── actionTypes.js ├── actions.js ├── helpers.js ├── index.js ├── reducer.js └── simpleReduxForm.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015", "stage-0"], 3 | "env": { 4 | "test" : { 5 | "plugins": [ 6 | ["transform-class-properties"], 7 | ], 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | webpack.config.js 2 | dist/* 3 | static/* 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | }, 8 | "rules": { 9 | "react/no-multi-comp": 0, 10 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 11 | "import/default": 0, 12 | "import/no-duplicates": 0, 13 | "import/named": 0, 14 | "import/namespace": 0, 15 | "import/no-unresolved": 0, 16 | "comma-dangle": 0, 17 | "import/no-named-as-default": 2, 18 | "indent": [2, 2, {"SwitchCase": 1}], 19 | "no-console": 0, 20 | "no-underscore-dangle": ["error", { "allowAfterThis": true }], 21 | "no-alert": 0, 22 | "eqeqeq" : 1 23 | }, 24 | "plugins": [ 25 | "react" 26 | ], 27 | "settings": { 28 | "import/resolve": { 29 | moduleDirectory: ["node_modules", "src"] 30 | } 31 | }, 32 | "globals": { 33 | "__DEVELOPMENT__": true, 34 | "__DEBUG__": true, 35 | "__SERVER__": true, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | dist/ 4 | lib/ 5 | coverage/ 6 | *.iml 7 | *.log 8 | *.logs 9 | .DS_Store 10 | npm-debug.log 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | scripts 2 | docs 3 | .babelrc 4 | .eslint* 5 | .idea 6 | .editorconfig 7 | .npmignore 8 | .travis.yml 9 | webpack.* 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Simplest Redux Form

2 | 3 | > Higher order component for React Redux forms (inspired by [redux-form](https://github.com/erikras/redux-form)) 4 | 5 | ## Note 6 | 7 | Idea of this library is 100% inspired from [redux-form](https://github.com/erikras/redux-form) (v5). 8 | 9 | This library is subset of [redux-form](https://github.com/erikras/redux-form) for small / few forms. 10 | If your application is form heavey with large / complex form please use [redux-form](https://github.com/erikras/redux-form). 11 | 12 | I have implemented this libray for following reasons :- 13 | 14 | * [redux-form](https://github.com/erikras/redux-form) is great way of managing forms within application with react and redux. 15 | * For small forms using large library will add up unnecessary bundle size increase, this library focus on simple and small version of `redux-from` 16 | * Scope of this library will be very minimal, if you want full fledge library please use `redux-form`. 17 | 18 | ## Installation 19 | 20 | ``` 21 | $ npm install --save simple-redux-form 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Step #1 27 | 28 | The first thing, you have to mount `simple-redux-form` reducer to your redux reducers. 29 | Configure this inside your rootReducers. 30 | 31 | ```js 32 | import {reducer as simpleFormReducer} from 'simple-redux-form'; 33 | const reducers = { 34 | // your other reducers 35 | form: simpleFormReducer 36 | } 37 | ``` 38 | 39 | ### Step #2 40 | 41 | You need to decorate your component with simpleReduxForm. 42 | 43 | ```js 44 | import simpleReduxForm from 'simple-redux-form' 45 | const fields = ['firstName', 'lastName']; 46 | function validate(values) { 47 | const errors = {}; 48 | if (!values.firstName) { 49 | errors.firstName = 'Required'; 50 | } 51 | if (!values.lastName) { 52 | errors.lastName = 'Required'; 53 | } 54 | return errors; 55 | } 56 | 57 | const MyNewForm = ({ fields: {firstName, lastName } }) => ( 58 |
59 | 60 | 61 |
62 | ) 63 | 64 | export default simpleReduxForm(MyForm, { 65 | form: 'test' 66 | fields, 67 | validate, 68 | }); 69 | 70 | ``` 71 | 72 | Each field in the fields prop contains the `value` a `onChange`, `error` , `touched` as sugger props to each field. 73 | 74 | You can also pass fields as props. 75 | 76 | For custom Input components this library expose , `setValue` function with each field for setting vlaues manually. 77 | 78 | 79 | ### Todo 80 | 81 | * [ ] Docs 82 | * [ ] Examples 83 | 84 | ## License 85 | 86 | MIT 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-redux-form", 3 | "version": "0.0.5", 4 | "description": "This is simplest redux form", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "build": "npm run build:lib && npm run build:npm && npm run build:min", 8 | "build:lib": "babel src --out-dir lib", 9 | "build:npm": "NODE_ENV=development webpack src/index.js dist/simple-redux-form.js", 10 | "build:min": "NODE_ENV=production webpack src/index.js dist/simple-redux-form.min.js", 11 | "test": "mocha --compilers js:babel-register --recursive 'src/__test__/*'", 12 | "test:coverage": "npm run build:lib && istanbul cover _mocha -- recursive 'lib/__test__/*'", 13 | "test:lint": "eslint src", 14 | "show:coverage": "open coverage/lcov-report/index.html", 15 | "clean": "rimraf lib coverage dist" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/mihirsoni/simple-redux-form.git" 20 | }, 21 | "keywords": [ 22 | "react", 23 | "reactjs", 24 | "flux", 25 | "redux", 26 | "react-redux", 27 | "tiny-redux-form", 28 | "simple-redux-form", 29 | "small-redux-form", 30 | "redux-form", 31 | "redux-form-validations", 32 | "forms", 33 | "decorator" 34 | ], 35 | "bugs": { 36 | "url": "https://github.com/mihirsoni/simple-redux-form/issues" 37 | }, 38 | "npmName": "simple-redux-form", 39 | "dependencies": { 40 | "deep-equal": "^1.0.1", 41 | "react": "^15.3.0", 42 | "react-redux": "^4.4.5", 43 | "redux": "^3.5.2" 44 | }, 45 | "devDependencies": { 46 | "babel": "^6.5.2", 47 | "babel-cli": "^6.11.4", 48 | "babel-core": "^6.13.2", 49 | "babel-eslint": "^6.1.2", 50 | "babel-loader": "^6.2.4", 51 | "babel-preset-es2015": "^6.13.2", 52 | "babel-preset-react": "^6.11.1", 53 | "babel-preset-stage-0": "^6.5.0", 54 | "babel-register": "^6.11.6", 55 | "deep-freeze": "0.0.1", 56 | "eslint": "^3.2.2", 57 | "eslint-config-airbnb": "^10.0.0", 58 | "eslint-plugin-import": "^1.12.0", 59 | "eslint-plugin-jsx-a11y": "^2.0.1", 60 | "eslint-plugin-react": "^6.0.0", 61 | "expect": "^1.20.2", 62 | "istanbul": "^0.4.4", 63 | "mocha": "^3.0.1", 64 | "rimraf": "^2.5.4", 65 | "webpack": "^1.13.1" 66 | }, 67 | "author": "Mihir Soni (http://mihir.pro)", 68 | "license": "MIT" 69 | } 70 | -------------------------------------------------------------------------------- /src/__test__/actions.specs.js: -------------------------------------------------------------------------------- 1 | /* global define, it, describe */ 2 | /* eslint-disable import/no-extraneous-dependencies */ 3 | import expect from 'expect'; 4 | import { INITIALIZE, DESTROY, SET_FIELD, TOUCH_ALL } from '../actionTypes.js'; 5 | import { initialize, setField, touchAll, destroy } from '../actions.js'; 6 | 7 | describe('actions', () => { 8 | it('should create an action to initialize all form fields with an initial value', () => { 9 | const actionType = initialize( 10 | { field1: 'foo', field2: 'bar', field3: 'baz' }, 11 | 'mockedForm', 12 | ['field1', 'field2', 'field3']); 13 | const action = { 14 | type: INITIALIZE, 15 | initialValue: { field1: 'foo', field2: 'bar', field3: 'baz' }, 16 | form: 'mockedForm', 17 | fields: ['field1', 'field2', 'field3'] 18 | }; 19 | expect(actionType).toEqual(action); 20 | }); 21 | it('should create action for setting a value to the form field', () => { 22 | const actionType = setField('mockedField', 'mockedValue', 'mockedForm'); 23 | const action = { 24 | type: SET_FIELD, 25 | field: 'mockedField', 26 | value: 'mockedValue', 27 | form: 'mockedForm' 28 | }; 29 | expect(actionType).toEqual(action); 30 | }); 31 | it('should create action for touching all the values of the field', () => { 32 | const actionType = touchAll('mockedForm', ['field1', 'field2', 'field3']); 33 | const action = { 34 | type: TOUCH_ALL, 35 | form: 'mockedForm', 36 | fields: ['field1', 'field2', 'field3'] 37 | }; 38 | expect(actionType).toEqual(action); 39 | }); 40 | it('should create action for destroying the form', () => { 41 | const actionType = destroy('mockedForm'); 42 | const action = { 43 | type: DESTROY, 44 | form: 'mockedForm' 45 | }; 46 | expect(actionType).toEqual(action); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/__test__/reducer.specs.js: -------------------------------------------------------------------------------- 1 | /* global define, it, describe */ 2 | /* eslint-disable import/no-extraneous-dependencies */ 3 | import expect from 'expect'; 4 | import deepFreeze from 'deep-freeze'; 5 | import { initialize, setField, touchAll, destroy } from '../actions.js'; 6 | import reducer from '../reducer'; 7 | 8 | describe('reducers', () => { 9 | it('should initial from with fields and given values', () => { 10 | const stateBefore = {}; 11 | const action = initialize( 12 | { field1: 'foo', field2: 'bar', field3: 'baz' }, 13 | 'mockedForm', 14 | ['field1', 'field2', 'field3']); 15 | const stateAfter = { 16 | mockedForm: { 17 | field1: { value: 'foo' }, 18 | field2: { value: 'bar' }, 19 | field3: { value: 'baz' }, 20 | initialized: true 21 | } 22 | }; 23 | deepFreeze(stateBefore); 24 | deepFreeze(stateAfter); 25 | expect(reducer(stateBefore, action)).toEqual(stateAfter); 26 | }); 27 | it('should modify the value of the given field, if the field exists', () => { 28 | const stateBefore = { 29 | mockedForm: { 30 | field1: { value: 'foo' }, 31 | field2: { value: 'bar' }, 32 | field3: { value: 'baz' }, 33 | initialized: true 34 | } 35 | }; 36 | const action = setField('field1', 'modifiedFoo', 'mockedForm'); 37 | const stateAfter = { 38 | mockedForm: { 39 | field1: { touched: true, value: 'modifiedFoo' }, 40 | field2: { value: 'bar' }, 41 | field3: { value: 'baz' }, 42 | initialized: true 43 | } 44 | }; 45 | deepFreeze(stateBefore); 46 | deepFreeze(stateAfter); 47 | expect(reducer(stateBefore, action)).toEqual(stateAfter); 48 | }); 49 | it('should add a new field, if the given field does not exist', () => { 50 | const stateBefore = { 51 | mockedForm: { 52 | field1: { value: 'foo' }, 53 | field2: { value: 'bar' }, 54 | field3: { value: 'baz' }, 55 | initialized: true 56 | } 57 | }; 58 | const action = setField('field4', 'tar', 'mockedForm'); 59 | const stateAfter = { 60 | mockedForm: { 61 | field1: { value: 'foo' }, 62 | field2: { value: 'bar' }, 63 | field3: { value: 'baz' }, 64 | field4: { touched: true, value: 'tar' }, 65 | initialized: true 66 | } 67 | }; 68 | deepFreeze(stateBefore); 69 | deepFreeze(stateAfter); 70 | expect(reducer(stateBefore, action)).toEqual(stateAfter); 71 | }); 72 | it('should add set touched propery of all fields to true, and if not exist add them', () => { 73 | const stateBefore = { 74 | mockedForm: { 75 | field1: { value: 'foo', touched: true }, 76 | field2: { value: 'bar' }, 77 | field3: { value: 'baz' }, 78 | initialized: true 79 | } 80 | }; 81 | const action = touchAll('mockedForm', ['field1', 'field2', 'field3']); 82 | const stateAfter = { 83 | mockedForm: { 84 | field1: { value: 'foo', touched: true }, 85 | field2: { value: 'bar', touched: true }, 86 | field3: { value: 'baz', touched: true }, 87 | initialized: true 88 | } 89 | }; 90 | deepFreeze(stateBefore); 91 | deepFreeze(stateAfter); 92 | expect(reducer(stateBefore, action)).toEqual(stateAfter); 93 | }); 94 | it('should destory the mounted FORM, from the state tree', () => { 95 | const stateBefore = { 96 | mockedForm: { 97 | field1: { value: 'foo', touched: true }, 98 | field2: { value: 'bar' }, 99 | field3: { value: 'baz' }, 100 | initialized: true 101 | }, 102 | otherState: { 103 | viewState: 'VIEW_ALL' 104 | } 105 | }; 106 | const action = destroy('mockedForm'); 107 | const stateAfter = { 108 | otherState: { 109 | viewState: 'VIEW_ALL' 110 | }, 111 | }; 112 | deepFreeze(stateBefore); 113 | deepFreeze(stateAfter); 114 | expect(reducer(stateBefore, action)).toEqual(stateAfter); 115 | }); 116 | }); 117 | 118 | -------------------------------------------------------------------------------- /src/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const INITIALIZE = 'simple-redux-form/INITIALIZE'; 2 | export const DESTROY = 'simple-redux-form/DESTROY'; 3 | export const SET_FIELD = 'simple-redux-form/SET_FIELD'; 4 | export const TOUCH_ALL = 'simple-redux-form/TOUCH_ALL'; 5 | -------------------------------------------------------------------------------- /src/actions.js: -------------------------------------------------------------------------------- 1 | import { INITIALIZE, DESTROY, SET_FIELD, TOUCH_ALL } from './actionTypes'; 2 | 3 | export function initialize(initialValue, form, fields) { 4 | return { 5 | type: INITIALIZE, 6 | initialValue, 7 | form, 8 | fields 9 | }; 10 | } 11 | 12 | export function setField(field, value, form) { 13 | return { 14 | type: SET_FIELD, field, value, form 15 | }; 16 | } 17 | 18 | export function touchAll(form, fields) { 19 | return { 20 | type: TOUCH_ALL, form, fields 21 | }; 22 | } 23 | 24 | export function destroy(form) { 25 | return { 26 | type: DESTROY, form 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | /* 2 | This are set of helpers function to make simpleReduxForm work 3 | */ 4 | export function getFieldValue(field, formValues) { 5 | if (formValues && formValues[field]) { 6 | return formValues[field].value; 7 | } 8 | return undefined; 9 | } 10 | export function simplifiedVlaues(formValues, fields) { 11 | return fields.reduce((acc, field) => ({ 12 | ...acc, 13 | [field]: getFieldValue(field, formValues) 14 | }), Object.create(null)); 15 | } 16 | export function createField(field, onChange) { 17 | const fieldObject = { 18 | name: field, 19 | touched: false, 20 | onChange: ({ target: { type, checked, value } }) => { 21 | const isCheckbox = type && type.toLowerCase() === 'checkbox'; 22 | onChange(field, isCheckbox ? checked : value); 23 | } 24 | }; 25 | return { 26 | ...fieldObject, 27 | setValue(value) { // If custome component set value directly 28 | onChange(field, value); 29 | } 30 | }; 31 | } 32 | export function hasSyncErrors(errors) { 33 | let allErrors = errors; 34 | if (allErrors == null) { 35 | allErrors = {}; 36 | } 37 | let hasError = false; 38 | const fieldKeys = Object.keys(allErrors); 39 | for (let i = 0; i < fieldKeys.length; i++) { 40 | if (allErrors[fieldKeys[i]] !== undefined) { 41 | hasError = true; 42 | break; 43 | } 44 | } 45 | return hasError; 46 | } 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export reducer from './reducer'; 2 | export * as formActions from './actionTypes'; 3 | export simpleReduxForm from './simpleReduxForm'; 4 | -------------------------------------------------------------------------------- /src/reducer.js: -------------------------------------------------------------------------------- 1 | import { INITIALIZE, DESTROY, SET_FIELD, TOUCH_ALL } from './actionTypes'; 2 | 3 | const initialState = {}; 4 | 5 | export default function reducer(state = initialState, action) { 6 | switch (action.type) { 7 | case INITIALIZE : 8 | return { 9 | ...state, 10 | [action.form]: { 11 | ...action.fields.reduce((acc, field) => ({ 12 | ...acc, 13 | [field]: { 14 | value: action.initialValue[field] 15 | } 16 | }), {}), 17 | initialized: true, 18 | } 19 | }; 20 | case DESTROY : { 21 | const updateDState = { ...state }; 22 | delete updateDState[action.form]; 23 | return { 24 | ...updateDState 25 | }; 26 | } 27 | case SET_FIELD: { 28 | const { field, value, form } = action; 29 | return { 30 | ...state, 31 | [form]: { 32 | ...state[form], 33 | [field]: { 34 | touched: true, 35 | value, 36 | } 37 | } 38 | }; 39 | } 40 | case TOUCH_ALL: { 41 | const { fields, form } = action; 42 | return { 43 | ...state, 44 | [form]: { 45 | ...state[form], 46 | ...fields.reduce((prevField, field) => ({ 47 | ...prevField, 48 | [field]: { 49 | value: state[form] && state[form][field] ? state[form][field].value : '', 50 | touched: true 51 | } 52 | }), {}) 53 | } 54 | }; 55 | } 56 | default: 57 | return state; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/simpleReduxForm.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes, Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import deepEqual from 'deep-equal'; 5 | import { setField, initialize, touchAll } from './actions'; 6 | import { simplifiedVlaues, createField, hasSyncErrors } from './helpers'; 7 | 8 | // Higher order component for huge fast dynamic deeply nested universal forms. 9 | export default function simpleReduxForm(Wrapped, options) { 10 | const { 11 | form = '', 12 | fields: initFields = [], 13 | getInitialState, 14 | validate = () => {} 15 | } = options; 16 | 17 | class SimpleReduxForm extends Component { 18 | constructor(props) { 19 | super(props); 20 | this.state = { 21 | model: null 22 | }; 23 | this.onFieldChange = this.onFieldChange.bind(this); 24 | this.validate = this.validate.bind(this); 25 | } 26 | componentWillMount() { 27 | this.createFields(this.props.fields); // Create all the fields 28 | this.setModel(); // set Current state of HOC 29 | } 30 | componentDidMount() { 31 | /* 32 | initialize the form on client side, as we can access storage easily and 33 | can avoid the Dom difference. 34 | */ 35 | let initialState = getInitialState && getInitialState(this.props); 36 | if (!initialState) { 37 | initialState = {}; 38 | } 39 | const state = this.props.currentForm; 40 | const initialized = state && state.initialized ? state.initialized : false; 41 | // Make initialized only if object is not empty 42 | if (!initialized && Object.keys(initialState).length > 0) { 43 | this.props.actions.initialize(initialState, form, this.props.fields); 44 | this.setModel(); 45 | } 46 | } 47 | componentWillReceiveProps(nextProps) { 48 | // console.log('NextProps.currentForm', nextProps.currentForm); 49 | if (!deepEqual(this.props.currentForm, nextProps.currentForm)) { 50 | const currentFields = Object.keys(this.fields); 51 | if (!deepEqual(currentFields, nextProps.fields)) { 52 | this.createFields(nextProps.fields); // Create all the fields 53 | } 54 | this.setModel(nextProps.currentForm); // set Current state of HOC 55 | } 56 | // Need to compare and then do this thing 57 | const state = this.props.currentForm; 58 | const initialized = state && state.initialized ? state.initialized : false; 59 | if (!initialized) { 60 | const initialState = getInitialState && getInitialState(nextProps); 61 | if (initialState) { 62 | this.props.actions.initialize(initialState, form, this.props.fields); 63 | } 64 | } 65 | } 66 | componentWillUnmount() { 67 | this.fields = null; 68 | } 69 | onFieldChange(field, value) { 70 | this.props.actions.setField(field, value, form); 71 | } 72 | setModel(newState) { 73 | const fieldsKeys = Object.keys(this.fields); 74 | this.values = simplifiedVlaues(newState, fieldsKeys); 75 | // We are passing two arguments to validate function 76 | // Second can be used for dynamic validation usecase 77 | const errors = validate(this.values, this.props); 78 | fieldsKeys.forEach(field => { 79 | const { fields, values } = this; 80 | fields[field].value = values[field]; 81 | fields[field].error = errors && errors[field] ? errors[field] : undefined; 82 | fields[field].touched = newState && newState[field] ? newState[field].touched : false; 83 | }); 84 | this.fields = { ...this.fields }; 85 | this.allValid = !hasSyncErrors(errors); 86 | // this.setState({ model: newState }); 87 | } 88 | /* 89 | TODO::This needs to be triggred before every submit. 90 | We can commbine this to handle All submit which will 91 | make sure it validates and gives value back with returning 92 | promise. 93 | */ 94 | validate() { 95 | this.props.actions.touchAll(form, this.props.fields); 96 | return this.allValid; 97 | } 98 | // Create all Fields with all sugar functions 99 | createFields(fieldList) { 100 | const formFields = fieldList.reduce((fields, field) => ({ 101 | ...fields, 102 | [field]: createField(field, this.onFieldChange) 103 | }), {}); 104 | this.fields = { ...formFields }; 105 | } 106 | render() { 107 | return ( 108 | ); 115 | } 116 | } 117 | SimpleReduxForm.propTypes = { 118 | fields: PropTypes.array, 119 | actions: PropTypes.object, 120 | currentForm: PropTypes.object, 121 | }; 122 | SimpleReduxForm.defaultProps = { 123 | fields: initFields // Take either from the Decorator or else as props 124 | }; 125 | function mapStateToProps(state) { 126 | return { 127 | currentForm: state.forms[form] 128 | }; 129 | } 130 | function mapDispatchToProps(dispatch) { 131 | return { 132 | actions: bindActionCreators({ 133 | setField, 134 | initialize, 135 | touchAll, 136 | }, dispatch), 137 | dispatch 138 | }; 139 | } 140 | return connect(mapStateToProps, mapDispatchToProps)(SimpleReduxForm); 141 | } 142 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var env = process.env.NODE_ENV; 3 | 4 | var reactExternal = { 5 | root: 'React', 6 | commonjs2: 'react', 7 | commonjs: 'react', 8 | amd: 'react' 9 | }; 10 | 11 | var plugins = [ 12 | new webpack.DefinePlugin({ 13 | 'process.env.NODE_ENV': JSON.stringify(env) 14 | }), 15 | new webpack.optimize.OccurenceOrderPlugin() 16 | ]; 17 | 18 | if (env === 'production') { 19 | plugins.push( 20 | new webpack.optimize.UglifyJsPlugin({ 21 | compressor: { 22 | screw_ie8: true, 23 | warnings: false 24 | } 25 | }) 26 | ); 27 | } 28 | 29 | module.exports = { 30 | externals: { 31 | react: reactExternal 32 | }, 33 | module: { 34 | loaders: [ 35 | { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ } 36 | ] 37 | }, 38 | output: { 39 | library: 'SimpleReduxForm', 40 | libraryTarget: 'umd' 41 | }, 42 | plugins: plugins, 43 | resolve: { 44 | extensions: ['', '.js'] 45 | } 46 | }; 47 | --------------------------------------------------------------------------------