diff --git a/package.json b/package.json index d5855ac..030f981 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,10 @@ "description": "Gogo - React Bootstrap 4 Admin Dashboard Template", "private": true, "dependencies": { + "@babel/cli": "^7.12.10", + "@babel/preset-react": "^7.12.10", + "@babel/register": "^7.12.10", + "@babel/runtime": "^7.12.5", "@glidejs/glide": "^3.4.1", "@rodrigogs/mysql-events": "^0.6.0", "@tensorflow/tfjs": "^2.3.0", @@ -40,6 +44,8 @@ "firebase": "^7.16.0", "formik": "^2.1.4", "http": "0.0.1-security", + "https": "^1.0.0", + "ignore-styles": "^5.0.1", "moment": "2.27.0", "mousetrap": "^1.6.5", "mysql": "^2.18.1", @@ -100,6 +106,8 @@ "eject": "react-scripts eject", "server": "nodemon server/app", "dev": "HTTPS=true concurrently \"npm run server\" \"npm run start\"", + "start-ssr-server": "nodemon server/ssr/parser", + "ssr-dev": "cross-env HTTPS=true concurrently \"npm run server\" \"npm run start-ssr-server\"", "lint": "eslint --debug src/", "lint:write": "eslint --debug src/ --fix", "precommit": "lint-staged" diff --git a/server/api/orderBook.js b/server/api/orderBook.js index cdb54b6..8745945 100644 --- a/server/api/orderBook.js +++ b/server/api/orderBook.js @@ -26,7 +26,7 @@ const monitorOrderBookDB = async (pool, io) => { statement: MySQLEvents.STATEMENTS.ALL, // all type of operations, for insert alone MySQLEvents.STATEMENTS.INSERT, onEvent: () => { let result; - pool.query('SELECT glass from history_siz0 ORDER BY id DESC LIMIT 1', (err, rows) => { + pool.query('SELECT glass from history_si ORDER BY id DESC LIMIT 1', (err, rows) => { if (err) { return res.end('{}'); } @@ -60,7 +60,7 @@ router.get('/', (req, res) => { console.log('Connection Established, Monitoring DB for any change.'), ) .catch(console.error); - pool.query('SELECT glass from history_siz0 ORDER BY id DESC LIMIT 1', (err, rows) => { + pool.query('SELECT glass from history_si ORDER BY id DESC LIMIT 1', (err, rows) => { if (err) { console.log('err is', err); return res.end('{}'); diff --git a/server/ssr/middleware/serverRenderer.js b/server/ssr/middleware/serverRenderer.js new file mode 100644 index 0000000..b90269e --- /dev/null +++ b/server/ssr/middleware/serverRenderer.js @@ -0,0 +1,62 @@ +const path = require('path') +const fs = require('fs') + +const React = require('react') +const {Provider} = require('react-redux') +const {renderToString} = require('react-dom/server') +const {StaticRouter} = require('react-router-dom') +import { IntlProvider } from 'react-intl'; +import { createMemoryHistory } from 'history'; + +const history = createMemoryHistory(); + +const { configureStore } = require('../../../src/redux/store') +const Login = require('../../../src/views/user/login').default +import enLang from '../../../src/lang/entries/en-US'; + + +module.exports = function serverRenderer(req, res, next) { + if(req._possible404){ + res.sendFile(path.join(__dirname, '..', '..', '..', 'build', 'index.html')); + } else { + if(req.path == "/user/login") { + const filePath = path.resolve(__dirname, '..', '..', '..', 'build', 'index.html'); + + fs.readFile(filePath, 'utf8', (err, htmlData)=>{ + if (err) { + console.error('read err', err) + return res.status(404).end() + } + const context = {} + const store = configureStore(); + const markup = renderToString( + + <> + + + + + + + + ) + + if (context.url) { + // Somewhere a `` was rendered + res.redirect(301, context.url) + } else { + // we're good, send the response + const RenderedApp = htmlData.replace('
', `${markup}`) + res.send(RenderedApp) + } + }) + } else { + req._possible404 = true; + //res.sendFile(path.join(__dirname, '..', '..', '..','build', 'index.html')); + return next(); + } + } +} \ No newline at end of file diff --git a/server/ssr/parser.js b/server/ssr/parser.js new file mode 100644 index 0000000..2205094 --- /dev/null +++ b/server/ssr/parser.js @@ -0,0 +1,19 @@ +require('ignore-styles'); +require('@babel/register')({ + ignore: [ /\/(build|node_modules)\// ], + presets: [ + '@babel/preset-env', + '@babel/preset-react', + ], + plugins: [ + ['@babel/transform-runtime'], + [ + '@babel/plugin-proposal-class-properties', + { + "loose": true + } + ] + ] +}); + +require('./ssrServer'); \ No newline at end of file diff --git a/server/ssr/security/server.cert b/server/ssr/security/server.cert new file mode 100644 index 0000000..d11aa5c --- /dev/null +++ b/server/ssr/security/server.cert @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIClTCCAf6gAwIBAgIJAJvkiXzGlK/RMA0GCSqGSIb3DQEBBQUAMDwxCzAJBgNV +BAYTAklOMQwwCgYDVQQIEwNBQkMxDDAKBgNVBAcTA0FCQzERMA8GA1UEChMIb3Bl +eGZsb3cwHhcNMjAxMjI5MTM1ODE1WhcNMjEwMTI4MTM1ODE1WjA8MQswCQYDVQQG +EwJJTjEMMAoGA1UECBMDQUJDMQwwCgYDVQQHEwNBQkMxETAPBgNVBAoTCG9wZXhm +bG93MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgXNmOJ/VJ/LCywLhx5kqD +7ShSZ9sPkUWDXLBkaKtrkdarIIRuFghzwh74Fbwk++G0rHw51luNZnx80+jZyYt6 +M+NMO3yqENc8upIfGmZV1YNqdB73PRvYIQA42U5D6z2eNzgXq1v14kGKPAlxQHob +rVyPSJzkYxUQoJZfM0GGEQIDAQABo4GeMIGbMB0GA1UdDgQWBBR2kizL+BGMcDJY +BzJ699f1wcQs9TBsBgNVHSMEZTBjgBR2kizL+BGMcDJYBzJ699f1wcQs9aFApD4w +PDELMAkGA1UEBhMCSU4xDDAKBgNVBAgTA0FCQzEMMAoGA1UEBxMDQUJDMREwDwYD +VQQKEwhvcGV4Zmxvd4IJAJvkiXzGlK/RMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQEFBQADgYEAEI8Cj47WYYHEgxLjjbRXEZtB4vX5yRuMFyrgLsmlUghrBoG7EEiB +WAODThW4D+X3rhYIYKKVKobyN6ZjX9zqGcSgpXEQTm5c9kFIMctZdYgrDAQBb3lY +hOvkRbmxKZU3ZshUrIi9vAsb6yqcUdX0FziWyWLbbK5yYdg0wGxU3jU= +-----END CERTIFICATE----- diff --git a/server/ssr/security/server.key b/server/ssr/security/server.key new file mode 100644 index 0000000..49785da --- /dev/null +++ b/server/ssr/security/server.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDgXNmOJ/VJ/LCywLhx5kqD7ShSZ9sPkUWDXLBkaKtrkdarIIRu +Fghzwh74Fbwk++G0rHw51luNZnx80+jZyYt6M+NMO3yqENc8upIfGmZV1YNqdB73 +PRvYIQA42U5D6z2eNzgXq1v14kGKPAlxQHobrVyPSJzkYxUQoJZfM0GGEQIDAQAB +AoGAFcGLKxi+1VzWeY7sk8bkBOTzWwJNILZSiklrpWDs9nJe4Zs2nEIwsaDqRd49 +r0xpd46eQTGDETQV8DjQRIYhqxptm2A2Vzs8knDCOTjTFqvJb89WWI1G2vY+pG1S +trkFhKdS3I1C7ffghN21n6Pggryzzug0FWwUpdOlw4LGqV0CQQD0wBTGVcLjRo4d +OjL0+tBbEhOjuY2YpWIxPAtOMPJvuugXwX/FfKCJo4g2jFHiFFqJPzlM/QYa/r/n +j3B6W+67AkEA6qzfUz6xS8kXdWVguVPa7I+RWs2W751nrBs+Qym5Q0P2lRwfSPMk +u2mRyHru40krPRF30gMkKpjWNaO/sKG/owJAXlaPa2dxKENw0ck2DQGEQCY2lbwW +3QiaUZnwTaJGQFTN0yJNiqSgCI2VGll50mfAAfjxsEAzE0KwW6QJWdCHswJBAKpJ +BMg/7qDiaz5JcNUp7urHBp9QHV0D581v+077AK65qzzpqh3iKN5BLYK/CYctec2X +Vk2y79RlENLdXmRKCmcCQG6Wtk8wgGTNkRscL7Mvc9J+k21N1EjcHGWcGDOgNJhV +JvrAQdaVstdKBtz9nA1j7W4pMAX88Okv5sdANAMkXAA= +-----END RSA PRIVATE KEY----- diff --git a/server/ssr/ssrServer.js b/server/ssr/ssrServer.js new file mode 100644 index 0000000..477c2f0 --- /dev/null +++ b/server/ssr/ssrServer.js @@ -0,0 +1,22 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); +const https = require('https'); +const serverRenderer = require('./middleware/serverRenderer'); + +const PORT = 3000; + +const ssrApp = express(); + +ssrApp.get('/*', serverRenderer); + +ssrApp.use(express.static(path.resolve(__dirname, '..', '..', 'build'))); + +ssrApp.use(serverRenderer); + +const httpsServer = https.createServer({ + key: fs.readFileSync(__dirname + '/security/server.key'), + cert: fs.readFileSync(__dirname + '/security/server.cert') +}, ssrApp); + +httpsServer.listen(PORT, () => console.log(`Client listening on port ${PORT}!`)); \ No newline at end of file diff --git a/src/redux/auth/reducer.js b/src/redux/auth/reducer.js index 86e349c..6cc5906 100644 --- a/src/redux/auth/reducer.js +++ b/src/redux/auth/reducer.js @@ -15,7 +15,7 @@ import { } from '../actions'; const INIT_STATE = { - user: localStorage.getItem('user_id'), + user: typeof localStorage == 'undefined' ? '' : localStorage.getItem('user_id'), forgotUserMail: '', newPassword: '', resetPasswordCode: '', diff --git a/src/redux/settings/reducer.js b/src/redux/settings/reducer.js index 387f24b..d425594 100644 --- a/src/redux/settings/reducer.js +++ b/src/redux/settings/reducer.js @@ -5,7 +5,7 @@ import { } from '../actions'; const INIT_STATE = { - locale: (localStorage.getItem('currentLanguage') && localeOptions.filter(x => x.id === localStorage.getItem('currentLanguage')).length > 0) ? localStorage.getItem('currentLanguage') : defaultLocale, + locale: typeof localStorage == 'undefined' ? 'en' : ((localStorage.getItem('currentLanguage') && localeOptions.filter(x => x.id === localStorage.getItem('currentLanguage')).length > 0) ? localStorage.getItem('currentLanguage') : defaultLocale), }; export default (state = INIT_STATE, action) => { diff --git a/src/views/user/login.js b/src/views/user/login.js index 9c766b8..348c9d9 100644 --- a/src/views/user/login.js +++ b/src/views/user/login.js @@ -72,7 +72,7 @@ class Login extends Component { } render() { - let host = `https://${window.location.host}`; + let host = typeof window == 'undefined' ? `https://${this.props.serverRequest.headers.host}` : `https://${window.location.host}`; if (host.indexOf(3000) !== -1) { host = host.replace('3000', '3001').replace('https', 'http'); }