Skip to content

Commit 409557e

Browse files
committed
Upload all File from local
0 parents commit 409557e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+12899
-0
lines changed

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# See https://help.github.com/ignore-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
6+
# testing
7+
/coverage
8+
9+
# production
10+
/build
11+
12+
# misc
13+
.DS_Store
14+
.env.local
15+
.env.development.local
16+
.env.test.local
17+
.env.production.local
18+
19+
npm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*

README.md

Lines changed: 2444 additions & 0 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "simple-react-web",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"axios": "^0.18.0",
7+
"connected-react-router": "^4.3.0",
8+
"cookie-parser": "^1.4.3",
9+
"font-awesome": "^4.7.0",
10+
"forcedomain": "^1.0.0",
11+
"gh-pages": "^1.2.0",
12+
"ignore-styles": "^5.0.1",
13+
"js-cookie": "^2.2.0",
14+
"md5-file": "^4.0.0",
15+
"morgan": "^1.9.0",
16+
"react": "^16.4.1",
17+
"react-dom": "^16.4.1",
18+
"react-frontload": "^1.0.1",
19+
"react-helmet": "^5.2.0",
20+
"react-loadable": "^5.4.0",
21+
"react-redux": "^5.0.7",
22+
"react-router-dom": "^4.3.1",
23+
"react-scripts": "1.1.4",
24+
"redux": "^4.0.0",
25+
"redux-form": "^7.4.2",
26+
"redux-logger": "^3.0.6",
27+
"redux-promise-middleware": "^5.1.1",
28+
"semantic-ui-css": "^2.3.3",
29+
"semantic-ui-react": "^0.82.0",
30+
"validatorjs": "^3.14.2"
31+
},
32+
"scripts": {
33+
"start": "react-scripts start",
34+
"build": "react-scripts build",
35+
"test": "react-scripts test --env=jsdom",
36+
"eject": "react-scripts eject",
37+
"serve": "NODE_ENV=production node ./server/index.js"
38+
}
39+
}

public/favicon.ico

3.78 KB
Binary file not shown.

public/index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta name="theme-color" content="#000000">
7+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
8+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
9+
<title>Home | Simple Website</title>
10+
</head>
11+
<body>
12+
<noscript>
13+
You need to enable JavaScript to run this app.
14+
</noscript>
15+
<div id="root"></div>
16+
</body>
17+
</html>

public/manifest.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"short_name": "SRW",
3+
"name": "Simple React Web",
4+
"icons": [
5+
{
6+
"src": "favicon.ico",
7+
"sizes": "64x64 32x32 24x24 16x16",
8+
"type": "image/x-icon"
9+
}
10+
],
11+
"start_url": "./index.html",
12+
"display": "standalone",
13+
"theme_color": "#000000",
14+
"background_color": "#ffffff"
15+
}

server/index.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const md5File = require('md5-file');
2+
const path = require('path');
3+
4+
// CSS styles will be imported on load and that complicates matters... ignore those bad boys!
5+
const ignoreStyles = require('ignore-styles');
6+
const register = ignoreStyles.default;
7+
8+
// We also want to ignore all image requests
9+
// When running locally these will load from a standard import
10+
// When running on the server, we want to load via their hashed version in the build folder
11+
const extensions = ['.gif', '.jpeg', '.jpg', '.png', '.svg'];
12+
13+
// Override the default style ignorer, also modifying all image requests
14+
register(ignoreStyles.DEFAULT_EXTENSIONS, (mod, filename) => {
15+
if (!extensions.find(f => filename.endsWith(f))) {
16+
// If we find a style
17+
return ignoreStyles.noOp();
18+
} else {
19+
// If we find an image
20+
const hash = md5File.sync(filename).slice(0, 8);
21+
const bn = path.basename(filename).replace(/(\.\w{3})$/, `.${hash}$1`);
22+
23+
mod.exports = `/static/media/${bn}`;
24+
}
25+
});
26+
27+
// Set up babel to do its thing... env for the latest toys, react-app for CRA
28+
// Notice three plugins: the first two allow us to use import rather than require, the third is for code splitting
29+
require('babel-register')({
30+
ignore: /\/(build|node_modules)\//,
31+
presets: ['env', 'react-app'],
32+
plugins: [
33+
'syntax-dynamic-import',
34+
'dynamic-import-node',
35+
'react-loadable/babel'
36+
]
37+
});
38+
39+
// Now that the nonsense is over... load up the server entry point
40+
require('./server');

server/loader.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Express requirements
2+
import path from 'path';
3+
import fs from 'fs';
4+
5+
// React requirements
6+
import React from 'react';
7+
import { renderToString } from 'react-dom/server';
8+
import Helmet from 'react-helmet';
9+
import { Provider } from 'react-redux';
10+
import { StaticRouter } from 'react-router';
11+
import { Frontload, frontloadServerRender } from 'react-frontload';
12+
import Loadable from 'react-loadable';
13+
14+
// Our store, entrypoint, and manifest
15+
import createStore from '../src/store';
16+
import App from '../src/app/app';
17+
import manifest from '../build/asset-manifest.json';
18+
19+
// Some optional Redux functions related to user authentication
20+
import { setCurrentUser, logoutUser } from '../src/modules/auth';
21+
22+
// LOADER
23+
export default (req, res) => {
24+
/*
25+
A simple helper function to prepare the HTML markup. This loads:
26+
- Page title
27+
- SEO meta tags
28+
- Preloaded state (for Redux) depending on the current route
29+
- Code-split script tags depending on the current route
30+
*/
31+
const injectHTML = (data, { html, title, meta, body, scripts, state }) => {
32+
data = data.replace('<html>', `<html ${html}>`);
33+
data = data.replace(/<title>.*?<\/title>/g, title);
34+
data = data.replace('</head>', `${meta}</head>`);
35+
data = data.replace(
36+
'<div id="root"></div>',
37+
`<div id="root">${body}</div><script>window.__PRELOADED_STATE__ = ${state}</script>`
38+
);
39+
data = data.replace('</body>', scripts.join('') + '</body>');
40+
41+
return data;
42+
};
43+
44+
// Load in our HTML file from our build
45+
fs.readFile(
46+
path.resolve(__dirname, '../build/index.html'),
47+
'utf8',
48+
(err, htmlData) => {
49+
// If there's an error... serve up something nasty
50+
if (err) {
51+
console.error('Read error', err);
52+
53+
return res.status(404).end();
54+
}
55+
56+
// Create a store (with a memory history) from our current url
57+
const { store } = createStore(req.url);
58+
59+
// If the user has a cookie (i.e. they're signed in) - set them as the current user
60+
// Otherwise, we want to set the current state to be logged out, just in case this isn't the default
61+
if ('mywebsite' in req.cookies) {
62+
store.dispatch(setCurrentUser(req.cookies.mywebsite));
63+
} else {
64+
store.dispatch(logoutUser());
65+
}
66+
67+
const context = {};
68+
const modules = [];
69+
70+
/*
71+
Here's the core funtionality of this file. We do the following in specific order (inside-out):
72+
1. Load the <App /> component
73+
2. Inside of the Frontload HOC
74+
3. Inside of a Redux <StaticRouter /> (since we're on the server), given a location and context to write to
75+
4. Inside of the store provider
76+
5. Inside of the React Loadable HOC to make sure we have the right scripts depending on page
77+
6. Render all of this sexiness
78+
7. Make sure that when rendering Frontload knows to get all the appropriate preloaded requests
79+
80+
In English, we basically need to know what page we're dealing with, and then load all the appropriate scripts and
81+
data for that page. We take all that information and compute the appropriate state to send to the user. This is
82+
then loaded into the correct components and sent as a Promise to be handled below.
83+
*/
84+
frontloadServerRender(() =>
85+
renderToString(
86+
<Loadable.Capture report={m => modules.push(m)}>
87+
<Provider store={store}>
88+
<StaticRouter location={req.url} context={context}>
89+
<Frontload isServer>
90+
<App />
91+
</Frontload>
92+
</StaticRouter>
93+
</Provider>
94+
</Loadable.Capture>
95+
)
96+
).then(routeMarkup => {
97+
if (context.url) {
98+
// If context has a url property, then we need to handle a redirection in Redux Router
99+
res.writeHead(302, {
100+
Location: context.url
101+
});
102+
103+
res.end();
104+
} else {
105+
// Otherwise, we carry on...
106+
107+
// Let's give ourself a function to load all our page-specific JS assets for code splitting
108+
const extractAssets = (assets, chunks) =>
109+
Object.keys(assets)
110+
.filter(asset => chunks.indexOf(asset.replace('.js', '')) > -1)
111+
.map(k => assets[k]);
112+
113+
// Let's format those assets into pretty <script> tags
114+
const extraChunks = extractAssets(manifest, modules).map(
115+
c => `<script type="text/javascript" src="/${c}"></script>`
116+
);
117+
118+
// We need to tell Helmet to compute the right meta tags, title, and such
119+
const helmet = Helmet.renderStatic();
120+
121+
// NOTE: Disable if you desire
122+
// Let's output the title, just to see SSR is working as intended
123+
console.log('THE TITLE', helmet.title.toString());
124+
125+
// Pass all this nonsense into our HTML formatting function above
126+
const html = injectHTML(htmlData, {
127+
html: helmet.htmlAttributes.toString(),
128+
title: helmet.title.toString(),
129+
meta: helmet.meta.toString(),
130+
body: routeMarkup,
131+
scripts: extraChunks,
132+
state: JSON.stringify(store.getState()).replace(/</g, '\\u003c')
133+
});
134+
135+
// We have all the final HTML, let's send it to the user already!
136+
res.send(html);
137+
}
138+
});
139+
}
140+
);
141+
};

server/server.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Express requirements
2+
import bodyParser from 'body-parser';
3+
import compression from 'compression';
4+
import express from 'express';
5+
import morgan from 'morgan';
6+
import path from 'path';
7+
// import forceDomain from 'forcedomain';
8+
import Loadable from 'react-loadable';
9+
import cookieParser from 'cookie-parser';
10+
11+
// Our loader - this basically acts as the entry point for each page load
12+
import loader from './loader';
13+
14+
// Create our express app using the port optionally specified
15+
const app = express();
16+
const PORT = process.env.PORT || 3000;
17+
18+
// NOTE: UNCOMMENT THIS IF YOU WANT THIS FUNCTIONALITY
19+
/*
20+
Forcing www and https redirects in production, totally optional.
21+
22+
http://mydomain.com
23+
http://www.mydomain.com
24+
https://mydomain.com
25+
26+
Resolve to: https://www.mydomain.com
27+
*/
28+
// if (process.env.NODE_ENV === 'production') {
29+
// app.use(
30+
// forceDomain({
31+
// hostname: 'www.mydomain.com',
32+
// protocol: 'https'
33+
// })
34+
// );
35+
// }
36+
37+
// Compress, parse, log, and raid the cookie jar
38+
app.use(compression());
39+
app.use(bodyParser.json());
40+
app.use(bodyParser.urlencoded({ extended: false }));
41+
app.use(morgan('dev'));
42+
app.use(cookieParser());
43+
44+
// Set up homepage, static assets, and capture everything else
45+
app.use(express.Router().get('/', loader));
46+
app.use(express.static(path.resolve(__dirname, '../build')));
47+
app.use(loader);
48+
49+
// We tell React Loadable to load all required assets and start listening - ROCK AND ROLL!
50+
Loadable.preloadAll().then(() => {
51+
app.listen(PORT, console.log(`App listening on port ${PORT}!`));
52+
});
53+
54+
// Handle the bugs somehow
55+
app.on('error', error => {
56+
if (error.syscall !== 'listen') {
57+
throw error;
58+
}
59+
60+
const bind = typeof PORT === 'string' ? 'Pipe ' + PORT : 'Port ' + PORT;
61+
62+
switch (error.code) {
63+
case 'EACCES':
64+
console.error(bind + ' requires elevated privileges');
65+
process.exit(1);
66+
break;
67+
case 'EADDRINUSE':
68+
console.error(bind + ' is already in use');
69+
process.exit(1);
70+
break;
71+
default:
72+
throw error;
73+
}
74+
});

0 commit comments

Comments
 (0)