Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/using hapi #8

Open
wants to merge 8 commits into
base: react-router
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13,984 changes: 13,984 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

49 changes: 33 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,47 @@
"private": false,
"homepage": "./",
"dependencies": {
"babel-plugin-dynamic-import-node": "^2.0.0",
"@babel/register": "^7.4.4",
"@hapi/hapi": "^18.3.1",
"@hapi/inert": "^5.2.0",
"babel-plugin-dynamic-import-node": "^2.3.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react-app": "^3.1.1",
"express": "^4.16.2",
"file-loader": "^1.1.6",
"bootstrap": "^4.3.1",
"express": "^4.17.1",
"file-loader": "^4.0.0",
"ignore-styles": "^5.0.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-helmet": "^5.2.0",
"react-loadable": "^5.3.1",
"react-redux": "^5.0.6",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-scripts": "^1.1.4",
"redux": "^4.0.0",
"node-sass": "^4.12.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1",
"react-loadable": "^5.5.0",
"react-redux": "^7.1.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "^3.0.1",
"reactstrap": "^8.0.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"url-loader": "^1.0.1"
"url-loader": "^2.0.0"
},
"resolutions": {
"babel-core": "7.0.0-bridge.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"server": "NODE_ENV=production node server/bootstrap.js"
"server": "npm run build && SET NODE_ENV=production && nodemon server/bootstrap.js",
"serve:development": "npm run build && SET NODE_ENV=development && nodemon server/bootstrap.js"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"devDependencies": {
"babel-polyfill": "^6.26.0"
}
}
7 changes: 4 additions & 3 deletions server/bootstrap.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
require('ignore-styles');
require('url-loader');
require('file-loader');
require('babel-register')({
require('@babel/register')({
ignore: [ /(node_modules)/ ],
presets: ['es2015', 'react-app'],
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
'syntax-dynamic-import',
'dynamic-import-node',
'react-loadable/babel'
]
});
require('./index');
// require('./index');
require('./index-hapi');
85 changes: 85 additions & 0 deletions server/controllers/index-hapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import 'babel-polyfill';
import hapi from '@hapi/hapi';
import Inert from '@hapi/inert';
import path from "path";

import serverRenderer from '../middleware/renderer';
import configureStore from '../../src/store/configureStore';

const router = express.Router();

const init = async () => {

const server = hapi.server({
port: 1030,
host: 'localhost'
});

await server.register(Inert);

// Serve static files
server.route({
method: 'GET',
path: '/{filepath*}',
config: {
auth: false,
// cache: {
// expiresIn: 24 * 60 * 60 * 1000,
// privacy: 'public'
// }
},
handler: {
directory: {
path: path.join(__dirname, '../../build'),
listing: false,
index: false
}
}
});

server.route({
method: 'GET',
path:'/',
handler: (request, reply) => {
const context = { };
const jsx = (
<StaticRouter context={ context } location={ request.url }>
<Layout />
</StaticRouter>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I don't see StaticRouter or Layout in scope of this file...

);
const reactDom = renderToString( jsx );
return htmlTemplate( reactDom );
}
});

await server.start();
console.log('Server running on %s', server.info.uri);
};

process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});

init();

const actionIndex = (req, res, next) => {
const store = configureStore();
serverRenderer(store)(req, res, next);
};


// root (/) should always serve our server rendered page
router.use('^/$', actionIndex);

// other static resources should just be served as they are
router.use(express.static(
path.resolve(__dirname, '..', '..', 'build'),
{ maxAge: '30d' },
));

// any other route should be handled by react-router, so serve the index page
router.use('*', actionIndex);


export default router;
9 changes: 5 additions & 4 deletions server/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ const path = require("path");

const actionIndex = (req, res, next) => {
const store = configureStore();
serverRenderer(store)(req, res, next);

store.dispatch(setAsyncMessage("Hi, I'm from server!"))
.then(() => {
serverRenderer(store)(req, res, next);
});
// store.dispatch(setAsyncMessage(`Hi, I'm from server!`))
// .then(() => {
// serverRenderer(store)(req, res, next);
// });
};


Expand Down
78 changes: 78 additions & 0 deletions server/index-hapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'babel-polyfill';
import hapi from '@hapi/hapi';
import Inert from '@hapi/inert';
import path from "path";
import Loadable from 'react-loadable';

import serverRenderer from './middleware/renderer';
import configureStore from '../src/store/configureStore';

const init = async () => {

const server = hapi.server({
port: 1030,
host: 'localhost'
});

await server.register(Inert);

// Serve static files
server.route({
method: 'GET',
path: '/{filepath*}',
config: {
auth: false,
cache: {
expiresIn: 24 * 60 * 60 * 1000,
privacy: 'public'
}
},
handler: {
directory: {
path: path.join(__dirname, '../build'),
listing: false,
index: false
}
}
});

server.route([{
method: 'GET',
path:'/',
handler: async (request, reply) => {
const store = configureStore();
const htmlToRender = await serverRenderer(store)(request, reply);
if(!htmlToRender){
console.log(`Error occured!`);
}
console.log(`${JSON.stringify(request.params)}`);
return htmlToRender
}
}, {
method: 'GET',
path:'/another',
handler: async (request, reply) => {
return reply.redirect('/');
// const store = configureStore();
// const htmlToRender = await serverRenderer(store)(request, reply);
// if(!htmlToRender){
// console.log(`Error occured!`);
// }
// console.log(`${JSON.stringify(request.params)} - ${server.info.uri}`);
// return htmlToRender
}
}]);

await server.start();
console.log('Server running on %s', server.info.uri);

};

process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});

Loadable.preloadAll().then(() => {
init();
});
6 changes: 3 additions & 3 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Loadable from 'react-loadable';

import indexController from './controllers/index';

const PORT = 3000;
const PORT = 1030;

// initialize the application and create the routes
const app = express();
Expand All @@ -14,9 +14,9 @@ app.use(indexController);
Loadable.preloadAll().then(() => {
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
return console.log(`something bad happened`, error);
}

console.log("listening on " + PORT + "...");
console.log(`listening on ${PORT}...`);
});
});
78 changes: 38 additions & 40 deletions server/middleware/renderer.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'babel-polyfill';
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import Loadable from 'react-loadable';
Expand All @@ -6,7 +7,7 @@ import { StaticRouter } from 'react-router';
import { Helmet } from 'react-helmet';

// import our main App component
import App from '../../src/App';
import App from '../../src/App.jsx';

// import the manifest generated with the create-react-app build
import manifest from '../../build/asset-manifest.json';
Expand All @@ -20,51 +21,48 @@ const path = require("path");
const fs = require("fs");


export default (store) => (req, res, next) => {
export default (store) => async (req, res) => {
// get the html file created with the create-react-app build
const filePath = path.resolve(__dirname, '..', '..', 'build', 'index.html');
const filePath = await path.resolve(__dirname, '..', '..', 'build', 'index.html');
// console.log(`error logged! ${filePath}`);

fs.readFile(filePath, 'utf8', (err, htmlData) => {
if (err) {
console.error('err', err);
return res.status(404).end()
}
const htmlContext = await fs.readFileSync(filePath, 'utf8');
const modules = [];
const routerContext = {};

const modules = [];
const routerContext = {};
if (htmlContext instanceof Error) {
return htmlContext;
}

// render the app as a string
const html = ReactDOMServer.renderToString(
<Loadable.Capture report={m => modules.push(m)}>
<ReduxProvider store={store}>
<StaticRouter location={req.baseUrl} context={routerContext}>
<App/>
</StaticRouter>
</ReduxProvider>
</Loadable.Capture>
);
// render the app as a string
const html = await ReactDOMServer.renderToString(
<Loadable.Capture report={m => modules.push(m)}>
<ReduxProvider store={store}>
<StaticRouter location={req.baseUrl} context={routerContext}>
<App/>
</StaticRouter>
</ReduxProvider>
</Loadable.Capture>
);

// get the stringified state
const reduxState = JSON.stringify(store.getState());
// get the stringified state
const reduxState = await JSON.stringify(store.getState());

// map required assets to script tags
const extraChunks = extractAssets(manifest, modules)
.map(c => `<script type="text/javascript" src="/${c}"></script>`);
// map required assets to script tags
const extraChunks = await extractAssets(manifest, modules)
.map(c => `<script type="text/javascript" src="/${c}"></script>`);

// get HTML headers
const helmet = Helmet.renderStatic();
// get HTML headers
const helmet = await Helmet.renderStatic();

// now inject the rendered app into our html and send it to the client
return res.send(
htmlData
// write the React app
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
// write the string version of our state
.replace('__REDUX_STATE__={}', `__REDUX_STATE__=${reduxState}`)
// append the extra js assets
.replace('</body>', extraChunks.join('') + '</body>')
// write the HTML header tags
.replace('<title></title>', helmet.title.toString() + helmet.meta.toString())
);
});
// now inject the rendered app into our html and send it to the client
return htmlContext
// write the React app
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
// write the string version of our state
.replace('__REDUX_STATE__={}', `__REDUX_STATE__=${reduxState}`)
// append the extra js assets
.replace('</body>', extraChunks.join('') + '</body>')
// write the HTML header tags
.replace('<title></title>', helmet.title.toString() + helmet.meta.toString());
}
Loading