350 open graph react #360
|
@ -17,7 +17,7 @@ spee.ch is a single-serving site that reads and publishes images and videos to a
|
|||
* create your `speechConfig.js` file
|
||||
* copy `speechConfig.js.example` and name it `speechConfig.js`
|
||||
* replace the `null` values in the config file with the appropriate values for your environement
|
||||
* to start the server, from your command line run `node speech.js`
|
||||
* to start the server, from your command line run `node serverindex.js`
|
||||
* To run hot, use `nodemon` instead of `node`
|
||||
* visit [localhost:3000](http://localhost:3000)
|
||||
|
||||
|
|
32
helpers/handleRender.jsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { renderToString } from 'react-dom/server';
|
||||
import { createStore } from 'redux';
|
||||
import Reducer from '../react/reducers';
|
||||
import renderFullPage from './renderFullPage.js';
|
||||
|
||||
import StaticRouter from 'react-router-dom/StaticRouter';
|
||||
import GAListener from '../react/components/GAListener';
|
||||
import App from '../react/app';
|
||||
|
||||
module.exports = (req, res) => {
|
||||
let context = {};
|
||||
|
||||
// create a new Redux store instance
|
||||
const store = createStore(Reducer);
|
||||
|
||||
// render component to a string
|
||||
const html = renderToString(
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={req.url} context={context}>
|
||||
<GAListener>
|
||||
<App />
|
||||
</GAListener>
|
||||
</StaticRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
// get the initial state from our Redux store
|
||||
const preloadedState = store.getState();
|
||||
|
||||
// send the rendered page back to the client
|
||||
res.send(renderFullPage(html, preloadedState));
|
||||
};
|
21
helpers/renderFullPage.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
module.exports = (html, preloadedState) => {
|
||||
// take the html and preloadedState and return the full page
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
|
||||
<head>
|
||||
<!--google font-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet">
|
||||
</head>
|
||||
<body id="main-body">
|
||||
<div class="row row--tall flex-container--column">
|
||||
<div id="react-app" class="row row--tall flex-container--column">${html}</div>
|
||||
</div>
|
||||
<script>
|
||||
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\\u003c')}
|
||||
</script>
|
||||
<script src="/static/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
|
@ -7,7 +7,6 @@ const handlebarsHelpers = require('./helpers/handlebarsHelpers.js');
|
|||
const { populateLocalsDotUser, serializeSpeechUser, deserializeSpeechUser } = require('./helpers/authHelpers.js');
|
||||
const config = require('./config/speechConfig.js');
|
||||
const logger = require('winston');
|
||||
const { getDownloadDirectory } = require('./helpers/lbryApi');
|
||||
const helmet = require('helmet');
|
||||
const PORT = 3000; // set port
|
||||
const app = express(); // create an Express application
|
||||
|
@ -67,14 +66,7 @@ app.use(populateLocalsDotUser);
|
|||
// start the server
|
||||
db.sequelize
|
||||
.sync() // sync sequelize
|
||||
.then(() => { // get the download directory from the daemon
|
||||
logger.info('Retrieving daemon download directory...');
|
||||
return getDownloadDirectory();
|
||||
})
|
||||
.then(hostedContentPath => {
|
||||
// add the hosted content folder at a static path
|
||||
app.use('/media', express.static(hostedContentPath));
|
||||
// require routes
|
||||
.then(() => { // require routes
|
||||
require('./routes/auth-routes.js')(app);
|
||||
require('./routes/api-routes.js')(app);
|
||||
require('./routes/page-routes.js')(app);
|
|
@ -6,7 +6,7 @@
|
|||
"scripts": {
|
||||
"test": "mocha --recursive",
|
||||
"test-all": "mocha --recursive",
|
||||
"start": "node speech.js",
|
||||
"start": "node server.js",
|
||||
"lint": "eslint .",
|
||||
"fix": "eslint . --fix",
|
||||
"precommit": "eslint .",
|
||||
|
@ -57,6 +57,7 @@
|
|||
"sequelize-cli": "^3.0.0-3",
|
||||
"sleep": "^5.1.1",
|
||||
"universal-analytics": "^0.4.13",
|
||||
"webpack-node-externals": "^1.6.0",
|
||||
"whatwg-fetch": "^2.0.3",
|
||||
"winston": "^2.3.1",
|
||||
"winston-slack-webhook": "billbitt/winston-slack-webhook"
|
||||
|
@ -64,12 +65,15 @@
|
|||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"babel-register": "^6.26.0",
|
||||
"chai": "^4.1.2",
|
||||
"chai-http": "^3.0.0",
|
||||
"css-loader": "^0.28.9",
|
||||
"eslint": "3.19.0",
|
||||
"eslint-config-standard": "10.2.1",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
|
|
|
@ -10,18 +10,24 @@ import rootSaga from 'sagas';
|
|||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
import GAListener from 'components/GAListener';
|
||||
import App from './app';
|
||||
|
||||
// get the state from a global variable injected into the server-generated HTML
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
const preloadedState = window.__PRELOADED_STATE__ || null;
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
// Allow the passed state to be garbage-collected
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
delete window.__PRELOADED_STATE__
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
// create and apply middleware
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
const middleware = applyMiddleware(sagaMiddleware);
|
||||
const reduxMiddleware = window.__REDUX_DEVTOOLS_EXTENSION__ ? compose(middleware, window.__REDUX_DEVTOOLS_EXTENSION__()) : middleware;
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
|
||||
const enhancer = window.__REDUX_DEVTOOLS_EXTENSION__ ? compose(middleware, window.__REDUX_DEVTOOLS_EXTENSION__()) : middleware;
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
let store = createStore(
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
Reducer,
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
enhancer,
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
);
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
// create teh store
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
let store = createStore(Reducer, preloadedState, reduxMiddleware);
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
|
||||
// run the saga middlweare
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
sagaMiddleware.run(rootSaga);
|
||||
|
||||
// render the app
|
||||
Probably don't need these Probably don't need these `console.log`s here.
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
|
@ -1,4 +1,5 @@
|
|||
const { site } = require('../config/speechConfig.js');
|
||||
// const handleRender = require('../helpers/handleRender.jsx');
|
||||
|
||||
module.exports = (app) => {
|
||||
// route for the home page
|
||||
|
|
|
@ -1,32 +1,67 @@
|
|||
const Path = require('path');
|
||||
I would recommend creating separate webpack configs for dev/prod. Before we did our big restructure changes the apps webpack setup had three files: A base config: contains the generic stuff like babel, entry/output points, css loader, etc.
I would recommend creating separate webpack configs for dev/prod. Before we did our big restructure changes the apps webpack setup had three files:
A base config: contains the generic stuff like babel, entry/output points, css loader, etc.
A dev config which extends the base config: contains stuff like `watch: true` (not needed in prod) and source maps
A prod config which extends the base config: contains stuff like minification (that's the main thing)
`webpack-merge` is a great tool for this
https://github.com/survivejs/webpack-merge
|
||||
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
const REACT_ROOT = Path.resolve(__dirname, 'react/');
|
||||
|
||||
module.exports = {
|
||||
entry : ['babel-polyfill', 'whatwg-fetch', './react/index.js'],
|
||||
output: {
|
||||
path : Path.join(__dirname, '/public/bundle/'),
|
||||
filename: 'bundle.js',
|
||||
},
|
||||
watch : true,
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test : /.jsx?$/,
|
||||
loader : 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
query : {
|
||||
presets: ['es2015', 'react', 'stage-2'],
|
||||
console.log('REACT_ROOT:', REACT_ROOT);
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
target: 'web',
|
||||
entry : ['babel-polyfill', 'whatwg-fetch', './react/client.js'],
|
||||
output: {
|
||||
path : Path.join(__dirname, 'public/bundle/'),
|
||||
publicPath: 'public/bundle/',
|
||||
filename : 'bundle.js',
|
||||
},
|
||||
watch : true,
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test : /.jsx?$/,
|
||||
loader : 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
query : {
|
||||
presets: ['es2015', 'react', 'stage-2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
REACT_ROOT,
|
||||
'node_modules',
|
||||
__dirname,
|
||||
],
|
||||
extensions: ['.js', '.jsx', '.scss'],
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
REACT_ROOT,
|
||||
'node_modules',
|
||||
__dirname,
|
||||
],
|
||||
extensions: ['.js', '.jsx', '.scss'],
|
||||
{
|
||||
target : 'node',
|
||||
externals: nodeExternals(),
|
||||
entry : ['./index.js'],
|
||||
output : {
|
||||
path : __dirname,
|
||||
publicPath: '',
|
||||
filename : 'server.js',
|
||||
},
|
||||
watch : true,
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
loader : 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
query : {
|
||||
presets: ['es2015'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
'node_modules',
|
||||
__dirname,
|
||||
],
|
||||
extensions: ['.js'],
|
||||
},
|
||||
},
|
||||
};
|
||||
];
|
||||
|
|
Probably don't need these
console.log
s here.