diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..87aaf4b
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["es2015", "stage-0", "react"],
+ "plugins": ["transform-runtime"]
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9f9fc21
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.DS_STORE
+node_modules
+static
+.module-cache
+*.log*
+
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..ecbd96b
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,75 @@
+# Ventura Next Poc
+
+Un proof of concept di una struttura a plugin per una applicazione react
+
+## Contiene
+
+- [x] [Webpack](https://webpack.github.io)
+- [x] [React](https://facebook.github.io/react/)
+- [x] [Redux](https://github.com/reactjs/redux)
+- [x] [Babel](https://babeljs.io/)
+
+## Setup
+
+```
+$ npm install
+```
+
+## Running
+
+```
+$ npm start
+```
+
+## Come funziona
+
+Nel file package.json alcune dipendenze possono essere specificate anche dentro l'array *venturaPlugins*. Questo marca queste dipendenze come plugin compatibili con il sistema descritto in seguito, cio non toglie che questi plugin saranno gestibili come pacchetti npm indipendenti.
+```json
+"venturaPlugins": [
+ "Settings",
+ "Clients",
+ "Maps"
+],
+```
+Attraverso webpack viene letto l'array dei plugin e messo in una costante *VENTURA_PLUGINS* che sarà disponibile nell'applicazione.
+
+```javascript
+new webpack.DefinePlugin({
+ VENTURA_PLUGINS: JSON.stringify(require("./package.json").venturaPlugins)
+})
+```
+
+*App*, che è il nostro componente connesso con lo stato di redux, legge la costante VENTURA_PLUGINS e richiede i plugin durante la fase di boot dell'applicazione
+```javascript
+const plugins = VENTURA_PLUGINS.map(plugin => {
+ return require('components/' + plugin + '/index.js').default
+});
+```
+Successivamente salva i nostri plugin nello stato di redux
+```javascript
+actions.addPlugins(plugins);
+```
+A questo punto, il nostro redux store è informato dei plugin che sono presenti.
+
+Per esempio, un plugin che voglia aggiungere una voce al menu dell'applicazione, può passare tramite props il componente che implementa questa voce di menu al componente builtin *SideBar*
+
+In questo POC i plugin sono fondamentalmente delle voci di menu a cui è associato un altro
+componente che viene visualizzato nella sezione principale.
+
+Ogni plugin caricato nella sidebar può essere associato una serie di componenti dipendenti, in questo caso cliccando su un elemento della sidebar viene caricato il componente selezionato in *MainSection*, nel nostro esempio viene caricato un h1 diverso.
+
+## Caricamento Lazy dei plugin
+
+Utilizzando [**bundle-loader**](https://github.com/webpack/bundle-loader) di webpack è possibile ottenere il caricamento Lazy dei plugin che quindi, inizialmente non fanno parte del bundle ma vengono caricati dinamicamente in un secondo momento.
+
+```javascript
+const plugin = 'Orders';
+const waitForChunk = require('bundle?lazy!./../../../plugins/Orders/index.js')
+
+waitForChunk((file) => {
+ const newPlugin = file.default
+ actions.addPlugins([newPlugin]);
+});
+```
+
+Schiacciando sul bottone Add Order in alto a destra del POC, viene caricato un nuovo bundle js che aggiunge una nuova voce di menu, Orders nel nostro caso, caricando anche il suo componente figlio.
diff --git a/client/actions/todos.js b/client/actions/todos.js
new file mode 100644
index 0000000..5594d6e
--- /dev/null
+++ b/client/actions/todos.js
@@ -0,0 +1,9 @@
+
+import { createAction } from 'redux-actions'
+
+export const addPlugins = createAction('add plugins')
+export const showPlugin = createAction('show plugin')
+export const editTodo = createAction('edit todo')
+export const completeTodo = createAction('complete todo')
+export const completeAll = createAction('complete all')
+export const clearCompleted = createAction('clear complete')
diff --git a/client/components/Clients/index.js b/client/components/Clients/index.js
new file mode 100644
index 0000000..e009368
--- /dev/null
+++ b/client/components/Clients/index.js
@@ -0,0 +1,20 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+import ClientsMain from './main'
+
+
+class Clients extends Component {
+ renderPlugin = () => {
+ this.props.actions.showPlugin( );
+ };
+ render() {
+ return (
+
+ Clients
+
+ );
+ }
+}
+
+export default Clients
diff --git a/client/components/Clients/main.js b/client/components/Clients/main.js
new file mode 100644
index 0000000..d4ba598
--- /dev/null
+++ b/client/components/Clients/main.js
@@ -0,0 +1,17 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+
+
+class ClientsMain extends Component {
+
+ render() {
+ return (
+
+ Clients
+
+ );
+ }
+}
+
+export default ClientsMain
diff --git a/client/components/Clients/style.css b/client/components/Clients/style.css
new file mode 100644
index 0000000..e02e374
--- /dev/null
+++ b/client/components/Clients/style.css
@@ -0,0 +1,5 @@
+.main {
+ flex: 1;
+ border-bottom: 1px solid #fff;
+ color: #fff;
+}
diff --git a/client/components/Footer/index.js b/client/components/Footer/index.js
new file mode 100644
index 0000000..840c1b3
--- /dev/null
+++ b/client/components/Footer/index.js
@@ -0,0 +1,66 @@
+
+import React, { Component } from 'react'
+import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from 'constants/filters'
+import classnames from 'classnames'
+import style from './style.css'
+
+const FILTER_TITLES = {
+ [SHOW_ALL]: 'All',
+ [SHOW_ACTIVE]: 'Active',
+ [SHOW_COMPLETED]: 'Completed'
+}
+
+class Footer extends Component {
+ renderTodoCount = () => {
+ const { activeCount } = this.props
+ const itemWord = activeCount === 1 ? 'item' : 'items'
+
+ return (
+
+ {activeCount || 'No'} {itemWord} left
+
+ )
+ };
+
+ renderFilterLink = (filter) => {
+ const title = FILTER_TITLES[filter]
+ const { filter: selectedFilter, onShow } = this.props
+
+ return (
+ onShow(filter)}>
+ {title}
+
+ )
+ };
+
+ renderClearButton = () => {
+ const { completedCount, onClearCompleted } = this.props
+ if (completedCount > 0) {
+ return (
+
+ Clear completed
+
+ )
+ }
+ };
+
+ render() {
+ return (
+
+ {this.renderTodoCount()}
+
+ {[SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED].map(filter =>
+
+ {this.renderFilterLink(filter)}
+
+ )}
+
+ {this.renderClearButton()}
+
+ )
+ }
+}
+
+export default Footer
diff --git a/client/components/Footer/style.css b/client/components/Footer/style.css
new file mode 100644
index 0000000..8cb9a8d
--- /dev/null
+++ b/client/components/Footer/style.css
@@ -0,0 +1,96 @@
+
+.normal {
+ color: #777;
+ padding: 10px 15px;
+ height: 20px;
+ text-align: center;
+ border-top: 1px solid #e6e6e6;
+}
+
+.normal:before {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 50px;
+ overflow: hidden;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
+ 0 8px 0 -3px #f6f6f6,
+ 0 9px 1px -3px rgba(0, 0, 0, 0.2),
+ 0 16px 0 -6px #f6f6f6,
+ 0 17px 2px -6px rgba(0, 0, 0, 0.2);
+}
+
+.filters {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ right: 0;
+ left: 0;
+}
+
+.filters li {
+ display: inline;
+}
+
+.filters li a {
+ color: inherit;
+ margin: 3px;
+ padding: 3px 7px;
+ text-decoration: none;
+ border: 1px solid transparent;
+ border-radius: 3px;
+}
+
+.filters li a.selected,
+.filters li a:hover {
+ border-color: rgba(175, 47, 47, 0.1);
+}
+
+.filters li a.selected {
+ border-color: rgba(175, 47, 47, 0.2);
+}
+
+.count {
+ float: left;
+ text-align: left;
+}
+
+.count strong {
+ font-weight: 300;
+}
+
+.clearCompleted,
+html .clearCompleted:active {
+ float: right;
+ position: relative;
+ line-height: 20px;
+ text-decoration: none;
+ cursor: pointer;
+ visibility: hidden;
+ position: relative;
+}
+
+.clearCompleted::after {
+ visibility: visible;
+ content: 'Clear completed';
+ position: absolute;
+ right: 0;
+ white-space: nowrap;
+}
+
+.clearCompleted:hover::after {
+ text-decoration: underline;
+}
+
+@media (max-width: 430px) {
+ .normal {
+ height: 50px;
+ }
+
+ .filters {
+ bottom: 10px;
+ }
+}
\ No newline at end of file
diff --git a/client/components/Header/index.js b/client/components/Header/index.js
new file mode 100644
index 0000000..2caf7dd
--- /dev/null
+++ b/client/components/Header/index.js
@@ -0,0 +1,14 @@
+
+import React, { Component } from 'react'
+
+class Header extends Component {
+ render() {
+ return (
+
+ React redux plugin POC
+
+ )
+ }
+}
+
+export default Header
diff --git a/client/components/MainSection/index.js b/client/components/MainSection/index.js
new file mode 100644
index 0000000..8eca5e4
--- /dev/null
+++ b/client/components/MainSection/index.js
@@ -0,0 +1,23 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+
+
+class MainSection extends Component {
+ render() {
+ const {
+ plugin
+ } = this.props;
+ return (
+
+ {
+ Object.keys(plugin).length > 0 && JSON.stringify(plugin) !== JSON.stringify({})
+ ? plugin
+ :
Dashboard
+ }
+
+ );
+ }
+}
+
+export default MainSection
diff --git a/client/components/MainSection/style.css b/client/components/MainSection/style.css
new file mode 100644
index 0000000..1ff1947
--- /dev/null
+++ b/client/components/MainSection/style.css
@@ -0,0 +1,7 @@
+
+.main {
+ flex: 3;
+ padding: 2em;
+ background: darkseagreen;
+ color: #fff;
+}
diff --git a/client/components/Maps/index.js b/client/components/Maps/index.js
new file mode 100644
index 0000000..9889c4b
--- /dev/null
+++ b/client/components/Maps/index.js
@@ -0,0 +1,20 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+import MapsMain from './main'
+
+
+class Maps extends Component {
+ renderPlugin = () => {
+ this.props.actions.showPlugin( );
+ };
+ render() {
+ return (
+
+ Maps
+
+ );
+ }
+}
+
+export default Maps
diff --git a/client/components/Maps/main.js b/client/components/Maps/main.js
new file mode 100644
index 0000000..01ee55a
--- /dev/null
+++ b/client/components/Maps/main.js
@@ -0,0 +1,17 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+
+
+class MapsMain extends Component {
+
+ render() {
+ return (
+
+ Maps
+
+ );
+ }
+}
+
+export default MapsMain
diff --git a/client/components/Maps/style.css b/client/components/Maps/style.css
new file mode 100644
index 0000000..e02e374
--- /dev/null
+++ b/client/components/Maps/style.css
@@ -0,0 +1,5 @@
+.main {
+ flex: 1;
+ border-bottom: 1px solid #fff;
+ color: #fff;
+}
diff --git a/client/components/Settings/index.js b/client/components/Settings/index.js
new file mode 100644
index 0000000..375a566
--- /dev/null
+++ b/client/components/Settings/index.js
@@ -0,0 +1,20 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+import SettingsMain from './main'
+
+class Settings extends Component {
+ renderPlugin = () => {
+ console.log(SettingsMain);
+ this.props.actions.showPlugin( );
+ };
+ render() {
+ return (
+
+ Settings
+
+ );
+ }
+}
+
+export default Settings
diff --git a/client/components/Settings/main.js b/client/components/Settings/main.js
new file mode 100644
index 0000000..7462e0f
--- /dev/null
+++ b/client/components/Settings/main.js
@@ -0,0 +1,17 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+
+
+class SettingsMain extends Component {
+
+ render() {
+ return (
+
+ Settings
+
+ );
+ }
+}
+
+export default SettingsMain
diff --git a/client/components/Settings/style.css b/client/components/Settings/style.css
new file mode 100644
index 0000000..e02e374
--- /dev/null
+++ b/client/components/Settings/style.css
@@ -0,0 +1,5 @@
+.main {
+ flex: 1;
+ border-bottom: 1px solid #fff;
+ color: #fff;
+}
diff --git a/client/components/SideBar/index.js b/client/components/SideBar/index.js
new file mode 100644
index 0000000..7654a4e
--- /dev/null
+++ b/client/components/SideBar/index.js
@@ -0,0 +1,23 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+import Settings from 'components/Settings'
+
+class SideBar extends Component {
+ renderPlugins = () => {
+ return this.props.plugins.map((Component, i) => {
+ return ;
+ })
+ };
+ render() {
+ return (
+
+
+ {this.renderPlugins()}
+
+
+ );
+ }
+}
+
+export default SideBar
diff --git a/client/components/SideBar/style.css b/client/components/SideBar/style.css
new file mode 100644
index 0000000..fb7a276
--- /dev/null
+++ b/client/components/SideBar/style.css
@@ -0,0 +1,15 @@
+.main {
+ flex: 1;
+ background: #333;
+ color: #fff;
+}
+.ul {
+ padding: 0;
+ list-style-type: none;
+}
+.li {
+ flex: 1;
+ padding: 1em;
+ border-bottom: 1px solid #fff;
+ color: #fff;
+}
diff --git a/client/constants/filters.js b/client/constants/filters.js
new file mode 100644
index 0000000..1547670
--- /dev/null
+++ b/client/constants/filters.js
@@ -0,0 +1,4 @@
+
+export const SHOW_ALL = 'show_all'
+export const SHOW_COMPLETED = 'show_completed'
+export const SHOW_ACTIVE = 'show_active'
diff --git a/client/containers/App/index.js b/client/containers/App/index.js
new file mode 100644
index 0000000..361674d
--- /dev/null
+++ b/client/containers/App/index.js
@@ -0,0 +1,68 @@
+
+import React, { Component } from 'react'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+import Header from 'components/Header'
+import MainSection from 'components/MainSection'
+import SideBar from 'components/SideBar'
+import * as TodoActions from 'actions/todos'
+import style from './style.css'
+
+class App extends Component {
+ componentDidMount() {
+ const { actions, children } = this.props
+ // EXTERNAL_PLUGINS comes from webpack config
+ const plugins = EXTERNAL_PLUGINS.map(plugin => {
+ const waitForChunk = require('bundle?lazy!components/' + plugin + '/index.js')
+ waitForChunk((file) => {
+ const newPlugin = file.default
+ actions.addPlugins([newPlugin]);
+ });
+ });
+ }
+ addPluginRuntime = () => {
+ const { actions, children } = this.props
+ const plugin = 'Orders';
+ const waitForChunk = require('bundle?lazy!./../../../plugins/Orders/index.js')
+
+ waitForChunk((file) => {
+ const newPlugin = file.default
+ actions.addPlugins([newPlugin]);
+ });
+
+ }
+ render() {
+ const { plugin, plugins, actions, children } = this.props
+ console.log(plugins);
+ return (
+
+ )
+ }
+}
+
+function mapStateToProps(state) {
+ return {
+ plugins: state.plugins,
+ plugin: state.plugin
+ }
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(TodoActions, dispatch)
+ }
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(App)
diff --git a/client/containers/App/style.css b/client/containers/App/style.css
new file mode 100644
index 0000000..8dea626
--- /dev/null
+++ b/client/containers/App/style.css
@@ -0,0 +1,56 @@
+
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: none;
+ font-size: 100%;
+ vertical-align: baseline;
+ font-family: inherit;
+ font-weight: inherit;
+ color: inherit;
+ appearance: none;
+ font-smoothing: antialiased;
+}
+
+body {
+ margin: 0 auto;
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ font-weight: 300;
+ line-height: 1.4em;
+ color: #4d4d4d;
+ background: #f5f5f5;
+}
+
+button,
+input[type="checkbox"] {
+ outline: none;
+}
+
+.container {
+ position: relative;
+ margin: 0 auto;
+ width: 1200px;
+ max-width: 100%;
+}
+.mainContainer {
+ display: flex;
+ justify-content: center;
+ min-height: 600px;
+}
+.button {
+ position: absolute;
+ right: 0;
+ padding: 0.5em 1em;
+ background: gold;
+}
diff --git a/client/index.html b/client/index.html
new file mode 100644
index 0000000..acc645d
--- /dev/null
+++ b/client/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+ React redux plugin
+
+
+
+
+
+
+
+
+
diff --git a/client/index.js b/client/index.js
new file mode 100644
index 0000000..5e4450a
--- /dev/null
+++ b/client/index.js
@@ -0,0 +1,22 @@
+
+import { Router, Route, browserHistory } from 'react-router'
+import { syncHistoryWithStore } from 'react-router-redux'
+import { Provider } from 'react-redux'
+import ReactDOM from 'react-dom'
+import React from 'react'
+
+import App from 'containers/App'
+import configure from 'store'
+
+const store = configure()
+const history = syncHistoryWithStore(browserHistory, store)
+
+ReactDOM.render(
+
+
+
+
+
+ ,
+ document.getElementById('root')
+)
diff --git a/client/middleware/index.js b/client/middleware/index.js
new file mode 100644
index 0000000..3810c74
--- /dev/null
+++ b/client/middleware/index.js
@@ -0,0 +1,6 @@
+
+import logger from './logger'
+
+export {
+ logger
+}
\ No newline at end of file
diff --git a/client/middleware/logger.js b/client/middleware/logger.js
new file mode 100644
index 0000000..e83552b
--- /dev/null
+++ b/client/middleware/logger.js
@@ -0,0 +1,5 @@
+
+export default store => next => action => {
+ console.log(action)
+ return next(action)
+}
\ No newline at end of file
diff --git a/client/reducers/index.js b/client/reducers/index.js
new file mode 100644
index 0000000..5f78f88
--- /dev/null
+++ b/client/reducers/index.js
@@ -0,0 +1,11 @@
+
+import { routerReducer as routing } from 'react-router-redux'
+import { combineReducers } from 'redux'
+import plugins from './plugins'
+import plugin from './plugin'
+
+export default combineReducers({
+ routing,
+ plugins,
+ plugin
+})
diff --git a/client/reducers/plugin.js b/client/reducers/plugin.js
new file mode 100644
index 0000000..d07ae0d
--- /dev/null
+++ b/client/reducers/plugin.js
@@ -0,0 +1,12 @@
+
+import { handleActions } from 'redux-actions'
+
+const initialState = {}
+
+export default handleActions({
+ 'show plugin' (state, action) {
+ return {
+ ...action.payload
+ }
+ },
+}, initialState)
diff --git a/client/reducers/plugins.js b/client/reducers/plugins.js
new file mode 100644
index 0000000..973f3e5
--- /dev/null
+++ b/client/reducers/plugins.js
@@ -0,0 +1,10 @@
+
+import { handleActions } from 'redux-actions'
+
+const initialState = []
+
+export default handleActions({
+ 'add plugins' (state, action) {
+ return [...state, ...action.payload]
+ },
+}, initialState)
diff --git a/client/store/index.js b/client/store/index.js
new file mode 100644
index 0000000..543ff14
--- /dev/null
+++ b/client/store/index.js
@@ -0,0 +1,26 @@
+
+import { createStore, applyMiddleware } from 'redux'
+
+import { logger } from 'middleware'
+import rootReducer from 'reducers'
+
+export default function configure(initialState) {
+ const create = window.devToolsExtension
+ ? window.devToolsExtension()(createStore)
+ : createStore
+
+ const createStoreWithMiddleware = applyMiddleware(
+ logger
+ )(create)
+
+ const store = createStoreWithMiddleware(rootReducer, initialState)
+
+ if (module.hot) {
+ module.hot.accept('reducers', () => {
+ const nextReducer = require('reducers')
+ store.replaceReducer(nextReducer)
+ })
+ }
+
+ return store
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..31d5f91
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "react-redux-plugin",
+ "version": "1.0.0",
+ "private": true,
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "webpack-dev-server -d --history-api-fallback --hot --inline --progress --colors --port 3000",
+ "build": "NODE_ENV=production webpack --progress --colors"
+ },
+ "license": "MIT",
+ "plugins": [
+ "Settings",
+ "Clients",
+ "Maps"
+ ],
+ "devDependencies": {
+ "babel-core": "^6.5.2",
+ "babel-loader": "^6.2.3",
+ "babel-plugin-transform-runtime": "^6.5.2",
+ "babel-preset-es2015": "^6.5.0",
+ "babel-preset-react": "^6.5.0",
+ "babel-preset-stage-0": "^6.5.0",
+ "babel-runtime": "^6.5.0",
+ "bundle-loader": "^0.5.4",
+ "classnames": "^2.2.3",
+ "css-loader": "^0.23.1",
+ "file-loader": "^0.8.5",
+ "postcss-loader": "^0.8.1",
+ "react": "^15.0.0",
+ "react-dom": "^15.0.0",
+ "react-hot-loader": "^1.3.0",
+ "react-redux": "^4.4.0",
+ "react-router": "^2.0.0",
+ "react-router-redux": "^4.0.0",
+ "redux": "^3.3.1",
+ "redux-actions": "^0.9.1",
+ "rucksack-css": "^0.8.5",
+ "style-loader": "^0.13.0",
+ "webpack": "^1.12.14",
+ "webpack-dev-server": "^1.14.1",
+ "webpack-hot-middleware": "^2.7.1"
+ }
+}
diff --git a/plugins/Orders/index.js b/plugins/Orders/index.js
new file mode 100644
index 0000000..1b183f4
--- /dev/null
+++ b/plugins/Orders/index.js
@@ -0,0 +1,20 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+import OrdersMain from './main'
+
+
+class Orders extends Component {
+ renderPlugin = () => {
+ this.props.actions.showPlugin( );
+ };
+ render() {
+ return (
+
+ Orders
+
+ );
+ }
+}
+
+export default Orders
diff --git a/plugins/Orders/main.js b/plugins/Orders/main.js
new file mode 100644
index 0000000..1fd91be
--- /dev/null
+++ b/plugins/Orders/main.js
@@ -0,0 +1,17 @@
+
+import React, { Component } from 'react'
+import style from './style.css'
+
+
+class OrdersMain extends Component {
+
+ render() {
+ return (
+
+ Orders
+
+ );
+ }
+}
+
+export default OrdersMain
diff --git a/plugins/Orders/style.css b/plugins/Orders/style.css
new file mode 100644
index 0000000..e02e374
--- /dev/null
+++ b/plugins/Orders/style.css
@@ -0,0 +1,5 @@
+.main {
+ flex: 1;
+ border-bottom: 1px solid #fff;
+ color: #fff;
+}
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 0000000..3dfb008
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,78 @@
+var rucksack = require('rucksack-css')
+var webpack = require('webpack')
+var path = require('path')
+
+module.exports = {
+ context: path.join(__dirname, './client'),
+ entry: {
+ jsx: './index.js',
+ html: './index.html',
+ vendor: [
+ 'react',
+ 'react-dom',
+ 'react-redux',
+ 'react-router',
+ 'react-router-redux',
+ 'redux'
+ ],
+ },
+ output: {
+ path: path.join(__dirname, './static'),
+ filename: 'bundle.js',
+ },
+ module: {
+ loaders: [
+ {
+ test: /\.html$/,
+ loader: 'file?name=[name].[ext]'
+ },
+ {
+ test: /\.css$/,
+ include: /client/,
+ loaders: [
+ 'style-loader',
+ 'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
+ 'postcss-loader'
+ ]
+ },
+ {
+ test: /\.css$/,
+ exclude: /client/,
+ loader: 'style!css'
+ },
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /node_modules/,
+ loaders: [
+ 'react-hot',
+ 'babel-loader'
+ ]
+ },
+ ],
+ },
+ resolve: {
+ modulesDirectories: [
+ 'client',
+ 'node_modules',
+ ],
+ extensions: ['', '.js', '.jsx']
+ },
+ postcss: [
+ rucksack({
+ autoprefixer: true
+ })
+ ],
+ plugins: [
+ new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
+ new webpack.DefinePlugin({
+ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development') }
+ }),
+ new webpack.DefinePlugin({
+ EXTERNAL_PLUGINS: JSON.stringify(require("./package.json").plugins)
+ })
+ ],
+ devServer: {
+ contentBase: './client',
+ hot: true
+ }
+}