├── .babelrc ├── .gitconfig ├── .gitignore ├── .npmignore ├── .package.json ├── .webpack.config.js ├── README.md ├── customize.js ├── devserver.js ├── index.tpl.html ├── package.json ├── src ├── component.js ├── dev.js ├── index.js ├── reducers │ ├── index.js │ └── sample.js └── redux-setup.js ├── test └── test.spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react", "babel-preset-stage-0"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | precomposeunicode = true 8 | [remote "origin"] 9 | url = https://github.com/calvinfroedge/react-redux-workbench.git 10 | fetch = +refs/heads/*:refs/remotes/origin/* 11 | [branch "master"] 12 | remote = origin 13 | merge = refs/heads/master 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | node_modules 3 | dist 4 | lib 5 | es 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | .gitconfig 3 | .package.json 4 | .webpack.config.js 5 | -------------------------------------------------------------------------------- /.package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-workbench", 3 | "version": "0.0.1", 4 | "description": "description-customize-me", 5 | "main": "lib/index.js", 6 | "jsnext:main": "es/index.js", 7 | "scripts": { 8 | "clean": "rimraf lib dist es", 9 | "test": "cross-env NODE_ENV=build BABEL_ENV=commonjs mocha --compilers js:babel-register --recursive", 10 | "build:commonjs": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs ./node_modules/babel-cli/bin/babel.js src --out-dir lib", 11 | "build:es": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=es ./node_modules/babel-cli/bin/babel.js src --out-dir es", 12 | "build:umd": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=build ./node_modules/webpack/bin/webpack.js src/index.js dist/react-redux-workbench.js", 13 | "build:umd:min": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=production ./node_modules/webpack/bin/webpack.js src/index.js dist/react-redux-workbench.min.js", 14 | "build": "NODE_ENV=build npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", 15 | "customize": "./node_modules/babel-cli/bin/babel-node.js customize.js", 16 | "development": "NODE_ENV=development nodemon devserver.js --ignore src/ --exec ./node_modules/babel-cli/bin/babel-node.js", 17 | "prepublish": "npm run clean && npm run build" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/calvinfroedge/react-redux-workbench.git" 22 | }, 23 | "keywords": [ 24 | "react", 25 | "redux", 26 | "helpers", 27 | "state", 28 | "modifiers" 29 | ], 30 | "author": "Calvin Froedge ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/calvinfroedge/react-redux-workbench/issues" 34 | }, 35 | "homepage": "https://github.com/calvinfroedge/react-redux-workbench#readme", 36 | "dependencies": { 37 | "html-webpack-plugin": "^2.16.0", 38 | "webpack-hot-middleware": "^2.10.0" 39 | }, 40 | "devDependencies": { 41 | "babel-cli": "^6.7.5", 42 | "babel-core": "^6.7.4", 43 | "babel-loader": "^6.2.4", 44 | "babel-plugin-transform-runtime": "^6.6.0", 45 | "babel-preset-es2015": "^6.6.0", 46 | "babel-preset-react": "^6.5.0", 47 | "babel-preset-stage-0": "^6.5.0", 48 | "babel-register": "^6.7.2", 49 | "cross-env": "^1.0.7", 50 | "expect": "^1.16.0", 51 | "express": "^4.13.4", 52 | "jsdom": "^8.1.0", 53 | "mocha": "^2.4.5", 54 | "mocha-jsdom": "^1.1.0", 55 | "react": "^15.0.1", 56 | "react-dom": "^15.0.1", 57 | "react-redux": "^4.4.5", 58 | "redux": "^3.4.0", 59 | "redux-actions": "^0.9.1", 60 | "redux-devtools": "^3.2.0", 61 | "redux-devtools-dock-monitor": "^1.1.1", 62 | "redux-devtools-log-monitor": "^1.0.11", 63 | "rimraf": "^2.5.2", 64 | "webpack": "^1.12.14", 65 | "webpack-dev-middleware": "^1.6.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var webpack = require('webpack') 4 | var path = require('path') 5 | var HtmlWebpackPlugin = require('html-webpack-plugin') 6 | 7 | var env = process.env.NODE_ENV; 8 | 9 | var config = { 10 | module: { 11 | loaders: [ 12 | { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }, 13 | { test: /\.json?$/, loader: 'json' }, 14 | { test: /\.css$/, loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]' }, 15 | { test: /\.less$/, loader: "style!css!less" } 16 | ] 17 | }, 18 | plugins: [ 19 | new webpack.optimize.OccurenceOrderPlugin(), 20 | new webpack.DefinePlugin({ 21 | 'process.env.NODE_ENV': JSON.stringify(env) 22 | }) 23 | ] 24 | }; 25 | 26 | if(env === 'build'){ 27 | config.output = { 28 | library: 'ReactReduxWorkbench', 29 | libraryTarget: 'umd' 30 | } 31 | } else if(env === 'development'){ 32 | config.devtool = 'eval-source-map'; 33 | 34 | config.entry = [ 35 | 'webpack-hot-middleware/client?reload=true', 36 | path.join(__dirname, 'src/dev.js') 37 | ]; 38 | 39 | config.output = { 40 | path: path.join(__dirname, '/dist/'), 41 | filename: 'react-redux-workbench.js', 42 | publicPath: '/' 43 | }; 44 | 45 | config.plugins = config.plugins.concat([ 46 | new HtmlWebpackPlugin({ 47 | template: 'index.tpl.html', 48 | inject: 'body', 49 | filename: 'index.html' 50 | }), 51 | new webpack.HotModuleReplacementPlugin(), 52 | new webpack.NoErrorsPlugin() 53 | ]); 54 | } else if (env === 'production') { 55 | config.plugins.push( 56 | new webpack.optimize.UglifyJsPlugin({ 57 | compressor: { 58 | pure_getters: true, 59 | unsafe: true, 60 | unsafe_comps: true, 61 | screw_ie8: true, 62 | warnings: false 63 | } 64 | }) 65 | ) 66 | } 67 | 68 | module.exports = config 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Motivation 2 | 3 | This project was borne out of the need to quickly spin up a new environment for authoring React + Redux components. 4 | 5 | The hope is that you can essentially run `npm install && npm run development` and have a work panel with hot reloading for building your component interactively. 6 | 7 | `react`, `webpack`, and `redux` are all used. Running `npm run development` starts a webpack dev server, and you can get to work building out your component! 8 | 9 | When you're ready to run tests, you can run `npm test`. 10 | 11 | If you want to customize the project to point at your github / npm repo, after `npm install` just customize this readme, clear out git commits from this project: 12 | 13 | ``` 14 | rm -rf .git 15 | git init 16 | git add . 17 | ``` 18 | 19 | ...and 20 | 21 | ``` 22 | npm install 23 | ``` 24 | 25 | and run... 26 | 27 | ```js 28 | PROJECT_NAME=foo-bar PROJECT_DESCRIPTION='A really cool project' GITHUB_USERNAME=foo AUTHOR_NAME="Calvin Froedge" AUTHOR_EMAIL=calvinfroedge@gmail.com npm run customize 29 | ``` 30 | 31 | # Important Commands 32 | 33 | ## `npm test` 34 | 35 | Run tests (files in test folder named `TESTNAME.spec.js`) using mocha / expect. 36 | 37 | ## `npm build` 38 | 39 | Builds for es, commonjs, umd. This is ignored in git, but will be included in npm package. 40 | 41 | ## `npm run development` 42 | 43 | Starts the dev server. Go to `localhost:3000` to see your new component with live reload. You can pass `PORT` environment variable to customize this. 44 | 45 | # When you're ready to publish... 46 | 47 | Make sure you clean up the files you don't need! Here's a quick command: 48 | 49 | `rm .gitconfig .webpack.config.js .package.json` 50 | -------------------------------------------------------------------------------- /customize.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | let { PROJECT_NAME, PROJECT_DESCRIPTION, GITHUB_USERNAME, AUTHOR_NAME, AUTHOR_EMAIL } = process.env; 4 | 5 | if(!PROJECT_NAME || !PROJECT_DESCRIPTION || !GITHUB_USERNAME || !AUTHOR_NAME || !AUTHOR_EMAIL){ 6 | console.error('Must provide PROJECT_NAME, PROJECT_DESCRIPTION, GITHUB_USERNAME, AUTHOR_NAME, AUTHOR_EMAIL as environment variables!'); 7 | process.exit(); 8 | } 9 | 10 | RegExp.quote = function(str) { 11 | return str.replace(/([.?*+^$[\]\\(){}-])/g, "\\$1"); 12 | }; 13 | 14 | String.prototype.replaceAll = function(search, replace) 15 | { 16 | var re = new RegExp(RegExp.quote(search),"g"); 17 | return this.replace(re, replace); 18 | }; 19 | 20 | let oldName = 'react-redux-workbench'; 21 | let packageJSON = fs.readFileSync('./.package.json').toString(); 22 | let oldVersion = '"version": "'+JSON.parse(packageJSON).version+'"'; 23 | let newVersion = '"version": "0.0.1"'; 24 | let gitConfig = fs.readFileSync('./.gitconfig').toString(); 25 | let webpackConfig = fs.readFileSync('./.webpack.config.js').toString(); 26 | let projectName = PROJECT_NAME; 27 | let repo = [GITHUB_USERNAME, `${projectName}`].join('/'); 28 | let gitConfigNew = gitConfig.replaceAll(`calvinfroedge/${oldName}`, repo); 29 | let file = projectName.replaceAll(' ', '-').toLowerCase(); 30 | let packageJSONNEW = packageJSON.replaceAll(oldName, file).replaceAll('Calvin Froedge', AUTHOR_NAME).replaceAll('calvinfroedge@gmail.com', AUTHOR_EMAIL).replaceAll('description-customize-me', PROJECT_DESCRIPTION).replaceAll(oldVersion, newVersion); 31 | let webpackConfigNEW = webpackConfig.replaceAll('ReactReduxWorkbench', projectName.replaceAll(' ', '')).replaceAll(oldName, file); 32 | fs.writeFileSync('./.git/config', gitConfigNew); 33 | fs.writeFileSync('./package.json', packageJSONNEW); 34 | fs.writeFileSync('./webpack.config.js', webpackConfigNEW); 35 | console.info('Wrote updates to package.json, .git/config, and wepback.config.js.\n'); 36 | -------------------------------------------------------------------------------- /devserver.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import express from 'express'; 3 | import webpack from 'webpack'; 4 | import webpackMiddleware from 'webpack-dev-middleware'; 5 | import webpackHotMiddleware from 'webpack-hot-middleware'; 6 | import config from './webpack.config.js'; 7 | 8 | const port = process.env.PORT ? process.env.PORT : 3000; 9 | const app = express(); 10 | const compiler = webpack(config); 11 | const middleware = webpackMiddleware(compiler, { 12 | publicPath: config.output.publicPath, 13 | contentBase: 'src', 14 | stats: { 15 | colors: true, 16 | hash: false, 17 | timings: true, 18 | chunks: false, 19 | chunkModules: false, 20 | modules: false 21 | } 22 | }); 23 | 24 | app.use(middleware); 25 | app.use(webpackHotMiddleware(compiler)); 26 | app.get('*', (req, res)=>{ 27 | res.write(middleware.fileSystem.readFileSync(path.join(__dirname, 'dist/index.html'))); 28 | res.end(); 29 | }); 30 | 31 | app.listen(port, '0.0.0.0', (err)=>{ 32 | if (err) { 33 | console.log(err); 34 | } 35 | console.info('==> 🌎 Listening on port %s. Open up http://0.0.0.0:%s/ in your browser.', port, port); 36 | }); 37 | -------------------------------------------------------------------------------- /index.tpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | react-kickstart 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-workbench", 3 | "version": "0.0.5", 4 | "description": "Get your react + redux components off the ground faster", 5 | "main": "lib/index.js", 6 | "jsnext:main": "es/index.js", 7 | "scripts": { 8 | "clean": "rimraf lib dist es", 9 | "test": "cross-env NODE_ENV=build BABEL_ENV=commonjs mocha --compilers js:babel-register --recursive", 10 | "build:commonjs": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs ./node_modules/babel-cli/bin/babel.js src --out-dir lib", 11 | "build:es": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=es ./node_modules/babel-cli/bin/babel.js src --out-dir es", 12 | "build:umd": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=build ./node_modules/webpack/bin/webpack.js src/index.js dist/react-redux-workbench.js", 13 | "build:umd:min": "./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=production ./node_modules/webpack/bin/webpack.js src/index.js dist/react-redux-workbench.min.js", 14 | "build": "NODE_ENV=build npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", 15 | "customize": "./node_modules/babel-cli/bin/babel-node.js customize.js", 16 | "development": "NODE_ENV=development nodemon devserver.js --ignore src/ --exec ./node_modules/babel-cli/bin/babel-node.js", 17 | "prepublish": "npm run clean && npm run build" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/calvinfroedge/react-redux-workbench.git" 22 | }, 23 | "keywords": [ 24 | "react", 25 | "redux", 26 | "helpers", 27 | "state", 28 | "modifiers" 29 | ], 30 | "author": "Calvin Froedge ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/calvinfroedge/react-redux-workbench/issues" 34 | }, 35 | "homepage": "https://github.com/calvinfroedge/react-redux-workbench#readme", 36 | "dependencies": { 37 | "html-webpack-plugin": "^2.16.0", 38 | "webpack-hot-middleware": "^2.10.0" 39 | }, 40 | "devDependencies": { 41 | "babel-cli": "^6.7.5", 42 | "babel-core": "^6.7.4", 43 | "babel-loader": "^6.2.4", 44 | "babel-plugin-transform-runtime": "^6.6.0", 45 | "babel-preset-es2015": "^6.6.0", 46 | "babel-preset-react": "^6.5.0", 47 | "babel-preset-stage-0": "^6.5.0", 48 | "babel-register": "^6.7.2", 49 | "cross-env": "^1.0.7", 50 | "expect": "^1.16.0", 51 | "express": "^4.13.4", 52 | "jsdom": "^8.1.0", 53 | "mocha": "^2.4.5", 54 | "mocha-jsdom": "^1.1.0", 55 | "react": "^15.0.1", 56 | "react-dom": "^15.0.1", 57 | "react-redux": "^4.4.5", 58 | "redux": "^3.4.0", 59 | "redux-actions": "^0.9.1", 60 | "redux-devtools": "^3.2.0", 61 | "redux-devtools-dock-monitor": "^1.1.1", 62 | "redux-devtools-log-monitor": "^1.0.11", 63 | "rimraf": "^2.5.2", 64 | "webpack": "^1.12.14", 65 | "webpack-dev-middleware": "^1.6.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/component.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | class BaseComponent extends React.Component { 4 | render(){ 5 | return
Hello, world!
6 | } 7 | } 8 | 9 | export default BaseComponent; 10 | -------------------------------------------------------------------------------- /src/dev.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { BaseComponent } from './index'; 4 | 5 | //Redux 6 | import {DevTools, store} from './redux-setup.js'; 7 | import { Provider } from 'react-redux'; 8 | 9 | ReactDOM.render( 10 | 11 |
12 | 13 | 14 |
15 |
16 | , document.getElementById('root') 17 | ); 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export BaseComponent from './component' 2 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | export sample from './sample' 2 | -------------------------------------------------------------------------------- /src/reducers/sample.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | 3 | export default handleActions({ 4 | 'sample': (state, action)=>{ 5 | return state; 6 | } 7 | }, 'this is only a sample reducer!'); 8 | -------------------------------------------------------------------------------- /src/redux-setup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | //Redux DevTools 4 | import { createDevTools } from 'redux-devtools'; 5 | import LogMonitor from 'redux-devtools-log-monitor'; 6 | import DockMonitor from 'redux-devtools-dock-monitor'; 7 | 8 | //Redux 9 | import { applyMiddleware, compose, createStore, combineReducers } from 'redux'; 10 | 11 | //Reducers 12 | import * as reducers from './reducers/index'; 13 | 14 | //Set up Redux Middleware 15 | const reducer = combineReducers({ 16 | ...reducers 17 | }) 18 | 19 | //Set up Dev Tools 20 | const DevTools = createDevTools( 21 | 23 | 24 | 25 | ) 26 | 27 | //Create the store 28 | const finalCreateStore = compose( 29 | DevTools.instrument() 30 | )(createStore); 31 | 32 | const store = finalCreateStore(reducer); 33 | 34 | //Exports 35 | export default store; 36 | export {DevTools, store} 37 | -------------------------------------------------------------------------------- /test/test.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | 3 | describe('Test should run', ()=>{ 4 | it('should add 1 and 1', ()=>{ 5 | expect(1+1).toBe(2); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var webpack = require('webpack') 4 | var path = require('path') 5 | var HtmlWebpackPlugin = require('html-webpack-plugin') 6 | 7 | var env = process.env.NODE_ENV; 8 | 9 | var config = { 10 | module: { 11 | loaders: [ 12 | { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }, 13 | { test: /\.json?$/, loader: 'json' }, 14 | { test: /\.css$/, loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]' }, 15 | { test: /\.less$/, loader: "style!css!less" } 16 | ] 17 | }, 18 | plugins: [ 19 | new webpack.optimize.OccurenceOrderPlugin(), 20 | new webpack.DefinePlugin({ 21 | 'process.env.NODE_ENV': JSON.stringify(env) 22 | }) 23 | ] 24 | }; 25 | 26 | if(env === 'build'){ 27 | config.output = { 28 | library: 'ReactReduxWorkbench', 29 | libraryTarget: 'umd' 30 | } 31 | } else if(env === 'development'){ 32 | config.devtool = 'eval-source-map'; 33 | 34 | config.entry = [ 35 | 'webpack-hot-middleware/client?reload=true', 36 | path.join(__dirname, 'src/dev.js') 37 | ]; 38 | 39 | config.output = { 40 | path: path.join(__dirname, '/dist/'), 41 | filename: 'react-redux-workbench.js', 42 | publicPath: '/' 43 | }; 44 | 45 | config.plugins = config.plugins.concat([ 46 | new HtmlWebpackPlugin({ 47 | template: 'index.tpl.html', 48 | inject: 'body', 49 | filename: 'index.html' 50 | }), 51 | new webpack.HotModuleReplacementPlugin(), 52 | new webpack.NoErrorsPlugin() 53 | ]); 54 | } else if (env === 'production') { 55 | config.plugins.push( 56 | new webpack.optimize.UglifyJsPlugin({ 57 | compressor: { 58 | pure_getters: true, 59 | unsafe: true, 60 | unsafe_comps: true, 61 | screw_ie8: true, 62 | warnings: false 63 | } 64 | }) 65 | ) 66 | } 67 | 68 | module.exports = config 69 | --------------------------------------------------------------------------------