I have an application with webpack configured as a module bundler and babel as my js compiler. all on a node engine. I stetted up that when I run npm run dev
the following flow will happen:
The webpack-dev-server.js
will run. the file is the following:
const Express = require('express'); const webpack = require('webpack'); const webpackConfig = require('./dev.config'); const compiler = webpack(webpackConfig); const host = 'localhost'; const port = 8080; const serverOptions = { contentBase: `http://${host}:${port}`, quiet: true, noInfo: true, hot: true, inline: true, lazy: false, publicPath: webpackConfig.output.publicPath, headers: { 'Access-Control-Allow-Origin': '*' }, stats: { colors: true }, }; const app = new Express(); app.use(require('webpack-dev-middleware')(compiler, serverOptions)); app.use(require('webpack-hot-middleware')(compiler)); app.listen(port, function onAppListening(err) { if (err) { console.error(err); } else { console.info('==> Webpack development server listening on port %s', port); } });
Then the server.js
require('./../server.babel'); const path = require('path'); const WebpackIsomorphicTools = require('webpack-isomorphic-tools'); const rootDir = path.resolve(require('../server/config').rootDir); global.__CLIENT__ = false; global.__SERVER__ = true; global.__DEVELOPMENT__ = process.env.NODE_ENV !== 'production'; if (__DEVELOPMENT__) { if (!require('piping')({ hook: true, ignore: /(\/\.|~$|\.json|\.scss$)/i })) { return; } } global.webpackIsomorphicTools = new WebpackIsomorphicTools(require('../webpack/webpack-isomorphic-tools')) .development(__DEVELOPMENT__) .server(rootDir, () => { require('../server/server'); });
express and React rendering:
import 'babel-polyfill'; // Server import express from 'express'; import session from 'express-session'; import cookieParser from 'cookie-parser'; // React import React from 'react'; import ReactDOM from 'react-dom/server'; import createHistory from 'react-router/lib/createMemoryHistory'; import { match } from 'react-router'; // Redux import { Provider } from 'react-redux'; import { ReduxAsyncConnect, loadOnServer } from 'redux-connect'; import { syncHistoryWithStore } from 'react-router-redux'; import path from 'path'; import csurf from 'csurf'; import bodyParser from 'body-parser'; // Relative imports import Html from '../shared/html'; import proxy from './proxy'; import createStore from '../shared/redux/create'; import { staticPath } from './config'; import { getRoutes } from '../shared/routes'; require('dotenv').config({ path: path.resolve(__dirname, '../.env'), }); const SERVER_PORT = process.env.SERVER_PORT; const APP_SECRET = process.env.APP_SECRET; const API_PORT = process.env.API_PORT; const API_HOST = process.env.API_HOST; function renderPage({ renderProps, store, res, client, csrfToken }) { loadOnServer({ ...renderProps, store, helpers: { client } }) .then(() => { const component = ( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ); res.status(200); res.send('<!doctype html>\n' + ReactDOM.renderToString( <Html assets={webpackIsomorphicTools.assets()} component={component} csrfToken={csrfToken} store={store} />, ), ); }) .catch((err) => { console.error(err.stack); }); } const app = express(); const csrf = csurf(); // express middlewares // app.use(favicon(path.resolve(__dirname, '../static/favicon.ico'))); @TODO favicon @ilanus app.use(bodyParser.json()); app.use(express.static(staticPath)); app.use(cookieParser(APP_SECRET)); app.use(session({ secret: APP_SECRET, saveUninitialized: true, resave: true, })); app.use(csrf); app.use('/api', (req, res) => { if (!req.xhr) res.redirect('/'); proxy.web(req, res, { target: `http://${API_HOST}:${API_PORT}` }); }); app.use((req, res) => { const csrfToken = req.csrfToken(); if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh(); } const memoryHistory = createHistory(req.originalUrl); const store = createStore({}, memoryHistory); const history = syncHistoryWithStore(memoryHistory, store); match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', error); res.status(500); } else if (renderProps) { renderPage({ renderProps, store, res, csrfToken }); } else { res.status(404).send('Not found'); } }); }); app.use((err, req, res) => { if (err === 'EBADCSRFTOKEN') { res.status(403); res.send('invalid csrf token'); } else { res.status(500); res.send('Oops, internal server error'); } }); app.listen(SERVER_PORT, (error) => { if (error) { console.error(error); } else { console.info(`App started listening on port ${SERVER_PORT}`); } });
Now whenever I try to console.log('window', window, 'sessionStorage', sessionStorage);
within a render()
function or componentDidMount()
of a react component I end up with: sessionStorage is not defined, window is not defined
errors. I guess that's because I am running the stack on the server-side and those are not available there what am I missing?