diff --git a/index.ts b/index.ts index f4d687a6b5fe01444c0a69d529c1273aed93a1b0..fe390a142b4080e7052bf9a154c995f93229ee3d 100755 --- a/index.ts +++ b/index.ts @@ -1,4 +1,4 @@ -let server = require('./server').default; +let server = require('./src/server').default; const PORT = process.env.PORT || 3000; diff --git a/server.tsx b/server.tsx deleted file mode 100644 index b4c71a8d1736eb0ed9d239246d07bd3c23c7c41d..0000000000000000000000000000000000000000 --- a/server.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import * as express from 'express'; -import * as proxy from 'express-http-proxy'; -import * as React from 'react'; -import {renderToString} from 'react-dom/server'; -import {RouterContext, match} from 'react-router'; -import {createLocation} from 'history'; -import routes from './assets/components/routes'; -import {Provider} from 'react-redux'; -import rootReducer from './assets/reducers'; -import fetchComponentData from './assets/middleware/fetchComponentData'; -import * as serialize from 'serialize-javascript'; -import {browserHistory} from 'react-router'; -import {routerMiddleware} from 'react-router-redux'; -import { - createStore, - applyMiddleware, -} from 'redux'; - -import 'path'; -import * as path from 'path'; -import * as fs from 'fs'; -import thunk from 'redux-thunk'; -import * as cookieParser from 'cookie-parser'; -import config from './config/config'; -import checkAuthToken from './assets/middleware/checkAuthToken'; - -const app = express(); - -const html = fs.readFileSync(__dirname + '/react.html', {encoding: 'utf8'}); - -app.use('/proxy', proxy(config.apiUrl, { - filter: function(req, res) { - if (req.url.indexOf('/api') === 0) { - console.log(req.headers['authorization']); - return typeof req.headers['authorization'] !== 'undefined'; - } - return true; - }, - proxyReqPathResolver(req) { - let path = req.url; - if (path.indexOf('/oauth/token') === 0) { - const grantType = req.query['grant_type']; - if(grantType === 'client_credentials' || grantType === 'password') { - path = `${path}&client_id=${config.clientId}&client_secret=${config.clientSecret}`; - } - } else if (path.indexOf('/google/verify-token') === 0) { - path = `${path}&clientId=${config.clientId}`; - } - return path; - }, -})); - -app.use(express.static(path.join(__dirname))); -app.use(cookieParser()); -app.use((req, res) => { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Headers', 'X-Requested-With'); - const location = createLocation(req.url); - const store = applyMiddleware(thunk, routerMiddleware(browserHistory))(createStore)(rootReducer); - - match({routes, location}, (err, redirectLocation, renderProps) => { - if (err) { - console.error(err); - return res.status(500).end('Internal server error'); - } - - if (!renderProps) { - return res.status(404).end('Not found'); - } - - if (redirectLocation) { - // todo - } - function renderView() { - const InitialView = ( - - - - ); - - const componentHTML = renderToString(InitialView); - - const initialState = store.getState(); - - return html.replace('SERVER_RENDERED_HTML', componentHTML) - .replace('SERVER_RENDERED_STATE', serialize(initialState, {isJSON: true})); - } - - checkAuthToken(req, res, store.dispatch) - .then(() => fetchComponentData(store.dispatch, renderProps.components, renderProps.params)) - .then(renderView) - .then((template) => res.end(template)) - .catch((err) => res.end(err.message)); - }); -}); - -export default app; diff --git a/src/middlewares/httpProxy.ts b/src/middlewares/httpProxy.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8906d6608f576aad0bc254afba718580d0c231a --- /dev/null +++ b/src/middlewares/httpProxy.ts @@ -0,0 +1,26 @@ +import * as proxy from 'express-http-proxy'; +import config from '../../config/config'; + +const httpProxy = proxy(config.apiUrl, { + filter: function(req, res) { + if (req.url.indexOf('/api') === 0) { + console.log(req.headers['authorization']); + return typeof req.headers['authorization'] !== 'undefined'; + } + return true; + }, + proxyReqPathResolver(req) { + let path = req.url; + if (path.indexOf('/oauth/token') === 0) { + const grantType = req.query['grant_type']; + if(grantType === 'client_credentials' || grantType === 'password') { + path = `${path}&client_id=${config.clientId}&client_secret=${config.clientSecret}`; + } + } else if (path.indexOf('/google/verify-token') === 0) { + path = `${path}&clientId=${config.clientId}`; + } + return path; + }, +}); + +export default httpProxy; diff --git a/src/middlewares/prerenderer.tsx b/src/middlewares/prerenderer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..822f59d17b8aa06fcb5787b3af0ec7b3b204aeeb --- /dev/null +++ b/src/middlewares/prerenderer.tsx @@ -0,0 +1,59 @@ +import * as React from 'react'; +import {renderToString} from 'react-dom/server'; +import {RouterContext, match} from 'react-router'; +import {createLocation} from 'history'; +import {Provider} from 'react-redux'; +import * as serialize from 'serialize-javascript'; +import {browserHistory} from 'react-router'; +import {routerMiddleware} from 'react-router-redux'; +import {createStore, applyMiddleware} from 'redux'; +import thunk from 'redux-thunk'; + +import routes from '../../assets/components/routes'; +import rootReducer from '../../assets/reducers'; +import fetchComponentData from '../../assets/middleware/fetchComponentData'; +import checkAuthToken from '../../assets/middleware/checkAuthToken'; + +const prerenderer = (html) => (req, res) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Headers', 'X-Requested-With'); + const location = createLocation(req.url); + const store = applyMiddleware(thunk, routerMiddleware(browserHistory))(createStore)(rootReducer); + + match({routes, location}, (err, redirectLocation, renderProps) => { + if (err) { + console.error(err); + return res.status(500).end('Internal server error'); + } + + if (!renderProps) { + return res.status(404).end('Not found'); + } + + if (redirectLocation) { + // todo + } + function renderView() { + const InitialView = ( + + + + ); + + const componentHTML = renderToString(InitialView); + + const initialState = store.getState(); + + return html.replace('SERVER_RENDERED_HTML', componentHTML) + .replace('SERVER_RENDERED_STATE', serialize(initialState, {isJSON: true})); + } + + checkAuthToken(req, res, store.dispatch) + .then(() => fetchComponentData(store.dispatch, renderProps.components, renderProps.params)) + .then(renderView) + .then((template) => res.end(template)) + .catch((err) => res.end(err.message)); + }); +}; + +export default prerenderer; \ No newline at end of file diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000000000000000000000000000000000000..58119de54d8d478ae4f71de3a603282f54ff5893 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,22 @@ +import * as express from 'express'; +import * as path from 'path'; +import * as cookieParser from 'cookie-parser'; +import {readFileSync} from 'fs'; + +import prerenderer from './middlewares/prerenderer'; +import httpProxy from './middlewares/httpProxy'; +import robots from './utils/robots'; + +__dirname = __dirname + '/../'; + +const app = express(); + +const html = readFileSync(__dirname + '/react.html', {encoding: 'utf8'}); + +app.use('/proxy', httpProxy); +app.get('/robots.txt', robots); +app.use(express.static(path.join(__dirname))); +app.use(cookieParser()); +app.use(prerenderer(html)); + +export default app; diff --git a/src/utils/robots.ts b/src/utils/robots.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ba0fe188f4e677182b153b8ac83265e1ef33a06 --- /dev/null +++ b/src/utils/robots.ts @@ -0,0 +1,8 @@ +const robots = (req, res) => { + const allow = process.env.ALLOW_ROBOTS === 'true' ? 'Allow: /': 'Disallow: /'; + + res.type('text/plain'); + res.send('User-Agent: *\n' + allow); +}; + +export default robots;