├── .gitignore ├── README.md ├── basic-deku ├── .babelrc ├── README.md ├── index.html ├── package.json ├── server.js ├── serverDev.js ├── src │ ├── Counter │ │ ├── Counter.js │ │ └── style.css │ ├── app.css │ └── index.js ├── webpack.config.dev.js └── webpack.config.js ├── basic-react ├── .babelrc ├── README.md ├── index.html ├── package.json ├── server.js ├── serverDev.js ├── src │ ├── App.js │ ├── Counter │ │ ├── Counter.js │ │ └── style.css │ ├── app.css │ └── index.js ├── webpack.config.dev.js └── webpack.config.js ├── post-css ├── .babelrc ├── README.md ├── index.html ├── package.json ├── server.js ├── serverDev.js ├── src │ ├── App.js │ ├── Grid │ │ ├── Grid.js │ │ └── style.css │ ├── app.css │ └── index.js ├── webpack.config.dev.js └── webpack.config.js ├── redux-deku ├── .babelrc ├── README.md ├── index.html ├── package.json ├── server.js ├── serverDev.js ├── src │ ├── actions │ │ └── draft.js │ ├── api.js │ ├── components │ │ ├── App.css │ │ ├── App.js │ │ ├── Compose.css │ │ ├── Compose.js │ │ ├── Inbox.js │ │ ├── InboxItem.js │ │ ├── InboxList.css │ │ ├── InboxList.js │ │ ├── Main.js │ │ ├── Message.css │ │ ├── Message.js │ │ ├── Nav.js │ │ └── NotFound.js │ ├── create-router.js │ ├── index.js │ ├── reducers │ │ ├── draft.js │ │ └── emails.js │ └── store.js ├── webpack.config.dev.js └── webpack.config.js └── redux-react ├── .babelrc ├── README.md ├── index.html ├── package.json ├── server.js ├── serverDev.js ├── src ├── actions │ └── FriendsActions.js ├── components │ ├── AddFriendInput.css │ ├── AddFriendInput.js │ ├── FriendList.css │ ├── FriendList.js │ ├── FriendListItem.css │ ├── FriendListItem.js │ └── NotFound.js ├── constants │ └── ActionTypes.js ├── containers │ ├── FriendListContainer.css │ ├── FriendListContainer.js │ └── Main.js ├── create-router.js ├── index.js ├── reducers │ └── friendlist.js └── store.js ├── webpack.config.dev.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | public -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webpack-css-loader-examples 2 | 3 | Some examples of using [css-loader](https://github.com/webpack/css-loader) with react and deku. 4 | 5 | #### basic use of css-loader 6 | 7 | * [basic react](https://github.com/StevenIseki/webpack-css-loader-examples/tree/master/basic-react) 8 | * [basic deku](https://github.com/StevenIseki/webpack-css-loader-examples/tree/master/basic-deku) 9 | * [post-css](https://github.com/StevenIseki/webpack-css-loader-examples/tree/master/post-css) 10 | 11 | #### css module examples 12 | 13 | * [redux react](https://github.com/StevenIseki/webpack-css-loader-examples/tree/master/redux-react) 14 | * [redux deku](https://github.com/StevenIseki/webpack-css-loader-examples/tree/master/redux-deku) 15 | 16 | ## Dependancies 17 | 18 | Here are the latest dependancies: 19 | 20 | [![npm version](https://badge.fury.io/js/babel-core.svg)](https://badge.fury.io/js/babel-core) 21 | babel-core 22 | 23 | [![npm version](https://badge.fury.io/js/babel-loader.svg)](https://badge.fury.io/js/babel-loader) 24 | babel-loader 25 | 26 | [![npm version](https://badge.fury.io/js/css-loader.svg)](https://badge.fury.io/js/css-loader) 27 | css-loader 28 | 29 | [![npm version](https://badge.fury.io/js/deku.svg)](https://badge.fury.io/js/deku) 30 | deku 31 | 32 | [![npm version](https://badge.fury.io/js/react.svg)](https://badge.fury.io/js/react) 33 | react 34 | 35 | [![npm version](https://badge.fury.io/js/redux.svg)](https://badge.fury.io/js/redux) 36 | redux 37 | 38 | [![npm version](https://badge.fury.io/js/router5.svg)](https://badge.fury.io/js/router5) 39 | router5 40 | 41 | [![npm version](https://badge.fury.io/js/webpack.svg)](https://badge.fury.io/js/webpack) 42 | webpack 43 | 44 | These examples have the following versions for dependancies 45 | 46 | ```json 47 | "devDependencies": { 48 | "autoprefixer": "^6.1.0", 49 | "babel-core": "^6.0.20", 50 | "babel-loader": "^6.0.1", 51 | "babel-preset-es2015": "^6.0.15", 52 | "babel-preset-react": "^6.0.15", 53 | "babel-preset-stage-0": "^6.0.15", 54 | "css-loader": "^0.15.1", 55 | "deku": "^0.5.6", 56 | "express": "^4.13.3", 57 | "postcss-loader": "^0.7.0", 58 | "react": "^0.14.0", 59 | "react-dom": "^0.14.0", 60 | "style-loader": "^0.12.3", 61 | "webpack": "^1.9.6", 62 | "webpack-dev-middleware": "^1.2.0" 63 | } 64 | ``` 65 | 66 | 67 | -------------------------------------------------------------------------------- /basic-deku/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /basic-deku/README.md: -------------------------------------------------------------------------------- 1 | Basic React Example 2 | ===================== 3 | 4 | This example is to show off basic use of css-loader as documented in the [webpack docs](https://christianalfoni.github.io/react-webpack-cookbook/Loading-CSS.html). 5 | 6 | Note that this does not cover css-modules, it is simple for adding css imports to your deku components. You can use this method and stick to [BEM](https://css-tricks.com/bem-101/) for naming convention in your components, or you can try out the awesome css-modules: 7 | 8 | To change over from just using **css-loader** to use **css modules** update your css loader from 9 | 10 | **from** 11 | 12 | `{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }` 13 | 14 | **to** 15 | 16 | `{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') }` 17 | 18 | and in your components 19 | 20 | **from** 21 | 22 | ```js 23 | import './style.css'; 24 | 25 | className="counter" 26 | ``` 27 | 28 | **to** 29 | 30 | ```js 31 | import styles from './AddFriendInput.css'; 32 | 33 | className={styles.addFriendInput} 34 | ``` 35 | 36 | ## Run Dev 37 | 38 | ``` 39 | npm install 40 | npm start 41 | open http://localhost:3000 42 | ``` 43 | 44 | ## Run Prod 45 | 46 | ``` 47 | npm install 48 | npm run build 49 | npm start:prod 50 | open http://localhost:3000 51 | ``` 52 | 53 | ## License 54 | 55 | [MIT](http://isekivacenz.mit-license.org/) 56 | -------------------------------------------------------------------------------- /basic-deku/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | css loader - basic example 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /basic-deku/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-css-basic-example", 3 | "version": "1.0.0", 4 | "description": "webpack css basic example", 5 | "scripts": { 6 | "dist": "webpack --config webpack.config.js", 7 | "build": "npm run clean && npm run dist", 8 | "clean": "rm -rf public/scripts", 9 | "start": "npm run start:dev", 10 | "start:dev": "node serverDev.js", 11 | "start:prod": "NODE_ENV=production node server.js" 12 | }, 13 | "author": "Steven Iseki ", 14 | "license": "MIT", 15 | "homepage": "https://github.com/StevenIseki/webpack-css-loader-examples", 16 | "devDependencies": { 17 | "babel-core": "^6.0.20", 18 | "babel-loader": "^6.0.1", 19 | "babel-preset-es2015": "^6.0.15", 20 | "babel-preset-react": "^6.0.15", 21 | "babel-preset-stage-0": "^6.0.15", 22 | "css-loader": "^0.15.1", 23 | "express": "^4.13.3", 24 | "style-loader": "^0.12.3", 25 | "webpack": "^1.9.6", 26 | "webpack-dev-middleware": "^1.2.0" 27 | }, 28 | "dependencies": { 29 | "deku": "^0.5.6", 30 | "virtual-element": "^1.2.0" 31 | } 32 | } -------------------------------------------------------------------------------- /basic-deku/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var path = require('path') 3 | var port = process.env.PORT || 3000 4 | 5 | express() 6 | .use('/public', express.static(__dirname + '/public')) 7 | .get('*', function (req, res) { 8 | res.sendFile(path.join(__dirname, '/index.html')) 9 | }) 10 | .listen(port, function () { 11 | /* console.log(process.env) */ 12 | console.log('Listening on ' + port + '.') 13 | console.log('Go to in your browser.') 14 | }) -------------------------------------------------------------------------------- /basic-deku/serverDev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config.dev'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath 12 | })); 13 | 14 | app.get('*', function(req, res) { 15 | res.sendFile(path.join(__dirname, 'index.html')); 16 | }); 17 | 18 | app.listen(3000, 'localhost', function(err) { 19 | if (err) { 20 | console.log(err); 21 | return; 22 | } 23 | 24 | console.log('Listening at http://localhost:3000'); 25 | }); 26 | -------------------------------------------------------------------------------- /basic-deku/src/Counter/Counter.js: -------------------------------------------------------------------------------- 1 | /** @jsx element */ 2 | 3 | import './style.css'; 4 | import {render,tree} from 'deku' 5 | import element from 'virtual-element' 6 | 7 | let Counter = { 8 | 9 | initialState () { 10 | return { secondsElapsed: 0 } 11 | }, 12 | 13 | render (component) { 14 | let { props, state } = component; 15 | let { secondsElapsed } = state; 16 | 17 | return ( 18 |
19 |

20 | Counter: { secondsElapsed } 21 |

22 |
23 | ); 24 | }, 25 | 26 | afterUpdate (component) { 27 | let { props, state } = component; 28 | }, 29 | 30 | afterMount (component, el, setState) { 31 | var counter = 0; 32 | component.interval = setInterval(() => { 33 | setState({ secondsElapsed: counter++ }) 34 | }, 1000); 35 | }, 36 | 37 | beforeUnmount (component) { 38 | clearInterval(component.interval); 39 | } 40 | } 41 | 42 | export {Counter} 43 | -------------------------------------------------------------------------------- /basic-deku/src/Counter/style.css: -------------------------------------------------------------------------------- 1 | .counter { 2 | background-color: #EEE; 3 | padding: 5px; 4 | } 5 | 6 | .counter--darkred { 7 | color: darkred; 8 | } 9 | 10 | .counter--pink { 11 | color: pink; 12 | } 13 | -------------------------------------------------------------------------------- /basic-deku/src/app.css: -------------------------------------------------------------------------------- 1 | .app { 2 | background-color: purple; 3 | padding: 20px; 4 | } -------------------------------------------------------------------------------- /basic-deku/src/index.js: -------------------------------------------------------------------------------- 1 | /** @jsx element */ 2 | 3 | import element from 'virtual-element' 4 | import { Counter } from './Counter/Counter'; 5 | import './app.css'; 6 | import {render,tree} from 'deku' 7 | 8 | let counter = tree( 9 |
10 | 11 | 12 |
13 | ); 14 | 15 | render(counter, document.getElementById('root')) 16 | -------------------------------------------------------------------------------- /basic-deku/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'source-map', 6 | entry: ['./src/index'], 7 | output: { 8 | filename: 'bundle.js', 9 | path: path.join(__dirname, 'scripts'), 10 | publicPath: '/public/scripts/' 11 | }, 12 | module: { 13 | loaders: [ 14 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 15 | { test: /\.css$/,loader: 'style!css'} 16 | ] 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /basic-deku/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: [ 6 | './src/index' 7 | ], 8 | output: { 9 | filename: 'bundle.js', 10 | path: path.join(__dirname, 'public/scripts'), 11 | publicPath: '/static/' 12 | }, 13 | plugins: [ 14 | new webpack.optimize.OccurenceOrderPlugin(), 15 | new webpack.DefinePlugin({ 16 | 'process.env': { 17 | 'NODE_ENV': JSON.stringify('production') 18 | } 19 | }), 20 | new webpack.optimize.UglifyJsPlugin({ 21 | compressor: { 22 | warnings: false 23 | } 24 | }) 25 | ], 26 | module: { 27 | loaders: [ 28 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 29 | { test: /\.css$/,loader: 'style!css'} 30 | ] 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /basic-react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /basic-react/README.md: -------------------------------------------------------------------------------- 1 | Basic React Example 2 | ===================== 3 | 4 | This example is to show off basic use of css-loader as documented in the [webpack docs](https://christianalfoni.github.io/react-webpack-cookbook/Loading-CSS.html). 5 | 6 | Note that this does not cover css-modules, it is simple for adding css imports to your react components. You can use this method and stick to [BEM](https://css-tricks.com/bem-101/) for naming convention in your components, or you can try out the awesome css-modules: 7 | 8 | To change over from just using **css-loader** to use **css modules** update your css loader from 9 | 10 | **from** 11 | 12 | `{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }` 13 | 14 | **to** 15 | 16 | `{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') }` 17 | 18 | and in your components 19 | 20 | **from** 21 | 22 | ```js 23 | import './style.css'; 24 | 25 | className="counter" 26 | ``` 27 | 28 | **to** 29 | 30 | ```js 31 | import styles from './AddFriendInput.css'; 32 | 33 | className={styles.addFriendInput} 34 | ``` 35 | 36 | ## Run Dev 37 | 38 | ``` 39 | npm install 40 | npm start 41 | open http://localhost:3000 42 | ``` 43 | 44 | ## Run Prod 45 | 46 | ``` 47 | npm install 48 | npm run build 49 | npm start:prod 50 | open http://localhost:3000 51 | ``` 52 | 53 | ## License 54 | 55 | [MIT](http://isekivacenz.mit-license.org/) 56 | -------------------------------------------------------------------------------- /basic-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | css loader - basic example 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /basic-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-css-basic-example", 3 | "version": "1.0.0", 4 | "description": "webpack css basic example", 5 | "scripts": { 6 | "dist": "webpack --config webpack.config.js", 7 | "build": "npm run clean && npm run dist", 8 | "clean": "rm -rf public/scripts", 9 | "start": "npm run start:dev", 10 | "start:dev": "node serverDev.js", 11 | "start:prod": "NODE_ENV=production node server.js" 12 | }, 13 | "author": "Steven Iseki ", 14 | "license": "MIT", 15 | "homepage": "https://github.com/StevenIseki/webpack-css-loader-examples", 16 | "devDependencies": { 17 | "babel-core": "^6.0.20", 18 | "babel-loader": "^6.0.1", 19 | "babel-preset-es2015": "^6.0.15", 20 | "babel-preset-react": "^6.0.15", 21 | "babel-preset-stage-0": "^6.0.15", 22 | "css-loader": "^0.15.1", 23 | "express": "^4.13.3", 24 | "style-loader": "^0.12.3", 25 | "webpack": "^1.9.6", 26 | "webpack-dev-middleware": "^1.2.0" 27 | }, 28 | "dependencies": { 29 | "react": "^0.14.0", 30 | "react-dom": "^0.14.0" 31 | } 32 | } -------------------------------------------------------------------------------- /basic-react/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var path = require('path') 3 | var port = process.env.PORT || 3000 4 | 5 | express() 6 | .use('/public', express.static(__dirname + '/public')) 7 | .get('*', function (req, res) { 8 | res.sendFile(path.join(__dirname, '/index.html')) 9 | }) 10 | .listen(port, function () { 11 | /* console.log(process.env) */ 12 | console.log('Listening on ' + port + '.') 13 | console.log('Go to in your browser.') 14 | }) -------------------------------------------------------------------------------- /basic-react/serverDev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config.dev'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath 12 | })); 13 | 14 | app.get('*', function(req, res) { 15 | res.sendFile(path.join(__dirname, 'index.html')); 16 | }); 17 | 18 | app.listen(3000, 'localhost', function(err) { 19 | if (err) { 20 | console.log(err); 21 | return; 22 | } 23 | 24 | console.log('Listening at http://localhost:3000'); 25 | }); 26 | -------------------------------------------------------------------------------- /basic-react/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Counter } from './Counter/Counter' 3 | import './app.css'; 4 | 5 | export class App extends Component { 6 | render() { 7 | return ( 8 |
9 | 10 | 11 |
12 | ); 13 | } 14 | } -------------------------------------------------------------------------------- /basic-react/src/Counter/Counter.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | import React, { Component } from 'react'; 3 | import { render } from 'react-dom'; 4 | 5 | export class Counter extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { counter: 0 }; 9 | this.interval = setInterval(() => this.tick(), 1000); 10 | } 11 | 12 | tick() { 13 | this.setState({ 14 | counter: this.state.counter + this.props.increment 15 | }); 16 | } 17 | 18 | componentWillUnmount() { 19 | clearInterval(this.interval); 20 | } 21 | 22 | render() { 23 | return ( 24 |
25 |

26 | Counter ({this.props.increment}): {this.state.counter} 27 |

28 |
29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /basic-react/src/Counter/style.css: -------------------------------------------------------------------------------- 1 | .counter { 2 | background-color: #EEE; 3 | padding: 5px; 4 | } 5 | 6 | .counter--darkred { 7 | color: darkred; 8 | } 9 | 10 | .counter--pink { 11 | color: pink; 12 | } 13 | -------------------------------------------------------------------------------- /basic-react/src/app.css: -------------------------------------------------------------------------------- 1 | .app { 2 | background-color: purple; 3 | padding: 20px; 4 | } -------------------------------------------------------------------------------- /basic-react/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { App } from './App'; 4 | 5 | render(, document.getElementById('root')); -------------------------------------------------------------------------------- /basic-react/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'source-map', 6 | entry: ['./src/index'], 7 | output: { 8 | filename: 'bundle.js', 9 | path: path.join(__dirname, 'scripts'), 10 | publicPath: '/public/scripts/' 11 | }, 12 | module: { 13 | loaders: [ 14 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 15 | { test: /\.css$/,loader: 'style!css'} 16 | ] 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /basic-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: [ 6 | './src/index' 7 | ], 8 | output: { 9 | filename: 'bundle.js', 10 | path: path.join(__dirname, 'public/scripts'), 11 | publicPath: '/static/' 12 | }, 13 | plugins: [ 14 | new webpack.optimize.OccurenceOrderPlugin(), 15 | new webpack.DefinePlugin({ 16 | 'process.env': { 17 | 'NODE_ENV': JSON.stringify('production') 18 | } 19 | }), 20 | new webpack.optimize.UglifyJsPlugin({ 21 | compressor: { 22 | warnings: false 23 | } 24 | }) 25 | ], 26 | module: { 27 | loaders: [ 28 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 29 | { test: /\.css$/,loader: 'style!css'} 30 | ] 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /post-css/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /post-css/README.md: -------------------------------------------------------------------------------- 1 | Basic Post-CSS Example 2 | ===================== 3 | 4 | This example is to show off basic use of css-loader as documented in the [webpack docs](https://christianalfoni.github.io/react-webpack-cookbook/Loading-CSS.html) with post-css and autoprefixer. 5 | 6 | Note that this does not cover css-modules, it is simple for adding css imports to your react components. I prefer to use this setup and stick to [BEM](https://css-tricks.com/bem-101/) for naming convention. 7 | 8 | Note the autoprefixer postcss plugin is in use, which will as you would imagine automatically add prefixes for us. 9 | 10 | ```css 11 | a { 12 | display: flex; 13 | } 14 | ``` 15 | 16 | compiles to 17 | 18 | ```css 19 | a { 20 | display: -webkit-box; 21 | display: -webkit-flex; 22 | display: -ms-flexbox; 23 | display: flex 24 | } 25 | ``` 26 | 27 | ## Run Dev 28 | 29 | ``` 30 | npm install 31 | npm start 32 | open http://localhost:3000 33 | ``` 34 | 35 | ## Run Prod 36 | 37 | ``` 38 | npm install 39 | npm run build 40 | npm start:prod 41 | open http://localhost:3000 42 | ``` 43 | 44 | ## License 45 | 46 | [MIT](http://isekivacenz.mit-license.org/) -------------------------------------------------------------------------------- /post-css/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | css loader - post-css example 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /post-css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-css-post-css-example", 3 | "version": "1.0.0", 4 | "description": "webpack css post-css example", 5 | "scripts": { 6 | "dist": "webpack --config webpack.config.js", 7 | "build": "npm run clean && npm run dist", 8 | "clean": "rm -rf public/scripts", 9 | "start": "npm run start:dev", 10 | "start:dev": "node serverDev.js", 11 | "start:prod": "NODE_ENV=production node server.js" 12 | }, 13 | "author": "Steven Iseki ", 14 | "license": "MIT", 15 | "homepage": "https://github.com/StevenIseki/webpack-css-loader-examples", 16 | "devDependencies": { 17 | "autoprefixer": "^6.1.0", 18 | "babel-core": "^6.0.20", 19 | "babel-loader": "^6.0.1", 20 | "babel-preset-es2015": "^6.0.15", 21 | "babel-preset-react": "^6.0.15", 22 | "babel-preset-stage-0": "^6.0.15", 23 | "css-loader": "^0.15.1", 24 | "express": "^4.13.3", 25 | "postcss-loader": "^0.7.0", 26 | "style-loader": "^0.12.3", 27 | "webpack": "^1.9.6", 28 | "webpack-dev-middleware": "^1.2.0" 29 | }, 30 | "dependencies": { 31 | "react": "^0.14.0", 32 | "react-dom": "^0.14.0" 33 | } 34 | } -------------------------------------------------------------------------------- /post-css/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var path = require('path') 3 | var port = process.env.PORT || 3000 4 | 5 | express() 6 | .use('/public', express.static(__dirname + '/public')) 7 | .get('*', function (req, res) { 8 | res.sendFile(path.join(__dirname, '/index.html')) 9 | }) 10 | .listen(port, function () { 11 | /* console.log(process.env) */ 12 | console.log('Listening on ' + port + '.') 13 | console.log('Go to in your browser.') 14 | }) -------------------------------------------------------------------------------- /post-css/serverDev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config.dev'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath 12 | })); 13 | 14 | app.get('*', function(req, res) { 15 | res.sendFile(path.join(__dirname, 'index.html')); 16 | }); 17 | 18 | app.listen(3000, 'localhost', function(err) { 19 | if (err) { 20 | console.log(err); 21 | return; 22 | } 23 | 24 | console.log('Listening at http://localhost:3000'); 25 | }); 26 | -------------------------------------------------------------------------------- /post-css/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Grid } from './Grid/Grid' 3 | import './app.css'; 4 | 5 | export class App extends Component { 6 | render() { 7 | return ( 8 |
9 | 10 |
11 | ); 12 | } 13 | } -------------------------------------------------------------------------------- /post-css/src/Grid/Grid.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | import React, { Component } from 'react'; 3 | import { render } from 'react-dom'; 4 | 5 | export class Grid extends Component { 6 | constructor(props) { 7 | super(props); 8 | } 9 | 10 | componentWillUnmount() { 11 | } 12 | 13 | render() { 14 | return ( 15 |
16 |
17 | cell 1 18 |
19 |
20 | cell 2 21 |
22 |
23 | cell 3 24 |
25 |
26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /post-css/src/Grid/style.css: -------------------------------------------------------------------------------- 1 | .Grid { 2 | display: flex; 3 | background-color: rgba(147,128,108,.1); 4 | padding: 10px; 5 | } 6 | 7 | .Grid__cell { 8 | flex: 1; 9 | } -------------------------------------------------------------------------------- /post-css/src/app.css: -------------------------------------------------------------------------------- 1 | .app { 2 | background-color: #fff; 3 | padding: 20px; 4 | } -------------------------------------------------------------------------------- /post-css/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { App } from './App'; 4 | 5 | render(, document.getElementById('root')); -------------------------------------------------------------------------------- /post-css/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | 5 | module.exports = { 6 | devtool: 'source-map', 7 | entry: ['./src/index'], 8 | output: { 9 | filename: 'bundle.js', 10 | path: path.join(__dirname, 'scripts'), 11 | publicPath: '/public/scripts/' 12 | }, 13 | module: { 14 | loaders: [ 15 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 16 | { test: /\.css$/,loader: 'style-loader!css-loader!postcss-loader'} 17 | ] 18 | }, 19 | postcss: function () { 20 | return [autoprefixer]; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /post-css/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | 5 | module.exports = { 6 | entry: [ 7 | './src/index' 8 | ], 9 | output: { 10 | filename: 'bundle.js', 11 | path: path.join(__dirname, 'public/scripts'), 12 | publicPath: '/static/' 13 | }, 14 | plugins: [ 15 | new webpack.optimize.OccurenceOrderPlugin(), 16 | new webpack.DefinePlugin({ 17 | 'process.env': { 18 | 'NODE_ENV': JSON.stringify('production') 19 | } 20 | }), 21 | new webpack.optimize.UglifyJsPlugin({ 22 | compressor: { 23 | warnings: false 24 | } 25 | }) 26 | ], 27 | module: { 28 | loaders: [ 29 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 30 | { test: /\.css$/,loader: 'style-loader!css-loader!postcss-loader'} 31 | ] 32 | }, 33 | postcss: function () { 34 | return [autoprefixer]; 35 | } 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /redux-deku/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /redux-deku/README.md: -------------------------------------------------------------------------------- 1 | Redux Deku Example 2 | ===================== 3 | 4 | * redux, webpack, deku, router5 5 | * styling with css-modules 6 | 7 | extended from thomas roch's awesome [router5 examples](https://github.com/router5/examples) 8 | 9 | ## Run Dev 10 | 11 | ``` 12 | npm install 13 | npm start 14 | open http://localhost:3000 15 | ``` 16 | 17 | ## Run Prod 18 | 19 | ``` 20 | npm install 21 | npm run build 22 | npm start:prod 23 | open http://localhost:3000 24 | ``` 25 | 26 | ![](https://raw.githubusercontent.com/StevenIseki/redux-examples/master/redux-deku/public/img/screenshot.png) 27 | 28 | ## License 29 | 30 | [MIT](http://isekivacenz.mit-license.org/) 31 | -------------------------------------------------------------------------------- /redux-deku/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redux Deku Example 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /redux-deku/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-deku-example", 3 | "version": "1.0.0", 4 | "description": "redux deku example", 5 | "scripts": { 6 | "dist": "webpack --config webpack.config.js", 7 | "build": "npm run clean && npm run dist", 8 | "clean": "rm -rf public/scripts", 9 | "start": "npm run start:dev", 10 | "start:dev": "node serverDev.js", 11 | "start:prod": "NODE_ENV=production node server.js" 12 | }, 13 | "author": "Steven Iseki ", 14 | "license": "MIT", 15 | "homepage": "https://github.com/StevenIseki/webpack-css-loader-examples", 16 | "devDependencies": { 17 | "autoprefixer": "^6.1.0", 18 | "babel-core": "^6.0.20", 19 | "babel-loader": "^6.0.1", 20 | "babel-preset-es2015": "^6.0.15", 21 | "babel-preset-react": "^6.0.15", 22 | "babel-preset-stage-0": "^6.0.15", 23 | "css-loader": "^0.15.1", 24 | "express": "^4.13.3", 25 | "extract-text-webpack-plugin": "^0.9.1", 26 | "postcss-loader": "^0.7.0", 27 | "redux-devtools": "^2.1.5", 28 | "style-loader": "^0.13.0", 29 | "webpack": "^1.9.6", 30 | "webpack-dev-middleware": "^1.2.0", 31 | "webpack-hot-middleware": "^2.0.0" 32 | }, 33 | "dependencies": { 34 | "deku": "^0.5.6", 35 | "deku-redux": "^1.0.0", 36 | "deku-router5": "^1.0.0", 37 | "lodash.find": "^3.2.1", 38 | "redux": "^3.0.4", 39 | "redux-thunk": "^1.0.0", 40 | "redux-devtools": "^2.1.5", 41 | "redux-router5": "^1.0.0", 42 | "router5": "^1.0.0", 43 | "router5-history": "^1.0.0", 44 | "router5-listeners": "^1.0.0", 45 | "virtual-element": "^1.2.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /redux-deku/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var path = require('path') 3 | 4 | var port = process.env.PORT || 3000 5 | 6 | express() 7 | .use('/public', express.static(__dirname + '/public')) 8 | .get('*', function (req, res) { 9 | res.sendFile(path.join(__dirname, '/index.html')) 10 | }) 11 | .listen(port, function () { 12 | console.log(process.env) 13 | console.log('Listening on ' + port + '.') 14 | console.log('Go to in your browser.') 15 | }) -------------------------------------------------------------------------------- /redux-deku/serverDev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config.dev'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath 12 | })); 13 | 14 | app.use(require('webpack-hot-middleware')(compiler)); 15 | 16 | app.get('*', function(req, res) { 17 | res.sendFile(path.join(__dirname, 'index.html')); 18 | }); 19 | 20 | app.listen(3000, 'localhost', function(err) { 21 | if (err) { 22 | console.log(err); 23 | return; 24 | } 25 | 26 | console.log('Listening at http://localhost:3000'); 27 | }); 28 | -------------------------------------------------------------------------------- /redux-deku/src/actions/draft.js: -------------------------------------------------------------------------------- 1 | export function updateTitle(title) { 2 | return { 3 | type: 'UPDATE_TITLE', 4 | title 5 | }; 6 | } 7 | 8 | export function updateMessage(message) { 9 | return { 10 | type: 'UPDATE_MESSAGE', 11 | message 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /redux-deku/src/api.js: -------------------------------------------------------------------------------- 1 | const emails = [ 2 | { 3 | "id": "1", 4 | "mailTitle": "Why router5?", 5 | "mailMessage": "I imagine a lot of developers who will first see router5 will ask themselves the question: is it yet another router? is it any good? Why oh why do people keep writing new routers all the time? It is not always easy to see the potential of something straight away, or understand the motivations behind. I therefore decided to try to tell you more about router5, why I decided to develop an entire new routing solution, and what problems it tries to solve." 6 | }, 7 | { 8 | "id": "2", 9 | "mailTitle": "Use with React", 10 | "mailMessage": "I have just started playing with it. It does make sense to use a flux-like implementation, to provide a layer between the router and view updates." 11 | }, 12 | { 13 | "id": "3", 14 | "mailTitle": "Compose a new message", 15 | "mailMessage": "Click on compose, start to fill title and message fields and then try to navigate away by clicking on app links, or by using the back button." 16 | } 17 | ]; 18 | 19 | export function getEmails() { 20 | return emails; 21 | } 22 | 23 | export function getEmail(id) { 24 | let index; 25 | 26 | if (emails) { 27 | for (index in emails) { 28 | if (emails[index].id === id) return emails[index]; 29 | } 30 | } 31 | return null; 32 | } 33 | -------------------------------------------------------------------------------- /redux-deku/src/components/App.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 20px; 3 | line-height: 1.5rem; 4 | font-family: sans-serif, Arial; 5 | padding: 0; 6 | } 7 | 8 | a { 9 | text-decoration: none; 10 | } 11 | 12 | #root { 13 | margin: 40px auto; 14 | max-width: 1050px; 15 | } 16 | 17 | .mailClient { 18 | widht: 100%; 19 | height: 450px; 20 | background-color: #f4f4f4; 21 | position: relative; 22 | border: 1px solid #CCC; 23 | } 24 | 25 | .mailClient > aside { 26 | position: absolute; 27 | top: 0; 28 | right: 0; 29 | height: 45px; 30 | left: 0; 31 | border-bottom: 1px solid #ccc; 32 | } 33 | 34 | .mailClient > main { 35 | position: absolute; 36 | top: 46px; 37 | right: 0; 38 | bottom: 0; 39 | left: 0; 40 | } 41 | 42 | .mailClient > aside > nav > a { 43 | display: inline-block; 44 | padding: .5rem 1rem; 45 | color: #336699; 46 | } 47 | 48 | .mailClient > aside > nav > a.active { 49 | background-color: #336699; 50 | color: white; 51 | } 52 | 53 | 54 | 55 | @media (min-width: 1025px) { 56 | .mailClient > aside { 57 | height: auto; 58 | top: 0; 59 | width: 150px; 60 | bottom: 0; 61 | left: 0; 62 | border-bottom: none; 63 | border-right: 1px solid #ccc; 64 | } 65 | 66 | .mailClient > main { 67 | top: 0; 68 | right: 0; 69 | bottom: 0; 70 | left: 151px; 71 | } 72 | 73 | .mailClient > aside > nav > a { 74 | display: block; 75 | } 76 | } -------------------------------------------------------------------------------- /redux-deku/src/components/App.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import Nav from './Nav'; 3 | import Main from './Main'; 4 | import styles from './App.css'; 5 | 6 | const App = { 7 | render({ props }) { 8 | return element('div', {class: styles.mailClient}, [ 9 | element('aside', {}, element(Nav)), 10 | element('main', {}, element(Main)) 11 | ]); 12 | } 13 | } 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /redux-deku/src/components/Compose.css: -------------------------------------------------------------------------------- 1 | .compose { 2 | padding: 0 1rem; 3 | } 4 | 5 | .compose > h4 { 6 | padding: .5rem 0; 7 | margin: 0; 8 | } 9 | 10 | .compose > input, 11 | .compose > textarea { 12 | padding: .5rem; 13 | line-height: 1.2rem; 14 | font-size: 0.9rem; 15 | display: block; 16 | width: calc(100% - 2rem); 17 | max-width: 400px; 18 | margin-top: 1rem; 19 | } 20 | 21 | .compose > textarea { 22 | min-height: 200px; 23 | } 24 | 25 | .compose > p { 26 | color: red; 27 | margin: 0; 28 | padding: .5rem 0; 29 | line-height: 1.5em; 30 | font-size: 0.9rem; 31 | } 32 | -------------------------------------------------------------------------------- /redux-deku/src/components/Compose.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import { connect } from 'deku-redux'; 3 | import { createSelector } from 'reselect'; 4 | import { updateTitle, updateMessage } from '../actions/draft'; 5 | import styles from './Compose.css'; 6 | 7 | const draftSelector = createSelector( 8 | state => state.draft, 9 | state => state.router, 10 | (draft, router) => ({ 11 | title: draft.title, 12 | message: draft.message, 13 | error: hasCannotDeactivateError(router.transitionError) 14 | }) 15 | ); 16 | 17 | function hasCannotDeactivateError(error) { 18 | return error && error.code === 'CANNOT_DEACTIVATE' && error.segment === 'compose'; 19 | } 20 | 21 | const Compose = { 22 | propTypes: { 23 | router: { source: 'router' } 24 | }, 25 | 26 | intitalState(props) { 27 | return { title: '', message: '' }; 28 | }, 29 | 30 | render({ state, props }, setState) { 31 | const { title, message, error, updateTitle, updateMessage, router } = props; 32 | 33 | const updateState = prop => evt => setState(prop, evt.target.value); 34 | router.canDeactivate('compose', !title && !message); 35 | 36 | return element('div', { class: styles.compose }, [ 37 | element('h4', {}, 'Compose a new message'), 38 | element('input', { name: 'title', value: title, onChange: updateState('title') }), 39 | element('textarea', { name: 'message', value: message, onChange: updateState('message') }), 40 | error ? element('p', {}, 'Clear inputs before continuing') : null 41 | ]); 42 | } 43 | }; 44 | 45 | export default connect(draftSelector, { updateTitle, updateMessage })(Compose); 46 | -------------------------------------------------------------------------------- /redux-deku/src/components/Inbox.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import InboxList from './InboxList'; 3 | import Message from './Message'; 4 | import { connect } from 'deku-redux'; 5 | import { routeNodeSelector } from 'redux-router5'; 6 | import { getEmails } from '../api'; 7 | 8 | const Inbox = { 9 | displayName: 'Inbox', 10 | render({ props }) { 11 | const { route } = props; 12 | 13 | return element('div', { class: 'inbox' }, [ 14 | element(InboxList, { emails: getEmails() }), 15 | route && route.name === 'inbox.message' ? element(Message, { messageId: route.params.id, key: route.params.id }) : null 16 | ]); 17 | } 18 | }; 19 | 20 | export default connect(routeNodeSelector('inbox'))(Inbox); 21 | -------------------------------------------------------------------------------- /redux-deku/src/components/InboxItem.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | 3 | const InboxItem = { 4 | propTypes: { 5 | router: {source: 'router'}, 6 | }, 7 | 8 | render({ props }) { 9 | const { mailTitle, mailMessage, router, id } = props; 10 | 11 | return element('li', { onClick: () => router.navigate('inbox.message', { id }) }, [ 12 | element('h4', {}, mailTitle), 13 | element('p', {}, mailMessage) 14 | ]); 15 | } 16 | }; 17 | 18 | export default InboxItem; 19 | -------------------------------------------------------------------------------- /redux-deku/src/components/InboxList.css: -------------------------------------------------------------------------------- 1 | .inboxList { 2 | list-style: none; 3 | margin: 0; 4 | padding: 0; 5 | flex: 1; 6 | overflow: hidden; 7 | } 8 | 9 | .inboxList > li { 10 | padding: 0; 11 | cursor: pointer; 12 | border-bottom: 1px solid #ddd; 13 | } 14 | 15 | .inboxList > li:hover { 16 | background-color: #eee; 17 | } 18 | 19 | .inboxList > li > h4 { 20 | padding: .5rem 1rem 0; 21 | margin: 0; 22 | } 23 | 24 | .inboxList > li > p { 25 | margin: 0; 26 | padding: 0 1rem .5rem; 27 | line-height: 1.5em; 28 | font-size: 0.85rem; 29 | } 30 | 31 | .inboxList > li > h4, 32 | .inboxList > li > p { 33 | overflow: hidden; 34 | width: calc(100% - 2rem); 35 | white-space: nowrap; 36 | text-overflow: ellipsis; 37 | } -------------------------------------------------------------------------------- /redux-deku/src/components/InboxList.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import InboxItem from './InboxItem'; 3 | import styles from './InboxList.css'; 4 | 5 | const InboxList = { 6 | render({ props }) { 7 | return element( 8 | 'ul', 9 | { class: styles.inboxList }, 10 | props.emails.map(mail => element(InboxItem, { ...mail, key: mail.id })) 11 | ); 12 | } 13 | }; 14 | 15 | export default InboxList; 16 | -------------------------------------------------------------------------------- /redux-deku/src/components/Main.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import Inbox from './Inbox'; 3 | import Compose from './Compose'; 4 | import NotFound from './NotFound'; 5 | import { connect } from 'deku-redux'; 6 | import { routeNodeSelector } from 'redux-router5'; 7 | 8 | const components = { 9 | 'inbox': Inbox, 10 | 'compose': Compose 11 | }; 12 | 13 | const Main = { 14 | render({ props }) { 15 | const { route } = props; 16 | const segment = route ? route.name.split('.')[0] : undefined; 17 | 18 | return element(components[segment] || NotFound); 19 | } 20 | }; 21 | 22 | export default connect(routeNodeSelector(''))(Main); 23 | -------------------------------------------------------------------------------- /redux-deku/src/components/Message.css: -------------------------------------------------------------------------------- 1 | .message { 2 | border-left: 2px solid #ddd; 3 | overflow: auto; 4 | flex: 2; 5 | } 6 | 7 | .message > h4 { 8 | padding: 1rem 1rem 0; 9 | margin: 0; 10 | font-size: 0.8rem; 11 | } 12 | 13 | .message > p { 14 | margin: 0; 15 | padding: 1rem; 16 | line-height: 1.5em; 17 | font-size: 0.8rem; 18 | } -------------------------------------------------------------------------------- /redux-deku/src/components/Message.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import { getEmail } from '../api'; 3 | import styles from './Message.css'; 4 | 5 | const Message = { 6 | render({ props }) { 7 | const { mailTitle, mailMessage } = getEmail(props.messageId); 8 | 9 | return element('section', { class: styles.message } , [ 10 | element('h4', {}, mailTitle), 11 | element('p', {}, mailMessage) 12 | ]); 13 | } 14 | }; 15 | 16 | export default Message; 17 | -------------------------------------------------------------------------------- /redux-deku/src/components/Nav.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | import { Link } from 'deku-router5'; 3 | import { connect } from 'deku-redux'; 4 | import { actions } from 'redux-router5'; 5 | 6 | const Nav = { 7 | propTypes: { 8 | router: { source: 'router' } 9 | }, 10 | 11 | render({ props }) { 12 | const { router, navigateTo } = props; 13 | 14 | return element('nav', {}, [ 15 | element(Link, { routeName: 'inbox', routeOptions: { reload: true } }, 'Inbox'), 16 | element(Link, { routeName: 'compose' }, 'Compose'), 17 | element(Link, { routeName: 'contacts' }, 'Contacts') 18 | ]); 19 | } 20 | }; 21 | 22 | export default connect( 23 | state => state.router.route, 24 | { navigateTo: actions.navigateTo } 25 | )(Nav); 26 | -------------------------------------------------------------------------------- /redux-deku/src/components/NotFound.js: -------------------------------------------------------------------------------- 1 | import element from 'virtual-element'; 2 | 3 | const NotFound = { 4 | render() { 5 | return element('div', { class: 'not-found' }, 'Purposely not found (not a bug)'); 6 | } 7 | }; 8 | 9 | export default NotFound; 10 | -------------------------------------------------------------------------------- /redux-deku/src/create-router.js: -------------------------------------------------------------------------------- 1 | import { Router5 } from 'router5' 2 | import historyPlugin from 'router5-history'; 3 | 4 | export default function createRouter(routes) { 5 | const router = new Router5() 6 | .setOption('useHash', true) 7 | // .setOption('hashPrefix', '!') 8 | .setOption('defaultRoute', 'inbox') 9 | // Routes 10 | .addNode('inbox', '/inbox') 11 | .addNode('inbox.message', '/message/:id') 12 | .addNode('compose', '/compose') 13 | .addNode('contacts', '/contacts') 14 | // Plugins 15 | .usePlugin(Router5.loggerPlugin()) 16 | .usePlugin(historyPlugin()); 17 | 18 | return router; 19 | }; 20 | -------------------------------------------------------------------------------- /redux-deku/src/index.js: -------------------------------------------------------------------------------- 1 | import { tree, render } from 'deku'; 2 | import element from 'virtual-element'; 3 | import { storePlugin } from 'deku-redux'; 4 | import { routerPlugin } from 'deku-router5'; 5 | import App from './components/App'; 6 | import createRouter from './create-router' 7 | import configureStore from './store'; 8 | 9 | const router = createRouter(); 10 | 11 | router.start((err, state) => { 12 | const store = configureStore(router, { router: { route: state }}); 13 | 14 | const app = tree() 15 | .use(storePlugin(store)) 16 | .set('router', router) 17 | .mount(element(App)); 18 | 19 | render(app, document.getElementById('root')); 20 | }); 21 | -------------------------------------------------------------------------------- /redux-deku/src/reducers/draft.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | title: '', 3 | message: '' 4 | }; 5 | 6 | export default function draft(state = initialState, action) { 7 | switch (action.type) { 8 | case 'UPDATE_TITLE': 9 | return { 10 | ...state, 11 | title: action.title 12 | }; 13 | 14 | case 'UPDATE_MESSAGE': 15 | return { 16 | ...state, 17 | message: action.message 18 | }; 19 | 20 | default: 21 | return state; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /redux-deku/src/reducers/emails.js: -------------------------------------------------------------------------------- 1 | const initialState = [ 2 | { 3 | "id": "1", 4 | "mailTitle": "Why router5?", 5 | "mailMessage": "I imagine a lot of developers who will first see router5 will ask themselves the question: is it yet another router? is it any good? Why oh why do people keep writing new routers all the time? It is not always easy to see the potential of something straight away, or understand the motivations behind. I therefore decided to try to tell you more about router5, why I decided to develop an entire new routing solution, and what problems it tries to solve." 6 | }, 7 | { 8 | "id": "2", 9 | "mailTitle": "Use with React", 10 | "mailMessage": "I have just started playing with it. It does make sense to use a flux-like implementation, to provide a layer between the router and view updates." 11 | }, 12 | { 13 | "id": "3", 14 | "mailTitle": "Compose a new message", 15 | "mailMessage": "Click on compose, start to fill title and message fields and then try to navigate away by clicking on app links, or by using the back button." 16 | } 17 | ]; 18 | 19 | export default function emails(state = initialState, action) { 20 | switch (action.type) { 21 | default: 22 | return state; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /redux-deku/src/store.js: -------------------------------------------------------------------------------- 1 | import { compose, createStore, applyMiddleware, combineReducers } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { router5Middleware, router5Reducer } from 'redux-router5'; 4 | import emails from './reducers/emails'; 5 | import draft from './reducers/draft'; 6 | 7 | export default function configureStore(router, initialState = {}) { 8 | const createStoreWithMiddleware = applyMiddleware(router5Middleware(router))(createStore); 9 | 10 | const store = createStoreWithMiddleware(combineReducers({ 11 | router: router5Reducer, 12 | emails, 13 | draft 14 | }), initialState); 15 | 16 | window.store = store; 17 | return store; 18 | } 19 | -------------------------------------------------------------------------------- /redux-deku/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | devtool: 'source-map', 8 | entry: ['./src/index'], 9 | output: { 10 | filename: 'bundle.js', 11 | path: path.join(__dirname, 'public'), 12 | publicPath: '/public/' 13 | }, 14 | module: { 15 | loaders: [ 16 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 17 | { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') } 18 | ] 19 | }, 20 | postcss: function () { 21 | return [autoprefixer]; 22 | }, 23 | plugins: [ 24 | new ExtractTextPlugin('style.css', { allChunks: true }) 25 | ] 26 | 27 | }; -------------------------------------------------------------------------------- /redux-deku/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | entry: [ 8 | './src/index' 9 | ], 10 | output: { 11 | filename: 'bundle.js', 12 | path: path.join(__dirname, 'public'), 13 | publicPath: '/public/' 14 | }, 15 | plugins: [ 16 | new ExtractTextPlugin('style.css', { allChunks: true }), 17 | new webpack.optimize.OccurenceOrderPlugin(), 18 | new webpack.DefinePlugin({ 19 | 'process.env': { 20 | 'NODE_ENV': JSON.stringify('production') 21 | } 22 | }), 23 | new webpack.optimize.UglifyJsPlugin({ 24 | compressor: { 25 | warnings: false 26 | } 27 | }) 28 | ], 29 | module: { 30 | loaders: [ 31 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 32 | { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') } 33 | ] 34 | }, 35 | postcss: function () { 36 | return [autoprefixer]; 37 | } 38 | 39 | }; -------------------------------------------------------------------------------- /redux-react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /redux-react/README.md: -------------------------------------------------------------------------------- 1 | Redux React App Example 2 | ===================== 3 | 4 | * redux, webpack, react, router5 5 | * styling with css-modules 6 | * Check out this [simple example](https://github.com/StevenIseki/redux-examples/tree/master/redux-friends-app) for BEM style class names imported with css-loader. 7 | 8 | extended from Jérôme Chapron's awesome [friendlist example](https://github.com/jchapron/redux-friendlist-demo) 9 | 10 | ## Run Dev 11 | 12 | ``` 13 | npm install 14 | npm start 15 | open http://localhost:3000 16 | ``` 17 | 18 | ## Run Prod 19 | 20 | ``` 21 | npm install 22 | npm run build 23 | npm start:prod 24 | open http://localhost:3000 25 | ``` 26 | 27 | ![](https://raw.githubusercontent.com/StevenIseki/redux-examples/master/redux-friends-app/public/screenshot.png) 28 | 29 | ## License 30 | 31 | [MIT](http://isekivacenz.mit-license.org/) 32 | -------------------------------------------------------------------------------- /redux-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redux Friends App Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /redux-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-react-app", 3 | "version": "1.0.0", 4 | "description": "redux react app", 5 | "scripts": { 6 | "dist": "webpack --config webpack.config.js", 7 | "build": "npm run clean && npm run dist", 8 | "clean": "rm -rf public/scripts", 9 | "start": "npm run start:dev", 10 | "start:dev": "node serverDev.js", 11 | "start:prod": "NODE_ENV=production node server.js" 12 | }, 13 | "author": "Steven Iseki ", 14 | "license": "MIT", 15 | "homepage": "https://github.com/StevenIseki/webpack-css-loader-examples", 16 | "devDependencies": { 17 | "autoprefixer": "^6.1.0", 18 | "babel-core": "^6.0.20", 19 | "babel-loader": "^6.0.1", 20 | "babel-preset-es2015": "^6.0.15", 21 | "babel-preset-react": "^6.0.15", 22 | "babel-preset-stage-0": "^6.0.15", 23 | "css-loader": "^0.15.1", 24 | "express": "^4.13.3", 25 | "extract-text-webpack-plugin": "^0.9.1", 26 | "postcss-loader": "^0.7.0", 27 | "redux-devtools": "^2.1.5", 28 | "style-loader": "^0.13.0", 29 | "webpack": "^1.9.6", 30 | "webpack-dev-middleware": "^1.2.0", 31 | "webpack-hot-middleware": "^2.0.0" 32 | }, 33 | "dependencies": { 34 | "react": "^0.14.0", 35 | "react-dom": "^0.14.0", 36 | "react-redux": "^4.0.0", 37 | "react-router5": "^1.0.0", 38 | "redux": "^3.0.4", 39 | "redux-router5": "^1.0.0", 40 | "redux-thunk": "^1.0.0", 41 | "router5": "^1.0.0", 42 | "router5-history": "^1.0.0", 43 | "router5-listeners": "^1.0.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /redux-react/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var path = require('path') 3 | 4 | var port = process.env.PORT || 3000 5 | 6 | express() 7 | .use('/public', express.static(__dirname + '/public')) 8 | .get('*', function (req, res) { 9 | res.sendFile(path.join(__dirname, '/index.html')) 10 | }) 11 | .listen(port, function () { 12 | /* console.log(process.env) */ 13 | console.log('Listening on ' + port + '.') 14 | console.log('Go to in your browser.') 15 | }) -------------------------------------------------------------------------------- /redux-react/serverDev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config.dev'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath 12 | })); 13 | 14 | app.get('*', function(req, res) { 15 | res.sendFile(path.join(__dirname, 'index.html')); 16 | }); 17 | 18 | app.listen(3000, 'localhost', function(err) { 19 | if (err) { 20 | console.log(err); 21 | return; 22 | } 23 | 24 | console.log('Listening at http://localhost:3000'); 25 | }); 26 | -------------------------------------------------------------------------------- /redux-react/src/actions/FriendsActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | export function addFriend(name) { 4 | return { 5 | type: types.ADD_FRIEND, 6 | name 7 | }; 8 | } 9 | 10 | export function deleteFriend(id) { 11 | return { 12 | type: types.DELETE_FRIEND, 13 | id 14 | }; 15 | } 16 | 17 | export function starFriend(id) { 18 | return { 19 | type: types.STAR_FRIEND, 20 | id 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /redux-react/src/components/AddFriendInput.css: -------------------------------------------------------------------------------- 1 | .addFriendInput { 2 | border-radius: 0; 3 | border-color: #ABAAAA; 4 | border-left: 0; 5 | border-right: 0; 6 | } 7 | -------------------------------------------------------------------------------- /redux-react/src/components/AddFriendInput.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import styles from './AddFriendInput.css'; 3 | 4 | export default class AddFriendInput extends Component { 5 | 6 | static propTypes = { 7 | addFriend: PropTypes.func.isRequired 8 | } 9 | 10 | render () { 11 | return ( 12 | 21 | ); 22 | } 23 | 24 | constructor (props, context) { 25 | super(props, context); 26 | this.state = { 27 | name: this.props.name || '', 28 | }; 29 | } 30 | 31 | handleChange (e) { 32 | this.setState({ name: e.target.value }); 33 | } 34 | 35 | handleSubmit (e) { 36 | const name = e.target.value.trim(); 37 | if (e.which === 13) { 38 | this.props.addFriend(name); 39 | this.setState({ name: '' }); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /redux-react/src/components/FriendList.css: -------------------------------------------------------------------------------- 1 | .friendList { 2 | padding-left: 0; 3 | margin-bottom: 0; 4 | } -------------------------------------------------------------------------------- /redux-react/src/components/FriendList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import FriendListItem from '../components/FriendListItem'; 3 | import { connect } from 'react-redux'; 4 | import { bindActionCreators } from 'redux'; 5 | import { actions } from 'redux-router5'; 6 | import styles from './FriendList.css'; 7 | 8 | import * as FriendsActions from '../actions/FriendsActions'; 9 | 10 | function FriendList(props) { 11 | return ( 12 |
    13 | { 14 | props.friends.map( 15 | friend => props.deleteFriend(friend.id) } 18 | starFriend={ () => props.starFriend(friend.id) } 19 | /> 20 | ) 21 | } 22 |
23 | ); 24 | } 25 | 26 | export default connect( 27 | state => ({ friends: state.friendlist.friends }), 28 | dispatch => bindActionCreators(FriendsActions, dispatch) 29 | )(FriendList); 30 | -------------------------------------------------------------------------------- /redux-react/src/components/FriendListItem.css: -------------------------------------------------------------------------------- 1 | .friendListItem { 2 | list-style: none; 3 | padding: 20px 10px 20px 20px; 4 | background-color: white; 5 | border-bottom: 1px solid #E3E3E3; 6 | display: flex; 7 | } 8 | 9 | .friendInfos { 10 | flex: 1 0 auto; 11 | } 12 | 13 | .friendInfos span { 14 | font-weight: bold; 15 | } 16 | 17 | .friendActions { 18 | flex: 0 0 90px; 19 | } 20 | 21 | .btn-default, 22 | .btn-default:active, 23 | .btn-default:focus, 24 | .btn-default:hover { 25 | margin-right: 5px; 26 | color: #5C75B0; 27 | } 28 | 29 | button:focus { 30 | outline: 0 !important; 31 | } 32 | -------------------------------------------------------------------------------- /redux-react/src/components/FriendListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './FriendListItem.css'; 3 | 4 | function FriendListItem(props) { 5 | const { name, starred, starFriend, deleteFriend } = props; 6 | 7 | let starClassName = 'fa fa-star-o' 8 | if(starred){ 9 | starClassName = 'fa fa-star' 10 | } 11 | 12 | 13 | return ( 14 | 15 |
  • 16 |
    17 |
    18 | {props.name} 19 |
    20 |
    21 |
    22 | 25 | 28 |
    29 |
  • 30 | 31 | ); 32 | } 33 | 34 | export default FriendListItem; 35 | -------------------------------------------------------------------------------- /redux-react/src/components/NotFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function NotFound(props) { 4 | return
    Purposely Not found (not a bug)
    ; 5 | } 6 | -------------------------------------------------------------------------------- /redux-react/src/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_FRIEND = 'ADD_FRIEND'; 2 | export const STAR_FRIEND = 'STAR_FRIEND'; 3 | export const DELETE_FRIEND = 'DELETE_FRIEND'; 4 | -------------------------------------------------------------------------------- /redux-react/src/containers/FriendListContainer.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F4F3F0; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | } 7 | 8 | .friendListApp { 9 | width: 300px; 10 | padding-top: 18px; 11 | background-color: #5C75B0; 12 | border: 1px solid #E3E3E3; 13 | } 14 | 15 | .friendListApp h1 { 16 | color: white; 17 | font-size: 16px; 18 | line-height: 20px; 19 | margin-bottom: 10px; 20 | margin-top: 0; 21 | padding-left: 10px; 22 | font-family: Helvetica; 23 | } 24 | -------------------------------------------------------------------------------- /redux-react/src/containers/FriendListContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './FriendListContainer.css'; 3 | import AddFriendInput from '../components/AddFriendInput'; 4 | import FriendList from '../components/FriendList'; 5 | import { connect } from 'react-redux'; 6 | import { routeNodeSelector } from 'redux-router5'; 7 | import { bindActionCreators } from 'redux'; 8 | import * as FriendsActions from '../actions/FriendsActions'; 9 | 10 | function FriendListContainer( props) { 11 | 12 | const { route } = props; 13 | 14 | const actions = { 15 | addFriend: props.addFriend, 16 | deleteFriend: props.deleteFriend, 17 | starFriend: props.starFriend 18 | } 19 | 20 | return ( 21 |
    22 |

    The FriendList

    23 | 24 | 25 |
    26 | ); 27 | } 28 | 29 | export default connect( 30 | routeNodeSelector('friends'), 31 | dispatch => bindActionCreators(FriendsActions, dispatch) 32 | )(FriendListContainer); 33 | -------------------------------------------------------------------------------- /redux-react/src/containers/Main.js: -------------------------------------------------------------------------------- 1 | import React, { createElement } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { routeNodeSelector } from 'redux-router5'; 4 | 5 | import FriendListContainer from './FriendListContainer'; 6 | import NotFound from '../components/NotFound'; 7 | 8 | const components = { 9 | 'friends': FriendListContainer 10 | }; 11 | 12 | function Main(props) { 13 | const { route } = props; 14 | const segment = route ? route.name.split('.')[0] : undefined; 15 | return createElement(components[segment] || NotFound); 16 | } 17 | 18 | export default connect(routeNodeSelector(''))(Main); 19 | -------------------------------------------------------------------------------- /redux-react/src/create-router.js: -------------------------------------------------------------------------------- 1 | import { Router5 } from 'router5' 2 | import historyPlugin from 'router5-history'; 3 | 4 | export default function createRouter(routes) { 5 | const router = new Router5() 6 | .setOption('useHash', false) 7 | .setOption('defaultRoute', 'friends') 8 | // Routes 9 | .addNode('friends', '/friends') 10 | // Plugins 11 | .usePlugin(Router5.loggerPlugin()) 12 | .usePlugin(historyPlugin()); 13 | 14 | return router; 15 | }; 16 | -------------------------------------------------------------------------------- /redux-react/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import { RouterProvider } from 'react-router5'; 4 | import ReactDOM from 'react-dom'; 5 | import createRouter from './create-router' 6 | import configureStore from './store'; 7 | 8 | import Main from './containers/Main'; 9 | 10 | function App(props) { 11 | return ( 12 |
    13 |
    14 |
    15 | ); 16 | } 17 | 18 | 19 | const router = createRouter(); 20 | 21 | router.start((err, state) => { 22 | const store = configureStore(router, { router: { route: state }}); 23 | 24 | const wrappedApp = ( 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | 32 | ReactDOM.render(wrappedApp, document.getElementById('root')); 33 | }); 34 | -------------------------------------------------------------------------------- /redux-react/src/reducers/friendlist.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | const initialState = { 4 | friendsAdded: 3, 5 | friends: [ 6 | { 7 | id: 1, 8 | name: 'Brian Lara', 9 | starred: false 10 | }, 11 | { 12 | id: 2, 13 | name: 'Sachin Tendulkar', 14 | starred: false 15 | }, 16 | { 17 | id: 3, 18 | name: 'Ricky Ponting', 19 | starred: false 20 | } 21 | ] 22 | } 23 | 24 | export default function friends(state = initialState, action) { 25 | switch (action.type) { 26 | 27 | case types.ADD_FRIEND: 28 | const newFriend = { 29 | id: state.friendsAdded + 1, 30 | name: action.name 31 | } 32 | 33 | return { 34 | ...state, 35 | friendsAdded: state.friendsAdded + 1, 36 | friends: state.friends.concat(newFriend) 37 | } 38 | 39 | case types.DELETE_FRIEND: 40 | 41 | const newFriends = state.friends.filter(function(friend) { 42 | return friend.id !== action.id; 43 | }); 44 | 45 | return { 46 | ...state, 47 | friends: newFriends 48 | } 49 | 50 | case types.STAR_FRIEND: 51 | 52 | const starredFriends = state.friends.map(function(friend) { 53 | if(friend.id === action.id){ 54 | friend.starred = true; 55 | } 56 | return friend; 57 | }); 58 | 59 | return { 60 | ...state, 61 | friends: starredFriends 62 | } 63 | 64 | default: 65 | return state; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /redux-react/src/store.js: -------------------------------------------------------------------------------- 1 | import { compose, createStore, applyMiddleware, combineReducers } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { router5Middleware, router5Reducer } from 'redux-router5'; 4 | import friendlist from './reducers/friendlist'; 5 | 6 | export default function configureStore(router, initialState = {}) { 7 | const createStoreWithMiddleware = applyMiddleware(router5Middleware(router))(createStore); 8 | 9 | const store = createStoreWithMiddleware(combineReducers({ 10 | router: router5Reducer, 11 | friendlist 12 | }), initialState); 13 | 14 | window.store = store; 15 | return store; 16 | } 17 | -------------------------------------------------------------------------------- /redux-react/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | devtool: 'source-map', 8 | entry: ['./src/index'], 9 | output: { 10 | filename: 'bundle.js', 11 | path: path.join(__dirname, 'public'), 12 | publicPath: '/public/' 13 | }, 14 | module: { 15 | loaders: [ 16 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 17 | { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') } 18 | ] 19 | }, 20 | postcss: function () { 21 | return [autoprefixer]; 22 | }, 23 | plugins: [ 24 | new ExtractTextPlugin('style.css', { allChunks: true }) 25 | ] 26 | 27 | }; -------------------------------------------------------------------------------- /redux-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | entry: [ 8 | './src/index' 9 | ], 10 | output: { 11 | filename: 'bundle.js', 12 | path: path.join(__dirname, 'public'), 13 | publicPath: '/public/' 14 | }, 15 | plugins: [ 16 | new ExtractTextPlugin('style.css', { allChunks: true }), 17 | new webpack.optimize.OccurenceOrderPlugin(), 18 | new webpack.DefinePlugin({ 19 | 'process.env': { 20 | 'NODE_ENV': JSON.stringify('production') 21 | } 22 | }), 23 | new webpack.optimize.UglifyJsPlugin({ 24 | compressor: { 25 | warnings: false 26 | } 27 | }) 28 | ], 29 | module: { 30 | loaders: [ 31 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, 32 | { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') } 33 | ] 34 | }, 35 | postcss: function () { 36 | return [autoprefixer]; 37 | } 38 | 39 | }; --------------------------------------------------------------------------------