├── .editorconfig ├── .eslintrc ├── .gitignore ├── README.md ├── client ├── css │ └── main.css └── js │ ├── pages │ ├── async.js │ ├── chat.js │ └── todo.js │ └── utils │ ├── createApp.js │ ├── spaRenderer.js │ └── sw.js ├── common ├── App.jsx ├── actions │ ├── async.js │ ├── todo.js │ └── vote.js ├── components │ ├── async │ │ ├── Picker.jsx │ │ └── Posts.jsx │ ├── chat │ │ ├── ChangeNameForm.jsx │ │ ├── Messages.jsx │ │ └── UsersList.jsx │ ├── common │ │ └── Tab.jsx │ └── todo │ │ ├── AddTodo.jsx │ │ ├── Footer.jsx │ │ ├── Todo.jsx │ │ └── TodoList.jsx ├── config.js ├── fetchList │ ├── clientFetch.js │ ├── package.json │ └── serverFetch.js ├── pages │ ├── App │ │ ├── About.jsx │ │ ├── App.jsx │ │ └── Vote.jsx │ ├── Base.jsx │ ├── async │ │ └── Page.jsx │ ├── chat │ │ └── Page.jsx │ └── todo │ │ └── Todo.jsx ├── reducers │ ├── about.js │ ├── async.js │ ├── spaReducers.js │ ├── todo.js │ └── vote.js ├── routes.js ├── store │ ├── index.js │ └── spaStore.js └── utils │ ├── connectDataFetchers.js │ └── shallowEqual.js ├── create-webpack-libs.config.js ├── create-webpack.config.js ├── dist ├── server.js └── server.js.map ├── gulpfile.js ├── index.js ├── manifest-debug.json ├── manifest.json ├── nodemon.json ├── package.json ├── public ├── css │ ├── main-min.css │ ├── main.css │ └── main.css.map └── js │ ├── debug │ ├── Vote.js │ ├── app.js │ ├── async.js │ ├── chat.js │ └── todo.js │ ├── libs-debug.js │ ├── libs-min.js │ └── min │ ├── Vote-85c4768b46fe43df6032.js │ ├── app-5f3b653ecdc8e6fe9b59.js │ ├── async-883364dc66df5d4fa947.js │ ├── chat-9ed37d333f9142979733.js │ └── todo-7c925fbf328875163978.js ├── server ├── apis │ └── index.js ├── app.js ├── config │ └── config.json ├── controllers │ ├── async.js │ ├── chat.js │ └── todo.js ├── middlewares │ ├── allowCrossDomain.js │ ├── renderReactMiddleware.jsx │ └── spaRenderMatch.js ├── routes │ └── index.js ├── sockets │ └── socket.js ├── utils │ └── preRender.js └── views │ ├── chat.html │ ├── error.ejs │ └── index.html ├── starter.js ├── webpack-assets.json └── webpack.config-server.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{js,json,jshintrc,html,jsx}] 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [{package.json,.travis.yml}] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | // http://eslint.org/docs/rules/ 3 | "root": true, 4 | "parser": "babel-eslint", 5 | // "extends": "eslint:recommended", 6 | "parserOptions": { 7 | "ecmaVersion": 7, 8 | "sourceType": "module", 9 | "ecmaFeatures": { 10 | "jsx": true, 11 | "globalReturn ": true, 12 | "impliedStrict": true, 13 | "experimentalObjectRestSpread": true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "mocha": true, 19 | "node": true, 20 | "es6": true 21 | }, 22 | "globals": { 23 | "size": true, 24 | "compact": true, 25 | "window": true, 26 | "decode": true, 27 | "Inferno": true, 28 | "Mousetrap": true, 29 | "SERVER_URL": true, 30 | "STREAM_URL": true 31 | }, 32 | "rules": { 33 | "semi": 0, 34 | "no-var": 0, 35 | "vars-on-top": 0, 36 | "spaced-comment": 0, 37 | "prefer-template": 0, 38 | "no-unused-vars": 0, 39 | "no-inner-declarations": 0, 40 | "consistent-return": 0, 41 | "comma-dangle": 0, 42 | "no-use-before-define": 0, 43 | "no-return-assign": 0, 44 | "no-console": 0, 45 | "max-len": 0, 46 | "arrow-body-style": 0, 47 | "new-cap": 0, 48 | "quotes": 0, 49 | "quote-props": 0, 50 | "prefer-arrow-callback": 0, 51 | "func-names": 0, 52 | "padded-blocks": 0, 53 | "keyword-spacing": 0, 54 | "no-trailing-spaces": 0, 55 | "no-unused-expressions": 0, 56 | "space-before-function-paren": 0, 57 | "global-require": 0, 58 | "react/jsx-no-bind": 0, 59 | "react/jsx-space-before-closing": 0, 60 | "react/jsx-closing-bracket-location": 0, 61 | "react/prop-types": 0, 62 | "react/prefer-stateless-function": 0 63 | } 64 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | .idea 4 | .happypack 5 | log 6 | ./dist/server.js.map 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-ocean 2 | isomorphic/universal react app for high performance mobile web application. 3 | support server side render spa 4 | support multi-page architecture without heavy react-router. 5 | 6 | 7 | ## Technology Stack: 8 | - react 9 | - react-router (for spa route manage) 10 | - redux 11 | - immutableJS (optional) 12 | - express 13 | - ES2015 14 | - webpack 15 | - babel 6 16 | - Service Worker cache static files 17 | - Web Security support 18 | 19 | ## Before Start 20 | - we recommend using ES6 module for tree shaking optimization. 21 | 22 | ## Start: 23 | - npm install react-ocean 24 | - npm run build:dev // for development 25 | - contains 'in-line-source-map' for debugging 26 | - redux-logger 27 | - redux-dev-tool(window.devToolsExtension) 28 | - 'why-did-you-update' avoidable re-render checking 29 | - react hot module replacing 30 | - npm run build:prod // for production 31 | - npm run build:lib // build libs file 32 | - npm run build // both 33 | - npm run start // start server 34 | 35 | 36 | ### How To Add A Page? 37 | #### For Multi-page: 38 | 39 | #### For Server Side 40 | * register server route 41 | ``` javascript 42 | router.get('/', getIndex); 43 | ``` 44 | * define appName and renderData for server render 45 | ``` javascript 46 | module.exports = function (req, res, next) { 47 | res.renderReactHTML({ 48 | component: , 49 | locals: { 50 | appName: 'index', 51 | title: 'index page' 52 | }, 53 | data: fakeData, 54 | rootReducer 55 | }); 56 | }; 57 | ``` 58 | 59 | #### For Client 60 | * add a client page whose name is the same as appName 61 | ``` javascript 62 | initializeRender({ 63 | rootReducer, 64 | component: 65 | }) 66 | ``` 67 | 68 | ## Examples: 69 | * todos 70 | * async action 71 | * chat room 72 | 73 | #### add a SPA page 74 | ``` javascript 75 | 76 | { 77 | require.ensure([], require => { 78 | cb(null, require('./pages/App/Vote').default); 79 | }, 'Vote'); 80 | }}/> 81 | 82 | 83 | ``` 84 | 85 | ``` javascript 86 | import connectDataFetchers from '../../utils/connectDataFetchers'; 87 | import * as ACTIONS from '../../actions/vote'; 88 | 89 | @connect(function mapStateToProps(state) { 90 | return { 91 | message: state.vote.message 92 | }; 93 | }) 94 | @connectDataFetchers([ACTIONS.loadData]) 95 | class Vote extends Component { 96 | static pageConfig = { 97 | pageId: 'Vote' 98 | }; 99 | render() { 100 | return ( 101 |
102 | this is vote 103 | about 104 | test 105 | message: { this.props.message } 106 |
107 | ); 108 | } 109 | } 110 | ``` 111 | fetch data according to connectDataFetchers. 112 | 113 | ``` javascript 114 | import fetchList from '../../../fetchList'; 115 | 116 | export const LOAD_VOTE_SUCCESS = 'LOAD_VOTE_SUCCESS'; 117 | export const LOAD_VOTE_FAILED = 'LOAD_VOTE_FAILED'; 118 | 119 | export function loadData(opts, req){ 120 | return (dispatch) => { 121 | return fetchList.getVote(opts, req).then((resp) => { 122 | dispatch({ 123 | type: LOAD_VOTE_SUCCESS, 124 | payload: resp.data 125 | }); 126 | }).catch(() => { 127 | dispatch({ 128 | type: LOAD_VOTE_FAILED 129 | }); 130 | }); 131 | }; 132 | } 133 | ``` 134 | 135 | ## TodoList 136 | * add docker support 137 | 138 | -------------------------------------------------------------------------------- /client/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 16px; 3 | } -------------------------------------------------------------------------------- /client/js/pages/async.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Immutable from 'immutable'; 3 | 4 | import createRender from '../utils/createApp'; 5 | import Page from '../../../common/pages/async/Page.jsx'; 6 | import rootReducer from '../../../common/reducers/async'; 7 | 8 | import '../../css/main.css'; 9 | 10 | let createApp = createRender({ 11 | transformer: Immutable.fromJS 12 | }); 13 | 14 | createApp({ 15 | rootReducer, 16 | component: 17 | }).then((store) => { 18 | if (process.env.NODE_ENV !== 'production' && module.hot) { 19 | // Enable Webpack hot module replacement for reducers 20 | module.hot.accept(['../../../common/pages/async/Page.jsx', '../../../common/reducers/async'], () => { 21 | const NewPage = require('../../../common/pages/async/Page.jsx').default; 22 | const newRootReducer = require('../../../common/reducers/async').default; 23 | createApp({ 24 | rootReducer: newRootReducer, 25 | component: 26 | }); 27 | }); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /client/js/pages/chat.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import createRender from '../utils/createApp'; 4 | import Page from '../../../common/pages/chat/Page.jsx'; 5 | // import rootReducer from '../../../common/pages/chat/reducers'; 6 | 7 | import '../../css/main.css'; 8 | 9 | let createApp = createRender(); 10 | 11 | createApp({ 12 | component: 13 | }); 14 | -------------------------------------------------------------------------------- /client/js/pages/todo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Immutable from 'immutable'; 3 | 4 | import createRender from '../utils/createApp'; 5 | import Page from '../../../common/pages/todo/Todo.jsx'; 6 | import rootReducer from '../../../common/reducers/todo'; 7 | 8 | import '../../css/main.css'; 9 | 10 | let createApp = createRender({ 11 | transformer: Immutable.fromJS 12 | }); 13 | 14 | createApp({ 15 | rootReducer, 16 | component: 17 | }); 18 | -------------------------------------------------------------------------------- /client/js/utils/createApp.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {render} from 'react-dom'; 3 | import {Provider} from 'react-redux'; 4 | import fastclick from 'fastclick'; 5 | 6 | import App from '../../../common/App.jsx'; 7 | import configureStore from '../../../common/store/index'; 8 | 9 | if (process.env.NODE_ENV !== 'production') { 10 | var whyDidYouUpdate = require('why-did-you-update').default; 11 | whyDidYouUpdate(React); 12 | var ReactPerf = require('react-addons-perf'); 13 | window.ReactPerf = ReactPerf; 14 | } 15 | 16 | // fastclick解决ios和部分安卓click事件的问题 17 | fastclick.attach(document.body); 18 | 19 | export default function createRender(middlewareConfig = {}){ 20 | let store = null; 21 | let page = document.getElementById('page'); 22 | let onRenderCompleted = typeof middlewareConfig.onRenderCompleted === 'function' && middlewareConfig.onRenderCompleted; 23 | 24 | if (process.env.NODE_ENV !== 'production') { 25 | // React.addons.Perf性能分析使用 26 | if (window.ReactPerf) { 27 | ReactPerf.start(); 28 | } 29 | } 30 | 31 | return function ({ 32 | rootReducer = (() => { 33 | }), 34 | component = null 35 | }) { 36 | let transformedData = typeof middlewareConfig.transformer === 'function' 37 | ? middlewareConfig.transformer(window.__INITIAL_STATE__) : window.__INITIAL_STATE__; 38 | if (!store) { 39 | store = configureStore(transformedData, rootReducer); 40 | } 41 | // hot load from hmr 42 | else if (process.env.NODE_ENV !== 'production') { 43 | store.replaceReducer(rootReducer); 44 | } 45 | 46 | render(( 47 | 48 | 49 | { component } 50 | 51 | 52 | ), page, onRenderCompleted); 53 | 54 | return Promise.resolve(store); 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /client/js/utils/spaRenderer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { match, Router, browserHistory } from 'react-router'; 5 | import createRoutes from '../../../common/routes'; 6 | import configureStore from '../../../common/store/spaStore'; 7 | import App from '../../../common/App'; 8 | 9 | 10 | const store = configureStore(window.__INITIAL_STATE__, browserHistory); 11 | const routes = createRoutes(store); 12 | 13 | function onUpdate(){ 14 | window.scrollTo(0, 0); 15 | } 16 | 17 | match({ history: browserHistory, routes }, (error, redirectLocation, renderProps) => { 18 | render( 19 | 20 | 21 | 22 | 23 | , document.getElementById('page') 24 | ); 25 | }); 26 | -------------------------------------------------------------------------------- /client/js/utils/sw.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | db: 'sw_gamPportal_201612011014' 3 | }; 4 | 5 | var urlsToCache = [ 6 | 7 | ]; 8 | 9 | var addToCache = function (req) { 10 | return fetch(req.clone()).then(function (resp) { 11 | var cacheResp = resp.clone(); 12 | if (resp.status !== 200 || (resp.type !== 'basic' && resp.type !== 'cors')) { 13 | return resp; 14 | } 15 | caches.open(config.db).then(function (cache) { 16 | cache.put(req.clone(), cacheResp); 17 | }); 18 | return resp; 19 | }); 20 | }; 21 | 22 | 23 | // self.addEventListener('install', function (e) { 24 | // // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-skipwaiting 25 | // if (typeof self.skipWaiting === 'function') { 26 | // e.waitUntil(self.skipWaiting()); 27 | // } 28 | 29 | // }); 30 | 31 | self.addEventListener('activate', function (event) { 32 | // event.waitUntil(Promise.all([ 33 | // caches.keys().then(function (cacheNames) { 34 | // return Promise.all(cacheNames.map(function (cacheName) { 35 | // if (cacheName !== config.db) { 36 | // return caches.delete(cacheName); 37 | // } 38 | // })); 39 | // }), 40 | // typeof self.clients.claim === 'function' && self.clients.claim() 41 | // ])); 42 | 43 | // 内核的cache.delete有bug,这里先注释 44 | event.waitUntil(caches.keys().then(function (cacheNames) { 45 | return Promise.all(cacheNames.map(function (cacheName) { 46 | if (cacheName !== config.db) { 47 | return caches.delete(cacheName); 48 | } 49 | })); 50 | })); 51 | }); 52 | 53 | self.addEventListener('fetch', function (event) { 54 | var requestUrl = event.request.url; 55 | 56 | var match = false; 57 | for (var i = 0; i < urlsToCache.length; ++i) { 58 | var url = urlsToCache[i]; 59 | if (url instanceof RegExp) { 60 | match = url.test(requestUrl); 61 | } else if (requestUrl.indexOf(url) >= 0) { 62 | match = true; 63 | break; 64 | } 65 | } 66 | 67 | if (!match) { 68 | // event.respondWith(fetch(event.request.clone())); 69 | return; 70 | } 71 | 72 | var promise, req, url = event.request.url; 73 | 74 | if (url.indexOf('/ajax/') !== -1 || url.indexOf('bypass=1') !== -1 || url.indexOf('http:') === 0) { 75 | event.respondWith(fetch(event.request.clone())); 76 | return; 77 | } 78 | 79 | // if (url.indexOf('cors=1') !== -1) { 80 | req = new Request(url, { 81 | mode: 'cors' 82 | }); 83 | // } else { 84 | // req = event.request.clone(); 85 | // } 86 | 87 | promise = caches.open(config.db).then(function (cache) { 88 | return cache.match(req); 89 | }).then(function (response) { 90 | if (response) { 91 | return response; 92 | } else { 93 | return addToCache(req); 94 | } 95 | }); 96 | 97 | event.respondWith(promise); 98 | 99 | }); 100 | -------------------------------------------------------------------------------- /common/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import EventEmitter from 'events'; 3 | 4 | let mediator = new EventEmitter(); 5 | 6 | class App extends Component { 7 | constructor(props, context) { 8 | super(props, context); 9 | } 10 | 11 | getChildContext(){ 12 | return { 13 | $eventBus: mediator, 14 | $appConfig: this.props.appConfig 15 | } 16 | } 17 | 18 | componentDidMount(){ 19 | } 20 | 21 | componentDidUpdate(){ 22 | } 23 | 24 | componentWillUnmount(){ 25 | } 26 | 27 | render() { 28 | return React.Children.only(this.props.children); 29 | } 30 | } 31 | App.defaultProps = { 32 | appConfig: null 33 | }; 34 | App.propTypes = { 35 | appConfig: PropTypes.object 36 | }; 37 | App.childContextTypes = { 38 | $eventBus: PropTypes.instanceOf(EventEmitter), 39 | $appConfig: PropTypes.object 40 | }; 41 | 42 | export default App; 43 | -------------------------------------------------------------------------------- /common/actions/async.js: -------------------------------------------------------------------------------- 1 | import fetch from 'isomorphic-fetch' 2 | import Immutable from 'immutable'; 3 | 4 | export const REQUEST_POSTS = 'REQUEST_POSTS' 5 | export const RECEIVE_POSTS = 'RECEIVE_POSTS' 6 | export const SELECT_REDDIT = 'SELECT_REDDIT' 7 | export const INVALIDATE_REDDIT = 'INVALIDATE_REDDIT' 8 | 9 | export function selectReddit(reddit) { 10 | return { 11 | type: SELECT_REDDIT, 12 | reddit 13 | } 14 | } 15 | 16 | export function invalidateReddit(reddit) { 17 | return { 18 | type: INVALIDATE_REDDIT, 19 | reddit 20 | } 21 | } 22 | 23 | function requestPosts(reddit) { 24 | return { 25 | type: REQUEST_POSTS, 26 | reddit 27 | } 28 | } 29 | 30 | function receivePosts(reddit, json) { 31 | return { 32 | type: RECEIVE_POSTS, 33 | reddit, 34 | posts: Immutable.fromJS(json.data.children.map(child => child.data)), 35 | receivedAt: Date.now() 36 | } 37 | } 38 | 39 | function fetchPosts(reddit) { 40 | return async function(dispatch) { 41 | dispatch(requestPosts(reddit)) 42 | try { 43 | let response = await fetch(`https://www.reddit.com/r/${reddit}.json`, { 44 | method: 'GET', 45 | timeout: 5000 46 | }).then(response => response.json()); 47 | dispatch(receivePosts(reddit, response)) 48 | } catch(ex){ 49 | console.error(ex); 50 | } 51 | } 52 | } 53 | 54 | function shouldFetchPosts(state, reddit) { 55 | const posts = state.get('postsByReddit').get(reddit) 56 | if (!posts) { 57 | return true 58 | } 59 | if (posts.get('isFetching')) { 60 | return false 61 | } 62 | return posts.get('didInvalidate') 63 | } 64 | 65 | export function fetchPostsIfNeeded(reddit) { 66 | return (dispatch, getState) => { 67 | if (shouldFetchPosts(getState(), reddit)) { 68 | return dispatch(fetchPosts(reddit)) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /common/actions/todo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * action 类型 3 | */ 4 | 5 | export const ADD_TODO = 'ADD_TODO'; 6 | export const COMPLETE_TODO = 'COMPLETE_TODO'; 7 | export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER' 8 | 9 | /* 10 | * 其它的常量 11 | */ 12 | 13 | export const VisibilityFilters = { 14 | SHOW_ALL: 'SHOW_ALL', 15 | SHOW_COMPLETED: 'SHOW_COMPLETED', 16 | SHOW_ACTIVE: 'SHOW_ACTIVE' 17 | }; 18 | 19 | /* 20 | * action 创建函数 21 | */ 22 | 23 | export function addTodo(text) { 24 | return { type: ADD_TODO, text } 25 | } 26 | 27 | export function completeTodo(index) { 28 | return { type: COMPLETE_TODO, index } 29 | } 30 | 31 | export function setVisibilityFilter(filter) { 32 | return { type: SET_VISIBILITY_FILTER, filter } 33 | } 34 | -------------------------------------------------------------------------------- /common/actions/vote.js: -------------------------------------------------------------------------------- 1 | import fetchList from '../fetchList'; 2 | 3 | export const LOAD_VOTE_SUCCESS = 'LOAD_VOTE_SUCCESS'; 4 | export const LOAD_VOTE_FAILED = 'LOAD_VOTE_FAILED'; 5 | 6 | export function loadData(opts, req){ 7 | return (dispatch) => { 8 | return fetchList.getVote(opts, req).then((resp) => { 9 | dispatch({ 10 | type: LOAD_VOTE_SUCCESS, 11 | payload: resp.data 12 | }); 13 | }).catch(() => { 14 | dispatch({ 15 | type: LOAD_VOTE_FAILED 16 | }); 17 | }); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /common/components/async/Picker.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import Immutable from 'immutable'; 3 | import ImmutablePropTypes from 'react-immutable-proptypes'; 4 | import Base from '../../pages/Base'; 5 | 6 | export default class Picker extends Base { 7 | constructor(props, context) { 8 | super(props, context); 9 | } 10 | 11 | onChange(e) { 12 | this.props.onChange(e.target.value) 13 | } 14 | 15 | render() { 16 | const { value, onChange, options } = this.props 17 | 18 | return ( 19 | 20 |

{value}

21 | 29 |
30 | ) 31 | } 32 | } 33 | 34 | Picker.propTypes = { 35 | options: PropTypes.arrayOf( 36 | PropTypes.string.isRequired 37 | ).isRequired, 38 | value: PropTypes.string.isRequired, 39 | onChange: PropTypes.func.isRequired 40 | } 41 | -------------------------------------------------------------------------------- /common/components/async/Posts.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes, Component } from 'react' 2 | import ImmutablePropTypes from 'react-immutable-proptypes'; 3 | import Base from '../../pages/Base'; 4 | 5 | export default class Posts extends Base { 6 | render() { 7 | return ( 8 |
    9 | {this.props.posts.map((post, i) => 10 |
  • {post.get('title')}
  • 11 | )} 12 |
13 | ) 14 | } 15 | } 16 | 17 | Posts.propTypes = { 18 | posts: ImmutablePropTypes.list.isRequired 19 | } 20 | -------------------------------------------------------------------------------- /common/components/chat/ChangeNameForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | 5 | export default class ChangeNameForm extends Base { 6 | constructor(props, context) { 7 | super(props, context); 8 | 9 | this.state = {newName: ''}; 10 | } 11 | 12 | onKey(e) { 13 | this.setState({ newName : e.target.value }); 14 | } 15 | 16 | onSubmit(e) { 17 | e.preventDefault(); 18 | var newName = this.state.newName; 19 | this.props.onChangeName(newName); 20 | this.setState({ newName: '' }); 21 | } 22 | 23 | render() { 24 | return( 25 |
26 |

Change Name

27 |
28 | 32 |
33 |
34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/components/chat/Messages.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | export class Message extends Base { 5 | constructor(props, context) { 6 | super(props, context); 7 | } 8 | 9 | render() { 10 | return ( 11 |
12 | {this.props.user} : 13 | {this.props.text} 14 |
15 | ); 16 | } 17 | } 18 | Message.defaultProps = { 19 | user: '', 20 | text: '' 21 | }; 22 | Message.propTypes = { 23 | user: PropTypes.string.isRequired, 24 | text: PropTypes.string.isRequired 25 | }; 26 | 27 | export class MessageList extends Base { 28 | constructor(props, context) { 29 | super(props, context); 30 | } 31 | 32 | render() { 33 | return ( 34 |
35 |

Conversation:

36 | { 37 | this.props.messages.map((message, i) => { 38 | return ( 39 | 44 | ); 45 | }) 46 | } 47 |
48 | ); 49 | } 50 | } 51 | 52 | 53 | export class MessageForm extends Base { 54 | constructor(props, context) { 55 | super(props, context); 56 | 57 | this.state = {text: ''}; 58 | } 59 | 60 | onSubmit(e) { 61 | e.preventDefault(); 62 | if(!this.state.text) return; 63 | 64 | let message = { 65 | user : this.props.user, 66 | text : this.state.text 67 | }; 68 | this.props.onMessageSubmit(message); 69 | this.setState({ text: '' }); 70 | } 71 | 72 | onChange(e) { 73 | this.setState({ text : e.target.value }); 74 | } 75 | 76 | render() { 77 | return( 78 |
79 |

Write New Message

80 |
81 | 85 |
86 |
87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /common/components/chat/UsersList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | export default class UsersList extends Base { 5 | constructor(props, context) { 6 | super(props, context); 7 | } 8 | 9 | render() { 10 | return ( 11 |
12 |

Online Users

13 |
    14 | { 15 | this.props.users.map((user, i) => { 16 | return ( 17 |
  • 18 | {user} 19 |
  • 20 | ); 21 | }) 22 | } 23 |
24 |
25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/components/common/Tab.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | import Base from '../../pages/Base'; 4 | 5 | export default class Tabs extends Base { 6 | constructor(props, context) { 7 | super(props, context); 8 | 9 | this.state = { 10 | selectedTab: props.defaultSelectedTab || null 11 | }; 12 | 13 | this.firstTabLabel = null; 14 | } 15 | 16 | getChildContext(){ 17 | return { 18 | onSelect: this.onSelect.bind(this), 19 | selectedTab: this.state.selectedTab || this.props.defaultSelectedTab, 20 | activeStyle: this.props.activeLinkStyle || defaultActiveStyle, 21 | firstTabLabel: this.firstTabLabel 22 | }; 23 | } 24 | 25 | onSelect(tab, ...rest) { 26 | if(this.state.selectedTab === tab) return; 27 | 28 | this.setState({ 29 | selectedTab: tab 30 | }); 31 | 32 | if(typeof this.props.onSelect === 'function') { 33 | this.props.onSelect(tab, ...rest); 34 | } 35 | } 36 | 37 | findFirstTabLabel(children){ 38 | if (typeof children !== 'object' || this.firstTabLabel) { 39 | return; 40 | } 41 | 42 | React.Children.forEach(children, (child) => { 43 | if(child.props && child.props.label) { 44 | if(this.firstTabLabel == null){ 45 | this.firstTabLabel = child.props.label; 46 | return; 47 | } 48 | } 49 | 50 | this.findFirstTabLabel(child.props && child.props.children); 51 | }); 52 | } 53 | 54 | render() { 55 | this.findFirstTabLabel(this.props.children); 56 | 57 | return ( 58 |
59 | {this.props.children} 60 |
61 | ); 62 | } 63 | } 64 | Tabs.defaultProps = { 65 | onSelect: null, 66 | activeLinkStyle: null, 67 | defaultSelectedTab: '', 68 | className: '', 69 | style: null 70 | }; 71 | Tabs.propTypes = { 72 | onSelect: PropTypes.func, 73 | activeLinkStyle: PropTypes.object, 74 | defaultSelectedTab: PropTypes.string, 75 | className: PropTypes.string, 76 | style: PropTypes.object 77 | }; 78 | Tabs.childContextTypes = { 79 | onSelect: PropTypes.func, 80 | selectedTab: PropTypes.string, 81 | activeStyle: PropTypes.object, 82 | firstTabLabel: PropTypes.string 83 | }; 84 | 85 | const defaultActiveStyle = { 86 | fontWeight: 'bold' 87 | }; 88 | 89 | export class TabTitle extends Component { 90 | constructor(props, context){ 91 | super(props, context); 92 | 93 | this.onSelect = this.onSelect.bind(this); 94 | } 95 | 96 | onSelect(){ 97 | this.context.onSelect(this.props.label); 98 | } 99 | 100 | componentDidMount() { 101 | if (this.context.selectedTab === this.props.label || (!this.context.selectedTab && this.context.firstTabLabel === this.props.label)) { 102 | this.context.onSelect(this.props.label); 103 | } 104 | } 105 | 106 | render() { 107 | let style = null; 108 | let isActive = this.context.selectedTab === this.props.label; 109 | if (isActive) { 110 | style = this.context.activeStyle; 111 | } 112 | let clsNames = classnames(this.props.className, { active: isActive }); 113 | 114 | return ( 115 |
120 | {this.props.children} 121 |
122 | ); 123 | } 124 | } 125 | TabTitle.defaultProps = { 126 | label: '', 127 | className: 'tab-link' 128 | }; 129 | TabTitle.propTypes = { 130 | label: PropTypes.string.isRequired, 131 | className: PropTypes.string 132 | }; 133 | TabTitle.contextTypes = { 134 | onSelect: PropTypes.func, 135 | firstTabLabel: PropTypes.string, 136 | activeStyle: PropTypes.object, 137 | selectedTab: PropTypes.string 138 | }; 139 | 140 | const styles = { 141 | visible: { 142 | display: 'block' 143 | }, 144 | hidden: { 145 | display: 'none' 146 | } 147 | }; 148 | 149 | export class TabPanel extends Component { 150 | constructor(props, context){ 151 | super(props, context); 152 | 153 | for(let style in styles){ 154 | if(styles.hasOwnProperty(style)){ 155 | Object.assign(styles[style], this.props.style); 156 | } 157 | } 158 | } 159 | 160 | render() { 161 | let displayStyle = this.context.selectedTab === this.props.for 162 | ? styles.visible : styles.hidden; 163 | 164 | return ( 165 |
168 | {this.props.children} 169 |
170 | ); 171 | } 172 | } 173 | TabPanel.defaultProps = { 174 | for: '', 175 | className: 'tab-content', 176 | style: null 177 | }; 178 | TabPanel.propTypes = { 179 | for: PropTypes.string.isRequired, 180 | className: PropTypes.string, 181 | style: PropTypes.object 182 | }; 183 | TabPanel.contextTypes = { 184 | selectedTab: PropTypes.string 185 | }; 186 | -------------------------------------------------------------------------------- /common/components/todo/AddTodo.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | export default class AddTodo extends Base { 5 | constructor(props, context) { 6 | super(props, context); 7 | } 8 | 9 | render() { 10 | return ( 11 |
12 | 13 | 14 |
15 | ) 16 | } 17 | 18 | onClick(e) { 19 | const node = this.refs.input; 20 | const text = node.value.trim(); 21 | this.props.onAddClick(text); 22 | node.value = ''; 23 | } 24 | } 25 | 26 | AddTodo.propTypes = { 27 | onAddClick: PropTypes.func.isRequired 28 | }; 29 | -------------------------------------------------------------------------------- /common/components/todo/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | export default class Footer extends Base { 5 | constructor(props, context) { 6 | super(props, context); 7 | } 8 | 9 | renderFilter(filter, name) { 10 | if (filter === this.props.filter) { 11 | return name 12 | } 13 | 14 | return ( 15 | { 16 | e.preventDefault() 17 | this.props.onFilterChange(filter) 18 | } }> 19 | {name} 20 | 21 | ) 22 | } 23 | 24 | render() { 25 | return ( 26 |

27 | Show: 28 | {' '} 29 | {this.renderFilter('SHOW_ALL', 'All') } 30 | {', '} 31 | {this.renderFilter('SHOW_COMPLETED', 'Completed') } 32 | {', '} 33 | {this.renderFilter('SHOW_ACTIVE', 'Active') } 34 | . 35 |

36 | ) 37 | } 38 | } 39 | 40 | Footer.propTypes = { 41 | onFilterChange: PropTypes.func.isRequired, 42 | filter: PropTypes.oneOf([ 43 | 'SHOW_ALL', 44 | 'SHOW_COMPLETED', 45 | 'SHOW_ACTIVE' 46 | ]).isRequired 47 | } 48 | -------------------------------------------------------------------------------- /common/components/todo/Todo.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react'; 2 | import Base from '../../pages/Base'; 3 | 4 | let styles = { 5 | completed: { 6 | textDecoration: 'line-through', 7 | cursor: 'default' 8 | }, 9 | uncompleted: { 10 | textDecoration: 'none', 11 | cursor: 'pointer' 12 | } 13 | }; 14 | 15 | export default class Todo extends Base { 16 | constructor(props, context) { 17 | super(props, context); 18 | } 19 | 20 | componentDidMount() { 21 | this.on('test', function () { 22 | console.log('test event bus'); 23 | }); 24 | } 25 | 26 | componentWillUnmount(){ 27 | // unregister subscribe 28 | super.componentWillUnmount(); 29 | } 30 | 31 | render() { 32 | return ( 33 |
  • 35 | { this.props.text } 36 |
  • 37 | ) 38 | } 39 | } 40 | Todo.defaultProps = { 41 | onClick: function(){}, 42 | text: '', 43 | completed: false 44 | }; 45 | Todo.propTypes = { 46 | onClick: PropTypes.func.isRequired, 47 | text: PropTypes.string.isRequired, 48 | completed: PropTypes.bool.isRequired 49 | }; 50 | -------------------------------------------------------------------------------- /common/components/todo/TodoList.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | import { List } from 'immutable'; 3 | import ImmutablePropTypes from 'react-immutable-proptypes'; 4 | import Todo from './Todo' 5 | import Base from '../../pages/Base'; 6 | 7 | export default class TodoList extends Base { 8 | constructor(props, context) { 9 | super(props, context); 10 | } 11 | 12 | render() { 13 | return ( 14 |
      15 | { this.props.todos.map((todo, index) => 16 | this.props.onTodoClick(index) } /> 20 | ) } 21 |
    22 | ) 23 | } 24 | } 25 | 26 | TodoList.propTypes = { 27 | onTodoClick: PropTypes.func.isRequired, 28 | todos: ImmutablePropTypes.listOf(ImmutablePropTypes.contains({ 29 | text: PropTypes.string.isRequired, 30 | completed: PropTypes.bool.isRequired 31 | })) 32 | }; 33 | -------------------------------------------------------------------------------- /common/config.js: -------------------------------------------------------------------------------- 1 | export const VERSION = 'v3'; 2 | export const READY = 0; 3 | export const START = 1; 4 | export const SUCCESS = 2; 5 | export const FAILED = 3; 6 | export const NOMORE = 4; 7 | 8 | export default { 9 | "VERSION": VERSION, 10 | 11 | "READY": READY, 12 | "START": START, 13 | "SUCCESS": SUCCESS, 14 | "FAILED": FAILED, 15 | "NOMORE": NOMORE 16 | }; 17 | -------------------------------------------------------------------------------- /common/fetchList/clientFetch.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | getVote(opts){ 4 | return new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | resolve({ 7 | data: { 8 | message: 123 9 | } 10 | }); 11 | }, 500); 12 | }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /common/fetchList/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fetch-list", 3 | "version": "0.0.1", 4 | "browser": "clientFetch.js", 5 | "main": "serverFetch.js" 6 | } 7 | -------------------------------------------------------------------------------- /common/fetchList/serverFetch.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | getVote(opts, req){ 4 | return new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | resolve({ 7 | data: { 8 | message: 123 9 | } 10 | }); 11 | }, 500); 12 | }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /common/pages/App/About.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link } from 'react-router'; 3 | import { connect } from 'react-redux'; 4 | 5 | function mapStateToProps(state) { 6 | return { 7 | text: state.about 8 | }; 9 | } 10 | 11 | @connect(mapStateToProps) 12 | class About extends Component { 13 | static pageConfig = { 14 | pageId: 'About' 15 | }; 16 | 17 | render() { 18 | return ( 19 |
    20 | this is about page 21 | vote 22 | text: {this.props.text} 23 |
    24 | ); 25 | } 26 | } 27 | 28 | export default About; 29 | -------------------------------------------------------------------------------- /common/pages/App/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | let App = ({children}) => { 4 | return ( 5 | React.Children.only(children) 6 | ); 7 | }; 8 | 9 | App.propTypes = { 10 | children: PropTypes.object 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /common/pages/App/Vote.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Link } from 'react-router'; 4 | 5 | import connectDataFetchers from '../../utils/connectDataFetchers'; 6 | import * as ACTIONS from '../../actions/vote'; 7 | 8 | @connect(function mapStateToProps(state) { 9 | return { 10 | message: state.vote.message 11 | }; 12 | }) 13 | @connectDataFetchers([ACTIONS.loadData]) 14 | class Vote extends Component { 15 | static pageConfig = { 16 | pageId: 'Vote' 17 | }; 18 | render() { 19 | return ( 20 |
    21 | this is vote 22 | about 23 | test 24 | message: { this.props.message } 25 |
    26 | ); 27 | } 28 | } 29 | 30 | export default Vote; 31 | -------------------------------------------------------------------------------- /common/pages/Base.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes, Component } from 'react'; 2 | import shallowEqual from '../utils/shallowEqual'; 3 | import EventEmitter from 'events'; 4 | 5 | const eventMatchReg = /^on[A-Z]/; 6 | function getEventMethodsProps(instance){ 7 | let methods = Object.getOwnPropertyNames(instance) 8 | .filter((prop) => { 9 | return eventMatchReg.test(prop) 10 | && typeof instance[prop] === 'function'; 11 | }); 12 | 13 | let instancePrototype = Object.getPrototypeOf(instance); 14 | if(instancePrototype !== Object.prototype) { 15 | methods = methods.concat(getEventMethodsProps(instancePrototype)); 16 | } 17 | 18 | return methods 19 | } 20 | 21 | 22 | export default class Base extends Component { 23 | constructor(props, context){ 24 | super(props, context); 25 | 26 | this.__eventNames = {}; 27 | 28 | this.__bindFunctions(); 29 | } 30 | 31 | __bindFunctions(){ 32 | let props = getEventMethodsProps(this); 33 | for(let prop of props){ 34 | if(!this[prop].funcBinded){ 35 | this[prop] = this[prop].bind(this); 36 | this[prop].funcBinded = true; 37 | } 38 | } 39 | } 40 | 41 | on(eventName, fn){ 42 | if(typeof fn !== 'function') throw new Error('fn should be a function'); 43 | 44 | if(!this.__eventNames[eventName]){ 45 | this.__eventNames[eventName] = [fn]; 46 | } else { 47 | this.__eventNames[eventName].push(fn); 48 | } 49 | 50 | return this.context.$eventBus.addListener(eventName, fn); 51 | } 52 | 53 | emit(eventName, ...args){ 54 | return this.context.$eventBus.emit(eventName, ...args); 55 | } 56 | 57 | off(eventName, fn){ 58 | let events = this.__eventNames[eventName]; 59 | if(events){ 60 | let index = events.indexOf(fn); 61 | 62 | if(index >= 0) { 63 | this.context.$eventBus.removeListener(eventName, fn); 64 | 65 | events.splice(index, 1); 66 | 67 | if(!events.length) { 68 | delete this.__eventNames[eventName]; 69 | } 70 | } else { 71 | console.warn('event: ' + eventName + ' is not registered in ' + this._reactInternalInstance.getName() + ' Component'); 72 | } 73 | 74 | return true; 75 | } else { 76 | console.warn('event: ' + eventName + ' is not registered in ' + this.constructor.name + ' Component'); 77 | 78 | return false; 79 | } 80 | } 81 | 82 | 83 | /** 84 | * 检验组件更新 85 | * @param nextProps 86 | * @param nextState 87 | * @returns {*} 88 | */ 89 | shouldComponentUpdate(nextProps, nextState){ 90 | let shouldUpdate = !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); 91 | 92 | if(shouldUpdate && process.env.NODE_ENV !== 'production') { 93 | console.log('Component: ' + this.constructor.name + ' will update'); 94 | } 95 | 96 | return shouldUpdate; 97 | } 98 | 99 | componentWillUnmount(){ 100 | for(let eventName in this.__eventNames){ 101 | if(this.__eventNames.hasOwnProperty(eventName)){ 102 | for(let fn of this.__eventNames[eventName]){ 103 | this.off(eventName, fn); 104 | } 105 | } 106 | } 107 | } 108 | } 109 | Base.contextTypes = { 110 | $eventBus: PropTypes.instanceOf(EventEmitter) 111 | }; 112 | -------------------------------------------------------------------------------- /common/pages/async/Page.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react' 2 | import {connect} from 'react-redux' 3 | import Immutable from 'immutable'; 4 | import ImmutablePropTypes from 'react-immutable-proptypes'; 5 | import {selectReddit, fetchPostsIfNeeded, invalidateReddit} from '../../actions/async' 6 | import Picker from '../../components/async/Picker.jsx' 7 | import Posts from '../../components/async/Posts.jsx' 8 | import Base from '../Base.jsx'; 9 | 10 | class AsyncPage extends Base { 11 | constructor(props, context) { 12 | super(props, context); 13 | } 14 | 15 | componentDidMount() { 16 | const {dispatch, selectedReddit} = this.props 17 | dispatch(fetchPostsIfNeeded(selectedReddit)) 18 | } 19 | 20 | componentWillReceiveProps(nextProps) { 21 | if (nextProps.selectedReddit !== this.props.selectedReddit) { 22 | const {dispatch, selectedReddit} = nextProps 23 | dispatch(fetchPostsIfNeeded(selectedReddit)) 24 | } 25 | } 26 | 27 | onHandleChange(nextReddit) { 28 | this.props.dispatch(selectReddit(nextReddit)) 29 | } 30 | 31 | onHandleRefreshClick(e) { 32 | e.preventDefault() 33 | 34 | const {dispatch, selectedReddit} = this.props 35 | dispatch(invalidateReddit(selectedReddit)) 36 | dispatch(fetchPostsIfNeeded(selectedReddit)) 37 | } 38 | 39 | render() { 40 | const {selectedReddit, posts, isFetching, lastUpdated} = this.props 41 | const isEmpty = posts.size === 0 42 | return ( 43 |
    44 | 47 |

    48 | { 49 | lastUpdated ? ( 50 | 51 | Last updated at {new Date(lastUpdated).toLocaleTimeString('en-US', { 52 | hour12: false 53 | })}. 54 | {' '} 55 | 56 | ) : '' 57 | } 58 | {!isFetching && 59 | 61 | Refresh 62 | 63 | } 64 |

    65 | {isEmpty 66 | ? (isFetching ?

    Loading...

    :

    Empty.

    ) 67 | :
    68 | 69 |
    70 | } 71 |
    72 | ) 73 | } 74 | } 75 | AsyncPage.defaultProps = { 76 | selectedReddit: '', 77 | posts: new Immutable.List(), 78 | isFetching: false, 79 | lastUpdated: 0 80 | 81 | }; 82 | AsyncPage.propTypes = { 83 | selectedReddit: PropTypes.string.isRequired, 84 | posts: ImmutablePropTypes.list.isRequired, 85 | isFetching: PropTypes.bool.isRequired, 86 | lastUpdated: PropTypes.number 87 | } 88 | 89 | const defaultOptions = ['reactjs', 'frontend']; 90 | 91 | function mapStateToProps(state) { 92 | const selectedReddit = state.get('selectedReddit'); 93 | const postsByReddit = state.get('postsByReddit'); 94 | const data = postsByReddit.get(state.get('selectedReddit')) || new Immutable.Map({ 95 | isFetching: true, 96 | items: new Immutable.List() 97 | }); 98 | const isFetching = data.get('isFetching'); 99 | const lastUpdated = data.get('lastUpdated'); 100 | const posts = data.get('items'); 101 | 102 | return { 103 | selectedReddit, 104 | posts, 105 | isFetching, 106 | lastUpdated 107 | } 108 | } 109 | 110 | export default connect(mapStateToProps)(AsyncPage) 111 | -------------------------------------------------------------------------------- /common/pages/chat/Page.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react' 2 | import {connect} from 'react-redux' 3 | 4 | import Base from '../Base.jsx'; 5 | import UsersList from '../../components/chat/UsersList'; 6 | import { MessageForm, MessageList } from '../../components/chat/Messages'; 7 | import ChangeNameForm from '../../components/chat/ChangeNameForm'; 8 | 9 | if(process.browser){ 10 | var socket = io.connect(); 11 | } 12 | 13 | class Page extends Base { 14 | constructor(props, context) { 15 | super(props, context); 16 | 17 | this.state = { 18 | users: [], 19 | messages: [], 20 | text: '' 21 | }; 22 | } 23 | 24 | componentDidMount() { 25 | socket.on('init', this.initialize.bind(this)); 26 | socket.on('send:message', this.messageRecieve.bind(this)); 27 | socket.on('user:join', this.userJoined.bind(this)); 28 | socket.on('user:left', this.userLeft.bind(this)); 29 | socket.on('change:name', this.userChangedName.bind(this)); 30 | } 31 | 32 | initialize(data) { 33 | let {users, name} = data; 34 | this.setState({users, user: name}); 35 | } 36 | 37 | messageRecieve(message) { 38 | let {messages} = this.state; 39 | 40 | this.setState({ 41 | messages: [ 42 | ...messages, 43 | message 44 | ] 45 | }); 46 | } 47 | 48 | userJoined(data) { 49 | let {users, messages} = this.state; 50 | let {name} = data; 51 | 52 | this.setState({ 53 | users: [ 54 | users, 55 | name 56 | ], 57 | messages: [ 58 | ...messages, 59 | { 60 | user: 'APPLICATION BOT', 61 | text : name +' Joined' 62 | } 63 | ] 64 | }); 65 | } 66 | 67 | userLeft(data) { 68 | let {users, messages} = this.state; 69 | let {name} = data; 70 | let index = users.indexOf(name); 71 | users.splice(index, 1); 72 | 73 | this.setState({ 74 | users: [ 75 | ...users 76 | ], 77 | messages: [ 78 | ...messages, 79 | { 80 | user: 'APPLICATION BOT', 81 | text : name +' Left' 82 | } 83 | ] 84 | }); 85 | } 86 | 87 | userChangedName(data) { 88 | let {oldName, newName} = data; 89 | let {users, messages} = this.state; 90 | let index = users.indexOf(oldName); 91 | users.splice(index, 1, newName); 92 | 93 | this.setState({ 94 | users: [ 95 | ...users 96 | ], 97 | messages: [ 98 | ...messages, 99 | { 100 | user: 'APPLICATION BOT', 101 | text : 'Change Name : ' + oldName + ' ==> '+ newName 102 | } 103 | ] 104 | }); 105 | } 106 | 107 | onMessageSubmit(message) { 108 | let {messages} = this.state; 109 | 110 | this.setState({ 111 | messages: [ 112 | ...messages, 113 | message 114 | ] 115 | }); 116 | socket.emit('send:message', message); 117 | } 118 | 119 | onChangeName(newName) { 120 | let oldName = this.state.user; 121 | let {messages} = this.state; 122 | 123 | socket.emit('change:name', { name : newName}, (result) => { 124 | if(!result) { 125 | return alert('There was an error changing your name'); 126 | } 127 | let {users} = this.state; 128 | let index = users.indexOf(oldName); 129 | users.splice(index, 1, newName); 130 | 131 | messages = messages.map((message) => { 132 | if(message.user === oldName) { 133 | return Object.assign({}, message, { 134 | user: newName 135 | }); 136 | } else { 137 | return message; 138 | } 139 | }); 140 | 141 | this.setState({ 142 | users: [ 143 | ...users 144 | ], 145 | user: newName, 146 | messages 147 | }); 148 | }); 149 | } 150 | 151 | render() { 152 | return ( 153 |
    154 | 157 | 160 | 164 | 167 |
    168 | ); 169 | } 170 | } 171 | export default Page; 172 | -------------------------------------------------------------------------------- /common/pages/todo/Todo.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | import { connect } from 'react-redux' 3 | import { List } from 'immutable'; 4 | import Base from '../Base.jsx'; 5 | import { addTodo, completeTodo, setVisibilityFilter, VisibilityFilters } from '../../actions/todo' 6 | import AddTodo from '../../components/todo/AddTodo' 7 | import TodoList from '../../components/todo/TodoList' 8 | import Footer from '../../components/todo/Footer'; 9 | import Tabs, { TabTitle, TabPanel } from '../../components/common/Tab'; 10 | 11 | class Page extends Base { 12 | constructor(props, context) { 13 | super(props, context); 14 | } 15 | 16 | componentDidMount(){ 17 | console.log(this.context.$appConfig.user); 18 | 19 | this.emit('test'); 20 | } 21 | 22 | render() { 23 | // Injected by connect() call: 24 | const { dispatch, visibleTodos, visibilityFilter } = this.props 25 | return ( 26 |
    27 | 29 | dispatch(addTodo(text)) 30 | } /> 31 | 34 | dispatch(completeTodo(index)) 35 | } /> 36 |
    39 | dispatch(setVisibilityFilter(nextFilter)) 40 | } /> 41 | 42 | 43 | tab1 44 | 45 | 46 | tab2 47 | 48 | 49 | TabContent1 50 | 51 | 52 | TabContent2 53 | 54 | 55 |
    56 | ) 57 | } 58 | } 59 | 60 | Page.propTypes = { 61 | visibleTodos: PropTypes.instanceOf(List).isRequired, 62 | visibilityFilter: PropTypes.oneOf([ 63 | 'SHOW_ALL', 64 | 'SHOW_COMPLETED', 65 | 'SHOW_ACTIVE' 66 | ]).isRequired 67 | }; 68 | Page.contextTypes = { 69 | $appConfig: PropTypes.object, 70 | $eventBus: PropTypes.object 71 | }; 72 | 73 | function selectTodos(todos, filter) { 74 | switch (filter) { 75 | case VisibilityFilters.SHOW_ALL: 76 | return todos 77 | case VisibilityFilters.SHOW_COMPLETED: 78 | return todos.filter(todo => todo.get('completed')) 79 | case VisibilityFilters.SHOW_ACTIVE: 80 | return todos.filter(todo => !todo.get('completed')) 81 | } 82 | } 83 | 84 | // Which props do we want to inject, given the global state? 85 | // Note: use https://github.com/faassen/reselect for better performance. 86 | function select(state) { 87 | return { 88 | visibleTodos: selectTodos(state.get('todos'), state.get('visibilityFilter')), 89 | visibilityFilter: state.get('visibilityFilter') 90 | } 91 | } 92 | 93 | // 包装 component ,注入 dispatch 和 state 到其默认的 connect(select)(App) 中; 94 | export default connect(select)(Page); 95 | -------------------------------------------------------------------------------- /common/reducers/about.js: -------------------------------------------------------------------------------- 1 | 2 | import { combineReducers } from 'redux'; 3 | 4 | export default function text(state = 'test'){ 5 | return state; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /common/reducers/async.js: -------------------------------------------------------------------------------- 1 | // import { combineReducers } from 'redux' 2 | import Immutable from 'immutable'; 3 | import { combineReducers } from 'redux-immutablejs'; 4 | import { 5 | SELECT_REDDIT, INVALIDATE_REDDIT, 6 | REQUEST_POSTS, RECEIVE_POSTS 7 | } from '../actions/async' 8 | 9 | function selectedReddit(state = 'reactjs', action) { 10 | switch (action.type) { 11 | case SELECT_REDDIT: 12 | return action.reddit 13 | default: 14 | return state 15 | } 16 | } 17 | 18 | function posts(state = new Immutable.Map({ 19 | isFetching: false, 20 | didInvalidate: false, 21 | items: new Immutable.List() 22 | }), action) { 23 | switch (action.type) { 24 | case INVALIDATE_REDDIT: 25 | return state.set('didInvalidate', true) 26 | case REQUEST_POSTS: 27 | return state.merge({ 28 | isFetching: true, 29 | didInvalidate: false 30 | }); 31 | case RECEIVE_POSTS: 32 | return state.merge({ 33 | isFetching: false, 34 | didInvalidate: false, 35 | items: action.posts, 36 | lastUpdated: action.receivedAt 37 | }); 38 | default: 39 | return state 40 | } 41 | } 42 | 43 | function postsByReddit(state = new Immutable.Map(), action) { 44 | switch (action.type) { 45 | case INVALIDATE_REDDIT: 46 | case RECEIVE_POSTS: 47 | case REQUEST_POSTS: 48 | return state.set(action.reddit, posts(state[action.reddit], action)); 49 | default: 50 | return state 51 | } 52 | } 53 | 54 | const rootReducer = combineReducers({ 55 | postsByReddit, 56 | selectedReddit 57 | }) 58 | 59 | export default rootReducer 60 | -------------------------------------------------------------------------------- /common/reducers/spaReducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import about from './about'; 3 | import vote from './vote'; 4 | 5 | const rootReducer = combineReducers({ 6 | about, 7 | vote 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /common/reducers/todo.js: -------------------------------------------------------------------------------- 1 | // import { combineReducers } from 'redux' 2 | import { List, Map } from 'immutable'; 3 | import { combineReducers } from 'redux-immutablejs'; 4 | import { ADD_TODO, COMPLETE_TODO, SET_VISIBILITY_FILTER, VisibilityFilters } from '../actions/todo' 5 | const { SHOW_ALL } = VisibilityFilters 6 | 7 | function visibilityFilter(state = SHOW_ALL, action) { 8 | switch (action.type) { 9 | case SET_VISIBILITY_FILTER: 10 | return action.filter 11 | default: 12 | return state 13 | } 14 | } 15 | 16 | function todos(state = new List(), action) { 17 | switch (action.type) { 18 | case ADD_TODO: 19 | return state.push(new Map({ 20 | text: action.text, 21 | completed: false 22 | })) 23 | case COMPLETE_TODO: 24 | return state.update(action.index, function(item){ 25 | return item.set('completed', true); 26 | }); 27 | default: 28 | return state 29 | } 30 | } 31 | 32 | const todoApp = combineReducers({ 33 | visibilityFilter, 34 | todos 35 | }) 36 | 37 | export default todoApp 38 | -------------------------------------------------------------------------------- /common/reducers/vote.js: -------------------------------------------------------------------------------- 1 | import * as ACTIONS from '../actions/vote'; 2 | 3 | 4 | export default function Vote(state = {}, action = {}) { 5 | switch (action.type) { 6 | case ACTIONS.LOAD_VOTE_SUCCESS: 7 | return action.payload; 8 | default: 9 | return state; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /common/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, IndexRoute } from 'react-router'; 3 | 4 | import connectDataFetchers from './utils/connectDataFetchers'; 5 | import App from './pages/App/App'; 6 | // import Vote from './universalPage/Vote'; 7 | import About from './pages/App/About'; 8 | 9 | // require.ensure polyfill for node 10 | if (typeof require.ensure !== 'function') { 11 | require.ensure = function requireModule(deps, callback) { 12 | callback(require); 13 | }; 14 | } 15 | 16 | function onChange(prevState, nextState, replace, cb){ 17 | let lastRoute = nextState.routes[nextState.routes.length - 1]; 18 | 19 | if(lastRoute.component) { 20 | let component = lastRoute.component.WrappedComponent; 21 | let location = nextState.location; 22 | let pageComponent = component.OriginalPage ? component.OriginalPage : component; 23 | 24 | Object.assign(window.__APP_CONFIG__, { 25 | pageId: location.query.pageId || (pageComponent.pageConfig && pageComponent.pageConfig.pageId) 26 | }); 27 | } 28 | 29 | cb(); 30 | } 31 | 32 | 33 | export default (store) => { 34 | const requireAuth = (nextState, replace, callback) => { 35 | const { user: { authenticated }} = store.getState(); 36 | if (!authenticated) { 37 | replace({ 38 | pathname: '/login', 39 | state: { nextPathname: nextState.location.pathname } 40 | }); 41 | } 42 | callback(); 43 | }; 44 | 45 | const redirectAuth = (nextState, replace, callback) => { 46 | const { user: { authenticated }} = store.getState(); 47 | if (authenticated) { 48 | replace({ 49 | pathname: '/' 50 | }); 51 | } 52 | callback(); 53 | }; 54 | return ( 55 | 56 | { 57 | require.ensure([], require => { 58 | cb(null, require('./pages/App/Vote').default); 59 | }, 'Vote'); 60 | }}/> 61 | { 62 | require.ensure([], require => { 63 | cb(null, require('./pages/App/Vote').default); 64 | }, 'Vote'); 65 | }}/> 66 | 67 | 68 | ); 69 | }; 70 | -------------------------------------------------------------------------------- /common/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | 4 | if(process.env.NODE_ENV !== 'production' && process.browser){ 5 | var createLogger = require('redux-logger'); 6 | } 7 | 8 | const middlewareBuilder = () => { 9 | let middleware = applyMiddleware(thunk); 10 | 11 | if(process.env.NODE_ENV !== 'production' && process.browser){ 12 | if(!window.devToolsExtension) { 13 | middleware = applyMiddleware(thunk, createLogger()); 14 | } 15 | } 16 | 17 | let allComposeElements = [ 18 | middleware 19 | ]; 20 | 21 | if(process.env.NODE_ENV !== 'production' && process.browser){ 22 | if(window.devToolsExtension){ 23 | allComposeElements.push(window.devToolsExtension()); 24 | } 25 | } 26 | 27 | return allComposeElements; 28 | }; 29 | 30 | const finalCreateStore = compose(...middlewareBuilder())(createStore); 31 | 32 | export default function configureStore(initialState, rootReducer) { 33 | const store = finalCreateStore(rootReducer, initialState); 34 | 35 | return store; 36 | } 37 | -------------------------------------------------------------------------------- /common/store/spaStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | // import { routerMiddleware } from 'react-router-redux'; 3 | import thunk from 'redux-thunk'; 4 | import rootReducer from '../reducers/spaReducers'; 5 | 6 | if(process.env.NODE_ENV !== 'production' && process.browser){ 7 | var createLogger = require('redux-logger'); 8 | } 9 | 10 | export default function configureStore(initialState, history) { 11 | const middleware = [ 12 | thunk 13 | ]; 14 | let store; 15 | 16 | if (process.browser) { 17 | if(process.env.NODE_ENV !== 'production') { 18 | middleware.push(createLogger()); 19 | 20 | store = createStore(rootReducer, initialState, compose( 21 | applyMiddleware(...middleware), 22 | typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f 23 | )); 24 | } else { 25 | store = createStore(rootReducer, initialState, compose( 26 | applyMiddleware(...middleware) 27 | )); 28 | } 29 | 30 | } else { 31 | store = createStore(rootReducer, initialState, compose(applyMiddleware(...middleware), f => f)); 32 | } 33 | 34 | if (module.hot) { 35 | // Enable Webpack hot module replacement for reducers 36 | module.hot.accept('../reducers/spaReducers', () => { 37 | const nextReducer = require('../reducers/spaReducers'); 38 | store.replaceReducer(nextReducer); 39 | }); 40 | } 41 | 42 | return store; 43 | } 44 | -------------------------------------------------------------------------------- /common/utils/connectDataFetchers.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | PropTypes 3 | } from 'react'; 4 | import Base from '../pages/Base'; 5 | 6 | let IS_FIRST_MOUNT_AFTER_LOAD = true; 7 | if (process.browser) { 8 | var FIRST_PAGE_ID = window.__APP_CONFIG__.pageId; 9 | } 10 | 11 | export default function connectDataFetchers(actionCreators, cache) { 12 | return function (Page) { 13 | if (process.browser) { 14 | if (!Page.pageConfig) { 15 | console.error(`Page Component static propery pageConfig.pageId required!`); 16 | } else { 17 | IS_FIRST_MOUNT_AFTER_LOAD = Page.pageConfig.pageId === FIRST_PAGE_ID; 18 | } 19 | } 20 | 21 | class DataFetchersWrapper extends Base { 22 | static propTypes = { 23 | dispatch: PropTypes.func.isRequired, 24 | params: PropTypes.object, 25 | location: PropTypes.shape({ 26 | pathname: PropTypes.string.required, 27 | search: PropTypes.string, 28 | query: PropTypes.string.object 29 | }).isRequired 30 | }; 31 | 32 | static contextTypes = { 33 | $appConfig: PropTypes.object 34 | }; 35 | 36 | static OriginalPage = Page; 37 | 38 | static fetchData({ 39 | dispatch, 40 | location, 41 | params, 42 | appConfig, 43 | pageConfig 44 | }, req) { 45 | return Promise.all( 46 | actionCreators.map(actionCreator => dispatch(actionCreator({ 47 | dispatch, 48 | location, 49 | params, 50 | appConfig, 51 | pageConfig 52 | }, req))) 53 | ); 54 | } 55 | 56 | shouldComponentUpdate(nextProps) { 57 | return this.props !== nextProps; 58 | } 59 | 60 | componentDidUpdate(prevProps) { 61 | const { 62 | location 63 | } = this.props; 64 | const { 65 | location: prevLocation 66 | } = prevProps; 67 | 68 | const isUrlChanged = (location.pathname !== prevLocation.pathname) || 69 | (location.search.slice(1) !== prevLocation.search.slice(1)); 70 | 71 | if (isUrlChanged) { 72 | this._fetchDataOnClient(); 73 | } 74 | } 75 | 76 | componentDidMount() { 77 | if (!cache) { 78 | if (!IS_FIRST_MOUNT_AFTER_LOAD) { 79 | this._fetchDataOnClient(); 80 | } 81 | 82 | IS_FIRST_MOUNT_AFTER_LOAD = false; 83 | } else { 84 | if (!IS_FIRST_MOUNT_AFTER_LOAD && !Page.DATA_LOADED) { 85 | this._fetchDataOnClient(); 86 | } 87 | 88 | Page.DATA_LOADED = true; 89 | IS_FIRST_MOUNT_AFTER_LOAD = false; 90 | } 91 | } 92 | 93 | _fetchDataOnClient() { 94 | this.constructor.fetchData({ 95 | dispatch: this.props.dispatch, 96 | params: this.props.params, 97 | location: this.props.location, 98 | appConfig: this.context.$appConfig 99 | }); 100 | } 101 | 102 | render() { 103 | return ( 104 | 105 | ); 106 | } 107 | } 108 | 109 | return DataFetchersWrapper; 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /common/utils/shallowEqual.js: -------------------------------------------------------------------------------- 1 | // modified 2 | /** 3 | * Copyright (c) 2013-present, Facebook, Inc. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under the BSD-style license found in the 7 | * LICENSE file in the root directory of this source tree. An additional grant 8 | * of patent rights can be found in the PATENTS file in the same directory. 9 | * 10 | * @typechecks 11 | * 12 | */ 13 | 14 | /*eslint-disable no-self-compare */ 15 | 16 | 'use strict'; 17 | 18 | var hasOwnProperty = Object.prototype.hasOwnProperty; 19 | 20 | /** 21 | * inlined Object.is polyfill to avoid requiring consumers ship their own 22 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 23 | */ 24 | function is(x, y) { 25 | // SameValue algorithm 26 | if (x === y) { 27 | return true; 28 | } else { 29 | if(typeof x === 'function' && typeof y === 'function'){ 30 | return x.toString() === y.toString(); 31 | } 32 | return false; 33 | } 34 | } 35 | 36 | /** 37 | * Performs equality by iterating through keys on an object and returning false 38 | * when any key has values which are not strictly equal between the arguments. 39 | * Returns true when the values of all keys are strictly equal. 40 | */ 41 | function shallowEqual(objA, objB) { 42 | if (is(objA, objB)) { 43 | return true; 44 | } 45 | 46 | if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 47 | return false; 48 | } 49 | 50 | var keysA = Object.keys(objA); 51 | var keysB = Object.keys(objB); 52 | 53 | if (keysA.length !== keysB.length) { 54 | return false; 55 | } 56 | 57 | // Test for A's keys different from B. 58 | for (var i = 0; i < keysA.length; i++) { 59 | if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { 60 | return false; 61 | } 62 | } 63 | 64 | return true; 65 | } 66 | 67 | module.exports = shallowEqual; 68 | -------------------------------------------------------------------------------- /create-webpack-libs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Devicalin on 2015/11/15. 3 | */ 4 | 'use strict'; 5 | 6 | let webpack = require('webpack'); 7 | let path = require('path'); 8 | let fs = require('fs'); 9 | let ProgressBarPlugin = require('progress-bar-webpack-plugin'); 10 | let HappyPack = require('happypack'); 11 | 12 | module.exports = function(DEBUG){ 13 | let happyId = DEBUG ? 'libs-debug' : 'libs'; 14 | 15 | let plugins = [ 16 | new HappyPack({ id: happyId }), 17 | new webpack.optimize.OccurrenceOrderPlugin(), 18 | new ProgressBarPlugin({ 19 | format: ' build libs [:bar] :percent (:elapsed seconds)', 20 | clear: false 21 | }), 22 | new webpack.DllPlugin({ 23 | path: DEBUG ? 'manifest-debug.json' : 'manifest.json', 24 | name: '[name]_lib', 25 | context: __dirname 26 | }) 27 | ]; 28 | if (!DEBUG) { 29 | plugins.push( 30 | new webpack.optimize.UglifyJsPlugin({ 31 | output: { 32 | comments: false 33 | }, 34 | compress: { 35 | warnings: false 36 | }, 37 | sourceMap: false 38 | }), 39 | new webpack.optimize.DedupePlugin(), 40 | new webpack.DefinePlugin({ 41 | 'process.env': { 42 | NODE_ENV: JSON.stringify('production') 43 | } 44 | }), 45 | new webpack.NoErrorsPlugin() 46 | ); 47 | } 48 | 49 | let libs = [ 50 | 'react', 51 | 'react-dom', 52 | 'redux', 53 | 'react-redux', 54 | 'redux-thunk', 55 | 'react-router', 56 | 'react-router-redux', 57 | 'immutable', 58 | 'redux-immutablejs', 59 | 'react-immutable-proptypes', 60 | 'fastclick' 61 | ]; 62 | if(DEBUG) { 63 | libs.push( 64 | 'why-did-you-update', 65 | 'redux-logger', 66 | 'react-addons-perf' 67 | ); 68 | } 69 | 70 | let loaders = [ 71 | // Load ES6/JSX 72 | { 73 | test: /\.jsx?$/, 74 | exclude: /(node_modules|bower_components)/, 75 | loader: 'babel', 76 | query: { 77 | cacheDirectory: true, 78 | // "presets": ["es2015"], 79 | // "plugins": ["transform-runtime"] 80 | }, 81 | happy: { id: happyId } 82 | } 83 | ]; 84 | 85 | return { 86 | target: 'web', 87 | entry: { 88 | libs: libs 89 | }, 90 | output: { 91 | path: './public/', 92 | filename: DEBUG ? "./js/[name]-debug.js" : "./js/[name]-min.js", 93 | chunkFilename: DEBUG ? "./js/[name]-debug.js" : "./js/[name]-min.js", 94 | publicPath: '', 95 | pathinfo: false, 96 | libraryTarget: 'umd', 97 | library: '[name]_lib' 98 | }, 99 | 100 | cache: true, 101 | debug: DEBUG, 102 | 103 | // For options, see http://webpack.github.io/docs/configuration.html#devtool 104 | devtool: DEBUG && "eval-source-map", 105 | // devtool: DEBUG && "cheap-module-eval-source-map", 106 | 107 | module: { 108 | loaders: loaders, 109 | noParse: [] 110 | }, 111 | 112 | plugins: plugins, 113 | 114 | externals: { 115 | }, 116 | 117 | resolve: { 118 | root: path.resolve('/'), 119 | modulesDirectories: [ 120 | "node_modules", 121 | 122 | // https://github.com/webpack/webpack-dev-server/issues/60 123 | "web_modules" 124 | ], 125 | 126 | // Allow to omit extensions when requiring these files 127 | extensions: ["", ".js", ".jsx", ".es6", '.json'], 128 | 129 | alias: {} 130 | } 131 | }; 132 | 133 | }; 134 | -------------------------------------------------------------------------------- /create-webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Devicalin on 2015/11/15. 3 | */ 4 | 'use strict'; 5 | 6 | let webpack = require('webpack'); 7 | let path = require('path'); 8 | let fs = require('fs'); 9 | let ExtractTextPlugin = require('extract-text-webpack-plugin'); 10 | let ProgressBarPlugin = require('progress-bar-webpack-plugin'); 11 | let HappyPack = require('happypack'); 12 | 13 | 14 | module.exports = function (DEBUG) { 15 | let happyId = DEBUG ? 'app-debug' : 'app'; 16 | 17 | 18 | let plugins = [ 19 | new HappyPack({id: happyId}), 20 | new webpack.optimize.OccurrenceOrderPlugin(), 21 | //new NyanProgressPlugin() 22 | new ProgressBarPlugin({ 23 | format: ' build [:bar] :percent (:elapsed seconds)', 24 | clear: false 25 | }), 26 | new webpack.DllReferencePlugin({ 27 | context: __dirname, 28 | manifest: require('./' + (DEBUG ? 'manifest-debug.json' : 'manifest.json')) 29 | }), 30 | new ExtractTextPlugin(DEBUG ? './css/main.css' : './css/main-min.css', { 31 | allChunks: true 32 | }) 33 | ]; 34 | if (DEBUG) { 35 | plugins.push( 36 | new webpack.HotModuleReplacementPlugin() 37 | ); 38 | } else { 39 | plugins.push( 40 | new webpack.optimize.UglifyJsPlugin({ 41 | output: { 42 | comments: false 43 | }, 44 | compress: { 45 | warnings: false 46 | }, 47 | sourceMap: false 48 | }), 49 | function () { 50 | this.plugin("done", function (stats) { 51 | let jsonStats = stats.toJson({ 52 | chunkModules: true 53 | }); 54 | let assetsByChunkName = jsonStats.assetsByChunkName; 55 | let obj = {}; 56 | for (let key in assetsByChunkName) { 57 | if (!assetsByChunkName.hasOwnProperty(key)) continue; 58 | 59 | let value = assetsByChunkName[key]; 60 | let match = value[0].match(/-(\w+)\.js$/); 61 | if (match) { 62 | obj[key] = match[1]; 63 | } 64 | } 65 | 66 | fs.writeFileSync( 67 | __dirname + "/webpack-assets.json", 68 | JSON.stringify(obj) 69 | ); 70 | }); 71 | }, 72 | new webpack.optimize.DedupePlugin(), 73 | new webpack.DefinePlugin({ 74 | 'process.env': { 75 | NODE_ENV: JSON.stringify('production') 76 | } 77 | }), 78 | new webpack.NoErrorsPlugin() 79 | ); 80 | } 81 | 82 | function getPagesNames(dirPath) { 83 | let filesNames = fs.readdirSync(dirPath); 84 | let entries = { 85 | app: __dirname + '/client/js/utils/spaRenderer.js' 86 | }; 87 | 88 | for (let fileName of filesNames) { 89 | if (DEBUG) { 90 | entries[fileName.split('.').shift() || fileName] = [ 91 | // 'webpack-hot-middleware/client', 92 | `${dirPath}/${fileName}` 93 | ]; 94 | } else { 95 | entries[fileName.split('.').shift() || fileName] = [`${dirPath}/${fileName}`]; 96 | } 97 | } 98 | 99 | return entries; 100 | } 101 | 102 | let babelPlugins = [ 103 | "syntax-async-functions", 104 | 'transform-regenerator', 105 | "transform-decorators-legacy", 106 | "transform-class-properties", 107 | 108 | ["transform-runtime", { 109 | // "helpers": false, 110 | "polyfill": false, 111 | "regenerator": true 112 | }] 113 | ]; 114 | if (!DEBUG) { 115 | babelPlugins.push( 116 | 'transform-react-remove-prop-types', 117 | 'transform-react-constant-elements', 118 | 'transform-react-inline-elements' 119 | ); 120 | } 121 | 122 | return { 123 | target: 'web', 124 | entry: getPagesNames(__dirname + '/client/js/pages'), 125 | output: { 126 | path: __dirname + '/public/', 127 | filename: DEBUG ? "/js/debug/[name].js" : "/js/min/[name]-[chunkhash].js", 128 | // filename: DEBUG ? "./js/debug/[name].js" : "./js/min/[name].js", 129 | chunkFilename: DEBUG ? "/js/debug/[name].js" : "/js/min/[name]-[chunkhash].js", 130 | // chunkFilename: DEBUG ? "./js/debug/[name].js" : "./js/min/[name].js", 131 | publicPath: '/static', 132 | pathinfo: true 133 | }, 134 | 135 | cache: true, 136 | debug: DEBUG, 137 | 138 | // For options, see http://webpack.github.io/docs/configuration.html#devtool 139 | //devtool: DEBUG && "eval-source-map", 140 | devtool: DEBUG && "#inline-source-map", 141 | 142 | module: { 143 | loaders: [ 144 | // Load ES6/JSX 145 | { 146 | test: /\.jsx?$/, 147 | exclude: /(node_modules|bower_components)/, 148 | loader: require.resolve('babel-loader'), 149 | query: { 150 | cacheDirectory: true, 151 | // fixed resolve path in parent directory error 152 | "presets": [ 153 | "react", 154 | [ 155 | "es2015", 156 | { loose: true } 157 | ] 158 | ].map((preset) => { 159 | if (typeof preset === 'string') 160 | return require.resolve(`babel-preset-${preset}`); 161 | else if (Array.isArray(preset)) 162 | return [require.resolve(`babel-preset-${preset[0]}`), preset[1]]; 163 | }), 164 | "plugins": babelPlugins.map((preset) => { 165 | if (typeof preset === 'string') 166 | return require.resolve(`babel-plugin-${preset}`); 167 | else if (Array.isArray(preset)) 168 | return [require.resolve(`babel-plugin-${preset[0]}`), preset[1]]; 169 | }) 170 | }, 171 | happy: {id: happyId} 172 | }, 173 | 174 | { 175 | test: /\.json$/, 176 | exclude: /node_modules/, 177 | loaders: ['json-loader'] 178 | }, 179 | 180 | // Load styles 181 | { 182 | test: /\.css$/, 183 | loader: //DEBUG 184 | //? "style!css" : 185 | ExtractTextPlugin.extract("style-loader", "css-loader") 186 | }, 187 | 188 | // Load images 189 | {test: /\.jpg/, loader: "url-loader?limit=1024&mimetype=image/jpg&name=./img/[name].[ext]"}, 190 | {test: /\.gif/, loader: "url-loader?limit=1024&mimetype=image/gif&name=./img/[name].[ext]"}, 191 | {test: /\.png/, loader: "url-loader?limit=1024&mimetype=image/png&name=./img/[name].[ext]"}, 192 | {test: /\.svg/, loader: "url-loader?limit=1024&mimetype=image/svg&name=./img/[name].[ext]"}, 193 | 194 | // Load fonts 195 | { 196 | test: /\.woff$/, 197 | loader: "url-loader?limit=1024&minetype=application/font-woff&name=./font/[name].[ext]" 198 | }, 199 | {test: /\.(ttf|eot|svg)$/, loader: "file-loader?name=./font/[name].[ext]"} 200 | ], 201 | noParse: [] 202 | }, 203 | 204 | plugins: plugins, 205 | 206 | externals: {}, 207 | 208 | resolve: { 209 | root: path.resolve('/'), 210 | modulesDirectories: [ 211 | "node_modules", 212 | 213 | // https://github.com/webpack/webpack-dev-server/issues/60 214 | "web_modules" 215 | ], 216 | 217 | // Allow to omit extensions when requiring these files 218 | extensions: ["", ".js", ".jsx", ".es6", '.json'], 219 | 220 | alias: { 221 | // 'libs': path.join(__dirname, './common/libs') 222 | } 223 | } 224 | }; 225 | 226 | }; 227 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author Devicalin 3 | */ 4 | 5 | var fs = require('fs'); 6 | var gulp = require('gulp'); 7 | var webpack = require('webpack'); 8 | var createLibsWebpackConfig = require('./create-webpack-libs.config.js'); 9 | var createWebpackConfig = require('./create-webpack.config.js'); 10 | var del = require('del'); 11 | var browserSync = require('browser-sync').create(); 12 | 13 | gulp.task('default', ['build-dev', 'build']); 14 | 15 | gulp.task('clean', function (cb) { 16 | return del([ 17 | './public/js/min/' 18 | ], { 19 | force: true 20 | }); 21 | }); 22 | 23 | gulp.task('clean:dev', function (cb) { 24 | return del([ 25 | './public/js/debug/' 26 | ], { 27 | force: true 28 | }); 29 | }); 30 | 31 | gulp.task('build:lib', function(cb){ 32 | webpack(createLibsWebpackConfig(), function (err, stats) { 33 | if (err) throw new Error(err); 34 | 35 | if (stats.compilation.errors.length) { 36 | console.log(stats.compilation.errors[0]); 37 | } 38 | 39 | console.log('webpack libs end'); 40 | cb(); 41 | }); 42 | }); 43 | 44 | gulp.task('build', ['clean'], function (cb) { 45 | webpack(createWebpackConfig(), function (err, stats) { 46 | if (err) throw new Error(err); 47 | 48 | if (stats.compilation.errors.length) { 49 | console.log(stats.compilation.errors[0]); 50 | } 51 | 52 | console.log('webpack end'); 53 | cb(); 54 | }); 55 | }); 56 | 57 | gulp.task('build:lib:dev', function(cb){ 58 | webpack(createLibsWebpackConfig(true), function (err, stats) { 59 | if (err) throw new Error(err); 60 | 61 | if (stats.compilation.errors.length) { 62 | console.log(stats.compilation.errors[0]); 63 | } 64 | 65 | console.log('webpack libs dev end'); 66 | cb(); 67 | }); 68 | }); 69 | 70 | gulp.task('build:dev', ['clean:dev'], function (cb) { 71 | webpack(createWebpackConfig(true), function (err, stats) { 72 | if (err) throw new Error(err); 73 | 74 | if (stats.compilation.errors.length) { 75 | console.log(stats.compilation.errors[0].error); 76 | } 77 | 78 | console.log('webpack dev end'); 79 | 80 | browserSync.reload(); 81 | 82 | cb(); 83 | }); 84 | }); 85 | 86 | gulp.task('watch', ['build:dev'], function(){ 87 | browserSync.init({ 88 | files: ['public/**/*.*'], 89 | proxy: 'http://127.0.0.1:3000', 90 | port: 4000, 91 | open: false 92 | }); 93 | 94 | gulp.watch('client/**', ['build:dev']); 95 | gulp.watch('common/**', ['build:dev']); 96 | }); 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | if(process.env.NODE_ENV !== 'production') { 2 | console.log('start server in development mode'); 3 | require('babel-register'); 4 | require('./server/app'); 5 | } else { 6 | require('./dist/server'); 7 | } 8 | -------------------------------------------------------------------------------- /manifest-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libs_lib", 3 | "content": { 4 | "./node_modules/node-libs-browser/node_modules/process/browser.js": 1, 5 | "./node_modules/fbjs/lib/warning.js": 2, 6 | "./node_modules/fbjs/lib/invariant.js": 3, 7 | "./node_modules/react/lib/reactProdInvariant.js": 4, 8 | "./node_modules/object-assign/index.js": 5, 9 | "./node_modules/react/lib/ReactDOMComponentTree.js": 6, 10 | "./node_modules/react/react.js": 7, 11 | "./node_modules/fbjs/lib/ExecutionEnvironment.js": 8, 12 | "./node_modules/invariant/browser.js": 9, 13 | "./node_modules/react/lib/ReactInstrumentation.js": 10, 14 | "./node_modules/fbjs/lib/emptyFunction.js": 11, 15 | "./node_modules/react/lib/ReactComponentTreeHook.js": 12, 16 | "./node_modules/react/lib/ReactElement.js": 13, 17 | "./node_modules/react/lib/ReactUpdates.js": 14, 18 | "./node_modules/react/lib/EventConstants.js": 15, 19 | "./node_modules/react/lib/ReactCurrentOwner.js": 16, 20 | "./node_modules/react/lib/SyntheticEvent.js": 17, 21 | "./node_modules/why-did-you-update/node_modules/lodash/isArray.js": 18, 22 | "./node_modules/fbjs/lib/keyOf.js": 19, 23 | "./node_modules/history/lib/PathUtils.js": 20, 24 | "./node_modules/react-router/lib/RouteUtils.js": 21, 25 | "./node_modules/react/lib/PooledClass.js": 22, 26 | "./node_modules/warning/browser.js": 23, 27 | "./node_modules/react/lib/DOMProperty.js": 24, 28 | "./node_modules/why-did-you-update/node_modules/lodash/_root.js": 25, 29 | "./node_modules/why-did-you-update/node_modules/lodash/isObject.js": 26, 30 | "./node_modules/history/lib/LocationUtils.js": 27, 31 | "./node_modules/react-router/lib/PatternUtils.js": 28, 32 | "./node_modules/react-router/lib/routerWarning.js": 29, 33 | "./node_modules/react/lib/DOMLazyTree.js": 30, 34 | "./node_modules/react/lib/ReactReconciler.js": 31, 35 | "./node_modules/why-did-you-update/node_modules/lodash/_getNative.js": 32, 36 | "./node_modules/fbjs/lib/emptyObject.js": 33, 37 | "./node_modules/react-router/lib/InternalPropTypes.js": 34, 38 | "./node_modules/react/lib/EventPluginHub.js": 35, 39 | "./node_modules/react/lib/EventPropagators.js": 36, 40 | "./node_modules/react/lib/ReactInstanceMap.js": 37, 41 | "./node_modules/react/lib/SyntheticUIEvent.js": 38, 42 | "./node_modules/react/lib/Transaction.js": 39, 43 | "./node_modules/why-did-you-update/node_modules/lodash/isFunction.js": 40, 44 | "./node_modules/why-did-you-update/node_modules/lodash/isObjectLike.js": 41, 45 | "./node_modules/fbjs/lib/keyMirror.js": 42, 46 | "./node_modules/history/lib/Actions.js": 43, 47 | "./node_modules/history/lib/DOMUtils.js": 44, 48 | "./node_modules/immutable/dist/immutable.js": 45, 49 | "./node_modules/react/lib/DisabledInputUtils.js": 46, 50 | "./node_modules/react/lib/EventPluginRegistry.js": 47, 51 | "./node_modules/react/lib/ReactBrowserEventEmitter.js": 48, 52 | "./node_modules/react/lib/ReactPropTypeLocations.js": 49, 53 | "./node_modules/react/lib/SyntheticMouseEvent.js": 50, 54 | "./node_modules/react/lib/escapeTextContentForBrowser.js": 51, 55 | "./node_modules/react/lib/setInnerHTML.js": 52, 56 | "./node_modules/why-did-you-update/node_modules/lodash/_ListCache.js": 53, 57 | "./node_modules/why-did-you-update/node_modules/lodash/_assocIndexOf.js": 54, 58 | "./node_modules/why-did-you-update/node_modules/lodash/_getMapData.js": 55, 59 | "./node_modules/why-did-you-update/node_modules/lodash/_isKey.js": 56, 60 | "./node_modules/why-did-you-update/node_modules/lodash/_nativeCreate.js": 57, 61 | "./node_modules/why-did-you-update/node_modules/lodash/_toKey.js": 58, 62 | "./node_modules/why-did-you-update/node_modules/lodash/isArrayLike.js": 59, 63 | "./node_modules/why-did-you-update/node_modules/lodash/isLength.js": 60, 64 | "./node_modules/why-did-you-update/node_modules/lodash/isSymbol.js": 61, 65 | "./node_modules/why-did-you-update/node_modules/lodash/keys.js": 62, 66 | "./node_modules/fbjs/lib/shallowEqual.js": 63, 67 | "./node_modules/history/lib/BrowserProtocol.js": 64, 68 | "./node_modules/history/lib/ExecutionEnvironment.js": 65, 69 | "./node_modules/history/lib/createHistory.js": 66, 70 | "./node_modules/history/lib/runTransitionHook.js": 67, 71 | "./node_modules/lodash/isPlainObject.js": 68, 72 | "./node_modules/react-router/lib/AsyncUtils.js": 69, 73 | "./node_modules/react-router/lib/ContextUtils.js": 70, 74 | "./node_modules/react-router/lib/PropTypes.js": 71, 75 | "./node_modules/react-router/lib/RouterContext.js": 72, 76 | "./node_modules/react/lib/DOMChildrenOperations.js": 73, 77 | "./node_modules/react/lib/DOMNamespaces.js": 74, 78 | "./node_modules/react/lib/EventPluginUtils.js": 75, 79 | "./node_modules/react/lib/KeyEscapeUtils.js": 76, 80 | "./node_modules/react/lib/LinkedValueUtils.js": 77, 81 | "./node_modules/react/lib/ReactComponent.js": 78, 82 | "./node_modules/react/lib/ReactComponentEnvironment.js": 79, 83 | "./node_modules/react/lib/ReactErrorUtils.js": 80, 84 | "./node_modules/react/lib/ReactNoopUpdateQueue.js": 81, 85 | "./node_modules/react/lib/ReactPropTypeLocationNames.js": 82, 86 | "./node_modules/react/lib/ReactPropTypesSecret.js": 83, 87 | "./node_modules/react/lib/ReactUpdateQueue.js": 84, 88 | "./node_modules/react/lib/canDefineProperty.js": 85, 89 | "./node_modules/react/lib/createMicrosoftUnsafeLocalFunction.js": 86, 90 | "./node_modules/react/lib/getEventCharCode.js": 87, 91 | "./node_modules/react/lib/getEventModifierState.js": 88, 92 | "./node_modules/react/lib/getEventTarget.js": 89, 93 | "./node_modules/react/lib/getIteratorFn.js": 90, 94 | "./node_modules/react/lib/isEventSupported.js": 91, 95 | "./node_modules/react/lib/shouldUpdateReactComponent.js": 92, 96 | "./node_modules/react/lib/traverseAllChildren.js": 93, 97 | "./node_modules/react/lib/validateDOMNesting.js": 94, 98 | "./node_modules/why-did-you-update/node_modules/lodash/_MapCache.js": 95, 99 | "./node_modules/why-did-you-update/node_modules/lodash/_baseIsEqual.js": 96, 100 | "./node_modules/why-did-you-update/node_modules/lodash/_isIndex.js": 97, 101 | "./node_modules/why-did-you-update/node_modules/lodash/_setToArray.js": 98, 102 | "./node_modules/why-did-you-update/node_modules/lodash/isArguments.js": 99, 103 | "./node_modules/why-did-you-update/node_modules/lodash/isString.js": 100, 104 | "./node_modules/fbjs/lib/EventListener.js": 101, 105 | "./node_modules/fbjs/lib/focusNode.js": 102, 106 | "./node_modules/fbjs/lib/getActiveElement.js": 103, 107 | "./node_modules/history/lib/DOMStateStorage.js": 104, 108 | "./node_modules/history/lib/useBasename.js": 105, 109 | "./node_modules/history/lib/useQueries.js": 106, 110 | "./node_modules/hoist-non-react-statics/index.js": 107, 111 | "./node_modules/react-redux/lib/utils/storeShape.js": 108, 112 | "./node_modules/react-redux/lib/utils/warning.js": 109, 113 | "./node_modules/react-router-redux/lib/actions.js": 110, 114 | "./node_modules/react-router-redux/lib/reducer.js": 111, 115 | "./node_modules/react-router/lib/Link.js": 112, 116 | "./node_modules/react-router/lib/PromiseUtils.js": 113, 117 | "./node_modules/react-router/lib/Redirect.js": 114, 118 | "./node_modules/react-router/lib/RouterUtils.js": 115, 119 | "./node_modules/react-router/lib/createMemoryHistory.js": 116, 120 | "./node_modules/react-router/lib/createRouterHistory.js": 117, 121 | "./node_modules/react-router/lib/createTransitionManager.js": 118, 122 | "./node_modules/react-router/lib/useRouterHistory.js": 119, 123 | "./node_modules/react/lib/CSSProperty.js": 120, 124 | "./node_modules/react/lib/CallbackQueue.js": 121, 125 | "./node_modules/react/lib/DOMPropertyOperations.js": 122, 126 | "./node_modules/react/lib/ReactChildren.js": 123, 127 | "./node_modules/react/lib/ReactClass.js": 124, 128 | "./node_modules/react/lib/ReactDOMComponentFlags.js": 125, 129 | "./node_modules/react/lib/ReactDOMSelect.js": 126, 130 | "./node_modules/react/lib/ReactDebugTool.js": 127, 131 | "./node_modules/react/lib/ReactElementValidator.js": 128, 132 | "./node_modules/react/lib/ReactEmptyComponent.js": 129, 133 | "./node_modules/react/lib/ReactFeatureFlags.js": 130, 134 | "./node_modules/react/lib/ReactHostComponent.js": 131, 135 | "./node_modules/react/lib/ReactInputSelection.js": 132, 136 | "./node_modules/react/lib/ReactMount.js": 133, 137 | "./node_modules/react/lib/ReactMultiChildUpdateTypes.js": 134, 138 | "./node_modules/react/lib/ReactNodeTypes.js": 135, 139 | "./node_modules/react/lib/ReactPropTypes.js": 136, 140 | "./node_modules/react/lib/ReactVersion.js": 137, 141 | "./node_modules/react/lib/ViewportMetrics.js": 138, 142 | "./node_modules/react/lib/accumulateInto.js": 139, 143 | "./node_modules/react/lib/checkReactTypeSpec.js": 140, 144 | "./node_modules/react/lib/forEachAccumulated.js": 141, 145 | "./node_modules/react/lib/getHostComponentFromComposite.js": 142, 146 | "./node_modules/react/lib/getTextContentAccessor.js": 143, 147 | "./node_modules/react/lib/instantiateReactComponent.js": 144, 148 | "./node_modules/react/lib/isTextInputElement.js": 145, 149 | "./node_modules/react/lib/setTextContent.js": 146, 150 | "./node_modules/redux-logger/lib/helpers.js": 147, 151 | "./node_modules/redux/lib/compose.js": 148, 152 | "./node_modules/redux/lib/createStore.js": 149, 153 | "./node_modules/redux/lib/index.js": 150, 154 | "./node_modules/redux/lib/utils/warning.js": 151, 155 | "./node_modules/webpack/buildin/module.js": 152, 156 | "./node_modules/why-did-you-update/node_modules/lodash/_Map.js": 153, 157 | "./node_modules/why-did-you-update/node_modules/lodash/_Set.js": 154, 158 | "./node_modules/why-did-you-update/node_modules/lodash/_SetCache.js": 155, 159 | "./node_modules/why-did-you-update/node_modules/lodash/_Stack.js": 156, 160 | "./node_modules/why-did-you-update/node_modules/lodash/_Symbol.js": 157, 161 | "./node_modules/why-did-you-update/node_modules/lodash/_arraySome.js": 158, 162 | "./node_modules/why-did-you-update/node_modules/lodash/_baseGet.js": 159, 163 | "./node_modules/why-did-you-update/node_modules/lodash/_baseHas.js": 160, 164 | "./node_modules/why-did-you-update/node_modules/lodash/_baseProperty.js": 161, 165 | "./node_modules/why-did-you-update/node_modules/lodash/_castPath.js": 162, 166 | "./node_modules/why-did-you-update/node_modules/lodash/_equalArrays.js": 163, 167 | "./node_modules/why-did-you-update/node_modules/lodash/_getTag.js": 164, 168 | "./node_modules/why-did-you-update/node_modules/lodash/_isHostObject.js": 165, 169 | "./node_modules/why-did-you-update/node_modules/lodash/_isStrictComparable.js": 166, 170 | "./node_modules/why-did-you-update/node_modules/lodash/_mapToArray.js": 167, 171 | "./node_modules/why-did-you-update/node_modules/lodash/_matchesStrictComparable.js": 168, 172 | "./node_modules/why-did-you-update/node_modules/lodash/_toSource.js": 169, 173 | "./node_modules/why-did-you-update/node_modules/lodash/eq.js": 170, 174 | "./node_modules/why-did-you-update/node_modules/lodash/isArrayLikeObject.js": 171, 175 | "./node_modules/deep-diff/index.js": 172, 176 | "./node_modules/fastclick/lib/fastclick.js": 173, 177 | "./node_modules/fbjs/lib/camelize.js": 174, 178 | "./node_modules/fbjs/lib/camelizeStyleName.js": 175, 179 | "./node_modules/fbjs/lib/containsNode.js": 176, 180 | "./node_modules/fbjs/lib/createArrayFromMixed.js": 177, 181 | "./node_modules/fbjs/lib/createNodesFromMarkup.js": 178, 182 | "./node_modules/fbjs/lib/getMarkupWrap.js": 179, 183 | "./node_modules/fbjs/lib/getUnboundedScrollPosition.js": 180, 184 | "./node_modules/fbjs/lib/hyphenate.js": 181, 185 | "./node_modules/fbjs/lib/hyphenateStyleName.js": 182, 186 | "./node_modules/fbjs/lib/isNode.js": 183, 187 | "./node_modules/fbjs/lib/isTextNode.js": 184, 188 | "./node_modules/fbjs/lib/memoizeStringOnly.js": 185, 189 | "./node_modules/fbjs/lib/performance.js": 186, 190 | "./node_modules/fbjs/lib/performanceNow.js": 187, 191 | "./node_modules/history/lib/AsyncUtils.js": 188, 192 | "./node_modules/history/lib/HashProtocol.js": 189, 193 | "./node_modules/history/lib/RefreshProtocol.js": 190, 194 | "./node_modules/history/lib/createBrowserHistory.js": 191, 195 | "./node_modules/history/lib/createHashHistory.js": 192, 196 | "./node_modules/history/lib/createMemoryHistory.js": 193, 197 | "./node_modules/lodash/_getPrototype.js": 194, 198 | "./node_modules/lodash/_isHostObject.js": 195, 199 | "./node_modules/lodash/isObjectLike.js": 196, 200 | "./node_modules/query-string/index.js": 197, 201 | "./node_modules/react-addons-perf/index.js": 198, 202 | "./node_modules/react-dom/index.js": 199, 203 | "./node_modules/react-immutable-proptypes/dist/ImmutablePropTypes.js": 200, 204 | "./node_modules/react-redux/lib/components/Provider.js": 201, 205 | "./node_modules/react-redux/lib/components/connect.js": 202, 206 | "./node_modules/react-redux/lib/index.js": 203, 207 | "./node_modules/react-redux/lib/utils/shallowEqual.js": 204, 208 | "./node_modules/react-redux/lib/utils/wrapActionCreators.js": 205, 209 | "./node_modules/react-router-redux/lib/index.js": 206, 210 | "./node_modules/react-router-redux/lib/middleware.js": 207, 211 | "./node_modules/react-router-redux/lib/sync.js": 208, 212 | "./node_modules/react-router/lib/IndexLink.js": 209, 213 | "./node_modules/react-router/lib/IndexRedirect.js": 210, 214 | "./node_modules/react-router/lib/IndexRoute.js": 211, 215 | "./node_modules/react-router/lib/Route.js": 212, 216 | "./node_modules/react-router/lib/Router.js": 213, 217 | "./node_modules/react-router/lib/TransitionUtils.js": 214, 218 | "./node_modules/react-router/lib/applyRouterMiddleware.js": 215, 219 | "./node_modules/react-router/lib/browserHistory.js": 216, 220 | "./node_modules/react-router/lib/computeChangedRoutes.js": 217, 221 | "./node_modules/react-router/lib/getComponents.js": 218, 222 | "./node_modules/react-router/lib/getRouteParams.js": 219, 223 | "./node_modules/react-router/lib/hashHistory.js": 220, 224 | "./node_modules/react-router/lib/index.js": 221, 225 | "./node_modules/react-router/lib/isActive.js": 222, 226 | "./node_modules/react-router/lib/match.js": 223, 227 | "./node_modules/react-router/lib/matchRoutes.js": 224, 228 | "./node_modules/react-router/lib/withRouter.js": 225, 229 | "./node_modules/react/lib/AutoFocusUtils.js": 226, 230 | "./node_modules/react/lib/BeforeInputEventPlugin.js": 227, 231 | "./node_modules/react/lib/CSSPropertyOperations.js": 228, 232 | "./node_modules/react/lib/ChangeEventPlugin.js": 229, 233 | "./node_modules/react/lib/Danger.js": 230, 234 | "./node_modules/react/lib/DefaultEventPluginOrder.js": 231, 235 | "./node_modules/react/lib/EnterLeaveEventPlugin.js": 232, 236 | "./node_modules/react/lib/FallbackCompositionState.js": 233, 237 | "./node_modules/react/lib/HTMLDOMPropertyConfig.js": 234, 238 | "./node_modules/react/lib/React.js": 235, 239 | "./node_modules/react/lib/ReactChildReconciler.js": 236, 240 | "./node_modules/react/lib/ReactChildrenMutationWarningHook.js": 237, 241 | "./node_modules/react/lib/ReactComponentBrowserEnvironment.js": 238, 242 | "./node_modules/react/lib/ReactCompositeComponent.js": 239, 243 | "./node_modules/react/lib/ReactDOM.js": 240, 244 | "./node_modules/react/lib/ReactDOMButton.js": 241, 245 | "./node_modules/react/lib/ReactDOMComponent.js": 242, 246 | "./node_modules/react/lib/ReactDOMContainerInfo.js": 243, 247 | "./node_modules/react/lib/ReactDOMEmptyComponent.js": 244, 248 | "./node_modules/react/lib/ReactDOMFactories.js": 245, 249 | "./node_modules/react/lib/ReactDOMFeatureFlags.js": 246, 250 | "./node_modules/react/lib/ReactDOMIDOperations.js": 247, 251 | "./node_modules/react/lib/ReactDOMInput.js": 248, 252 | "./node_modules/react/lib/ReactDOMNullInputValuePropHook.js": 249, 253 | "./node_modules/react/lib/ReactDOMOption.js": 250, 254 | "./node_modules/react/lib/ReactDOMSelection.js": 251, 255 | "./node_modules/react/lib/ReactDOMTextComponent.js": 252, 256 | "./node_modules/react/lib/ReactDOMTextarea.js": 253, 257 | "./node_modules/react/lib/ReactDOMTreeTraversal.js": 254, 258 | "./node_modules/react/lib/ReactDOMUnknownPropertyHook.js": 255, 259 | "./node_modules/react/lib/ReactDefaultBatchingStrategy.js": 256, 260 | "./node_modules/react/lib/ReactDefaultInjection.js": 257, 261 | "./node_modules/react/lib/ReactEventEmitterMixin.js": 258, 262 | "./node_modules/react/lib/ReactEventListener.js": 259, 263 | "./node_modules/react/lib/ReactHostOperationHistoryHook.js": 260, 264 | "./node_modules/react/lib/ReactInjection.js": 261, 265 | "./node_modules/react/lib/ReactInvalidSetStateWarningHook.js": 262, 266 | "./node_modules/react/lib/ReactMarkupChecksum.js": 263, 267 | "./node_modules/react/lib/ReactMultiChild.js": 264, 268 | "./node_modules/react/lib/ReactOwner.js": 265, 269 | "./node_modules/react/lib/ReactPerf.js": 266, 270 | "./node_modules/react/lib/ReactPureComponent.js": 267, 271 | "./node_modules/react/lib/ReactReconcileTransaction.js": 268, 272 | "./node_modules/react/lib/ReactRef.js": 269, 273 | "./node_modules/react/lib/ReactServerRenderingTransaction.js": 270, 274 | "./node_modules/react/lib/ReactServerUpdateQueue.js": 271, 275 | "./node_modules/react/lib/SVGDOMPropertyConfig.js": 272, 276 | "./node_modules/react/lib/SelectEventPlugin.js": 273, 277 | "./node_modules/react/lib/SimpleEventPlugin.js": 274, 278 | "./node_modules/react/lib/SyntheticAnimationEvent.js": 275, 279 | "./node_modules/react/lib/SyntheticClipboardEvent.js": 276, 280 | "./node_modules/react/lib/SyntheticCompositionEvent.js": 277, 281 | "./node_modules/react/lib/SyntheticDragEvent.js": 278, 282 | "./node_modules/react/lib/SyntheticFocusEvent.js": 279, 283 | "./node_modules/react/lib/SyntheticInputEvent.js": 280, 284 | "./node_modules/react/lib/SyntheticKeyboardEvent.js": 281, 285 | "./node_modules/react/lib/SyntheticTouchEvent.js": 282, 286 | "./node_modules/react/lib/SyntheticTransitionEvent.js": 283, 287 | "./node_modules/react/lib/SyntheticWheelEvent.js": 284, 288 | "./node_modules/react/lib/adler32.js": 285, 289 | "./node_modules/react/lib/dangerousStyleValue.js": 286, 290 | "./node_modules/react/lib/findDOMNode.js": 287, 291 | "./node_modules/react/lib/flattenChildren.js": 288, 292 | "./node_modules/react/lib/getEventKey.js": 289, 293 | "./node_modules/react/lib/getNodeForCharacterOffset.js": 290, 294 | "./node_modules/react/lib/getVendorPrefixedEventName.js": 291, 295 | "./node_modules/react/lib/onlyChild.js": 292, 296 | "./node_modules/react/lib/quoteAttributeValueForBrowser.js": 293, 297 | "./node_modules/react/lib/renderSubtreeIntoContainer.js": 294, 298 | "./node_modules/redux-immutablejs/lib/index.js": 295, 299 | "./node_modules/redux-immutablejs/lib/utils/combineReducers.js": 296, 300 | "./node_modules/redux-immutablejs/lib/utils/createReducer.js": 297, 301 | "./node_modules/redux-logger/lib/core.js": 298, 302 | "./node_modules/redux-logger/lib/defaults.js": 299, 303 | "./node_modules/redux-logger/lib/diff.js": 300, 304 | "./node_modules/redux-logger/lib/index.js": 301, 305 | "./node_modules/redux-thunk/lib/index.js": 302, 306 | "./node_modules/redux/lib/applyMiddleware.js": 303, 307 | "./node_modules/redux/lib/bindActionCreators.js": 304, 308 | "./node_modules/redux/lib/combineReducers.js": 305, 309 | "./node_modules/strict-uri-encode/index.js": 306, 310 | "./node_modules/symbol-observable/index.js": 307, 311 | "./node_modules/symbol-observable/lib/index.js": 308, 312 | "./node_modules/symbol-observable/lib/ponyfill.js": 309, 313 | "./node_modules/why-did-you-update/lib/deepDiff.js": 310, 314 | "./node_modules/why-did-you-update/lib/getDisplayName.js": 311, 315 | "./node_modules/why-did-you-update/lib/index.js": 312, 316 | "./node_modules/why-did-you-update/lib/normalizeOptions.js": 313, 317 | "./node_modules/why-did-you-update/lib/shouldInclude.js": 314, 318 | "./node_modules/why-did-you-update/node_modules/lodash/_DataView.js": 315, 319 | "./node_modules/why-did-you-update/node_modules/lodash/_Hash.js": 316, 320 | "./node_modules/why-did-you-update/node_modules/lodash/_Promise.js": 317, 321 | "./node_modules/why-did-you-update/node_modules/lodash/_Uint8Array.js": 318, 322 | "./node_modules/why-did-you-update/node_modules/lodash/_WeakMap.js": 319, 323 | "./node_modules/why-did-you-update/node_modules/lodash/_apply.js": 320, 324 | "./node_modules/why-did-you-update/node_modules/lodash/_arrayIncludes.js": 321, 325 | "./node_modules/why-did-you-update/node_modules/lodash/_arrayIncludesWith.js": 322, 326 | "./node_modules/why-did-you-update/node_modules/lodash/_arrayMap.js": 323, 327 | "./node_modules/why-did-you-update/node_modules/lodash/_arrayPush.js": 324, 328 | "./node_modules/why-did-you-update/node_modules/lodash/_baseEach.js": 325, 329 | "./node_modules/why-did-you-update/node_modules/lodash/_baseFlatten.js": 326, 330 | "./node_modules/why-did-you-update/node_modules/lodash/_baseFor.js": 327, 331 | "./node_modules/why-did-you-update/node_modules/lodash/_baseForOwn.js": 328, 332 | "./node_modules/why-did-you-update/node_modules/lodash/_baseHasIn.js": 329, 333 | "./node_modules/why-did-you-update/node_modules/lodash/_baseIndexOf.js": 330, 334 | "./node_modules/why-did-you-update/node_modules/lodash/_baseIsEqualDeep.js": 331, 335 | "./node_modules/why-did-you-update/node_modules/lodash/_baseIsMatch.js": 332, 336 | "./node_modules/why-did-you-update/node_modules/lodash/_baseIteratee.js": 333, 337 | "./node_modules/why-did-you-update/node_modules/lodash/_baseKeys.js": 334, 338 | "./node_modules/why-did-you-update/node_modules/lodash/_baseMatches.js": 335, 339 | "./node_modules/why-did-you-update/node_modules/lodash/_baseMatchesProperty.js": 336, 340 | "./node_modules/why-did-you-update/node_modules/lodash/_basePropertyDeep.js": 337, 341 | "./node_modules/why-did-you-update/node_modules/lodash/_baseSome.js": 338, 342 | "./node_modules/why-did-you-update/node_modules/lodash/_baseTimes.js": 339, 343 | "./node_modules/why-did-you-update/node_modules/lodash/_baseToPairs.js": 340, 344 | "./node_modules/why-did-you-update/node_modules/lodash/_baseToString.js": 341, 345 | "./node_modules/why-did-you-update/node_modules/lodash/_baseUniq.js": 342, 346 | "./node_modules/why-did-you-update/node_modules/lodash/_cacheHas.js": 343, 347 | "./node_modules/why-did-you-update/node_modules/lodash/_checkGlobal.js": 344, 348 | "./node_modules/why-did-you-update/node_modules/lodash/_createBaseEach.js": 345, 349 | "./node_modules/why-did-you-update/node_modules/lodash/_createBaseFor.js": 346, 350 | "./node_modules/why-did-you-update/node_modules/lodash/_createSet.js": 347, 351 | "./node_modules/why-did-you-update/node_modules/lodash/_createToPairs.js": 348, 352 | "./node_modules/why-did-you-update/node_modules/lodash/_equalByTag.js": 349, 353 | "./node_modules/why-did-you-update/node_modules/lodash/_equalObjects.js": 350, 354 | "./node_modules/why-did-you-update/node_modules/lodash/_getLength.js": 351, 355 | "./node_modules/why-did-you-update/node_modules/lodash/_getMatchData.js": 352, 356 | "./node_modules/why-did-you-update/node_modules/lodash/_getPrototype.js": 353, 357 | "./node_modules/why-did-you-update/node_modules/lodash/_hasPath.js": 354, 358 | "./node_modules/why-did-you-update/node_modules/lodash/_hashClear.js": 355, 359 | "./node_modules/why-did-you-update/node_modules/lodash/_hashDelete.js": 356, 360 | "./node_modules/why-did-you-update/node_modules/lodash/_hashGet.js": 357, 361 | "./node_modules/why-did-you-update/node_modules/lodash/_hashHas.js": 358, 362 | "./node_modules/why-did-you-update/node_modules/lodash/_hashSet.js": 359, 363 | "./node_modules/why-did-you-update/node_modules/lodash/_indexKeys.js": 360, 364 | "./node_modules/why-did-you-update/node_modules/lodash/_indexOfNaN.js": 361, 365 | "./node_modules/why-did-you-update/node_modules/lodash/_isFlattenable.js": 362, 366 | "./node_modules/why-did-you-update/node_modules/lodash/_isIterateeCall.js": 363, 367 | "./node_modules/why-did-you-update/node_modules/lodash/_isKeyable.js": 364, 368 | "./node_modules/why-did-you-update/node_modules/lodash/_isPrototype.js": 365, 369 | "./node_modules/why-did-you-update/node_modules/lodash/_listCacheClear.js": 366, 370 | "./node_modules/why-did-you-update/node_modules/lodash/_listCacheDelete.js": 367, 371 | "./node_modules/why-did-you-update/node_modules/lodash/_listCacheGet.js": 368, 372 | "./node_modules/why-did-you-update/node_modules/lodash/_listCacheHas.js": 369, 373 | "./node_modules/why-did-you-update/node_modules/lodash/_listCacheSet.js": 370, 374 | "./node_modules/why-did-you-update/node_modules/lodash/_mapCacheClear.js": 371, 375 | "./node_modules/why-did-you-update/node_modules/lodash/_mapCacheDelete.js": 372, 376 | "./node_modules/why-did-you-update/node_modules/lodash/_mapCacheGet.js": 373, 377 | "./node_modules/why-did-you-update/node_modules/lodash/_mapCacheHas.js": 374, 378 | "./node_modules/why-did-you-update/node_modules/lodash/_mapCacheSet.js": 375, 379 | "./node_modules/why-did-you-update/node_modules/lodash/_setCacheAdd.js": 376, 380 | "./node_modules/why-did-you-update/node_modules/lodash/_setCacheHas.js": 377, 381 | "./node_modules/why-did-you-update/node_modules/lodash/_setToPairs.js": 378, 382 | "./node_modules/why-did-you-update/node_modules/lodash/_stackClear.js": 379, 383 | "./node_modules/why-did-you-update/node_modules/lodash/_stackDelete.js": 380, 384 | "./node_modules/why-did-you-update/node_modules/lodash/_stackGet.js": 381, 385 | "./node_modules/why-did-you-update/node_modules/lodash/_stackHas.js": 382, 386 | "./node_modules/why-did-you-update/node_modules/lodash/_stackSet.js": 383, 387 | "./node_modules/why-did-you-update/node_modules/lodash/_stringToPath.js": 384, 388 | "./node_modules/why-did-you-update/node_modules/lodash/get.js": 385, 389 | "./node_modules/why-did-you-update/node_modules/lodash/hasIn.js": 386, 390 | "./node_modules/why-did-you-update/node_modules/lodash/identity.js": 387, 391 | "./node_modules/why-did-you-update/node_modules/lodash/isEqual.js": 388, 392 | "./node_modules/why-did-you-update/node_modules/lodash/isNative.js": 389, 393 | "./node_modules/why-did-you-update/node_modules/lodash/isTypedArray.js": 390, 394 | "./node_modules/why-did-you-update/node_modules/lodash/memoize.js": 391, 395 | "./node_modules/why-did-you-update/node_modules/lodash/noop.js": 392, 396 | "./node_modules/why-did-you-update/node_modules/lodash/property.js": 393, 397 | "./node_modules/why-did-you-update/node_modules/lodash/rest.js": 394, 398 | "./node_modules/why-did-you-update/node_modules/lodash/some.js": 395, 399 | "./node_modules/why-did-you-update/node_modules/lodash/toFinite.js": 396, 400 | "./node_modules/why-did-you-update/node_modules/lodash/toInteger.js": 397, 401 | "./node_modules/why-did-you-update/node_modules/lodash/toNumber.js": 398, 402 | "./node_modules/why-did-you-update/node_modules/lodash/toPairs.js": 399, 403 | "./node_modules/why-did-you-update/node_modules/lodash/toString.js": 400, 404 | "./node_modules/why-did-you-update/node_modules/lodash/union.js": 401 405 | } 406 | } -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libs_lib", 3 | "content": { 4 | "./node_modules/fbjs/lib/invariant.js": 1, 5 | "./node_modules/react/lib/reactProdInvariant.js": 2, 6 | "./node_modules/fbjs/lib/warning.js": 3, 7 | "./node_modules/object-assign/index.js": 4, 8 | "./node_modules/react/lib/ReactDOMComponentTree.js": 5, 9 | "./node_modules/react/react.js": 6, 10 | "./node_modules/invariant/browser.js": 7, 11 | "./node_modules/fbjs/lib/ExecutionEnvironment.js": 8, 12 | "./node_modules/fbjs/lib/emptyFunction.js": 9, 13 | "./node_modules/react/lib/ReactInstrumentation.js": 10, 14 | "./node_modules/react/lib/ReactElement.js": 11, 15 | "./node_modules/react/lib/ReactUpdates.js": 12, 16 | "./node_modules/react/lib/EventConstants.js": 13, 17 | "./node_modules/react/lib/SyntheticEvent.js": 14, 18 | "./node_modules/fbjs/lib/keyOf.js": 15, 19 | "./node_modules/history/lib/PathUtils.js": 16, 20 | "./node_modules/react-router/lib/RouteUtils.js": 17, 21 | "./node_modules/react/lib/PooledClass.js": 18, 22 | "./node_modules/react/lib/ReactCurrentOwner.js": 19, 23 | "./node_modules/warning/browser.js": 20, 24 | "./node_modules/history/lib/LocationUtils.js": 21, 25 | "./node_modules/react-router/lib/PatternUtils.js": 22, 26 | "./node_modules/react-router/lib/routerWarning.js": 23, 27 | "./node_modules/react/lib/DOMLazyTree.js": 24, 28 | "./node_modules/react/lib/DOMProperty.js": 25, 29 | "./node_modules/react/lib/ReactReconciler.js": 26, 30 | "./node_modules/fbjs/lib/emptyObject.js": 27, 31 | "./node_modules/react-router/lib/InternalPropTypes.js": 28, 32 | "./node_modules/react/lib/EventPluginHub.js": 29, 33 | "./node_modules/react/lib/EventPropagators.js": 30, 34 | "./node_modules/react/lib/ReactInstanceMap.js": 31, 35 | "./node_modules/react/lib/SyntheticUIEvent.js": 32, 36 | "./node_modules/react/lib/Transaction.js": 33, 37 | "./node_modules/fbjs/lib/keyMirror.js": 34, 38 | "./node_modules/history/lib/Actions.js": 35, 39 | "./node_modules/history/lib/DOMUtils.js": 36, 40 | "./node_modules/immutable/dist/immutable.js": 37, 41 | "./node_modules/react/lib/DisabledInputUtils.js": 38, 42 | "./node_modules/react/lib/ReactBrowserEventEmitter.js": 39, 43 | "./node_modules/react/lib/SyntheticMouseEvent.js": 40, 44 | "./node_modules/react/lib/escapeTextContentForBrowser.js": 41, 45 | "./node_modules/react/lib/setInnerHTML.js": 42, 46 | "./node_modules/fbjs/lib/shallowEqual.js": 43, 47 | "./node_modules/history/lib/BrowserProtocol.js": 44, 48 | "./node_modules/history/lib/ExecutionEnvironment.js": 45, 49 | "./node_modules/history/lib/createHistory.js": 46, 50 | "./node_modules/history/lib/runTransitionHook.js": 47, 51 | "./node_modules/lodash/isPlainObject.js": 48, 52 | "./node_modules/node-libs-browser/node_modules/process/browser.js": 49, 53 | "./node_modules/react-router/lib/AsyncUtils.js": 50, 54 | "./node_modules/react-router/lib/ContextUtils.js": 51, 55 | "./node_modules/react-router/lib/PropTypes.js": 52, 56 | "./node_modules/react-router/lib/RouterContext.js": 53, 57 | "./node_modules/react/lib/DOMChildrenOperations.js": 54, 58 | "./node_modules/react/lib/DOMNamespaces.js": 55, 59 | "./node_modules/react/lib/EventPluginRegistry.js": 56, 60 | "./node_modules/react/lib/EventPluginUtils.js": 57, 61 | "./node_modules/react/lib/KeyEscapeUtils.js": 58, 62 | "./node_modules/react/lib/LinkedValueUtils.js": 59, 63 | "./node_modules/react/lib/ReactComponent.js": 60, 64 | "./node_modules/react/lib/ReactComponentEnvironment.js": 61, 65 | "./node_modules/react/lib/ReactComponentTreeHook.js": 62, 66 | "./node_modules/react/lib/ReactErrorUtils.js": 63, 67 | "./node_modules/react/lib/ReactNoopUpdateQueue.js": 64, 68 | "./node_modules/react/lib/ReactPropTypeLocationNames.js": 65, 69 | "./node_modules/react/lib/ReactPropTypeLocations.js": 66, 70 | "./node_modules/react/lib/ReactPropTypesSecret.js": 67, 71 | "./node_modules/react/lib/ReactUpdateQueue.js": 68, 72 | "./node_modules/react/lib/createMicrosoftUnsafeLocalFunction.js": 69, 73 | "./node_modules/react/lib/getEventCharCode.js": 70, 74 | "./node_modules/react/lib/getEventModifierState.js": 71, 75 | "./node_modules/react/lib/getEventTarget.js": 72, 76 | "./node_modules/react/lib/isEventSupported.js": 73, 77 | "./node_modules/react/lib/shouldUpdateReactComponent.js": 74, 78 | "./node_modules/react/lib/traverseAllChildren.js": 75, 79 | "./node_modules/react/lib/validateDOMNesting.js": 76, 80 | "./node_modules/fbjs/lib/EventListener.js": 77, 81 | "./node_modules/fbjs/lib/focusNode.js": 78, 82 | "./node_modules/fbjs/lib/getActiveElement.js": 79, 83 | "./node_modules/history/lib/DOMStateStorage.js": 80, 84 | "./node_modules/history/lib/useBasename.js": 81, 85 | "./node_modules/history/lib/useQueries.js": 82, 86 | "./node_modules/hoist-non-react-statics/index.js": 83, 87 | "./node_modules/react-redux/lib/utils/storeShape.js": 84, 88 | "./node_modules/react-redux/lib/utils/warning.js": 85, 89 | "./node_modules/react-router-redux/lib/actions.js": 86, 90 | "./node_modules/react-router-redux/lib/reducer.js": 87, 91 | "./node_modules/react-router/lib/Link.js": 88, 92 | "./node_modules/react-router/lib/PromiseUtils.js": 89, 93 | "./node_modules/react-router/lib/Redirect.js": 90, 94 | "./node_modules/react-router/lib/RouterUtils.js": 91, 95 | "./node_modules/react-router/lib/createMemoryHistory.js": 92, 96 | "./node_modules/react-router/lib/createRouterHistory.js": 93, 97 | "./node_modules/react-router/lib/createTransitionManager.js": 94, 98 | "./node_modules/react-router/lib/useRouterHistory.js": 95, 99 | "./node_modules/react/lib/CSSProperty.js": 96, 100 | "./node_modules/react/lib/CallbackQueue.js": 97, 101 | "./node_modules/react/lib/DOMPropertyOperations.js": 98, 102 | "./node_modules/react/lib/ReactChildren.js": 99, 103 | "./node_modules/react/lib/ReactClass.js": 100, 104 | "./node_modules/react/lib/ReactDOMComponentFlags.js": 101, 105 | "./node_modules/react/lib/ReactDOMSelect.js": 102, 106 | "./node_modules/react/lib/ReactEmptyComponent.js": 103, 107 | "./node_modules/react/lib/ReactFeatureFlags.js": 104, 108 | "./node_modules/react/lib/ReactHostComponent.js": 105, 109 | "./node_modules/react/lib/ReactInputSelection.js": 106, 110 | "./node_modules/react/lib/ReactMount.js": 107, 111 | "./node_modules/react/lib/ReactMultiChildUpdateTypes.js": 108, 112 | "./node_modules/react/lib/ReactNodeTypes.js": 109, 113 | "./node_modules/react/lib/ReactPropTypes.js": 110, 114 | "./node_modules/react/lib/ReactVersion.js": 111, 115 | "./node_modules/react/lib/ViewportMetrics.js": 112, 116 | "./node_modules/react/lib/accumulateInto.js": 113, 117 | "./node_modules/react/lib/canDefineProperty.js": 114, 118 | "./node_modules/react/lib/forEachAccumulated.js": 115, 119 | "./node_modules/react/lib/getHostComponentFromComposite.js": 116, 120 | "./node_modules/react/lib/getIteratorFn.js": 117, 121 | "./node_modules/react/lib/getTextContentAccessor.js": 118, 122 | "./node_modules/react/lib/instantiateReactComponent.js": 119, 123 | "./node_modules/react/lib/isTextInputElement.js": 120, 124 | "./node_modules/react/lib/setTextContent.js": 121, 125 | "./node_modules/redux/lib/compose.js": 122, 126 | "./node_modules/redux/lib/createStore.js": 123, 127 | "./node_modules/redux/lib/index.js": 124, 128 | "./node_modules/redux/lib/utils/warning.js": 125, 129 | "./node_modules/fastclick/lib/fastclick.js": 126, 130 | "./node_modules/fbjs/lib/camelize.js": 127, 131 | "./node_modules/fbjs/lib/camelizeStyleName.js": 128, 132 | "./node_modules/fbjs/lib/containsNode.js": 129, 133 | "./node_modules/fbjs/lib/createArrayFromMixed.js": 130, 134 | "./node_modules/fbjs/lib/createNodesFromMarkup.js": 131, 135 | "./node_modules/fbjs/lib/getMarkupWrap.js": 132, 136 | "./node_modules/fbjs/lib/getUnboundedScrollPosition.js": 133, 137 | "./node_modules/fbjs/lib/hyphenate.js": 134, 138 | "./node_modules/fbjs/lib/hyphenateStyleName.js": 135, 139 | "./node_modules/fbjs/lib/isNode.js": 136, 140 | "./node_modules/fbjs/lib/isTextNode.js": 137, 141 | "./node_modules/fbjs/lib/memoizeStringOnly.js": 138, 142 | "./node_modules/history/lib/AsyncUtils.js": 139, 143 | "./node_modules/history/lib/HashProtocol.js": 140, 144 | "./node_modules/history/lib/RefreshProtocol.js": 141, 145 | "./node_modules/history/lib/createBrowserHistory.js": 142, 146 | "./node_modules/history/lib/createHashHistory.js": 143, 147 | "./node_modules/history/lib/createMemoryHistory.js": 144, 148 | "./node_modules/lodash/_getPrototype.js": 145, 149 | "./node_modules/lodash/_isHostObject.js": 146, 150 | "./node_modules/lodash/isObjectLike.js": 147, 151 | "./node_modules/query-string/index.js": 148, 152 | "./node_modules/react-dom/index.js": 149, 153 | "./node_modules/react-immutable-proptypes/dist/ImmutablePropTypes.js": 150, 154 | "./node_modules/react-redux/lib/components/Provider.js": 151, 155 | "./node_modules/react-redux/lib/components/connect.js": 152, 156 | "./node_modules/react-redux/lib/index.js": 153, 157 | "./node_modules/react-redux/lib/utils/shallowEqual.js": 154, 158 | "./node_modules/react-redux/lib/utils/wrapActionCreators.js": 155, 159 | "./node_modules/react-router-redux/lib/index.js": 156, 160 | "./node_modules/react-router-redux/lib/middleware.js": 157, 161 | "./node_modules/react-router-redux/lib/sync.js": 158, 162 | "./node_modules/react-router/lib/IndexLink.js": 159, 163 | "./node_modules/react-router/lib/IndexRedirect.js": 160, 164 | "./node_modules/react-router/lib/IndexRoute.js": 161, 165 | "./node_modules/react-router/lib/Route.js": 162, 166 | "./node_modules/react-router/lib/Router.js": 163, 167 | "./node_modules/react-router/lib/TransitionUtils.js": 164, 168 | "./node_modules/react-router/lib/applyRouterMiddleware.js": 165, 169 | "./node_modules/react-router/lib/browserHistory.js": 166, 170 | "./node_modules/react-router/lib/computeChangedRoutes.js": 167, 171 | "./node_modules/react-router/lib/getComponents.js": 168, 172 | "./node_modules/react-router/lib/getRouteParams.js": 169, 173 | "./node_modules/react-router/lib/hashHistory.js": 170, 174 | "./node_modules/react-router/lib/index.js": 171, 175 | "./node_modules/react-router/lib/isActive.js": 172, 176 | "./node_modules/react-router/lib/match.js": 173, 177 | "./node_modules/react-router/lib/matchRoutes.js": 174, 178 | "./node_modules/react-router/lib/withRouter.js": 175, 179 | "./node_modules/react/lib/AutoFocusUtils.js": 176, 180 | "./node_modules/react/lib/BeforeInputEventPlugin.js": 177, 181 | "./node_modules/react/lib/CSSPropertyOperations.js": 178, 182 | "./node_modules/react/lib/ChangeEventPlugin.js": 179, 183 | "./node_modules/react/lib/Danger.js": 180, 184 | "./node_modules/react/lib/DefaultEventPluginOrder.js": 181, 185 | "./node_modules/react/lib/EnterLeaveEventPlugin.js": 182, 186 | "./node_modules/react/lib/FallbackCompositionState.js": 183, 187 | "./node_modules/react/lib/HTMLDOMPropertyConfig.js": 184, 188 | "./node_modules/react/lib/React.js": 185, 189 | "./node_modules/react/lib/ReactChildReconciler.js": 186, 190 | "./node_modules/react/lib/ReactComponentBrowserEnvironment.js": 187, 191 | "./node_modules/react/lib/ReactCompositeComponent.js": 188, 192 | "./node_modules/react/lib/ReactDOM.js": 189, 193 | "./node_modules/react/lib/ReactDOMButton.js": 190, 194 | "./node_modules/react/lib/ReactDOMComponent.js": 191, 195 | "./node_modules/react/lib/ReactDOMContainerInfo.js": 192, 196 | "./node_modules/react/lib/ReactDOMEmptyComponent.js": 193, 197 | "./node_modules/react/lib/ReactDOMFactories.js": 194, 198 | "./node_modules/react/lib/ReactDOMFeatureFlags.js": 195, 199 | "./node_modules/react/lib/ReactDOMIDOperations.js": 196, 200 | "./node_modules/react/lib/ReactDOMInput.js": 197, 201 | "./node_modules/react/lib/ReactDOMOption.js": 198, 202 | "./node_modules/react/lib/ReactDOMSelection.js": 199, 203 | "./node_modules/react/lib/ReactDOMTextComponent.js": 200, 204 | "./node_modules/react/lib/ReactDOMTextarea.js": 201, 205 | "./node_modules/react/lib/ReactDOMTreeTraversal.js": 202, 206 | "./node_modules/react/lib/ReactDefaultBatchingStrategy.js": 203, 207 | "./node_modules/react/lib/ReactDefaultInjection.js": 204, 208 | "./node_modules/react/lib/ReactEventEmitterMixin.js": 205, 209 | "./node_modules/react/lib/ReactEventListener.js": 206, 210 | "./node_modules/react/lib/ReactInjection.js": 207, 211 | "./node_modules/react/lib/ReactMarkupChecksum.js": 208, 212 | "./node_modules/react/lib/ReactMultiChild.js": 209, 213 | "./node_modules/react/lib/ReactOwner.js": 210, 214 | "./node_modules/react/lib/ReactPureComponent.js": 211, 215 | "./node_modules/react/lib/ReactReconcileTransaction.js": 212, 216 | "./node_modules/react/lib/ReactRef.js": 213, 217 | "./node_modules/react/lib/ReactServerRenderingTransaction.js": 214, 218 | "./node_modules/react/lib/ReactServerUpdateQueue.js": 215, 219 | "./node_modules/react/lib/SVGDOMPropertyConfig.js": 216, 220 | "./node_modules/react/lib/SelectEventPlugin.js": 217, 221 | "./node_modules/react/lib/SimpleEventPlugin.js": 218, 222 | "./node_modules/react/lib/SyntheticAnimationEvent.js": 219, 223 | "./node_modules/react/lib/SyntheticClipboardEvent.js": 220, 224 | "./node_modules/react/lib/SyntheticCompositionEvent.js": 221, 225 | "./node_modules/react/lib/SyntheticDragEvent.js": 222, 226 | "./node_modules/react/lib/SyntheticFocusEvent.js": 223, 227 | "./node_modules/react/lib/SyntheticInputEvent.js": 224, 228 | "./node_modules/react/lib/SyntheticKeyboardEvent.js": 225, 229 | "./node_modules/react/lib/SyntheticTouchEvent.js": 226, 230 | "./node_modules/react/lib/SyntheticTransitionEvent.js": 227, 231 | "./node_modules/react/lib/SyntheticWheelEvent.js": 228, 232 | "./node_modules/react/lib/adler32.js": 229, 233 | "./node_modules/react/lib/checkReactTypeSpec.js": 230, 234 | "./node_modules/react/lib/dangerousStyleValue.js": 231, 235 | "./node_modules/react/lib/findDOMNode.js": 232, 236 | "./node_modules/react/lib/flattenChildren.js": 233, 237 | "./node_modules/react/lib/getEventKey.js": 234, 238 | "./node_modules/react/lib/getNodeForCharacterOffset.js": 235, 239 | "./node_modules/react/lib/getVendorPrefixedEventName.js": 236, 240 | "./node_modules/react/lib/onlyChild.js": 237, 241 | "./node_modules/react/lib/quoteAttributeValueForBrowser.js": 238, 242 | "./node_modules/react/lib/renderSubtreeIntoContainer.js": 239, 243 | "./node_modules/redux-immutablejs/lib/index.js": 240, 244 | "./node_modules/redux-immutablejs/lib/utils/combineReducers.js": 241, 245 | "./node_modules/redux-immutablejs/lib/utils/createReducer.js": 242, 246 | "./node_modules/redux-thunk/lib/index.js": 243, 247 | "./node_modules/redux/lib/applyMiddleware.js": 244, 248 | "./node_modules/redux/lib/bindActionCreators.js": 245, 249 | "./node_modules/redux/lib/combineReducers.js": 246, 250 | "./node_modules/strict-uri-encode/index.js": 247, 251 | "./node_modules/symbol-observable/index.js": 248, 252 | "./node_modules/symbol-observable/lib/index.js": 249, 253 | "./node_modules/symbol-observable/lib/ponyfill.js": 250, 254 | "./node_modules/webpack/buildin/module.js": 251 255 | } 256 | } -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "restartable": "rs", 3 | "ignore": [ 4 | ".git", 5 | "node_modules/**/node_modules" 6 | ], 7 | "verbose": true, 8 | "watch": [ 9 | "server", 10 | "common" 11 | ], 12 | "env": { 13 | "NODE_ENV": "development" 14 | }, 15 | "ext": "js json jsx" 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ocean", 3 | "license": "ISC", 4 | "version": "0.13.1", 5 | "author": "LukeLin", 6 | "keywords": [ 7 | "react", 8 | "redux", 9 | "webpack", 10 | "babel", 11 | "immutable", 12 | "isomophic react", 13 | "universal react" 14 | ], 15 | "main": "./dist/server.js", 16 | "babel": { 17 | "presets": [ 18 | "react" 19 | ], 20 | "plugins": [ 21 | "transform-es2015-modules-commonjs", 22 | "transform-async-to-generator", 23 | "transform-decorators-legacy", 24 | "transform-class-properties" 25 | ] 26 | }, 27 | "dependencies": { 28 | "body-parser": "1.15.2", 29 | "classnames": "2.2.5", 30 | "compression": "1.6.2", 31 | "cookie-parser": "1.4.3", 32 | "csurf": "1.9.0", 33 | "ejs": "2.5.2", 34 | "express": "4.14.0", 35 | "express-session": "1.14.1", 36 | "fastclick": "1.0.6", 37 | "helmet": "2.3.0", 38 | "immutable": "3.8.1", 39 | "isomorphic-fetch": "2.2.1", 40 | "morgan": "1.7.0", 41 | "pm2": "2.0.18", 42 | "react": "15.3.2", 43 | "react-dom": "15.3.2", 44 | "react-immutable-proptypes": "2.1.0", 45 | "react-redux": "4.4.5", 46 | "react-router": "^3.0.0", 47 | "redux": "3.6.0", 48 | "redux-immutablejs": "0.0.8", 49 | "redux-thunk": "2.1.0", 50 | "secure-filters": "^1.0.5", 51 | "socket.io": "1.5.0", 52 | "source-map-support": "^0.4.5" 53 | }, 54 | "description": "isomophic-react-redux-starter", 55 | "devDependencies": { 56 | "babel-core": "^6.18.0", 57 | "babel-loader": "^6.2.5", 58 | "babel-plugin-syntax-async-functions": "^6.13.0", 59 | "babel-plugin-transform-async-to-generator": "^6.16.0", 60 | "babel-plugin-transform-class-properties": "^6.19.0", 61 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 62 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 63 | "babel-plugin-transform-react-constant-elements": "^6.9.1", 64 | "babel-plugin-transform-react-inline-elements": "^6.8.0", 65 | "babel-plugin-transform-react-remove-prop-types": "^0.2.10", 66 | "babel-plugin-transform-regenerator": "^6.16.1", 67 | "babel-plugin-transform-runtime": "^6.15.0", 68 | "babel-preset-es2015": "^6.18.0", 69 | "babel-preset-react": "^6.16.0", 70 | "babel-preset-react-hmre": "^1.1.1", 71 | "babel-runtime": "^6.18.0", 72 | "browser-sync": "^2.17.5", 73 | "css-loader": "^0.23.1", 74 | "del": "^2.2.2", 75 | "extract-text-webpack-plugin": "^1.0.1", 76 | "file-loader": "^0.8.5", 77 | "gulp": ">=3.9.0", 78 | "happypack": "^2.2.1", 79 | "json-loader": "^0.5.4", 80 | "nodemon": "^1.11.0", 81 | "progress-bar-webpack-plugin": "^1.9.0", 82 | "react-addons-perf": "^15.3.2", 83 | "redux-logger": "^2.7.0", 84 | "style-loader": "^0.13.1", 85 | "url-loader": "^0.5.7", 86 | "webpack": "^1.13.2", 87 | "webpack-dev-middleware": "^1.8.4", 88 | "webpack-hot-middleware": "^2.13.0", 89 | "why-did-you-update": "0.0.8" 90 | }, 91 | "scripts": { 92 | "start": "node starter.js", 93 | "kill": "pm2 delete react-ocean", 94 | "build:lib": "gulp build:lib:dev && gulp build:lib", 95 | "build:dev": "set NODE_ENV=development && gulp build:dev", 96 | "build": "npm run build:prod && npm run build:dev", 97 | "build:prod": "set NODE_ENV=production && gulp build", 98 | "build:server": "webpack --progress --config ./webpack.config-server.js", 99 | "local": "npm run build:server && nodemon index.js", 100 | "debug": "npm run build:server && node-debug index.js", 101 | "watch": "gulp watch" 102 | }, 103 | "engines": { 104 | "node": ">=6.0.0" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /public/css/main-min.css: -------------------------------------------------------------------------------- 1 | body{font-size:16px} -------------------------------------------------------------------------------- /public/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 16px; 3 | } 4 | /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiIuL2Nzcy9tYWluLmNzcyIsInNvdXJjZVJvb3QiOiIifQ==*/ -------------------------------------------------------------------------------- /public/css/main.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"./css/main.css","sources":[],"mappings":";;","sourceRoot":""} -------------------------------------------------------------------------------- /public/js/debug/Vote.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([0],{ 2 | 3 | /***/ 109: 4 | /*!***********************************!*\ 5 | !*** ./common/pages/App/Vote.jsx ***! 6 | \***********************************/ 7 | /***/ function(module, exports, __webpack_require__) { 8 | 9 | 'use strict'; 10 | 11 | exports.__esModule = true; 12 | 13 | var _classCallCheck2 = __webpack_require__(/*! babel-runtime/helpers/classCallCheck */ 11); 14 | 15 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 16 | 17 | var _possibleConstructorReturn2 = __webpack_require__(/*! babel-runtime/helpers/possibleConstructorReturn */ 13); 18 | 19 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 20 | 21 | var _inherits2 = __webpack_require__(/*! babel-runtime/helpers/inherits */ 12); 22 | 23 | var _inherits3 = _interopRequireDefault(_inherits2); 24 | 25 | var _dec, _dec2, _class, _class2, _temp; 26 | 27 | var _react = __webpack_require__(/*! react */ 3); 28 | 29 | var _react2 = _interopRequireDefault(_react); 30 | 31 | var _reactRedux = __webpack_require__(/*! react-redux */ 41); 32 | 33 | var _reactRouter = __webpack_require__(/*! react-router */ 99); 34 | 35 | var _connectDataFetchers = __webpack_require__(/*! ../../utils/connectDataFetchers */ 110); 36 | 37 | var _connectDataFetchers2 = _interopRequireDefault(_connectDataFetchers); 38 | 39 | var _vote = __webpack_require__(/*! ../../actions/vote */ 108); 40 | 41 | var ACTIONS = _interopRequireWildcard(_vote); 42 | 43 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 44 | 45 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 46 | 47 | var Vote = (_dec = (0, _reactRedux.connect)(function mapStateToProps(state) { 48 | return { 49 | message: state.vote.message 50 | }; 51 | }), _dec2 = (0, _connectDataFetchers2.default)([ACTIONS.loadData]), _dec(_class = _dec2(_class = (_temp = _class2 = function (_Component) { 52 | (0, _inherits3.default)(Vote, _Component); 53 | 54 | function Vote() { 55 | (0, _classCallCheck3.default)(this, Vote); 56 | return (0, _possibleConstructorReturn3.default)(this, _Component.apply(this, arguments)); 57 | } 58 | 59 | Vote.prototype.render = function render() { 60 | return _react2.default.createElement( 61 | 'div', 62 | { className: 'vote' }, 63 | 'this is vote', 64 | _react2.default.createElement( 65 | _reactRouter.Link, 66 | { to: '/about?debug=test' }, 67 | 'about' 68 | ), 69 | _react2.default.createElement( 70 | _reactRouter.Link, 71 | { to: '/test' }, 72 | 'test' 73 | ), 74 | 'message: ', 75 | this.props.message 76 | ); 77 | }; 78 | 79 | return Vote; 80 | }(_react.Component), _class2.pageConfig = { 81 | pageId: 'Vote' 82 | }, _temp)) || _class) || _class); 83 | exports.default = Vote; 84 | 85 | /***/ } 86 | 87 | }); 88 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9EOi93b3Jrc3BhY2UvamF2YXNjcmlwdC9pc29tb3JwaGljLXJlYWN0LXJlZHV4LXN0YXJ0ZXIvY29tbW9uL3BhZ2VzL0FwcC9Wb3RlLmpzeCJdLCJuYW1lcyI6WyJBQ1RJT05TIiwiVm90ZSIsIm1hcFN0YXRlVG9Qcm9wcyIsInN0YXRlIiwibWVzc2FnZSIsInZvdGUiLCJsb2FkRGF0YSIsInJlbmRlciIsInByb3BzIiwicGFnZUNvbmZpZyIsInBhZ2VJZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7OztBQUNBOztBQUNBOztBQUVBOzs7O0FBQ0E7O0tBQVlBLE87Ozs7OztLQVFOQyxJLFdBTkwseUJBQVEsU0FBU0MsZUFBVCxDQUF5QkMsS0FBekIsRUFBZ0M7QUFDckMsWUFBTztBQUNIQyxrQkFBU0QsTUFBTUUsSUFBTixDQUFXRDtBQURqQixNQUFQO0FBR0gsRUFKQSxDLFVBS0EsbUNBQW9CLENBQUNKLFFBQVFNLFFBQVQsQ0FBcEIsQzs7Ozs7Ozs7b0JBS0dDLE0scUJBQVM7QUFDTCxnQkFDSTtBQUFBO0FBQUEsZUFBSyxXQUFVLE1BQWY7QUFBQTtBQUVJO0FBQUE7QUFBQSxtQkFBTSxJQUFHLG1CQUFUO0FBQUE7QUFBQSxjQUZKO0FBR0k7QUFBQTtBQUFBLG1CQUFNLElBQUcsT0FBVDtBQUFBO0FBQUEsY0FISjtBQUFBO0FBSWUsa0JBQUtDLEtBQUwsQ0FBV0o7QUFKMUIsVUFESjtBQVFILE07Ozs4QkFaTUssVSxHQUFhO0FBQ2hCQyxhQUFRO0FBRFEsRTttQkFlVFQsSSIsImZpbGUiOiIvanMvZGVidWcvVm90ZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSZWFjdCwgeyBDb21wb25lbnQsIFByb3BUeXBlcyB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IGNvbm5lY3QgfSBmcm9tICdyZWFjdC1yZWR1eCc7XG5pbXBvcnQgeyBMaW5rIH0gZnJvbSAncmVhY3Qtcm91dGVyJztcblxuaW1wb3J0IGNvbm5lY3REYXRhRmV0Y2hlcnMgZnJvbSAnLi4vLi4vdXRpbHMvY29ubmVjdERhdGFGZXRjaGVycyc7XG5pbXBvcnQgKiBhcyBBQ1RJT05TIGZyb20gJy4uLy4uL2FjdGlvbnMvdm90ZSc7XG5cbkBjb25uZWN0KGZ1bmN0aW9uIG1hcFN0YXRlVG9Qcm9wcyhzdGF0ZSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIG1lc3NhZ2U6IHN0YXRlLnZvdGUubWVzc2FnZVxuICAgIH07XG59KVxuQGNvbm5lY3REYXRhRmV0Y2hlcnMoW0FDVElPTlMubG9hZERhdGFdKVxuY2xhc3MgVm90ZSBleHRlbmRzIENvbXBvbmVudCB7XG4gICAgc3RhdGljIHBhZ2VDb25maWcgPSB7XG4gICAgICAgIHBhZ2VJZDogJ1ZvdGUnXG4gICAgfTtcbiAgICByZW5kZXIoKSB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cInZvdGVcIj5cbiAgICAgICAgICAgICAgICB0aGlzIGlzIHZvdGVcbiAgICAgICAgICAgICAgICA8TGluayB0bz1cIi9hYm91dD9kZWJ1Zz10ZXN0XCI+YWJvdXQ8L0xpbms+XG4gICAgICAgICAgICAgICAgPExpbmsgdG89XCIvdGVzdFwiPnRlc3Q8L0xpbms+XG4gICAgICAgICAgICAgICAgbWVzc2FnZTogeyB0aGlzLnByb3BzLm1lc3NhZ2UgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBWb3RlO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIC4vRDovd29ya3NwYWNlL2phdmFzY3JpcHQvaXNvbW9ycGhpYy1yZWFjdC1yZWR1eC1zdGFydGVyL2NvbW1vbi9wYWdlcy9BcHAvVm90ZS5qc3giXSwic291cmNlUm9vdCI6IiJ9 -------------------------------------------------------------------------------- /public/js/min/Vote-85c4768b46fe43df6032.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([0],{103:function(e,t,n){"use strict";function a(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function u(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var o,r,s,l,f,i=n(11),d=u(i),c=n(13),p=u(c),m=n(12),g=u(m),v=n(2),h=u(v),_=n(40),b=n(96),y=n(104),k=u(y),E=n(102),M=a(E),w=(o=(0,_.connect)(function(e){return{message:e.vote.message}}),r=(0,k.default)([M.loadData]),o(s=r((f=l=function(e){function t(){return(0,d.default)(this,t),(0,p.default)(this,e.apply(this,arguments))}return(0,g.default)(t,e),t.prototype.render=function(){return h.default.createElement("div",{className:"vote"},"this is vote",h.default.createElement(b.Link,{to:"/about?debug=test"},"about"),h.default.createElement(b.Link,{to:"/test"},"test"),"message: ",this.props.message)},t}(v.Component),l.pageConfig={pageId:"Vote"},s=f))||s)||s);t.default=w}}); -------------------------------------------------------------------------------- /public/js/min/app-5f3b653ecdc8e6fe9b59.js: -------------------------------------------------------------------------------- 1 | !function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(r,i){for(var u,s,f=0,c=[];f=e.length)break;i=e[r++]}else{if(r=e.next(),r.done)break;i=r.value}var u=i;this[u].funcBinded||(this[u]=this[u].bind(this),this[u].funcBinded=!0)}},e.prototype.on=function(t,e){if("function"!=typeof e)throw new Error("fn should be a function");return this.__eventNames[t]?this.__eventNames[t].push(e):this.__eventNames[t]=[e],this.context.$eventBus.addListener(t,e)},e.prototype.emit=function(t){for(var e,n=arguments.length,r=Array(n>1?n-1:0),o=1;o=0?(this.context.$eventBus.removeListener(t,e),n.splice(r,1),n.length||delete this.__eventNames[t]):console.warn("event: "+t+" is not registered in "+this._reactInternalInstance.getName()+" Component"),!0}return console.warn("event: "+t+" is not registered in "+this.constructor.name+" Component"),!1},e.prototype.shouldComponentUpdate=function(t,e){var n=!(0,d.default)(this.props,t)||!(0,d.default)(this.state,e);return n},e.prototype.componentWillUnmount=function(){for(var t in this.__eventNames)if(this.__eventNames.hasOwnProperty(t))for(var e=this.__eventNames[t],n=Array.isArray(e),r=0,e=n?e:e[Symbol.iterator]();;){var o;if(n){if(r>=e.length)break;o=e[r++]}else{if(r=e.next(),r.done)break;o=r.value}var i=o;this.off(t,i)}},e}(l.Component);e.default=_,_.contextTypes={$eventBus:l.PropTypes.instanceOf(v.default)}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(61),i=r(o),u=n(60),s=r(u),f="function"==typeof s.default&&"symbol"==typeof i.default?function(t){return typeof t}:function(t){return t&&"function"==typeof s.default&&t.constructor===s.default&&t!==s.default.prototype?"symbol":typeof t};e.default="function"==typeof s.default&&"symbol"===f(i.default)?function(t){return"undefined"==typeof t?"undefined":f(t)}:function(t){return t&&"function"==typeof s.default&&t.constructor===s.default&&t!==s.default.prototype?"symbol":"undefined"==typeof t?"undefined":f(t)}},function(t,e){t.exports=!0},function(t,e){e.f={}.propertyIsEnumerable},function(t,e,n){var r=n(10).f,o=n(5),i=n(4)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,e,n){var r=n(14),o=n(74),i=n(28),u=n(30)("IE_PROTO"),s=function(){},f="prototype",c=function(){var t,e=n(38)("iframe"),r=i.length,o="<",u=">";for(e.style.display="none",n(51).appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write(o+"script"+u+"document.F=Object"+o+"/script"+u),t.close(),c=t.F;r--;)delete c[f][i[r]];return c()};t.exports=Object.create||function(t,e){var n;return null!==t?(s[f]=r(t),n=new s,s[f]=null,n[u]=t):n=c(),void 0===e?n:o(n,e)}},function(t,e,n){var r=n(31)("keys"),o=n(20);t.exports=function(t){return r[t]||(r[t]=o(t))}},function(t,e,n){var r=n(1),o="__core-js_shared__",i=r[o]||(r[o]={});t.exports=function(t){return i[t]||(i[t]={})}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e,n){var r=n(15);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(1),o=n(7),i=n(24),u=n(35),s=n(10).f;t.exports=function(t){var e=o.Symbol||(o.Symbol=i?{}:r.Symbol||{});"_"==t.charAt(0)||t in e||s(e,t,{value:u.f(t)})}},function(t,e,n){e.f=n(4)},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(49);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(15),o=n(1).document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){t.exports=n(3)(153)},function(t,e,n){t.exports=!n(8)&&!n(17)(function(){return 7!=Object.defineProperty(n(38)("div"),"a",{get:function(){return 7}}).a})},function(t,e,n){"use strict";var r=n(24),o=n(16),i=n(46),u=n(9),s=n(5),f=n(21),c=n(70),a=n(26),l=n(76),p=n(4)("iterator"),d=!([].keys&&"next"in[].keys()),h="@@iterator",v="keys",y="values",_=function(){return this};t.exports=function(t,e,n,m,g,b,x){c(n,e,m);var O,w,E,S=function(t){if(!d&&t in M)return M[t];switch(t){case v:return function(){return new n(this,t)};case y:return function(){return new n(this,t)}}return function(){return new n(this,t)}},j=e+" Iterator",C=g==y,P=!1,M=t.prototype,T=M[p]||M[h]||g&&M[g],L=T||S(g),A=g?C?S("entries"):L:void 0,k="Array"==e?M.entries||T:T;if(k&&(E=l(k.call(new t)),E!==Object.prototype&&(a(E,j,!0),r||s(E,p)||u(E,p,_))),C&&T&&T.name!==y&&(P=!0,L=function(){return T.call(this)}),r&&!x||!d&&!P&&M[p]||u(M,p,L),f[e]=L,f[j]=_,g)if(O={values:C?L:S(y),keys:b?L:S(v),entries:A},x)for(w in O)w in M||i(M,w,O[w]);else o(o.P+o.F*(d||P),e,O);return O}},function(t,e,n){var r=n(25),o=n(19),i=n(6),u=n(33),s=n(5),f=n(41),c=Object.getOwnPropertyDescriptor;e.f=n(8)?c:function(t,e){if(t=i(t),e=u(e,!0),f)try{return c(t,e)}catch(t){}if(s(t,e))return o(!r.f.call(t,e),t[e])}},function(t,e,n){var r=n(45),o=n(28).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},function(t,e,n){var r=n(5),o=n(6),i=n(67)(!1),u=n(30)("IE_PROTO");t.exports=function(t,e){var n,s=o(t),f=0,c=[];for(n in s)n!=u&&r(s,n)&&c.push(n);for(;e.length>f;)r(s,n=e[f++])&&(~i(c,n)||c.push(n));return c}},function(t,e,n){t.exports=n(9)},function(t,e){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(t){return"function"==typeof t}function o(t){return"number"==typeof t}function i(t){return"object"==typeof t&&null!==t}function u(t){return void 0===t}t.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(t){if(!o(t)||t<0||isNaN(t))throw TypeError("n must be a positive number");return this._maxListeners=t,this},n.prototype.emit=function(t){var e,n,o,s,f,c;if(this._events||(this._events={}),"error"===t&&(!this._events.error||i(this._events.error)&&!this._events.error.length)){if(e=arguments[1],e instanceof Error)throw e;var a=new Error('Uncaught, unspecified "error" event. ('+e+")");throw a.context=e,a}if(n=this._events[t],u(n))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:s=Array.prototype.slice.call(arguments,1),n.apply(this,s)}else if(i(n))for(s=Array.prototype.slice.call(arguments,1),c=n.slice(),o=c.length,f=0;f0&&this._events[t].length>o&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),"function"==typeof console.trace&&console.trace())),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(t,e){function n(){this.removeListener(t,n),o||(o=!0,e.apply(this,arguments))}if(!r(e))throw TypeError("listener must be a function");var o=!1;return n.listener=e,this.on(t,n),this},n.prototype.removeListener=function(t,e){var n,o,u,s;if(!r(e))throw TypeError("listener must be a function");if(!this._events||!this._events[t])return this;if(n=this._events[t],u=n.length,o=-1,n===e||r(n.listener)&&n.listener===e)delete this._events[t],this._events.removeListener&&this.emit("removeListener",t,e);else if(i(n)){for(s=u;s-- >0;)if(n[s]===e||n[s].listener&&n[s].listener===e){o=s;break}if(o<0)return this;1===n.length?(n.length=0,delete this._events[t]):n.splice(o,1),this._events.removeListener&&this.emit("removeListener",t,e)}return this},n.prototype.removeAllListeners=function(t){var e,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[t]&&delete this._events[t],this;if(0===arguments.length){for(e in this._events)"removeListener"!==e&&this.removeAllListeners(e);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[t],r(n))this.removeListener(t,n);else if(n)for(;n.length;)this.removeListener(t,n[n.length-1]);return delete this._events[t],this},n.prototype.listeners=function(t){var e;return e=this._events&&this._events[t]?r(this._events[t])?[this._events[t]]:this._events[t].slice():[]},n.prototype.listenerCount=function(t){if(this._events){var e=this._events[t];if(r(e))return 1;if(e)return e.length}return 0},n.listenerCount=function(t,e){return t.listenerCount(e)}},,function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e,n){t.exports=n(3)(124)},function(t,e,n){t.exports=n(1).document&&document.documentElement},function(t,e,n){var r=n(36);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==r(t)?t.split(""):Object(t)}},function(t,e,n){var r=n(32),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(27);t.exports=function(t){return Object(r(t))}},function(t,e){},function(t,e,n){"use strict";var r=n(78)(!0);n(42)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},function(t,e,n){n(80);for(var r=n(1),o=n(9),i=n(21),u=n(4)("toStringTag"),s=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],f=0;f<5;f++){var c=s[f],a=r[c],l=a&&a.prototype;l&&!l[u]&&o(l,u,c),i[c]=i.Array}},function(t,e,n){t.exports={default:n(62),__esModule:!0}},function(t,e,n){t.exports={default:n(63),__esModule:!0}},function(t,e,n){t.exports={default:n(64),__esModule:!0}},function(t,e,n){t.exports={default:n(65),__esModule:!0}},function(t,e,n){n(81);var r=n(7).Object;t.exports=function(t,e){return r.create(t,e)}},function(t,e,n){n(82),t.exports=n(7).Object.setPrototypeOf},function(t,e,n){n(83),n(55),n(84),n(85),t.exports=n(7).Symbol},function(t,e,n){n(56),n(57),t.exports=n(35).f("iterator")},function(t,e){t.exports=function(){}},function(t,e,n){var r=n(6),o=n(53),i=n(79);t.exports=function(t){return function(e,n,u){var s,f=r(e),c=o(f.length),a=i(u,c);if(t&&n!=n){for(;c>a;)if(s=f[a++],s!=s)return!0}else for(;c>a;a++)if((t||a in f)&&f[a]===n)return t||a||0;return!t&&-1}}},function(t,e,n){var r=n(18),o=n(39),i=n(25);t.exports=function(t){var e=r(t),n=o.f;if(n)for(var u,s=n(t),f=i.f,c=0;s.length>c;)f.call(t,u=s[c++])&&e.push(u);return e}},function(t,e,n){var r=n(36);t.exports=Array.isArray||function(t){return"Array"==r(t)}},function(t,e,n){"use strict";var r=n(29),o=n(19),i=n(26),u={};n(9)(u,n(4)("iterator"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(u,{next:o(1,n)}),i(t,e+" Iterator")}},function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},function(t,e,n){var r=n(18),o=n(6);t.exports=function(t,e){for(var n,i=o(t),u=r(i),s=u.length,f=0;s>f;)if(i[n=u[f++]]===e)return n}},function(t,e,n){var r=n(20)("meta"),o=n(15),i=n(5),u=n(10).f,s=0,f=Object.isExtensible||function(){return!0},c=!n(17)(function(){return f(Object.preventExtensions({}))}),a=function(t){u(t,r,{value:{i:"O"+ ++s,w:{}}})},l=function(t,e){if(!o(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!i(t,r)){if(!f(t))return"F";if(!e)return"E";a(t)}return t[r].i},p=function(t,e){if(!i(t,r)){if(!f(t))return!0;if(!e)return!1;a(t)}return t[r].w},d=function(t){return c&&h.NEED&&f(t)&&!i(t,r)&&a(t),t},h=t.exports={KEY:r,NEED:!1,fastKey:l,getWeak:p,onFreeze:d}},function(t,e,n){var r=n(10),o=n(14),i=n(18);t.exports=n(8)?Object.defineProperties:function(t,e){o(t);for(var n,u=i(e),s=u.length,f=0;s>f;)r.f(t,n=u[f++],e[n]);return t}},function(t,e,n){var r=n(6),o=n(44).f,i={}.toString,u="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(t){try{return o(t)}catch(t){return u.slice()}};t.exports.f=function(t){return u&&"[object Window]"==i.call(t)?s(t):o(r(t))}},function(t,e,n){var r=n(5),o=n(54),i=n(30)("IE_PROTO"),u=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,i)?t[i]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?u:null}},function(t,e,n){var r=n(15),o=n(14),i=function(t,e){if(o(t),!r(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,e,r){try{r=n(37)(Function.call,n(43).f(Object.prototype,"__proto__").set,2),r(t,[]),e=!(t instanceof Array)}catch(t){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:r(t,n),t}}({},!1):void 0),check:i}},function(t,e,n){var r=n(32),o=n(27);t.exports=function(t){return function(e,n){var i,u,s=String(o(e)),f=r(n),c=s.length;return f<0||f>=c?t?"":void 0:(i=s.charCodeAt(f),i<55296||i>56319||f+1===c||(u=s.charCodeAt(f+1))<56320||u>57343?t?s.charAt(f):i:t?s.slice(f,f+2):(i-55296<<10)+(u-56320)+65536)}}},function(t,e,n){var r=n(32),o=Math.max,i=Math.min;t.exports=function(t,e){return t=r(t),t<0?o(t+e,0):i(t,e)}},function(t,e,n){"use strict";var r=n(66),o=n(71),i=n(21),u=n(6);t.exports=n(42)(Array,"Array",function(t,e){this._t=u(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,o(1)):"keys"==e?o(0,n):"values"==e?o(0,t[n]):o(0,[n,t[n]])},"values"),i.Arguments=i.Array,r("keys"),r("values"),r("entries")},function(t,e,n){var r=n(16);r(r.S,"Object",{create:n(29)})},function(t,e,n){var r=n(16);r(r.S,"Object",{setPrototypeOf:n(77).set})},function(t,e,n){"use strict";var r=n(1),o=n(5),i=n(8),u=n(16),s=n(46),f=n(73).KEY,c=n(17),a=n(31),l=n(26),p=n(20),d=n(4),h=n(35),v=n(34),y=n(72),_=n(68),m=n(69),g=n(14),b=n(6),x=n(33),O=n(19),w=n(29),E=n(75),S=n(43),j=n(10),C=n(18),P=S.f,M=j.f,T=E.f,L=r.Symbol,A=r.JSON,k=A&&A.stringify,D="prototype",I=d("_hidden"),N=d("toPrimitive"),F={}.propertyIsEnumerable,R=a("symbol-registry"),U=a("symbols"),B=a("op-symbols"),V=Object[D],$="function"==typeof L,W=r.QObject,q=!W||!W[D]||!W[D].findChild,G=i&&c(function(){return 7!=w(M({},"a",{get:function(){return M(this,"a",{value:7}).a}})).a})?function(t,e,n){var r=P(V,e);r&&delete V[e],M(t,e,n),r&&t!==V&&M(V,e,r)}:M,J=function(t){var e=U[t]=w(L[D]);return e._k=t,e},H=$&&"symbol"==typeof L.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof L},K=function(t,e,n){return t===V&&K(B,e,n),g(t),e=x(e,!0),g(n),o(U,e)?(n.enumerable?(o(t,I)&&t[I][e]&&(t[I][e]=!1),n=w(n,{enumerable:O(0,!1)})):(o(t,I)||M(t,I,O(1,{})),t[I][e]=!0),G(t,e,n)):M(t,e,n)},z=function(t,e){g(t);for(var n,r=_(e=b(e)),o=0,i=r.length;i>o;)K(t,n=r[o++],e[n]);return t},Y=function(t,e){return void 0===e?w(t):z(w(t),e)},Q=function(t){var e=F.call(this,t=x(t,!0));return!(this===V&&o(U,t)&&!o(B,t))&&(!(e||!o(this,t)||!o(U,t)||o(this,I)&&this[I][t])||e)},Z=function(t,e){if(t=b(t),e=x(e,!0),t!==V||!o(U,e)||o(B,e)){var n=P(t,e);return!n||!o(U,e)||o(t,I)&&t[I][e]||(n.enumerable=!0),n}},X=function(t){for(var e,n=T(b(t)),r=[],i=0;n.length>i;)o(U,e=n[i++])||e==I||e==f||r.push(e);return r},tt=function(t){for(var e,n=t===V,r=T(n?B:b(t)),i=[],u=0;r.length>u;)!o(U,e=r[u++])||n&&!o(V,e)||i.push(U[e]);return i};$||(L=function(){if(this instanceof L)throw TypeError("Symbol is not a constructor!");var t=p(arguments.length>0?arguments[0]:void 0),e=function(n){this===V&&e.call(B,n),o(this,I)&&o(this[I],t)&&(this[I][t]=!1),G(this,t,O(1,n))};return i&&q&&G(V,t,{configurable:!0,set:e}),J(t)},s(L[D],"toString",function(){return this._k}),S.f=Z,j.f=K,n(44).f=E.f=X,n(25).f=Q,n(39).f=tt,i&&!n(24)&&s(V,"propertyIsEnumerable",Q,!0),h.f=function(t){return J(d(t))}),u(u.G+u.W+u.F*!$,{Symbol:L});for(var et="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),nt=0;et.length>nt;)d(et[nt++]);for(var et=C(d.store),nt=0;et.length>nt;)v(et[nt++]);u(u.S+u.F*!$,"Symbol",{for:function(t){return o(R,t+="")?R[t]:R[t]=L(t)},keyFor:function(t){if(H(t))return y(R,t);throw TypeError(t+" is not a symbol!")},useSetter:function(){q=!0},useSimple:function(){q=!1}}),u(u.S+u.F*!$,"Object",{create:Y,defineProperty:K,defineProperties:z,getOwnPropertyDescriptor:Z,getOwnPropertyNames:X,getOwnPropertySymbols:tt}),A&&u(u.S+u.F*(!$||c(function(){var t=L();return"[null]"!=k([t])||"{}"!=k({a:t})||"{}"!=k(Object(t))})),"JSON",{stringify:function(t){if(void 0!==t&&!H(t)){for(var e,n,r=[t],o=1;arguments.length>o;)r.push(arguments[o++]);return e=r[1],"function"==typeof e&&(n=e),!n&&m(e)||(e=function(t,e){if(n&&(e=n.call(this,t,e)),!H(e))return e}),r[1]=e,k.apply(A,r)}}}),L[D][N]||n(9)(L[D],N,L[D].valueOf),l(L,"Symbol"),l(Math,"Math",!0),l(r.JSON,"JSON",!0)},function(t,e,n){n(34)("asyncIterator")},function(t,e,n){n(34)("observable")},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(11),i=r(o),u=n(13),s=r(u),f=n(12),c=r(f),a=n(2),l=r(a),p=n(47),d=r(p),h=new d.default,v=function(t){function e(n,r){return(0,i.default)(this,e),(0,s.default)(this,t.call(this,n,r))}return(0,c.default)(e,t),e.prototype.getChildContext=function(){return{$eventBus:h,$appConfig:this.props.appConfig}},e.prototype.componentDidMount=function(){},e.prototype.componentDidUpdate=function(){},e.prototype.componentWillUnmount=function(){},e.prototype.render=function(){return l.default.Children.only(this.props.children)},e}(a.Component);v.defaultProps={appConfig:null},v.propTypes={appConfig:a.PropTypes.object},v.childContextTypes={$eventBus:a.PropTypes.instanceOf(d.default),$appConfig:a.PropTypes.object},e.default=v},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){return t===e||"function"==typeof t&&"function"==typeof e&&t.toString()===e.toString()}function i(t,e){if(o(t,e))return!0;if("object"!==("undefined"==typeof t?"undefined":(0,s.default)(t))||null===t||"object"!==("undefined"==typeof e?"undefined":(0,s.default)(e))||null===e)return!1;var n=Object.keys(t),r=Object.keys(e);if(n.length!==r.length)return!1;for(var i=0;ic;)for(var p,d=s(arguments[c++]),h=a?r(d).concat(a(d)):r(d),v=h.length,y=0;v>y;)l.call(d,p=h[y++])&&(n[p]=d[p]);return n}:f},,,,,function(t,e,n){var r=n(16);r(r.S+r.F,"Object",{assign:n(118)})},,,,,,,,,,,,,,,,,function(t,e){"use strict";e.__esModule=!0,e.default={getVote:function(t){return new Promise(function(t,e){setTimeout(function(){t({data:{message:123}})},500)})}}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t){return{text:t.about}}e.__esModule=!0;var i,u,s,f,c=n(11),a=r(c),l=n(13),p=r(l),d=n(12),h=r(d),v=n(2),y=r(v),_=n(96),m=n(40),g=(i=(0,m.connect)(o),i((f=s=function(t){function e(){return(0,a.default)(this,e),(0,p.default)(this,t.apply(this,arguments))}return(0,h.default)(e,t),e.prototype.render=function(){return y.default.createElement("div",{className:"about"},"this is about page",y.default.createElement(_.Link,{to:"/vote?debug=test"},"vote"),"text: ",this.props.text)},e}(v.Component),s.pageConfig={pageId:"About"},u=f))||u);e.default=g},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(2),i=r(o),u=function(t){var e=t.children;return i.default.Children.only(e)};u.propTypes={children:o.PropTypes.object},e.default=u},,,,function(t,e,n){"use strict";function r(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"test";return t}e.__esModule=!0,e.default=r;n(50)},,function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(50),i=n(146),u=r(i),s=n(150),f=r(s),c=(0,o.combineReducers)({about:u.default,vote:f.default});e.default=c},,function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e.default=t,e}function o(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};switch(e.type){case u.LOAD_VOTE_SUCCESS:return e.payload;default:return t}}e.__esModule=!0,e.default=o;var i=n(102),u=r(i)},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n,r){var o=e.routes[e.routes.length-1];if(o.component){var i=o.component.WrappedComponent,u=e.location,s=i.OriginalPage?i.OriginalPage:i;Object.assign(window.__APP_CONFIG__,{pageId:u.query.pageId||s.pageConfig&&s.pageConfig.pageId})}r()}e.__esModule=!0;var i=n(2),u=r(i),s=n(96),f=n(104),c=(r(f),n(142)),a=r(c),l=n(141),p=r(l);e.default=function(t){return u.default.createElement(s.Route,{path:"/",component:a.default,onChange:o},u.default.createElement(s.IndexRoute,{getComponent:function(t,e){n.e(0,function(t){e(null,n(103).default)})}}),u.default.createElement(s.Route,{path:"vote",getComponent:function(t,e){n.e(0,function(t){e(null,n(103).default)})}}),u.default.createElement(s.Route,{path:"about",component:p.default}))}},function(t,e,n){(function(t){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(e,n){var r=[s.default],o=void 0;return o=t.browser?(0,i.createStore)(c.default,e,(0,i.compose)(i.applyMiddleware.apply(void 0,r))):(0,i.createStore)(c.default,e,(0,i.compose)(i.applyMiddleware.apply(void 0,r),function(t){return t}))}e.__esModule=!0,e.default=o;var i=n(50),u=n(89),s=r(u),f=n(148),c=r(f)}).call(e,n(90))}]); -------------------------------------------------------------------------------- /public/js/min/chat-9ed37d333f9142979733.js: -------------------------------------------------------------------------------- 1 | !function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="/static",e(0)}([function(t,e,n){t.exports=n(128)},function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(t,e,n){t.exports=n(3)(6)},function(t,e){t.exports=libs_lib},function(t,e,n){var r=n(31)("wks"),o=n(20),i=n(1).Symbol,s="function"==typeof i,u=t.exports=function(t){return r[t]||(r[t]=s&&i[t]||(s?i:o)("Symbol."+t))};u.store=r},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(52),o=n(27);t.exports=function(t){return r(o(t))}},function(t,e){var n=t.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n)},function(t,e,n){t.exports=!n(17)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,e,n){var r=n(10),o=n(19);t.exports=n(8)?function(t,e,n){return r.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(14),o=n(41),i=n(33),s=Object.defineProperty;e.f=n(8)?Object.defineProperty:function(t,e,n){if(r(t),e=i(e,!0),r(n),o)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},function(t,e){"use strict";e.__esModule=!0,e.default=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(59),i=r(o),s=n(58),u=r(s),a=n(23),f=r(a);e.default=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof e?"undefined":(0,f.default)(e)));t.prototype=(0,u.default)(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(i.default?(0,i.default)(t,e):t.__proto__=e)}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(23),i=r(o);e.default=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!==("undefined"==typeof e?"undefined":(0,i.default)(e))&&"function"!=typeof e?t:e}},function(t,e,n){var r=n(15);t.exports=function(t){if(!r(t))throw TypeError(t+" is not an object!");return t}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(1),o=n(7),i=n(37),s=n(9),u="prototype",a=function(t,e,n){var f,c,l,p=t&a.F,d=t&a.G,h=t&a.S,v=t&a.P,y=t&a.B,m=t&a.W,_=d?o:o[e]||(o[e]={}),g=_[u],b=d?r:h?r[e]:(r[e]||{})[u];d&&(n=e);for(f in n)c=!p&&b&&void 0!==b[f],c&&f in _||(l=c?b[f]:n[f],_[f]=d&&"function"!=typeof b[f]?n[f]:y&&c?i(l,r):m&&b[f]==l?function(t){var e=function(e,n,r){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,n)}return new t(e,n,r)}return t.apply(this,arguments)};return e[u]=t[u],e}(l):v&&"function"==typeof l?i(Function.call,l):l,v&&((_.virtual||(_.virtual={}))[f]=l,t&a.R&&g&&!g[f]&&s(g,f,l)))};a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,t.exports=a},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){var r=n(45),o=n(28);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+r).toString(36))}},function(t,e){t.exports={}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t){var e=Object.getOwnPropertyNames(t).filter(function(e){return y.test(e)&&"function"==typeof t[e]}),n=Object.getPrototypeOf(t);return n!==Object.prototype&&(e=e.concat(o(n))),e}e.__esModule=!0,e.default=void 0;var i=n(11),s=r(i),u=n(13),a=r(u),f=n(12),c=r(f),l=n(2),p=(r(l),n(87)),d=r(p),h=n(47),v=r(h),y=/^on[A-Z]/,m=function(t){function e(n,r){(0,s.default)(this,e);var o=(0,a.default)(this,t.call(this,n,r));return o.__eventNames={},o.__bindFunctions(),o}return(0,c.default)(e,t),e.prototype.__bindFunctions=function(){for(var t=o(this),e=t,n=Array.isArray(e),r=0,e=n?e:e[Symbol.iterator]();;){var i;if(n){if(r>=e.length)break;i=e[r++]}else{if(r=e.next(),r.done)break;i=r.value}var s=i;this[s].funcBinded||(this[s]=this[s].bind(this),this[s].funcBinded=!0)}},e.prototype.on=function(t,e){if("function"!=typeof e)throw new Error("fn should be a function");return this.__eventNames[t]?this.__eventNames[t].push(e):this.__eventNames[t]=[e],this.context.$eventBus.addListener(t,e)},e.prototype.emit=function(t){for(var e,n=arguments.length,r=Array(n>1?n-1:0),o=1;o=0?(this.context.$eventBus.removeListener(t,e),n.splice(r,1),n.length||delete this.__eventNames[t]):console.warn("event: "+t+" is not registered in "+this._reactInternalInstance.getName()+" Component"),!0}return console.warn("event: "+t+" is not registered in "+this.constructor.name+" Component"),!1},e.prototype.shouldComponentUpdate=function(t,e){var n=!(0,d.default)(this.props,t)||!(0,d.default)(this.state,e);return n},e.prototype.componentWillUnmount=function(){for(var t in this.__eventNames)if(this.__eventNames.hasOwnProperty(t))for(var e=this.__eventNames[t],n=Array.isArray(e),r=0,e=n?e:e[Symbol.iterator]();;){var o;if(n){if(r>=e.length)break;o=e[r++]}else{if(r=e.next(),r.done)break;o=r.value}var i=o;this.off(t,i)}},e}(l.Component);e.default=m,m.contextTypes={$eventBus:l.PropTypes.instanceOf(v.default)}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(61),i=r(o),s=n(60),u=r(s),a="function"==typeof u.default&&"symbol"==typeof i.default?function(t){return typeof t}:function(t){return t&&"function"==typeof u.default&&t.constructor===u.default&&t!==u.default.prototype?"symbol":typeof t};e.default="function"==typeof u.default&&"symbol"===a(i.default)?function(t){return"undefined"==typeof t?"undefined":a(t)}:function(t){return t&&"function"==typeof u.default&&t.constructor===u.default&&t!==u.default.prototype?"symbol":"undefined"==typeof t?"undefined":a(t)}},function(t,e){t.exports=!0},function(t,e){e.f={}.propertyIsEnumerable},function(t,e,n){var r=n(10).f,o=n(5),i=n(4)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,e,n){var r=n(14),o=n(74),i=n(28),s=n(30)("IE_PROTO"),u=function(){},a="prototype",f=function(){var t,e=n(38)("iframe"),r=i.length,o="<",s=">";for(e.style.display="none",n(51).appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write(o+"script"+s+"document.F=Object"+o+"/script"+s),t.close(),f=t.F;r--;)delete f[a][i[r]];return f()};t.exports=Object.create||function(t,e){var n;return null!==t?(u[a]=r(t),n=new u,u[a]=null,n[s]=t):n=f(),void 0===e?n:o(n,e)}},function(t,e,n){var r=n(31)("keys"),o=n(20);t.exports=function(t){return r[t]||(r[t]=o(t))}},function(t,e,n){var r=n(1),o="__core-js_shared__",i=r[o]||(r[o]={});t.exports=function(t){return i[t]||(i[t]={})}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e,n){var r=n(15);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(1),o=n(7),i=n(24),s=n(35),u=n(10).f;t.exports=function(t){var e=o.Symbol||(o.Symbol=i?{}:r.Symbol||{});"_"==t.charAt(0)||t in e||u(e,t,{value:s.f(t)})}},function(t,e,n){e.f=n(4)},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(49);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(15),o=n(1).document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){t.exports=n(3)(153)},function(t,e,n){t.exports=!n(8)&&!n(17)(function(){return 7!=Object.defineProperty(n(38)("div"),"a",{get:function(){return 7}}).a})},function(t,e,n){"use strict";var r=n(24),o=n(16),i=n(46),s=n(9),u=n(5),a=n(21),f=n(70),c=n(26),l=n(76),p=n(4)("iterator"),d=!([].keys&&"next"in[].keys()),h="@@iterator",v="keys",y="values",m=function(){return this};t.exports=function(t,e,n,_,g,b,x){f(n,e,_);var w,O,S,E=function(t){if(!d&&t in P)return P[t];switch(t){case v:return function(){return new n(this,t)};case y:return function(){return new n(this,t)}}return function(){return new n(this,t)}},M=e+" Iterator",j=g==y,N=!1,P=t.prototype,L=P[p]||P[h]||g&&P[g],C=L||E(g),T=g?j?E("entries"):C:void 0,A="Array"==e?P.entries||L:L;if(A&&(S=l(A.call(new t)),S!==Object.prototype&&(c(S,M,!0),r||u(S,p)||s(S,p,m))),j&&L&&L.name!==y&&(N=!0,C=function(){return L.call(this)}),r&&!x||!d&&!N&&P[p]||s(P,p,C),a[e]=C,a[M]=m,g)if(w={values:j?C:E(y),keys:b?C:E(v),entries:T},x)for(O in w)O in P||i(P,O,w[O]);else o(o.P+o.F*(d||N),e,w);return w}},function(t,e,n){var r=n(25),o=n(19),i=n(6),s=n(33),u=n(5),a=n(41),f=Object.getOwnPropertyDescriptor;e.f=n(8)?f:function(t,e){if(t=i(t),e=s(e,!0),a)try{return f(t,e)}catch(t){}if(u(t,e))return o(!r.f.call(t,e),t[e])}},function(t,e,n){var r=n(45),o=n(28).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},function(t,e,n){var r=n(5),o=n(6),i=n(67)(!1),s=n(30)("IE_PROTO");t.exports=function(t,e){var n,u=o(t),a=0,f=[];for(n in u)n!=s&&r(u,n)&&f.push(n);for(;e.length>a;)r(u,n=e[a++])&&(~i(f,n)||f.push(n));return f}},function(t,e,n){t.exports=n(9)},function(t,e){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(t){return"function"==typeof t}function o(t){return"number"==typeof t}function i(t){return"object"==typeof t&&null!==t}function s(t){return void 0===t}t.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(t){if(!o(t)||t<0||isNaN(t))throw TypeError("n must be a positive number");return this._maxListeners=t,this},n.prototype.emit=function(t){var e,n,o,u,a,f;if(this._events||(this._events={}),"error"===t&&(!this._events.error||i(this._events.error)&&!this._events.error.length)){if(e=arguments[1],e instanceof Error)throw e;var c=new Error('Uncaught, unspecified "error" event. ('+e+")");throw c.context=e,c}if(n=this._events[t],s(n))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:u=Array.prototype.slice.call(arguments,1),n.apply(this,u)}else if(i(n))for(u=Array.prototype.slice.call(arguments,1),f=n.slice(),o=f.length,a=0;a0&&this._events[t].length>o&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),"function"==typeof console.trace&&console.trace())),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(t,e){function n(){this.removeListener(t,n),o||(o=!0,e.apply(this,arguments))}if(!r(e))throw TypeError("listener must be a function");var o=!1;return n.listener=e,this.on(t,n),this},n.prototype.removeListener=function(t,e){var n,o,s,u;if(!r(e))throw TypeError("listener must be a function");if(!this._events||!this._events[t])return this;if(n=this._events[t],s=n.length,o=-1,n===e||r(n.listener)&&n.listener===e)delete this._events[t],this._events.removeListener&&this.emit("removeListener",t,e);else if(i(n)){for(u=s;u-- >0;)if(n[u]===e||n[u].listener&&n[u].listener===e){o=u;break}if(o<0)return this;1===n.length?(n.length=0,delete this._events[t]):n.splice(o,1),this._events.removeListener&&this.emit("removeListener",t,e)}return this},n.prototype.removeAllListeners=function(t){var e,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[t]&&delete this._events[t],this;if(0===arguments.length){for(e in this._events)"removeListener"!==e&&this.removeAllListeners(e);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[t],r(n))this.removeListener(t,n);else if(n)for(;n.length;)this.removeListener(t,n[n.length-1]);return delete this._events[t],this},n.prototype.listeners=function(t){var e;return e=this._events&&this._events[t]?r(this._events[t])?[this._events[t]]:this._events[t].slice():[]},n.prototype.listenerCount=function(t){if(this._events){var e=this._events[t];if(r(e))return 1;if(e)return e.length}return 0},n.listenerCount=function(t,e){return t.listenerCount(e)}},,function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e,n){t.exports=n(3)(124)},function(t,e,n){t.exports=n(1).document&&document.documentElement},function(t,e,n){var r=n(36);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==r(t)?t.split(""):Object(t)}},function(t,e,n){var r=n(32),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(27);t.exports=function(t){return Object(r(t))}},function(t,e){},function(t,e,n){"use strict";var r=n(78)(!0);n(42)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},function(t,e,n){n(80);for(var r=n(1),o=n(9),i=n(21),s=n(4)("toStringTag"),u=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],a=0;a<5;a++){var f=u[a],c=r[f],l=c&&c.prototype;l&&!l[s]&&o(l,s,f),i[f]=i.Array}},function(t,e,n){t.exports={default:n(62),__esModule:!0}},function(t,e,n){t.exports={default:n(63),__esModule:!0}},function(t,e,n){t.exports={default:n(64),__esModule:!0}},function(t,e,n){t.exports={default:n(65),__esModule:!0}},function(t,e,n){n(81);var r=n(7).Object;t.exports=function(t,e){return r.create(t,e)}},function(t,e,n){n(82),t.exports=n(7).Object.setPrototypeOf},function(t,e,n){n(83),n(55),n(84),n(85),t.exports=n(7).Symbol},function(t,e,n){n(56),n(57),t.exports=n(35).f("iterator")},function(t,e){t.exports=function(){}},function(t,e,n){var r=n(6),o=n(53),i=n(79);t.exports=function(t){return function(e,n,s){var u,a=r(e),f=o(a.length),c=i(s,f);if(t&&n!=n){for(;f>c;)if(u=a[c++],u!=u)return!0}else for(;f>c;c++)if((t||c in a)&&a[c]===n)return t||c||0;return!t&&-1}}},function(t,e,n){var r=n(18),o=n(39),i=n(25);t.exports=function(t){var e=r(t),n=o.f;if(n)for(var s,u=n(t),a=i.f,f=0;u.length>f;)a.call(t,s=u[f++])&&e.push(s);return e}},function(t,e,n){var r=n(36);t.exports=Array.isArray||function(t){return"Array"==r(t)}},function(t,e,n){"use strict";var r=n(29),o=n(19),i=n(26),s={};n(9)(s,n(4)("iterator"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(s,{next:o(1,n)}),i(t,e+" Iterator")}},function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},function(t,e,n){var r=n(18),o=n(6);t.exports=function(t,e){for(var n,i=o(t),s=r(i),u=s.length,a=0;u>a;)if(i[n=s[a++]]===e)return n}},function(t,e,n){var r=n(20)("meta"),o=n(15),i=n(5),s=n(10).f,u=0,a=Object.isExtensible||function(){return!0},f=!n(17)(function(){return a(Object.preventExtensions({}))}),c=function(t){s(t,r,{value:{i:"O"+ ++u,w:{}}})},l=function(t,e){if(!o(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!i(t,r)){if(!a(t))return"F";if(!e)return"E";c(t)}return t[r].i},p=function(t,e){if(!i(t,r)){if(!a(t))return!0;if(!e)return!1;c(t)}return t[r].w},d=function(t){return f&&h.NEED&&a(t)&&!i(t,r)&&c(t),t},h=t.exports={KEY:r,NEED:!1,fastKey:l,getWeak:p,onFreeze:d}},function(t,e,n){var r=n(10),o=n(14),i=n(18);t.exports=n(8)?Object.defineProperties:function(t,e){o(t);for(var n,s=i(e),u=s.length,a=0;u>a;)r.f(t,n=s[a++],e[n]);return t}},function(t,e,n){var r=n(6),o=n(44).f,i={}.toString,s="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],u=function(t){try{return o(t)}catch(t){return s.slice()}};t.exports.f=function(t){return s&&"[object Window]"==i.call(t)?u(t):o(r(t))}},function(t,e,n){var r=n(5),o=n(54),i=n(30)("IE_PROTO"),s=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,i)?t[i]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?s:null}},function(t,e,n){var r=n(15),o=n(14),i=function(t,e){if(o(t),!r(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,e,r){try{r=n(37)(Function.call,n(43).f(Object.prototype,"__proto__").set,2),r(t,[]),e=!(t instanceof Array)}catch(t){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:r(t,n),t}}({},!1):void 0),check:i}},function(t,e,n){var r=n(32),o=n(27);t.exports=function(t){return function(e,n){var i,s,u=String(o(e)),a=r(n),f=u.length;return a<0||a>=f?t?"":void 0:(i=u.charCodeAt(a),i<55296||i>56319||a+1===f||(s=u.charCodeAt(a+1))<56320||s>57343?t?u.charAt(a):i:t?u.slice(a,a+2):(i-55296<<10)+(s-56320)+65536)}}},function(t,e,n){var r=n(32),o=Math.max,i=Math.min;t.exports=function(t,e){return t=r(t),t<0?o(t+e,0):i(t,e)}},function(t,e,n){"use strict";var r=n(66),o=n(71),i=n(21),s=n(6);t.exports=n(42)(Array,"Array",function(t,e){this._t=s(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,o(1)):"keys"==e?o(0,n):"values"==e?o(0,t[n]):o(0,[n,t[n]])},"values"),i.Arguments=i.Array,r("keys"),r("values"),r("entries")},function(t,e,n){var r=n(16);r(r.S,"Object",{create:n(29)})},function(t,e,n){var r=n(16);r(r.S,"Object",{setPrototypeOf:n(77).set})},function(t,e,n){"use strict";var r=n(1),o=n(5),i=n(8),s=n(16),u=n(46),a=n(73).KEY,f=n(17),c=n(31),l=n(26),p=n(20),d=n(4),h=n(35),v=n(34),y=n(72),m=n(68),_=n(69),g=n(14),b=n(6),x=n(33),w=n(19),O=n(29),S=n(75),E=n(43),M=n(10),j=n(18),N=E.f,P=M.f,L=S.f,C=r.Symbol,T=r.JSON,A=T&&T.stringify,k="prototype",I=d("_hidden"),F=d("toPrimitive"),B={}.propertyIsEnumerable,R=c("symbol-registry"),D=c("symbols"),W=c("op-symbols"),U=Object[k],$="function"==typeof C,J=r.QObject,K=!J||!J[k]||!J[k].findChild,z=i&&f(function(){return 7!=O(P({},"a",{get:function(){return P(this,"a",{value:7}).a}})).a})?function(t,e,n){var r=N(U,e);r&&delete U[e],P(t,e,n),r&&t!==U&&P(U,e,r)}:P,G=function(t){var e=D[t]=O(C[k]);return e._k=t,e},q=$&&"symbol"==typeof C.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof C},Y=function(t,e,n){return t===U&&Y(W,e,n),g(t),e=x(e,!0),g(n),o(D,e)?(n.enumerable?(o(t,I)&&t[I][e]&&(t[I][e]=!1),n=O(n,{enumerable:w(0,!1)})):(o(t,I)||P(t,I,w(1,{})),t[I][e]=!0),z(t,e,n)):P(t,e,n)},Q=function(t,e){g(t);for(var n,r=m(e=b(e)),o=0,i=r.length;i>o;)Y(t,n=r[o++],e[n]);return t},Z=function(t,e){return void 0===e?O(t):Q(O(t),e)},H=function(t){var e=B.call(this,t=x(t,!0));return!(this===U&&o(D,t)&&!o(W,t))&&(!(e||!o(this,t)||!o(D,t)||o(this,I)&&this[I][t])||e)},V=function(t,e){if(t=b(t),e=x(e,!0),t!==U||!o(D,e)||o(W,e)){var n=N(t,e);return!n||!o(D,e)||o(t,I)&&t[I][e]||(n.enumerable=!0),n}},X=function(t){for(var e,n=L(b(t)),r=[],i=0;n.length>i;)o(D,e=n[i++])||e==I||e==a||r.push(e);return r},tt=function(t){for(var e,n=t===U,r=L(n?W:b(t)),i=[],s=0;r.length>s;)!o(D,e=r[s++])||n&&!o(U,e)||i.push(D[e]);return i};$||(C=function(){if(this instanceof C)throw TypeError("Symbol is not a constructor!");var t=p(arguments.length>0?arguments[0]:void 0),e=function(n){this===U&&e.call(W,n),o(this,I)&&o(this[I],t)&&(this[I][t]=!1),z(this,t,w(1,n))};return i&&K&&z(U,t,{configurable:!0,set:e}),G(t)},u(C[k],"toString",function(){return this._k}),E.f=V,M.f=Y,n(44).f=S.f=X,n(25).f=H,n(39).f=tt,i&&!n(24)&&u(U,"propertyIsEnumerable",H,!0),h.f=function(t){return G(d(t))}),s(s.G+s.W+s.F*!$,{Symbol:C});for(var et="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),nt=0;et.length>nt;)d(et[nt++]);for(var et=j(d.store),nt=0;et.length>nt;)v(et[nt++]);s(s.S+s.F*!$,"Symbol",{for:function(t){return o(R,t+="")?R[t]:R[t]=C(t)},keyFor:function(t){if(q(t))return y(R,t);throw TypeError(t+" is not a symbol!")},useSetter:function(){K=!0},useSimple:function(){K=!1}}),s(s.S+s.F*!$,"Object",{create:Z,defineProperty:Y,defineProperties:Q,getOwnPropertyDescriptor:V,getOwnPropertyNames:X,getOwnPropertySymbols:tt}),T&&s(s.S+s.F*(!$||f(function(){var t=C();return"[null]"!=A([t])||"{}"!=A({a:t})||"{}"!=A(Object(t))})),"JSON",{stringify:function(t){if(void 0!==t&&!q(t)){for(var e,n,r=[t],o=1;arguments.length>o;)r.push(arguments[o++]);return e=r[1],"function"==typeof e&&(n=e),!n&&_(e)||(e=function(t,e){if(n&&(e=n.call(this,t,e)),!q(e))return e}),r[1]=e,A.apply(T,r)}}}),C[k][F]||n(9)(C[k],F,C[k].valueOf),l(C,"Symbol"),l(Math,"Math",!0),l(r.JSON,"JSON",!0)},function(t,e,n){n(34)("asyncIterator")},function(t,e,n){n(34)("observable")},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(11),i=r(o),s=n(13),u=r(s),a=n(12),f=r(a),c=n(2),l=r(c),p=n(47),d=r(p),h=new d.default,v=function(t){function e(n,r){return(0,i.default)(this,e),(0,u.default)(this,t.call(this,n,r))}return(0,f.default)(e,t),e.prototype.getChildContext=function(){return{$eventBus:h,$appConfig:this.props.appConfig}},e.prototype.componentDidMount=function(){},e.prototype.componentDidUpdate=function(){},e.prototype.componentWillUnmount=function(){},e.prototype.render=function(){return l.default.Children.only(this.props.children)},e}(c.Component);v.defaultProps={appConfig:null},v.propTypes={appConfig:c.PropTypes.object},v.childContextTypes={$eventBus:c.PropTypes.instanceOf(d.default),$appConfig:c.PropTypes.object},e.default=v},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){return t===e||"function"==typeof t&&"function"==typeof e&&t.toString()===e.toString()}function i(t,e){if(o(t,e))return!0;if("object"!==("undefined"==typeof t?"undefined":(0,u.default)(t))||null===t||"object"!==("undefined"==typeof e?"undefined":(0,u.default)(e))||null===e)return!1;var n=Object.keys(t),r=Object.keys(e);if(n.length!==r.length)return!1;for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:{},e=null,n=document.getElementById("page"),r="function"==typeof t.onRenderCompleted&&t.onRenderCompleted;return function(o){var i=o.rootReducer,f=void 0===i?function(){}:i,c=o.component,l=void 0===c?null:c,d="function"==typeof t.transformer?t.transformer(window.__INITIAL_STATE__):window.__INITIAL_STATE__;return e||(e=(0,h.default)(d,f)),(0,u.render)(s.default.createElement(a.Provider,{store:e},s.default.createElement(p.default,{appConfig:window.__APP_CONFIG__},l)),n,r),Promise.resolve(e)}}e.__esModule=!0,e.default=o;var i=n(2),s=r(i),u=n(88),a=n(40),f=n(94),c=r(f),l=n(86),p=r(l),d=n(93),h=r(d);c.default.attach(document.body)},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){var n=f(e,t);return n}e.__esModule=!0,e.default=o;var i=n(50),s=n(89),u=r(s),a=function(){var t=(0,i.applyMiddleware)(u.default),e=[t];return e},f=i.compose.apply(void 0,a())(i.createStore)},function(t,e,n){t.exports=n(3)(126)},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}var o=n(2),i=r(o),s=n(92),u=r(s),a=n(144),f=r(a);n(91);var c=(0,u.default)();c({component:i.default.createElement(f.default,null)})},,,,function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0,e.default=void 0;var o=n(11),i=r(o),s=n(13),u=r(s),a=n(12),f=r(a),c=n(2),l=r(c),p=n(22),d=r(p),h=function(t){function e(n,r){(0,i.default)(this,e);var o=(0,u.default)(this,t.call(this,n,r));return o.state={newName:""},o}return(0,f.default)(e,t),e.prototype.onKey=function(t){this.setState({newName:t.target.value})},e.prototype.onSubmit=function(t){t.preventDefault();var e=this.state.newName;this.props.onChangeName(e),this.setState({newName:""})},e.prototype.render=function(){return l.default.createElement("div",{className:"change_name_form"},l.default.createElement("h3",null," Change Name "),l.default.createElement("form",{onSubmit:this.onSubmit},l.default.createElement("input",{onChange:this.onKey,value:this.state.newName})))},e}(d.default);e.default=h},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0,e.MessageForm=e.MessageList=e.Message=void 0;var o=n(11),i=r(o),s=n(13),u=r(s),a=n(12),f=r(a),c=n(2),l=r(c),p=n(22),d=r(p),h=e.Message=function(t){function e(n,r){return(0,i.default)(this,e),(0,u.default)(this,t.call(this,n,r))}return(0,f.default)(e,t),e.prototype.render=function(){return l.default.createElement("div",{className:"message"},l.default.createElement("strong",null,this.props.user," :"),l.default.createElement("span",null,this.props.text))},e}(d.default);h.defaultProps={user:"",text:""},h.propTypes={user:c.PropTypes.string.isRequired,text:c.PropTypes.string.isRequired};e.MessageList=function(t){function e(n,r){return(0,i.default)(this,e),(0,u.default)(this,t.call(this,n,r))}return(0,f.default)(e,t),e.prototype.render=function(){return l.default.createElement("div",{className:"messages"},l.default.createElement("h2",null," Conversation: "),this.props.messages.map(function(t,e){return l.default.createElement(h,{key:e,user:t.user,text:t.text})}))},e}(d.default),e.MessageForm=function(t){function e(n,r){(0,i.default)(this,e);var o=(0,u.default)(this,t.call(this,n,r));return o.state={text:""},o}return(0,f.default)(e,t),e.prototype.onSubmit=function(t){if(t.preventDefault(),this.state.text){var e={user:this.props.user,text:this.state.text};this.props.onMessageSubmit(e),this.setState({text:""})}},e.prototype.onChange=function(t){this.setState({text:t.target.value})},e.prototype.render=function(){return l.default.createElement("div",{className:"message_form"},l.default.createElement("h3",null,"Write New Message"),l.default.createElement("form",{onSubmit:this.onSubmit},l.default.createElement("input",{onChange:this.onChange,value:this.state.text})))},e}(d.default)},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0,e.default=void 0;var o=n(11),i=r(o),s=n(13),u=r(s),a=n(12),f=r(a),c=n(2),l=r(c),p=n(22),d=r(p),h=function(t){function e(n,r){return(0,i.default)(this,e),(0,u.default)(this,t.call(this,n,r))}return(0,f.default)(e,t),e.prototype.render=function(){return l.default.createElement("div",{className:"users"},l.default.createElement("h3",null," Online Users "),l.default.createElement("ul",null,this.props.users.map(function(t,e){return l.default.createElement("li",{key:e},t)})))},e}(d.default);e.default=h},,,,,,,,,,function(t,e,n){(function(t){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}e.__esModule=!0;var o=n(11),i=r(o),s=n(13),u=r(s),a=n(12),f=r(a),c=n(2),l=r(c),p=(n(40),n(22)),d=r(p),h=n(134),v=r(h),y=n(133),m=n(132),_=r(m);if(t.browser)var g=io.connect();var b=function(t){function e(n,r){(0,i.default)(this,e);var o=(0,u.default)(this,t.call(this,n,r));return o.state={users:[],messages:[],text:""},o}return(0,f.default)(e,t),e.prototype.componentDidMount=function(){g.on("init",this.initialize.bind(this)),g.on("send:message",this.messageRecieve.bind(this)),g.on("user:join",this.userJoined.bind(this)),g.on("user:left",this.userLeft.bind(this)),g.on("change:name",this.userChangedName.bind(this))},e.prototype.initialize=function(t){var e=t.users,n=t.name;this.setState({users:e,user:n})},e.prototype.messageRecieve=function(t){var e=this.state.messages;this.setState({messages:[].concat(e,[t])})},e.prototype.userJoined=function(t){var e=this.state,n=e.users,r=e.messages,o=t.name;this.setState({users:[n,o],messages:[].concat(r,[{user:"APPLICATION BOT",text:o+" Joined"}])})},e.prototype.userLeft=function(t){var e=this.state,n=e.users,r=e.messages,o=t.name,i=n.indexOf(o);n.splice(i,1),this.setState({users:[].concat(n),messages:[].concat(r,[{user:"APPLICATION BOT",text:o+" Left"}])})},e.prototype.userChangedName=function(t){var e=t.oldName,n=t.newName,r=this.state,o=r.users,i=r.messages,s=o.indexOf(e);o.splice(s,1,n),this.setState({users:[].concat(o),messages:[].concat(i,[{user:"APPLICATION BOT",text:"Change Name : "+e+" ==> "+n}])})},e.prototype.onMessageSubmit=function(t){var e=this.state.messages;this.setState({messages:[].concat(e,[t])}),g.emit("send:message",t)},e.prototype.onChangeName=function(t){var e=this,n=this.state.user,r=this.state.messages;g.emit("change:name",{name:t},function(o){if(!o)return alert("There was an error changing your name");var i=e.state.users,s=i.indexOf(n);i.splice(s,1,t),r=r.map(function(e){return e.user===n?Object.assign({},e,{user:t}):e}),e.setState({users:[].concat(i),user:t,messages:r})})},e.prototype.render=function(){return l.default.createElement("div",null,l.default.createElement(v.default,{users:this.state.users}),l.default.createElement(y.MessageList,{messages:this.state.messages}),l.default.createElement(y.MessageForm,{onMessageSubmit:this.onMessageSubmit,user:this.state.user}),l.default.createElement(_.default,{onChangeName:this.onChangeName}))},e}(d.default);e.default=b}).call(e,n(90))}]); -------------------------------------------------------------------------------- /server/apis/index.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | let router = new Router(); 4 | 5 | router.post('/ajax', function(req, res, next){ 6 | if(error) { 7 | next(); 8 | } else { 9 | res.send('test') 10 | } 11 | }); 12 | 13 | export default router; 14 | 15 | 16 | -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | import http from 'http'; 2 | import express from 'express'; 3 | import compress from 'compression'; 4 | import logger from 'morgan'; 5 | import cookieParser from 'cookie-parser'; 6 | import bodyParser from 'body-parser'; 7 | import session from 'express-session'; 8 | import csurf from 'csurf'; 9 | import config from './config/config.json'; 10 | import routes from './routes/index'; 11 | import apis from './apis/index'; 12 | import allowCrossDomain from './middlewares/allowCrossDomain' 13 | import reactRender from './middlewares/renderReactMiddleware'; 14 | import Immutable from 'immutable'; 15 | import helmet from 'helmet'; 16 | import socket from './sockets/socket'; 17 | import spaRenderMatch from './middlewares/spaRenderMatch'; 18 | 19 | let app = express(); 20 | 21 | app.set('host', process.env.IP || '127.0.0.1'); 22 | app.set('port', process.env.PORT || 3000); 23 | app.disable('x-powered-by'); 24 | 25 | app.use(helmet.contentSecurityPolicy()); 26 | app.use(helmet.frameguard()); 27 | app.use(helmet.noSniff()); 28 | app.use(helmet.xssFilter()); 29 | app.use(helmet.hsts()); 30 | app.use(compress()); 31 | app.use(logger('dev')); 32 | app.use(bodyParser.json()); 33 | app.use(bodyParser.urlencoded({ extended: true })); 34 | app.use(cookieParser()); 35 | app.use(session({ 36 | resave: true, 37 | secret: 'mySecretCookieSalt', 38 | key: 'myCookieSessionId', 39 | saveUninitialized: true, 40 | cookie: { 41 | httpOnly: true, 42 | } 43 | })); 44 | 45 | // app.use(favicon(__dirname + '/../public/favicon.ico')); 46 | app.use('/static', express.static(__dirname + '/../public', { 47 | maxAge: 86400000 48 | })); 49 | 50 | // if(process.env.NODE_ENV !== 'production'){ 51 | // let webpack = require('webpack'); 52 | // let config = require('../create-webpack.config')(true); 53 | // let webpackDevMiddleware = require('webpack-dev-middleware'); 54 | // let webpackHotMiddleware = require('webpack-hot-middleware'); 55 | // let compiler = webpack(config); 56 | // app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })); 57 | // app.use(webpackHotMiddleware(compiler)); 58 | // } 59 | 60 | app.use(allowCrossDomain); 61 | 62 | app.use(csurf()); 63 | app.use(function (req, res, next) { 64 | res.locals.csrftoken = req.csrfToken(); 65 | next(); 66 | }); 67 | app.use(reactRender({ 68 | transformer: function(data){ 69 | return Immutable.fromJS(data); 70 | } 71 | })); 72 | 73 | app.use('/api', apis); 74 | app.use('/', routes); 75 | app.use('*', spaRenderMatch); 76 | 77 | // error handlers 78 | // no stacktraces leaked to user 79 | app.use(function(err, req, res, next) { 80 | console.dir(err); 81 | res.status(err.status || 500); 82 | if(err.status === 500) { 83 | console.error(err.stack); 84 | res.json({error: 'Internal Server Error'}); 85 | } 86 | else if(err.status === 404) { 87 | res.render('error'); //render error page 88 | } else { 89 | res.json({error: err.message}) 90 | } 91 | }); 92 | 93 | 94 | process.on('uncaughtException', err => { 95 | console.error(err.message + '\n' + err.stack); 96 | }); 97 | process.on('unhandledRejection', (reason, p) => { 98 | console.error("Unhandled Rejection at: Promise ", p, " reason: ", reason); 99 | }); 100 | process.on('rejectionHandled', (reason, p) => { 101 | console.warn("rejectionHandled at: Promise ", p, " reason: ", reason); 102 | }); 103 | 104 | let server = http.createServer(app); 105 | 106 | /* Socket.io Communication */ 107 | let io = require('socket.io').listen(server); 108 | io.sockets.on('connection', socket); 109 | 110 | server.listen(app.get('port'), app.get('host'), function() { 111 | let { address, port } = server.address(); 112 | console.log(`${ config.serverName } server listening at http://%s:%s`, address, port); 113 | }); 114 | 115 | -------------------------------------------------------------------------------- /server/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "application": { 3 | "version": { 4 | "css": "", 5 | "js": "" 6 | }, 7 | "debugName": "test" 8 | }, 9 | "serverName": "isomophic-react-redux-starter" 10 | } -------------------------------------------------------------------------------- /server/controllers/async.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import fetch from 'isomorphic-fetch'; 3 | import rootReducer from '../../common/reducers/async'; 4 | import Page from '../../common/pages/async/Page.jsx'; 5 | 6 | module.exports = async function (req, res, next) { 7 | let state = { 8 | postsByReddit: {}, 9 | selectedReddit: 'reactjs' 10 | }; 11 | 12 | try { 13 | let response = await fetch(`https://www.reddit.com/r/${state.selectedReddit}.json`, { 14 | method: 'GET', 15 | timeout: 5000 16 | }).then(response => response.json()); 17 | 18 | state.postsByReddit[state.selectedReddit] = { 19 | didInvalidate: false, 20 | isFetching: false, 21 | lastUpdated: Date.now(), 22 | items: response.data.children.map(child => child.data) 23 | }; 24 | 25 | } catch(ex){ 26 | console.error(ex); 27 | } 28 | 29 | res.renderReactHTML({ 30 | component: , 31 | locals: { 32 | appName: 'async', 33 | title: 'async page' 34 | }, 35 | data: state, 36 | rootReducer 37 | }); 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /server/controllers/chat.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Page from '../../common/pages/chat/Page'; 3 | import fs from 'fs'; 4 | 5 | let template = fs.readFileSync(__dirname + '/../views/chat.html', 'utf8'); 6 | let fakeData = { 7 | 8 | }; 9 | 10 | module.exports = function (req, res, next) { 11 | res.renderReactHTML({ 12 | template, 13 | component: , 14 | locals: { 15 | appName: 'chat', 16 | title: 'chat page' 17 | }, 18 | data: fakeData, 19 | needTransform: false 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /server/controllers/todo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import rootReducer from '../../common/reducers/todo'; 3 | import Page from '../../common/pages/todo/Todo'; 4 | 5 | let fakeData = { 6 | visibilityFilter: 'SHOW_ALL', 7 | todos: [ 8 | { 9 | text: 'one', 10 | completed: false 11 | }, 12 | { 13 | text: 'two', 14 | completed: true 15 | } 16 | ] 17 | }; 18 | 19 | module.exports = function (req, res, next) { 20 | res.renderReactHTML({ 21 | component: , 22 | locals: { 23 | appName: 'todo', 24 | title: 'todo page' 25 | }, 26 | data: fakeData, 27 | rootReducer, 28 | pageConfig: { 29 | user: 'test' 30 | } 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /server/middlewares/allowCrossDomain.js: -------------------------------------------------------------------------------- 1 | 2 | export default function allowCrossDomain(req, res, next) { 3 | let allowedOrigins = [ 4 | 'http://www.test.com' 5 | ]; 6 | let origin = req.headers.origin; 7 | if(allowedOrigins.indexOf(origin) > -1){ 8 | res.header('Access-Control-Allow-Origin', origin); 9 | } 10 | next(); 11 | } 12 | -------------------------------------------------------------------------------- /server/middlewares/renderReactMiddleware.jsx: -------------------------------------------------------------------------------- 1 | import ejs from 'ejs'; 2 | import React from 'react'; 3 | import {renderToString} from 'react-dom/server'; 4 | import {Provider} from 'react-redux'; 5 | import fs from 'fs'; 6 | import { jsObj as safeJSON } from 'secure-filters'; 7 | 8 | import configureStore from '../../common/store/index'; 9 | import App from '../../common/App.jsx'; 10 | import config from '../config/config.json'; 11 | 12 | const defaultTemplate = fs.readFileSync(__dirname + '/../views/index.html', 'utf8'); 13 | 14 | export function getDefaultJSVersion(name) { 15 | let webpackAssets = fs.readFileSync(__dirname + '/../../webpack-assets.json', 'utf8'); 16 | 17 | try { 18 | webpackAssets = JSON.parse(webpackAssets); 19 | } catch (ex) { 20 | console.log('webpack-assets.json parsed error'); 21 | webpackAssets = {}; 22 | } 23 | return webpackAssets[name]; 24 | } 25 | 26 | export default function reactRender(middlewareConfig = {}) { 27 | return function (req, res, next) { 28 | res.renderReactHTML = function (opts = {}) { 29 | let { 30 | template = '', 31 | component = '', 32 | data = {}, 33 | rootReducer = (() => { 34 | }), 35 | locals = {}, 36 | pageConfig = {}, 37 | needTransform = true 38 | } = opts; 39 | let transformedData = (typeof middlewareConfig.transformer === 'function' && needTransform) 40 | ? middlewareConfig.transformer(data) : data; 41 | let store = configureStore(transformedData, rootReducer); 42 | let html = ''; 43 | pageConfig = Object.assign(typeof middlewareConfig.appConfig === 'object' 44 | ? middlewareConfig.appConfig : {}, pageConfig); 45 | 46 | try { 47 | html = renderToString(( 48 | 49 | 50 | { component } 51 | 52 | 53 | )); 54 | } catch (ex) { 55 | html = 'internal server error: \n' + ex.message; 56 | console.error(ex.message); 57 | } 58 | 59 | let debug = req.query.debug && (req.query.debug === config.application.debugName); 60 | let version = config.application.version; 61 | let jsVersion = ''; 62 | // prefer config version, useful when using CDN config 63 | if (process.env.NODE_ENV === 'production') { 64 | jsVersion = version && version.js; 65 | } else { 66 | jsVersion = getDefaultJSVersion(locals.appName || 'index'); 67 | } 68 | template = template || middlewareConfig.defaultTemplate || defaultTemplate; 69 | 70 | let finalLocals = Object.assign({ 71 | html, 72 | state: safeJSON(data), 73 | appName: 'index', 74 | title: '', 75 | test: process.env.NODE_ENV !== 'production', 76 | debug, 77 | appConfig: safeJSON(pageConfig), 78 | version: { 79 | js: jsVersion, 80 | css: version && version.css 81 | } 82 | }, res.locals, locals); 83 | 84 | let pageStr = ejs.render(template, finalLocals, { 85 | compileDebug: false 86 | }); 87 | 88 | res.status(200).send(pageStr); 89 | }; 90 | 91 | next(); 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /server/middlewares/spaRenderMatch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {renderToString} from 'react-dom/server'; 3 | import {createMemoryHistory, match, RouterContext} from 'react-router'; 4 | import {Provider} from 'react-redux'; 5 | import createRoutes from '../../common/routes'; 6 | import configureStore from '../../common/store/spaStore'; 7 | import preRenderMiddleware from '../utils/preRender'; 8 | import ejs from 'ejs'; 9 | import config from '../config/config.json'; 10 | import { getDefaultJSVersion } from './renderReactMiddleware'; 11 | import App from '../../common/App.jsx'; 12 | import { jsObj as safeJSON } from 'secure-filters'; 13 | import fs from 'fs'; 14 | 15 | const defaultTemplate = fs.readFileSync(__dirname + '/../views/index.html', 'utf8'); 16 | 17 | 18 | export default function renderMatch(req, res) { 19 | const history = createMemoryHistory(); 20 | const store = configureStore({ 21 | user: {} 22 | }, history); 23 | let appConfig = { 24 | time: Date.now() 25 | }; 26 | const routes = createRoutes(store, appConfig); 27 | 28 | match({routes, location: req.originalUrl}, async function (err, redirect, props){ 29 | if (err) { 30 | res.status(500).json(err); 31 | } else if (redirect) { 32 | res.redirect(302, redirect.pathname + redirect.search); 33 | } else if (props) { 34 | let debug = req.query.debug && (req.query.debug === config.application.debugName); 35 | let version = config.application.version; 36 | let jsVersion = ''; 37 | // prefer config version, useful when using CDN config 38 | if (process.env.NODE_ENV === 'production') { 39 | jsVersion = version && version.js; 40 | } else { 41 | jsVersion = getDefaultJSVersion('app'); 42 | } 43 | let initialState = {}; 44 | let componentHTML = ''; 45 | let errorMsg = ''; 46 | 47 | try { 48 | await preRenderMiddleware(store.dispatch, props, appConfig, req); 49 | 50 | componentHTML = renderToString( 51 | 52 | 53 | 54 | 55 | 56 | ); 57 | 58 | initialState = store.getState(); 59 | 60 | } catch(ex){ 61 | errorMsg = ex.stack; 62 | console.log(ex.stack) 63 | } 64 | 65 | let pageStr = ejs.render(defaultTemplate, Object.assign({ 66 | errorMsg, 67 | html: componentHTML, 68 | state: safeJSON(initialState), 69 | appName: 'app', 70 | title: '', 71 | test: process.env.NODE_ENV !== 'production', 72 | debug: debug, 73 | appConfig: safeJSON(appConfig), 74 | version: { 75 | js: jsVersion, 76 | css: version && version.css 77 | } 78 | }, {}), { 79 | compileDebug: false 80 | }); 81 | 82 | res.status(200).send(pageStr); 83 | 84 | } else { 85 | res.redirect('/'); 86 | } 87 | }); 88 | } 89 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import fs from 'fs'; 3 | 4 | let router = new Router(); 5 | 6 | import IndexPage from '../controllers/todo'; 7 | import AsyncPage from '../controllers/async'; 8 | import ChatPage from '../controllers/chat'; 9 | 10 | 11 | /** 12 | * 首页请求 13 | */ 14 | router.get('/', IndexPage); 15 | router.get('/async', AsyncPage); 16 | router.get('/chat', ChatPage); 17 | 18 | 19 | /** 20 | * 静态资源 21 | */ 22 | let content = fs.readFileSync(__dirname + '/../../client/js/utils/sw.js', 'utf8'); 23 | 24 | router.get('/sw.js', async function(req, res){ 25 | res.set('Content-Type', 'application/javascript'); 26 | res.send(content); 27 | }); 28 | 29 | export default router; 30 | -------------------------------------------------------------------------------- /server/sockets/socket.js: -------------------------------------------------------------------------------- 1 | // Keep track of which names are used so that there are no duplicates 2 | let userNames = (function () { 3 | let names = {}; 4 | 5 | let claim = function (name) { 6 | if (!name || names[name]) { 7 | return false; 8 | } else { 9 | names[name] = true; 10 | return true; 11 | } 12 | }; 13 | 14 | // find the lowest unused "guest" name and claim it 15 | let getGuestName = function () { 16 | let name, 17 | nextUserId = 1; 18 | 19 | do { 20 | name = 'Guest ' + nextUserId; 21 | nextUserId += 1; 22 | } while (!claim(name)); 23 | 24 | return name; 25 | }; 26 | 27 | // serialize claimed names as an array 28 | let get = function () { 29 | let res = []; 30 | for (let user in names) { 31 | res.push(user); 32 | } 33 | 34 | return res; 35 | }; 36 | 37 | let free = function (name) { 38 | if (names[name]) { 39 | delete names[name]; 40 | } 41 | }; 42 | 43 | return { 44 | claim: claim, 45 | free: free, 46 | get: get, 47 | getGuestName: getGuestName 48 | }; 49 | }()); 50 | 51 | // export function for listening to the socket 52 | export default function (socket) { 53 | let name = userNames.getGuestName(); 54 | 55 | // send the new user their name and a list of users 56 | socket.emit('init', { 57 | name: name, 58 | users: userNames.get() 59 | }); 60 | 61 | // notify other clients that a new user has joined 62 | socket.broadcast.emit('user:join', { 63 | name: name 64 | }); 65 | 66 | // broadcast a user's message to other users 67 | socket.on('send:message', function (data) { 68 | socket.broadcast.emit('send:message', { 69 | user: name, 70 | text: data.text 71 | }); 72 | }); 73 | 74 | // validate a user's name change, and broadcast it on success 75 | socket.on('change:name', function (data, fn) { 76 | if (userNames.claim(data.name)) { 77 | let oldName = name; 78 | userNames.free(oldName); 79 | 80 | name = data.name; 81 | 82 | socket.broadcast.emit('change:name', { 83 | oldName: oldName, 84 | newName: name 85 | }); 86 | 87 | fn(true); 88 | } else { 89 | fn(false); 90 | } 91 | }); 92 | 93 | // clean up when a user leaves, and broadcast it to other users 94 | socket.on('disconnect', function () { 95 | socket.broadcast.emit('user:left', { 96 | name: name 97 | }); 98 | userNames.free(name); 99 | }); 100 | }; 101 | -------------------------------------------------------------------------------- /server/utils/preRender.js: -------------------------------------------------------------------------------- 1 | function preRenderMiddleware(dispatch, { components, location, params }, appConfig = {}, req) { 2 | const promises = components.map((current) => { 3 | if(!current) return null; 4 | 5 | const component = current.WrappedComponent ? current.WrappedComponent : current; 6 | const pageConfig = component.OriginalPage && component.OriginalPage.pageConfig; 7 | 8 | return component.fetchData ? component.fetchData({ dispatch, location, params, appConfig, pageConfig }, req) : null; 9 | }); 10 | 11 | let lastComponent = components[components.length - 1].WrappedComponent ? components[components.length - 1].WrappedComponent : components[components.length - 1]; 12 | appConfig.pageId = lastComponent && lastComponent.OriginalPage && lastComponent.OriginalPage.pageConfig && lastComponent.OriginalPage.pageConfig.pageId; 13 | 14 | return Promise.all(promises); 15 | } 16 | 17 | export default preRenderMiddleware; 18 | -------------------------------------------------------------------------------- /server/views/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= locals.title %> 10 | <% if(locals.test) { %> 11 | 12 | <% } else { %> 13 | 14 | <% } %> 15 | 16 | 17 | 18 |
    <%- locals.html %>
    19 | 23 | 42 | <% if(locals.debug) { %> 43 | 44 | <% } else if(locals.test){ %> 45 | 46 | <% } else { %> 47 | 48 | <% } %> 49 | 50 | <% if(locals.debug) { %> 51 | 52 | <% } else if(locals.test){ %> 53 | 54 | <% } else { %> 55 | 56 | <% } %> 57 | 58 | 59 | -------------------------------------------------------------------------------- /server/views/error.ejs: -------------------------------------------------------------------------------- 1 | <% include ./partials/header %> 2 |

    <%- message %>

    3 |

    <%- error.status %>

    4 |
    <%- error.stack %>
    5 | <% include ./partials/footer %> 6 | -------------------------------------------------------------------------------- /server/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= locals.title %> 10 | <% if(locals.test) { %> 11 | 12 | <% } else { %> 13 | 14 | <% } %> 15 | 16 | 17 | 18 |
    <%- locals.html %>
    19 | 20 | 24 | 43 | <% if(locals.debug) { %> 44 | 45 | <% } else if(locals.test){ %> 46 | 47 | <% } else { %> 48 | 49 | <% } %> 50 | <% if(locals.debug) { %> 51 | 52 | <% } else if(locals.test){ %> 53 | 54 | <% } else { %> 55 | 56 | <% } %> 57 | 58 | 59 | -------------------------------------------------------------------------------- /starter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let pm2 = require('pm2'); 4 | 5 | const instances = process.env.NODE_ENV === 'production' 6 | ? (process.env.WEB_CONCURRENCY || -1) : 1; // Set by Heroku or -1 to scale to max cpu core -1 7 | const maxMemory = process.env.WEB_MEMORY || 512; // " " " 8 | 9 | pm2.connect(function() { 10 | pm2.start({ 11 | script : './dist/server.js', 12 | name : 'react-ocean', 13 | exec_mode : 'cluster', 14 | instances : instances, 15 | maxMemoryRestart : `${ maxMemory }M`, // Auto restart if process taking more than XXmo 16 | maxRestarts: 5, 17 | minUptime: 5000, 18 | log_file : './log/combined.outer.log', 19 | error_file: './log/err.log', 20 | out_file: './log/out.log', 21 | merge_logs: true, 22 | env: { 23 | "NODE_ENV": "development" 24 | }, 25 | env_testing: { 26 | "NODE_ENV": "test" 27 | }, 28 | env_production: { 29 | "NODE_ENV": "production" 30 | } 31 | }, function(err) { 32 | pm2.disconnect(); // Disconnect from PM2 33 | 34 | if (err) 35 | return console.error('Error while launching applications', err.stack || err); 36 | 37 | console.log('PM2 and application has been successfully started'); 38 | 39 | // Display logs in standard output 40 | pm2.launchBus(function(err, bus) { 41 | console.log('[PM2] Log streaming started'); 42 | bus.on('log:out', function(packet) { 43 | console.log('[App:%s] %s', packet.process.name, packet.data); 44 | }); 45 | bus.on('log:err', function(packet) { 46 | console.error('[App:%s][Err] %s', packet.process.name, packet.data); 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /webpack-assets.json: -------------------------------------------------------------------------------- 1 | {"async":"883364dc66df5d4fa947","todo":"7c925fbf328875163978","chat":"9ed37d333f9142979733"} -------------------------------------------------------------------------------- /webpack.config-server.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs'); 2 | let path = require('path'); 3 | let webpack = require('webpack'); 4 | let packageJson = require('./package.json'); 5 | 6 | 7 | module.exports = { 8 | entry: path.resolve(__dirname, './server/app.js'), 9 | 10 | output: { 11 | path: path.resolve(__dirname, "./dist"), 12 | pathinfo: true, 13 | filename: 'server.js', 14 | libraryTarget: 'commonjs2' 15 | }, 16 | 17 | debug: true, 18 | cache: true, 19 | devtool: 'source-map', 20 | 21 | target: 'node', 22 | 23 | node: { 24 | __filename: true, 25 | __dirname: true 26 | }, 27 | 28 | resolve: { 29 | extensions: ['', '.js', '.jsx'], 30 | modulesDirectories: [ 31 | // 'client', 32 | 'node_modules', 33 | ], 34 | }, 35 | 36 | externals: Object.keys(packageJson.dependencies).filter((item) => { 37 | return (item !== 'react' && item !== 'react-dom') 38 | }).concat([ 39 | // { 40 | // 'react': 'react/dist/react.min.js' 41 | // }, 42 | 'react', 43 | 'react-dom/server' 44 | ]), 45 | 46 | module: { 47 | loaders: [ 48 | { 49 | test: /\.jsx?$/, 50 | exclude: /node_modules/, 51 | loader: 'babel-loader', 52 | // query: { 53 | // presets: [ 54 | // 'react' 55 | // ], 56 | // plugins: [ 57 | // "transform-es2015-modules-commonjs", 58 | // "transform-async-to-generator", 59 | // ] 60 | // }, 61 | }, { 62 | test: /\.json$/, 63 | loader: 'json-loader', 64 | }, 65 | ], 66 | }, 67 | plugins: [ 68 | new webpack.DefinePlugin({ 69 | 'process.env': { 70 | NODE_ENV: JSON.stringify('production') 71 | } 72 | }), 73 | new webpack.BannerPlugin('require("source-map-support").install();', 74 | { raw: true, entryOnly: false }), 75 | new webpack.optimize.OccurrenceOrderPlugin(), 76 | new webpack.optimize.DedupePlugin(), 77 | // new webpack.BannerPlugin('require("source-map-support").install();', 78 | // { raw: true, entryOnly: false }), 79 | new webpack.IgnorePlugin(/(\.(css|less)$)|zepto/) 80 | ], 81 | }; 82 | 83 | --------------------------------------------------------------------------------