overflow_app/src/ts/@overflow/app/index.tsx
crusader 7fa7da15c9 ing
2017-07-25 19:29:14 +09:00

245 lines
6.0 KiB
TypeScript

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
applyMiddleware,
compose,
createStore,
GenericStoreEnhancer,
Middleware,
Store,
} from 'redux';
import {
Provider,
} from 'react-redux';
import {
ConnectedRouter,
routerMiddleware,
} from 'react-router-redux';
import createSagaMiddleware, {
SagaMiddleware,
SagaIterator,
} from 'redux-saga';
import {
fork,
} from 'redux-saga/effects';
import {
createHashHistory,
History,
} from 'history';
import {
AppContainer,
} from 'react-hot-loader';
import * as injectTapEventPlugin from 'react-tap-event-plugin';
import Platform from '@overflow/commons/platform';
import AppContext from '@overflow/commons/context';
import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle';
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
import ReducerContext from '@overflow/commons/redux/ReducerContext';
import { SagaWatcher } from '@overflow/commons/redux-saga';
import appConfig, { Config, ReduxState } from './config';
import App from './views/App';
injectTapEventPlugin();
// const isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
// const useReduxDevTools = window.devToolsExtension && !isProduction ? true : false;
class Application {
private static isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
private static useReduxDevTools:boolean = window.devToolsExtension && !Application.isProduction ? true : false;
private config: Config;
private container: HTMLElement;
private context: AppContext;
private rpcClient: WebSocketRPC;
private store: Store<any>;
private sagaMiddleware: SagaMiddleware<any>;
private history: History;
public constructor() {
this.config = appConfig;
this.history = createHashHistory();
}
public static Run(): void {
let application = new Application();
application.start();
}
private async start(): Promise<void> {
try {
this.container = await Platform.getAppContainer(this.config.container.placeholderID);
this.displayLoading();
this.context = await this.initContext();
// this.rpcClient = await this.initRpcClient();
// this.context.put(this.rpcClient);
await this.initRedux();
this.store.dispatch(AppContextLifecycleActions.initialized());
this.displayApp();
} catch (e) {
console.error(e);
this.displayError(e);
}
}
private initContext(): Promise<AppContext> {
const appContext = new Promise<AppContext>(resolve => {
const context = AppContext.getContext();
resolve(context);
});
return appContext;
}
private initRpcClient(): Promise<WebSocketRPC> {
const rpcClient = new Promise<WebSocketRPC>((resolve, reject) => {
let client = new WebSocketRPC(this.config.rpc.url);
client.initialize()
.then(() => {
resolve(client);
})
.catch((err: any) => {
reject(err);
});
});
return rpcClient;
}
private initRedux(): Promise<void> {
const init = new Promise<void>(resolve => {
// state tree
// reducer
for (let reducerMap of this.config.redux.reducerMaps) {
ReducerContext.putReducers(reducerMap);
}
// middleware
let middlewares: Middleware[] = new Array();
this.sagaMiddleware = createSagaMiddleware();
middlewares.push(this.sagaMiddleware);
let routerReduxMiddleware = routerMiddleware(this.history);
middlewares.push(routerReduxMiddleware);
// store
let middleware: GenericStoreEnhancer = applyMiddleware(...middlewares);
this.store = createStore(
ReducerContext.reducer,
this.config.redux.state,
Application.useReduxDevTools ? compose(middleware, window.devToolsExtension()) : middleware,
);
// saga
this.sagaMiddleware.run(this.initReduxSagaWarchers, this.config.redux.sagaWarchers);
resolve();
});
return init;
}
private * initReduxSagaWarchers(sagaWarchers: (SagaWatcher[])[]): SagaIterator {
for (let sagaWarcher of sagaWarchers) {
for (let warcher of sagaWarcher) {
yield fork(warcher);
}
}
}
private displayLoading(): void {
ReactDOM.render(
<div style={{
width: '100vw',
height: '100vh',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<h1>Loading...</h1>
</div>,
this.container,
);
}
private displayError(e: Error): void {
ReactDOM.render(
<div style={{
width: '100vw',
height: '100vh',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<h1>{e.message}</h1>
</div>,
this.container,
);
}
private displayApp(): void {
Application.isProduction ? this.displayProductionApp() : this.displayDebugApp();
}
private displayProductionApp(): void {
ReactDOM.render(
<Provider store={this.store}>
<ConnectedRouter history={this.history}>
<App />
</ConnectedRouter>
</Provider>,
this.container,
);
}
private displayDebugApp(): void {
if (module.hot) {
module.hot.accept('./views/App', async () => {
const NextApp = (await import('./views/App')).default;
ReactDOM.render(
<AppContainer>
<Provider store={this.store}>
<ConnectedRouter history={this.history}>
<NextApp />
</ConnectedRouter>
</Provider>
</AppContainer>
,
this.container,
);
});
}
ReactDOM.render(
<AppContainer>
<Provider store={this.store}>
<ConnectedRouter history={this.history}>
<App />
</ConnectedRouter>
</Provider>
</AppContainer>
,
this.container,
);
}
}
Application.Run();