├── .gitignore ├── README.md ├── examples ├── react-example │ ├── .gitignore │ ├── README.md │ ├── car.js │ ├── carlist.js │ ├── carshop.js │ ├── package.json │ ├── public │ │ └── index.html │ ├── selection.js │ ├── server.js │ ├── server │ │ └── compiler.js │ └── webpack.config.js └── redux-example │ ├── .gitignore │ ├── README.md │ ├── actions.js │ ├── car.js │ ├── carlist.js │ ├── carshop.js │ ├── package.json │ ├── public │ └── index.html │ ├── reducerCars.js │ ├── root.js │ ├── selection.js │ ├── server.js │ ├── server │ └── compiler.js │ └── webpack.config.js ├── full-boilerplate ├── .gitignore ├── actions │ └── actions.js ├── compiler │ └── compiler.js ├── package.json ├── public │ └── index.html ├── reducers │ ├── reducerGreeting.js │ └── reducers.js ├── server.js ├── src │ ├── components │ │ ├── App.js │ │ ├── GoodbyeWorld.js │ │ └── HelloWorld.js │ ├── index.js │ ├── root.js │ └── routes.js ├── webpack.config.js └── webpack.production.config.js ├── react, express, webpack, basic ├── .babelrc ├── .gitignore ├── index.js ├── package.json ├── public │ └── index.html ├── server.js └── webpack.config.js ├── react, express, webpack, development ├── .babelrc ├── .gitignore ├── index.js ├── package.json ├── public │ └── index.html ├── server.js ├── server │ └── compiler.js └── webpack.config.js ├── react, express, webpack, production ├── .babelrc ├── .gitignore ├── index.js ├── npm-debug.log ├── package.json ├── public │ └── index.html ├── server.js ├── server │ └── compiler.js ├── webpack.config.js └── webpack.production.config.js └── react, redux, webpack, express, production ├── .gitignore ├── actions.js ├── index.js ├── package.json ├── public └── index.html ├── reducers.js ├── root.js ├── server.js ├── server └── compiler.js ├── webpack.config.js └── webpack.production.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bundle.js 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | As I was trying to learn the React ecosystem I had a hard time finding the barebones that I needed in order to start a project. My goal with this repo is to show the minimum that it takes to get a project off the ground in React using Webpack with a server. It has since grown to show a couple of examples--one in just React, and the other converted from just React to React and Redux. 3 | 4 | Read more about webpack here: https://medium.com/@colinlmcdonald/webpack-ec0dddea1195#.1z425oes1 5 | 6 | ## Installation 7 | In any of the folders run: 8 | 9 | npm install 10 | 11 | Please note that a for the production example, npm install will create a 'build' folder inside of 'public'. In order to have the webpack-dev-server running with Express, please delete that folder. 12 | 13 | The reason that it is there is because in package.json there is a 'postinstall' script that is run. This is for deploying to Heroku so that webpack bundles your project correctly before running npm start. 14 | 15 | # React, Webpack, Express, Basic 16 | ## To Start 17 | 18 | webpack OR webpack--watch 19 | 20 | node server.js 21 | 22 | The webpack command bundles your project and exports bundle.js to public/build folder. Webpack --watch does the same thing, but will re-bundle your project whenever you save. The express server serves index.html which points to your bundle.js. 23 | 24 | # React, Webpack, Express, Development 25 | ## To Start 26 | 27 | node server.js 28 | 29 | This example shows how to use an Express server alongside a webpack-dev-server. Webpack-dev-server itself creates a small Express server to serve your bundled static assets from memory. It does not create a physical copy of bundle.js. Your Express server, using http-proxy, proxies all requests to /build and sends it to your webpack-dev-server located on port 8080. 30 | 31 | # React, Webpack, Express, Production 32 | ## To Start 33 | 34 | node server.js 35 | 36 | This is the same as the development example with an added 'production' config for Webpack. It also has a 'postinstall' script that is ran after npm install is ran. The script will create a bundle.js in /public/build. If you want to use the development mode, delete the build folder or comment out the posinstall script in package.json before running npm install. 37 | 38 | The posinstall script is for when deploying to heroku so that a physical bundle.js is created. It also sets the NODE_ENV to production so that requests are not proxied to the webpack-dev-server. 39 | 40 | # React, Redux, Webpack, Express, Production 41 | ## To Start 42 | 43 | node server.js 44 | 45 | This is the same as the production example above but with a basic Redux layout. Redux manages the state of your application in something called a 'store'. Your components dispatch action objects to your store. A reducer then merges the previous state with what you want changed to create the new state. 46 | 47 | It also uses the react-redux module to implicitly pass down your store to your components so that they have access to the dispatch function, which is used to communicate with the store, in their props. See the comments in the files for more information on what is happening. 48 | 49 | # React Example 50 | ## To Start 51 | 52 | node server.js 53 | 54 | This example uses the 'development' webpack with express example mentioned previously. The example is a car shop which has different services. As you click on the different radio buttons, it updates the state with the chosen service. As you click 'add car' a car with that service is added to the corresponding queue. The UI/UX leaves much to be desired, but it shows some basic functionality with React, forms, and utilizing some of the cool things that are capable in ES2015. See the comments for more information. 55 | 56 | # Redux Example 57 | ## To Start 58 | 59 | node server.js 60 | 61 | This example also uses the 'development' webpack with express example. For this project I took the react-example and translated the state changes from the native methods of React into Redux. Redux does not ship with native async support for AJAX calls so you need to install redux-thunk. When the component will mount, an action creator is dispatched to the store. This action fetches the different car services from the server and then dispatches them to the store. See the comments for more information. 62 | -------------------------------------------------------------------------------- /examples/react-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /examples/react-example/README.md: -------------------------------------------------------------------------------- 1 | # React Example 2 | ## To Start 3 | npm install 4 | 5 | node server.js 6 | 7 | ## Organization 8 | Carshop.js is the heart of the app. Selection.js contains the radio buttons. Carlist.js is for the different lists of cars that get added to the carshop. Car.js is for an individual car added to list. 9 | -------------------------------------------------------------------------------- /examples/react-example/car.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | //See carlist for an explanation of a stateless functional component. 4 | const Car = ({car}) => ( 5 |
{car}
6 | ) 7 | 8 | export default Car -------------------------------------------------------------------------------- /examples/react-example/carlist.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Car from './car' 3 | 4 | //This is an example of a stateless functional React component. It uses the fat arrow function from ES2015 5 | //to return a single node (in this case a
). Here JSX is used within the HTML to map over the different 6 | //cars that have been passed down from the parent component. Map returns our Car component, passing in an individual 7 | //car. React uses the 'key' property of a component for its diffing algorithm, so it is important to include it 8 | //for performance reasons. 9 | const CarList = ({cars, service}) => ( 10 |
{service} 11 |
12 | {cars.map((car) => { 13 | return 14 | })} 15 |
16 |
17 | ) 18 | 19 | export default CarList 20 | 21 | //** Notice that this functional component is being passed {cars, service} as its argument. This is using 22 | //ES2015's object destructuring which takes the object that is passed in from the parent component and makes 23 | //its values available as cars & service. -------------------------------------------------------------------------------- /examples/react-example/carshop.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import Service from './selection' 4 | import CarList from './carlist' 5 | 6 | //Constructor is a method on the class object in ES2015. Here we set our initial state and also bind our methods. 7 | class CarShop extends Component { 8 | constructor(props) { 9 | super(props) 10 | this.state = { 11 | services: ['Car Wash', 'Smog Check', 'Repair'], 12 | 'Car Wash': [], 13 | 'Smog Check': [], 14 | 'Repair': [], 15 | chosen: '' 16 | } 17 | this.handleChange = this.handleChange.bind(this) 18 | this.addCar = this.addCar.bind(this) 19 | } 20 | 21 | //setState triggers a re-render of the component and does not immediately mutate the data. 22 | addCar(e) { 23 | e.preventDefault() 24 | const { chosen } = this.state 25 | //in ES2015 you can set keys as shown below with [chosen] 26 | this.setState({ [chosen]: this.state[chosen].concat([chosen])}) 27 | } 28 | 29 | handleChange(e, value) { 30 | this.setState({chosen: value}) 31 | } 32 | 33 | //onSubmit we are running a function that grabs the event and passes it to handleChange(). The event is represented by 'e'. 34 | render() { 35 | return ( 36 |
37 |
this.addCar(e)}> 38 | {/* We're mapping over this.state.services and returning a Service component for each service, passing down the service and this component's handleChange() method. It's important to also include a key as React uses this in its diffing algorithm. */} 39 | {this.state.services.map((service, i) => { 40 | return 41 | })} 42 | 43 | 44 |
45 | {this.state.services.map((service, i) => { 46 | return 47 | })} 48 |
49 |
50 | ) 51 | } 52 | } 53 | 54 | render(, document.getElementById('app')) 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/react-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "my1stnpmpackage": "^1.0.2", 4 | "react": "^0.14.7", 5 | "react-dom": "^0.14.7", 6 | "react-redux": "^4.4.1", 7 | "redux": "^3.3.1", 8 | "webpack": "^1.9.11" 9 | }, 10 | "devDependencies": { 11 | "babel-core": "^6.3.15", 12 | "babel-loader": "^6.2.0", 13 | "babel-preset-es2015": "^6.3.13", 14 | "babel-preset-react": "^6.3.13", 15 | "express": "^4.13.3", 16 | "http-proxy": "^1.13.2", 17 | "react-hot-loader": "^1.3.0", 18 | "webpack-dev-middleware": "^1.2.0", 19 | "webpack-dev-server": "^1.14.1", 20 | "webpack-hot-middleware": "^2.9.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/react-example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/react-example/selection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Service = ({service, handleChange, chosen}) => ( 4 |
5 | handleChange(e, service)} /> {service} 6 |
7 | ) 8 | 9 | export default Service 10 | -------------------------------------------------------------------------------- /examples/react-example/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | var port = 3000; 7 | 8 | // We need to add a configuration to our proxy server, 9 | // as we are now proxying outside localhost 10 | var proxy = httpProxy.createProxyServer({ 11 | changeOrigin: true 12 | }); 13 | 14 | var app = express(); 15 | 16 | //serving our index.html 17 | app.use(express.static(publicPath)); 18 | 19 | //server/compiler.js runs webpack-dev-server which creates the bundle.js which index.html serves. 20 | //The compiler adds some console logs for some extra sugar. 21 | //Notice that you will not see a physical bundle.js because webpack-dev-server runs it from memory. 22 | var bundle = require('./server/compiler.js') 23 | bundle() 24 | 25 | //express now processes all requests to localhost:8080/build/* 26 | //app.all is a special routing method used for loading middleware functions 27 | app.all('/build/*', function (req, res) { 28 | proxy.web(req, res, { 29 | target: 'http://localhost:8080' 30 | }) 31 | }) 32 | 33 | proxy.on('error', function(e) { 34 | console.log('Could not connect to proxy, please try again...') 35 | }); 36 | 37 | app.listen(port, function () { 38 | console.log('Server running on port ' + port) 39 | }); -------------------------------------------------------------------------------- /examples/react-example/server/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /examples/react-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './carshop.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /examples/redux-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /examples/redux-example/README.md: -------------------------------------------------------------------------------- 1 | # Redux Example 2 | ## To Start 3 | npm install 4 | 5 | node server.js 6 | 7 | ## File Structure 8 | Root.js provides some of the set-up for the frontend. This is where our Redux store is created and where React is directed to render our application. Carshop.js contains our components (carlist.js, car.js, selection.js). When our CarShop component will mount it dispataches an action (located in action.js) to our store which is then heard by our reducer (reducerCars.js) which creates our new state that is returned to our CarShop component. 9 | -------------------------------------------------------------------------------- /examples/redux-example/actions.js: -------------------------------------------------------------------------------- 1 | //Action creators must return an object, unless combined with thunk middleware. 2 | 3 | export const HANDLE_CHOSEN = 'HANDLE_CHOSEN' 4 | export const ADD_CAR = 'ADD_CAR' 5 | export const RECEIVE_SERVICES = 'RECEIVE_SERVICES' 6 | 7 | //This action creator returns an action object, which is what Redux is looking for. 8 | export function handleChosen(service) { 9 | return { 10 | type: HANDLE_CHOSEN, 11 | service 12 | } 13 | } 14 | 15 | export function addCarToService() { 16 | return { 17 | type: ADD_CAR 18 | } 19 | } 20 | 21 | //Here we're returning a function which we need the thunk middleware for. At line 24, dispatch is an argument available because of the thunk middlware. 22 | export function getServices() { 23 | return dispatch => { 24 | return fetch('/services') 25 | .then(response => response.json()) 26 | .then(json => dispatch(receiveServices(json))) 27 | } 28 | } 29 | 30 | function receiveServices(services) { 31 | return { 32 | type: RECEIVE_SERVICES, 33 | services 34 | } 35 | } -------------------------------------------------------------------------------- /examples/redux-example/car.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Car = ({car}) => ( 4 |
{car}
5 | ) 6 | 7 | export default Car -------------------------------------------------------------------------------- /examples/redux-example/carlist.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Car from './car' 3 | 4 | const CarList = ({cars, service}) => ( 5 |
{service} 6 |
7 | {cars.map((car, i) => { 8 | return 9 | })} 10 |
11 |
12 | ) 13 | 14 | export default CarList -------------------------------------------------------------------------------- /examples/redux-example/carshop.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import { connect } from 'react-redux' 4 | import Service from './selection' 5 | import CarList from './carlist' 6 | import { handleChosen, addCarToService, getServices } from './actions' 7 | 8 | //React class Component which gives our component to the React lifecycle methods. 9 | //We use the constructor method on the class object to handle our binding. 10 | class CarShop extends Component { 11 | constructor(props) { 12 | super(props) 13 | this.handleChange = this.handleChange.bind(this) 14 | this.addCar = this.addCar.bind(this) 15 | } 16 | 17 | addCar(e) { 18 | e.preventDefault() 19 | //Dispatch sends an action creator to the store. This action creator returns an action object. 20 | const { chosen, dispatch } = this.props 21 | dispatch(addCarToService()) 22 | } 23 | 24 | handleChange(e, value) { 25 | this.props.dispatch(handleChosen(value)) 26 | } 27 | 28 | //componentWillMount is a lifecycle method. Before the component is mounted, we dispatch an action creator 29 | //which makes a call to our server. We need the thunk middleware because it returns a promise, which is a function, 30 | //and native dispatch only accepts action objects. 31 | componentWillMount() { 32 | this.props.dispatch(getServices()) 33 | } 34 | 35 | render() { 36 | return ( 37 |
38 |
this.addCar(e)}> 39 | {this.props.services.map((service, i) => { 40 | return 41 | })} 42 | 43 | 44 |
45 | {this.props.services.map((service, i) => { 46 | return 47 | })} 48 |
49 |
50 | ) 51 | } 52 | } 53 | 54 | //We're literally mapping the state, which we receive from the store, to the props of this component. 55 | //The object that we return from this function will be available on this.props, i.e. this.props.services, 56 | //this.props.chosen, etc. 57 | function mapStateToProps(state) { 58 | const services = state.services 59 | const chosen = state.chosen 60 | if (services.length) { 61 | let serviceOptions 62 | services.forEach(service => { 63 | serviceOptions = Object.assign({}, serviceOptions, { 64 | [service]: state[service], 65 | services, 66 | chosen 67 | }) 68 | }) 69 | return serviceOptions 70 | } else { 71 | return { 72 | services, 73 | chosen 74 | } 75 | } 76 | } 77 | 78 | //Connect is a method from react-redux. This is what connects our different components to the store so 79 | //that they can see the new state that is returned. 80 | export default connect(mapStateToProps)(CarShop) 81 | 82 | 83 | -------------------------------------------------------------------------------- /examples/redux-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "isomorphic-fetch": "^2.2.1", 4 | "my1stnpmpackage": "^1.0.2", 5 | "react": "^0.14.7", 6 | "react-dom": "^0.14.7", 7 | "react-redux": "^4.4.1", 8 | "redux": "^3.3.1", 9 | "redux-thunk": "^2.1.0", 10 | "webpack": "^1.9.11" 11 | }, 12 | "devDependencies": { 13 | "babel-core": "^6.3.15", 14 | "babel-loader": "^6.2.0", 15 | "babel-preset-es2015": "^6.3.13", 16 | "babel-preset-react": "^6.3.13", 17 | "express": "^4.13.3", 18 | "http-proxy": "^1.13.2", 19 | "react-hot-loader": "^1.3.0", 20 | "webpack-dev-middleware": "^1.2.0", 21 | "webpack-dev-server": "^1.14.1", 22 | "webpack-hot-middleware": "^2.9.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/redux-example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/redux-example/reducerCars.js: -------------------------------------------------------------------------------- 1 | //We import the different action types from our actions file 2 | import { HANDLE_CHOSEN, RECEIVE_SERVICES, ADD_CAR } from './actions' 3 | 4 | //On its first pass, Redux passes 'undefined' and an empty object into all the reducers that handle the store. In ES2015 if you pass undefined into a function, as Redux does, you can set that argument to something, in this case an object with two keys: services & chosen. 5 | 6 | export default function cars(state = { 7 | services: [], 8 | chosen: '' 9 | }, action) { 10 | switch(action.type) { 11 | case HANDLE_CHOSEN: 12 | return Object.assign({}, state, { 13 | chosen: action.service 14 | }) 15 | case ADD_CAR: 16 | return Object.assign({}, state, { 17 | [state.chosen]: state[state.chosen].concat([state.chosen]) 18 | }) 19 | case RECEIVE_SERVICES: 20 | action.services.forEach(service => { 21 | state[service] = [] 22 | }) 23 | return Object.assign({}, state, { 24 | services: action.services 25 | }) 26 | default: 27 | return state 28 | } 29 | } 30 | 31 | //Redux and React rely on immutable data. As I understand it, they do a comparison of the old state and the new state and check to see what is different. If you directly mutate the old state, there is nothing to compare. 32 | 33 | //Object.assign() merges object(s) to an empty object. By returning this new object we have not mutated the state. -------------------------------------------------------------------------------- /examples/redux-example/root.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore, applyMiddleware } from 'redux' 4 | import { Provider } from 'react-redux' 5 | import CarShop from './carshop' 6 | import cars from './reducerCars' 7 | import thunk from 'redux-thunk' 8 | import 'isomorphic-fetch' 9 | 10 | 11 | //Use createStore to create your redux store 12 | //In this case since we only have one reducer we pass it in. If you have multiple reducers, 13 | //use combineReducers instead. 14 | let store = createStore(cars, applyMiddleware(thunk)) 15 | 16 | //The Provider tag passes the store down implicitly via context. This puts the dispatch method of the store 17 | //on the props of all the elements connected to the component, in this case CarShop, that it wraps. 18 | render( 19 | 20 | 21 | , document.getElementById('app') 22 | ) -------------------------------------------------------------------------------- /examples/redux-example/selection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | //See the carlist file for more information about what is happening here. The only unique thing is that 4 | //we have passed a method from the parent component down (handleChange). 5 | const Service = ({service, handleChange, chosen}) => ( 6 |
7 | handleChange(e, service)} /> {service} 8 |
9 | ) 10 | 11 | export default Service 12 | -------------------------------------------------------------------------------- /examples/redux-example/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | var port = 3000; 7 | 8 | // We need to add a configuration to our proxy server, 9 | // as we are now proxying outside localhost 10 | var proxy = httpProxy.createProxyServer({ 11 | changeOrigin: true 12 | }); 13 | 14 | var app = express(); 15 | 16 | //serving our index.html 17 | app.use(express.static(publicPath)); 18 | 19 | //server/compiler.js runs webpack-dev-server which creates the bundle.js which index.html serves. 20 | //The compiler adds some console logs for some extra sugar. 21 | //Notice that you will not see a physical bundle.js because webpack-dev-server runs it from memory. 22 | var bundle = require('./server/compiler.js') 23 | bundle() 24 | 25 | //Express now proxies all requests to localhost:8080/build/* 26 | //app.all is a special routing method used for loading middleware functions 27 | app.all('/build/*', function (req, res) { 28 | proxy.web(req, res, { 29 | target: 'http://localhost:8080' 30 | }) 31 | }) 32 | 33 | proxy.on('error', function(e) { 34 | console.log('Could not connect to proxy, please try again...') 35 | }); 36 | 37 | app.listen(port, function () { 38 | console.log('Server running on port ' + port) 39 | }); -------------------------------------------------------------------------------- /examples/redux-example/server/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /examples/redux-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './root.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /full-boilerplate/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /full-boilerplate/actions/actions.js: -------------------------------------------------------------------------------- 1 | export const GET_HELLO_WORLD = 'GET_HELLO_WORLD', 2 | GET_GOODBYE_WORLD = 'GET_GOODBYE_WORLD' 3 | 4 | export function getHelloWorld() { 5 | return { 6 | type: GET_HELLO_WORLD, 7 | } 8 | } 9 | 10 | export function getGoodbyeWorld() { 11 | return { 12 | type: GET_GOODBYE_WORLD, 13 | } 14 | } -------------------------------------------------------------------------------- /full-boilerplate/compiler/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /full-boilerplate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": "4.4.0" 4 | }, 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "postinstall": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors" 9 | }, 10 | "dependencies": { 11 | "react": "^0.14.7", 12 | "react-dom": "^0.14.7", 13 | "react-redux": "^4.4.1", 14 | "react-router": "^2.4.1", 15 | "redux": "^3.3.1", 16 | "redux-thunk": "^2.1.0", 17 | "webpack": "^1.9.11" 18 | }, 19 | "devDependencies": { 20 | "babel-core": "^6.3.15", 21 | "babel-loader": "^6.2.0", 22 | "babel-preset-es2015": "^6.3.13", 23 | "babel-preset-react": "^6.3.13", 24 | "express": "^4.13.3", 25 | "http-proxy": "^1.13.2", 26 | "react-hot-loader": "^1.3.0", 27 | "webpack-dev-middleware": "^1.2.0", 28 | "webpack-dev-server": "^1.14.1", 29 | "webpack-hot-middleware": "^2.9.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /full-boilerplate/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /full-boilerplate/reducers/reducerGreeting.js: -------------------------------------------------------------------------------- 1 | import { GET_HELLO_WORLD, GET_GOODBYE_WORLD } from '../actions/actions' 2 | 3 | export function greeting(state = { 4 | hello: '', 5 | goodbye: '' 6 | }, action) { 7 | switch(action.type) { 8 | case GET_HELLO_WORLD: 9 | return Object.assign({}, state, { 10 | hello: 'Hello World', 11 | }) 12 | case GET_GOODBYE_WORLD: 13 | return Object.assign({}, state, { 14 | goodbye: 'Goodbye World', 15 | }) 16 | default: 17 | return state 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /full-boilerplate/reducers/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import { greeting } from './reducerGreeting' 3 | 4 | export default combineReducers({ 5 | greeting 6 | }) -------------------------------------------------------------------------------- /full-boilerplate/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | // We need to add a configuration to our proxy server, 7 | // as we are now proxying outside localhost 8 | var isProduction = process.env.NODE_ENV === 'production'; 9 | var port = isProduction ? process.env.PORT : 3000; 10 | 11 | var proxy = httpProxy.createProxyServer({ 12 | changeOrigin: true 13 | }); 14 | var app = express(); 15 | 16 | app.use(express.static(publicPath)); 17 | 18 | // If you only want this for development, you would of course 19 | // put it in the "if" block below 20 | 21 | if (!isProduction) { 22 | var bundle = require('./compiler/compiler.js') 23 | bundle() 24 | app.all('/build/*', function (req, res) { 25 | proxy.web(req, res, { 26 | target: 'http://localhost:8080' 27 | }) 28 | }) 29 | }; 30 | 31 | proxy.on('error', function(e) { 32 | console.log('Could not connect to proxy, please try again...') 33 | }); 34 | 35 | app.listen(port, function () { 36 | console.log('Server running on port ' + port) 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /full-boilerplate/src/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import { Link } from 'react-router' 4 | 5 | import GoodbyeWorld from './GoodbyeWorld' 6 | import HelloWorld from './HelloWorld' 7 | 8 | export default class App extends Component { 9 | render() { 10 | return ( 11 |
12 |
What up?
13 |
No thanks!
14 | {this.props.children} 15 |
16 | ) 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /full-boilerplate/src/components/GoodbyeWorld.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import { connect } from 'react-redux' 4 | import { Link } from 'react-router' 5 | import { getGoodbyeWorld } from '../../actions/actions' 6 | 7 | const divStyle = { 8 | fontSize: '60px' 9 | } 10 | 11 | class GoodByeWorld extends Component { 12 | 13 | componentWillMount() { 14 | this.props.dispatch(getGoodbyeWorld()) 15 | } 16 | 17 | render() { 18 | return ( 19 |
20 | {this.props.goodbye} 21 |
22 | ) 23 | } 24 | } 25 | 26 | function mapStateToProps(state) { 27 | const goodbye = state.greeting.goodbye 28 | return { 29 | goodbye 30 | } 31 | } 32 | 33 | export default connect(mapStateToProps)(GoodByeWorld) 34 | 35 | 36 | -------------------------------------------------------------------------------- /full-boilerplate/src/components/HelloWorld.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import { connect } from 'react-redux' 4 | import { Link } from 'react-router' 5 | import { getHelloWorld } from '../../actions/actions' 6 | 7 | const divStyle = { 8 | fontSize: '60px' 9 | } 10 | 11 | class HelloWorld extends Component { 12 | 13 | componentWillMount() { 14 | this.props.dispatch(getHelloWorld()) 15 | } 16 | 17 | render() { 18 | return ( 19 |
20 | {this.props.hello} 21 |
22 | ) 23 | } 24 | } 25 | 26 | function mapStateToProps(state) { 27 | const hello = state.greeting.hello 28 | return { 29 | hello 30 | } 31 | } 32 | 33 | export default connect(mapStateToProps)(HelloWorld) 34 | 35 | 36 | -------------------------------------------------------------------------------- /full-boilerplate/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore, applyMiddleware } from 'redux' 4 | import { browserHistory } from 'react-router' 5 | import { syncHistoryWithStore } from 'react-router-redux' 6 | import thunk from 'redux-thunk' 7 | 8 | import Root from './root' 9 | import rootReducer from '../reducers/reducers' 10 | 11 | const store = createStore(rootReducer, applyMiddleware(thunk)) 12 | const history = browserHistory 13 | 14 | render( 15 | , 16 | document.getElementById('app') 17 | ) -------------------------------------------------------------------------------- /full-boilerplate/src/root.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | import { Provider } from 'react-redux' 3 | import routes from './routes' 4 | import { Router } from 'react-router' 5 | 6 | //Root receives the store and history from index.js and renders all of the different routes in our app 7 | export default class Root extends Component { 8 | render() { 9 | const { store, history } = this.props 10 | return ( 11 | 12 | {routes} 13 | 14 | ) 15 | } 16 | } 17 | 18 | //This means the store and history are required 19 | Root.propTypes = { 20 | store: PropTypes.object.isRequired, 21 | history: PropTypes.object.isRequired 22 | } -------------------------------------------------------------------------------- /full-boilerplate/src/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router, Route, browserHistory } from 'react-router' 3 | 4 | import App from './components/App' 5 | import HelloWorld from './components/HelloWorld' 6 | import GoodbyeWorld from './components/GoodbyeWorld' 7 | 8 | export default ( 9 | 10 | 11 | 12 | 13 | ) -------------------------------------------------------------------------------- /full-boilerplate/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './src/index.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /full-boilerplate/webpack.production.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var nodeModulesPath = path.resolve(__dirname, 'node_modules'); 4 | var buildPath = path.resolve(__dirname, 'public', 'build'); 5 | 6 | var config = { 7 | 8 | // We change to normal source mapping 9 | devtool: 'source-map', 10 | entry: './src/index.js', 11 | output: { 12 | path: buildPath, 13 | filename: 'bundle.js' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.UglifyJsPlugin({ 17 | minimize: true, 18 | compress: { 19 | warnings: false 20 | } 21 | }) 22 | ], 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.js$/, 28 | loader: 'babel?presets[]=react,presets[]=es2015', 29 | exclude: '/node_modules' 30 | }, 31 | //This converts our .css into JS 32 | { test: /\.s?css$/, loaders: ['style', 'css', 'sass?outputStyle=expanded'] }, 33 | ] 34 | }, 35 | 36 | resolve: { 37 | extensions: ['', '.js', '.jsx', '.css', '.scss', '.json'], 38 | modulesDirectories: [ 39 | 'node_modules' 40 | ] 41 | }, 42 | }; 43 | 44 | module.exports = config; -------------------------------------------------------------------------------- /react, express, webpack, basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } -------------------------------------------------------------------------------- /react, express, webpack, basic/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bundle.js 3 | .DS_Store 4 | /bundle -------------------------------------------------------------------------------- /react, express, webpack, basic/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | 4 | class HelloWorld extends Component { 5 | render() { 6 | return ( 7 |
Hello World!
8 | ) 9 | } 10 | } 11 | 12 | render(, document.getElementById('app')) -------------------------------------------------------------------------------- /react, express, webpack, basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "react": "^0.14.7", 4 | "react-dom": "^0.14.7", 5 | "react-redux": "^4.4.1", 6 | "redux": "^3.3.1", 7 | "webpack": "^1.9.11" 8 | }, 9 | "devDependencies": { 10 | "babel-core": "^6.3.15", 11 | "babel-loader": "^6.2.0", 12 | "babel-preset-es2015": "^6.3.13", 13 | "babel-preset-react": "^6.3.13", 14 | "express": "^4.13.3", 15 | "http-proxy": "^1.13.2", 16 | "react-hot-loader": "^1.3.0", 17 | "webpack-dev-middleware": "^1.2.0", 18 | "webpack-dev-server": "^1.14.1", 19 | "webpack-hot-middleware": "^2.9.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /react, express, webpack, basic/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /react, express, webpack, basic/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var publicPath = path.resolve(__dirname, 'public'); 4 | 5 | var port = 3000; 6 | 7 | var app = express(); 8 | 9 | //serving our index.html 10 | app.use(express.static(publicPath)); 11 | 12 | app.listen(port, function () { 13 | console.log('Server running on port ' + port) 14 | }); -------------------------------------------------------------------------------- /react, express, webpack, basic/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | //entry point for bundling 6 | entry: [ 7 | './index.js' 8 | ], 9 | //the output path and filename 10 | output: { 11 | path: path.join(__dirname, 'public', 'build'), 12 | filename: 'bundle.js', 13 | }, 14 | 15 | //babel-loader for use with jsx and es2015, does not transpile the node_modules folder 16 | module: { 17 | loaders: [ 18 | { 19 | test: /\.js$/, 20 | loader: 'babel-loader', 21 | query: { 22 | presets: ['es2015', 'react'] 23 | }, 24 | exclude: '/node_modules' 25 | }, 26 | ] 27 | }, 28 | }; -------------------------------------------------------------------------------- /react, express, webpack, development/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } -------------------------------------------------------------------------------- /react, express, webpack, development/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bundle.js 3 | .DS_Store -------------------------------------------------------------------------------- /react, express, webpack, development/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | 4 | class HelloWorld extends Component { 5 | render() { 6 | return ( 7 |
Hello World!
8 | ) 9 | } 10 | } 11 | 12 | render(, document.getElementById('app')) -------------------------------------------------------------------------------- /react, express, webpack, development/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "my1stnpmpackage": "^1.0.2", 4 | "react": "^0.14.7", 5 | "react-dom": "^0.14.7", 6 | "react-redux": "^4.4.1", 7 | "redux": "^3.3.1", 8 | "webpack": "^1.9.11" 9 | }, 10 | "devDependencies": { 11 | "babel-core": "^6.3.15", 12 | "babel-loader": "^6.2.0", 13 | "babel-preset-es2015": "^6.3.13", 14 | "babel-preset-react": "^6.3.13", 15 | "express": "^4.13.3", 16 | "http-proxy": "^1.13.2", 17 | "react-hot-loader": "^1.3.0", 18 | "webpack-dev-middleware": "^1.2.0", 19 | "webpack-dev-server": "^1.14.1", 20 | "webpack-hot-middleware": "^2.9.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /react, express, webpack, development/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /react, express, webpack, development/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | var port = 3000; 7 | 8 | // We need to add a configuration to our proxy server, 9 | // as we are now proxying outside localhost 10 | var proxy = httpProxy.createProxyServer({ 11 | changeOrigin: true 12 | }); 13 | 14 | var app = express(); 15 | 16 | //serving our index.html 17 | app.use(express.static(publicPath)); 18 | 19 | //server/compiler.js runs webpack-dev-server which creates the bundle.js which index.html serves 20 | //the compiler adds some console logs for some extra sugar 21 | //notice that you will not see a physical bundle.js because webpack-dev-server runs it from memory 22 | var bundle = require('./server/compiler.js') 23 | bundle() 24 | 25 | //express now processes all requests to localhost:8080 26 | //app.all is a special routing method used for loading middleware functions 27 | app.all('/build/*', function (req, res) { 28 | proxy.web(req, res, { 29 | target: 'http://localhost:8080' 30 | }) 31 | }) 32 | 33 | proxy.on('error', function(e) { 34 | console.log('Could not connect to proxy, please try again...') 35 | }); 36 | 37 | app.listen(port, function () { 38 | console.log('Server running on port ' + port) 39 | }); -------------------------------------------------------------------------------- /react, express, webpack, development/server/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /react, express, webpack, development/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './index.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /react, express, webpack, production/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } -------------------------------------------------------------------------------- /react, express, webpack, production/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bundle.js 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /react, express, webpack, production/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | 4 | class HelloWorld extends Component { 5 | render() { 6 | return ( 7 |
Hello World!
8 | ) 9 | } 10 | } 11 | 12 | render(, document.getElementById('app')) -------------------------------------------------------------------------------- /react, express, webpack, production/npm-debug.log: -------------------------------------------------------------------------------- 1 | 0 info it worked if it ends with ok 2 | 1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ] 3 | 2 info using npm@2.15.1 4 | 3 info using node@v4.4.3 5 | 4 verbose run-script [ 'prestart', 'start', 'poststart' ] 6 | 5 info prestart @ 7 | 6 info start @ 8 | 7 verbose unsafe-perm in lifecycle true 9 | 8 info @ Failed to exec start script 10 | 9 verbose stack Error: @ start: `node server.js` 11 | 9 verbose stack Exit status 1 12 | 9 verbose stack at EventEmitter. (/usr/local/lib/node_modules/npm/lib/utils/lifecycle.js:217:16) 13 | 9 verbose stack at emitTwo (events.js:87:13) 14 | 9 verbose stack at EventEmitter.emit (events.js:172:7) 15 | 9 verbose stack at ChildProcess. (/usr/local/lib/node_modules/npm/lib/utils/spawn.js:24:14) 16 | 9 verbose stack at emitTwo (events.js:87:13) 17 | 9 verbose stack at ChildProcess.emit (events.js:172:7) 18 | 9 verbose stack at maybeClose (internal/child_process.js:827:16) 19 | 9 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5) 20 | 10 verbose pkgid @ 21 | 11 verbose cwd /Users/colinmcdonald/Desktop/coding/react-redux-webpack/express, webpack, production 22 | 12 error Darwin 15.4.0 23 | 13 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start" 24 | 14 error node v4.4.3 25 | 15 error npm v2.15.1 26 | 16 error code ELIFECYCLE 27 | 17 error @ start: `node server.js` 28 | 17 error Exit status 1 29 | 18 error Failed at the @ start script 'node server.js'. 30 | 18 error This is most likely a problem with the package, 31 | 18 error not with npm itself. 32 | 18 error Tell the author that this fails on your system: 33 | 18 error node server.js 34 | 18 error You can get information on how to open an issue for this project with: 35 | 18 error npm bugs 36 | 18 error Or if that isn't available, you can get their info via: 37 | 18 error 38 | 18 error npm owner ls 39 | 18 error There is likely additional logging output above. 40 | 19 verbose exit [ 1, true ] 41 | -------------------------------------------------------------------------------- /react, express, webpack, production/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": "4.4.0" 4 | }, 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "postinstall": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors" 9 | 10 | },"dependencies": { 11 | "react": "^0.14.7", 12 | "react-dom": "^0.14.7", 13 | "react-redux": "^4.4.1", 14 | "redux": "^3.3.1", 15 | "webpack": "^1.9.11" 16 | }, 17 | "devDependencies": { 18 | "babel-core": "^6.3.15", 19 | "babel-loader": "^6.2.0", 20 | "babel-preset-es2015": "^6.3.13", 21 | "babel-preset-react": "^6.3.13", 22 | "express": "^4.13.3", 23 | "http-proxy": "^1.13.2", 24 | "react-hot-loader": "^1.3.0", 25 | "webpack-dev-middleware": "^1.2.0", 26 | "webpack-dev-server": "^1.14.1", 27 | "webpack-hot-middleware": "^2.9.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /react, express, webpack, production/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /react, express, webpack, production/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | // We need to add a configuration to our proxy server, 7 | // as we are now proxying outside localhost 8 | var isProduction = process.env.NODE_ENV === 'production'; 9 | var port = isProduction ? process.env.PORT : 3000; 10 | 11 | var proxy = httpProxy.createProxyServer({ 12 | changeOrigin: true 13 | }); 14 | var app = express(); 15 | 16 | app.use(express.static(publicPath)); 17 | 18 | // If you only want this for development, you would of course 19 | // put it in the "if" block below 20 | 21 | if (!isProduction) { 22 | var bundle = require('./server/compiler.js') 23 | bundle() 24 | app.all('/build/*', function (req, res) { 25 | proxy.web(req, res, { 26 | target: 'http://localhost:8080' 27 | }) 28 | }) 29 | }; 30 | 31 | proxy.on('error', function(e) { 32 | console.log('Could not connect to proxy, please try again...') 33 | }); 34 | 35 | app.listen(port, function () { 36 | console.log('Server running on port ' + port) 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /react, express, webpack, production/server/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /react, express, webpack, production/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './index.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /react, express, webpack, production/webpack.production.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var nodeModulesPath = path.resolve(__dirname, 'node_modules'); 4 | var buildPath = path.resolve(__dirname, 'public', 'build'); 5 | 6 | var config = { 7 | 8 | // We change to normal source mapping 9 | devtool: 'source-map', 10 | entry: './index.js', 11 | output: { 12 | path: buildPath, 13 | filename: 'bundle.js' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.UglifyJsPlugin({ 17 | minimize: true, 18 | compress: { 19 | warnings: false 20 | } 21 | }) 22 | ], 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.js$/, 28 | loader: 'babel?presets[]=react,presets[]=es2015', 29 | exclude: '/node_modules' 30 | }, 31 | //This converts our .css into JS 32 | { test: /\.s?css$/, loaders: ['style', 'css', 'sass?outputStyle=expanded'] }, 33 | ] 34 | }, 35 | 36 | resolve: { 37 | extensions: ['', '.js', '.jsx', '.css', '.scss', '.json'], 38 | modulesDirectories: [ 39 | 'node_modules' 40 | ] 41 | }, 42 | }; 43 | 44 | module.exports = config; -------------------------------------------------------------------------------- /react, redux, webpack, express, production/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/actions.js: -------------------------------------------------------------------------------- 1 | export const GET_HELLO_WORLD = 'GET_HELLO_WORLD' 2 | 3 | export function getHelloWorld() { 4 | return { 5 | type: GET_HELLO_WORLD, 6 | } 7 | } -------------------------------------------------------------------------------- /react, redux, webpack, express, production/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | import { connect } from 'react-redux' 4 | import { getHelloWorld } from './actions' 5 | 6 | class Index extends Component { 7 | 8 | componentWillMount() { 9 | this.props.dispatch(getHelloWorld()) 10 | } 11 | 12 | render() { 13 | return ( 14 |
{this.props.hello}
15 | ) 16 | } 17 | } 18 | 19 | function mapStateToProps(state) { 20 | console.log(state) 21 | const hello = state.hello 22 | return { 23 | hello 24 | } 25 | } 26 | 27 | export default connect(mapStateToProps)(Index) 28 | 29 | 30 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": "4.4.0" 4 | }, 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "postinstall": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors" 9 | 10 | },"dependencies": { 11 | "react": "^0.14.7", 12 | "react-dom": "^0.14.7", 13 | "react-redux": "^4.4.1", 14 | "redux": "^3.3.1", 15 | "webpack": "^1.9.11" 16 | }, 17 | "devDependencies": { 18 | "babel-core": "^6.3.15", 19 | "babel-loader": "^6.2.0", 20 | "babel-preset-es2015": "^6.3.13", 21 | "babel-preset-react": "^6.3.13", 22 | "express": "^4.13.3", 23 | "http-proxy": "^1.13.2", 24 | "react-hot-loader": "^1.3.0", 25 | "webpack-dev-middleware": "^1.2.0", 26 | "webpack-dev-server": "^1.14.1", 27 | "webpack-hot-middleware": "^2.9.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/reducers.js: -------------------------------------------------------------------------------- 1 | import { GET_HELLO_WORLD } from './actions' 2 | 3 | export default function cars(state = { 4 | hello: '' 5 | }, action) { 6 | switch(action.type) { 7 | case GET_HELLO_WORLD: 8 | return Object.assign({}, state, { 9 | hello: 'Hello World' 10 | }) 11 | default: 12 | return state 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/root.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore } from 'redux' 4 | import { Provider } from 'react-redux' 5 | import Index from './index' 6 | import Reducers from './reducers' 7 | 8 | let store = createStore(Reducers) 9 | 10 | render( 11 | 12 | 13 | , document.getElementById('app') 14 | ) -------------------------------------------------------------------------------- /react, redux, webpack, express, production/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var httpProxy = require('http-proxy'); 4 | var publicPath = path.resolve(__dirname, 'public'); 5 | 6 | // We need to add a configuration to our proxy server, 7 | // as we are now proxying outside localhost 8 | var isProduction = process.env.NODE_ENV === 'production'; 9 | var port = isProduction ? process.env.PORT : 3000; 10 | 11 | var proxy = httpProxy.createProxyServer({ 12 | changeOrigin: true 13 | }); 14 | var app = express(); 15 | 16 | app.use(express.static(publicPath)); 17 | 18 | // If you only want this for development, you would of course 19 | // put it in the "if" block below 20 | 21 | if (!isProduction) { 22 | var bundle = require('./server/compiler.js') 23 | bundle() 24 | app.all('/build/*', function (req, res) { 25 | proxy.web(req, res, { 26 | target: 'http://localhost:8080' 27 | }) 28 | }) 29 | }; 30 | 31 | proxy.on('error', function(e) { 32 | console.log('Could not connect to proxy, please try again...') 33 | }); 34 | 35 | app.listen(port, function () { 36 | console.log('Server running on port ' + port) 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /react, redux, webpack, express, production/server/compiler.js: -------------------------------------------------------------------------------- 1 | var Webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var WebpackConfig = require('./../webpack.config.js'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | module.exports = function () { 8 | // First we fire up Webpack an pass in the configuration we 9 | // created 10 | var bundleStart = null; 11 | var compiler = Webpack(WebpackConfig); 12 | 13 | // We give notice in the terminal when it starts bundling and 14 | // set the time it started 15 | compiler.plugin('compile', function() { 16 | console.log('Bundling...'); 17 | bundleStart = Date.now(); 18 | }); 19 | 20 | // We also give notice when it is done compiling, including the 21 | // time it took. Nice to have 22 | compiler.plugin('done', function() { 23 | console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!'); 24 | }); 25 | 26 | var bundler = new WebpackDevServer(compiler, { 27 | // We need to tell Webpack to serve our bundled application 28 | // from the build path. When proxying: 29 | // http://localhost:3000/build -> http://localhost:8080/build 30 | publicPath: '/build/', 31 | 32 | // Configure hot replacement 33 | hot: true, 34 | quiet: false, 35 | noInfo: true, 36 | stats: { 37 | colors: true 38 | } 39 | }); 40 | 41 | // We fire up the development server and give notice in the terminal 42 | // that we are starting the initial bundle 43 | bundler.listen(8080, function () { 44 | console.log('Bundling project, please wait...'); 45 | }); 46 | 47 | }; -------------------------------------------------------------------------------- /react, redux, webpack, express, production/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack =require('webpack') 3 | 4 | module.exports = { 5 | 6 | //fastest rebuild and build speed 7 | devtool: 'eval', 8 | entry: [ 9 | //for hot style updates 10 | 'webpack/hot/dev-server', 11 | //refreshes the browser when it can't hot update 12 | 'webpack-dev-server/client?http://localhost:8080', 13 | //our entry point 14 | './root.js' 15 | ], 16 | output: { 17 | path: path.join(__dirname, 'public', 'build'), 18 | filename: 'bundle.js', 19 | publicPath: '/build/' //the server will listen in on this path and then proxy Webpack 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | query: { 28 | presets: ['es2015', 'react'] 29 | }, 30 | exclude: '/node_modules' 31 | }, 32 | //This converts our .css into JS 33 | { 34 | test: /\.css$/, 35 | loader: 'css-loader' 36 | } 37 | ] 38 | }, 39 | //Since we're running Webpack from our server, need to manually add the 40 | //Hot Replacement plugin 41 | plugins: [ 42 | new webpack.HotModuleReplacementPlugin(), 43 | ] 44 | }; -------------------------------------------------------------------------------- /react, redux, webpack, express, production/webpack.production.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var nodeModulesPath = path.resolve(__dirname, 'node_modules'); 4 | var buildPath = path.resolve(__dirname, 'public', 'build'); 5 | 6 | var config = { 7 | 8 | // We change to normal source mapping 9 | devtool: 'source-map', 10 | entry: './index.js', 11 | output: { 12 | path: buildPath, 13 | filename: 'bundle.js' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.UglifyJsPlugin({ 17 | minimize: true, 18 | compress: { 19 | warnings: false 20 | } 21 | }) 22 | ], 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.js$/, 28 | loader: 'babel?presets[]=react,presets[]=es2015', 29 | exclude: '/node_modules' 30 | }, 31 | //This converts our .css into JS 32 | { test: /\.s?css$/, loaders: ['style', 'css', 'sass?outputStyle=expanded'] }, 33 | ] 34 | }, 35 | 36 | resolve: { 37 | extensions: ['', '.js', '.jsx', '.css', '.scss', '.json'], 38 | modulesDirectories: [ 39 | 'node_modules' 40 | ] 41 | }, 42 | }; 43 | 44 | module.exports = config; --------------------------------------------------------------------------------