react-redux-universal-hot-example
A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform
Top Related Projects
Set up a modern web app by running one command.
The React Framework
A JS library for predictable global state management
Get started with React, Redux, and React-Router.
The web's most popular Jamstack front-end template (boilerplate) for building web applications with React
Quick Overview
The erikras/react-redux-universal-hot-example is a comprehensive boilerplate for building universal (isomorphic) web applications using React, Redux, and Express. It demonstrates best practices for server-side rendering, code splitting, and hot reloading, providing developers with a solid foundation for creating modern, scalable web applications.
Pros
- Implements server-side rendering for improved performance and SEO
- Includes hot reloading for a smooth development experience
- Demonstrates code splitting for optimized loading times
- Integrates popular tools and libraries like Redux, React Router, and Webpack
Cons
- May be overwhelming for beginners due to its complexity
- Some dependencies and practices might be outdated
- Requires a deep understanding of React and Redux ecosystems
- Limited documentation and maintenance in recent years
Code Examples
- Server-side rendering setup:
import React from 'react';
import ReactDOM from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import { Provider } from 'react-redux';
export default (req, res, store, routes) => {
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
const component = (
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
);
res.status(200).send(renderFullPage(ReactDOM.renderToString(component), store.getState()));
} else {
res.status(404).send('Not found');
}
});
};
- Redux store configuration:
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
export default function configureStore(initialState) {
const middleware = [thunk];
const enhancers = [];
if (__DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__) {
const { persistState } = require('redux-devtools');
enhancers.push(persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)));
}
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
...enhancers
)
);
return store;
}
- React component with Redux connection:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { loadWidgets } from '../actions/widgetActions';
class WidgetList extends Component {
componentDidMount() {
this.props.loadWidgets();
}
render() {
const { widgets, loading } = this.props;
if (loading) return <div>Loading...</div>;
return (
<ul>
{widgets.map(widget => (
<li key={widget.id}>{widget.name}</li>
))}
</ul>
);
}
}
const mapStateToProps = state => ({
widgets: state.widgets.items,
loading: state.widgets.loading
});
export default connect(mapStateToProps, { loadWidgets })(WidgetList);
Getting Started
-
Clone the repository:
git clone https://github.com/erikras/react-redux-universal-hot-example.git
-
Install dependencies:
cd react-redux-universal-hot-example npm install
-
Start the development server:
npm run dev
-
Open your browser and navigate to
http://localhost:3000
to see the application running.
Competitor Comparisons
Set up a modern web app by running one command.
Pros of Create React App
- Simpler setup and configuration, ideal for beginners
- Regularly updated and maintained by Facebook
- Extensive documentation and community support
Cons of Create React App
- Less flexibility for advanced configurations
- Limited built-in features compared to the comprehensive stack in React Redux Universal Hot Example
- Requires ejecting or additional tools for more complex setups
Code Comparison
React Redux Universal Hot Example:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { RouterContext } from 'react-router';
const html = renderToString(
<Provider store={store} key="provider">
<RouterContext {...renderProps} />
</Provider>
);
Create React App:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
The React Redux Universal Hot Example provides a more complex setup with server-side rendering, Redux integration, and routing out of the box. Create React App offers a simpler starting point, focusing on client-side rendering and leaving additional features to be added as needed.
The React Framework
Pros of Next.js
- Built-in server-side rendering and static site generation
- Automatic code splitting for faster page loads
- Simpler routing system with file-based routing
Cons of Next.js
- Less flexibility in project structure compared to custom setups
- Steeper learning curve for developers new to server-side rendering
- Potential overhead for simple applications that don't require SSR
Code Comparison
Next.js routing:
// pages/about.js
export default function About() {
return <h1>About Page</h1>
}
react-redux-universal-hot-example routing:
// routes.js
export default (
<Route path="/" component={App}>
<Route path="about" component={About}/>
</Route>
);
Next.js offers a more straightforward approach to routing, with each file in the pages
directory automatically becoming a route. The react-redux-universal-hot-example uses a more traditional React Router setup, which provides more flexibility but requires more configuration.
Both projects aim to provide a comprehensive starting point for React applications, but Next.js focuses on simplifying server-side rendering and providing a more opinionated structure, while react-redux-universal-hot-example offers a more customizable boilerplate with additional features like Redux integration out of the box.
A JS library for predictable global state management
Pros of Redux
- Core library for state management in React applications
- Extensive documentation and large community support
- Lightweight and flexible, can be used with various UI libraries
Cons of Redux
- Steeper learning curve for beginners
- Requires more boilerplate code for setup and actions
- May be overkill for smaller applications
Code Comparison
Redux (basic store setup):
import { createStore } from 'redux'
const store = createStore(rootReducer)
React Redux Universal Hot Example (store configuration):
import { createStore, applyMiddleware } from 'redux'
import createMiddleware from './middleware/clientMiddleware'
const store = createStore(rootReducer, applyMiddleware(createMiddleware(client)))
Key Differences
- Redux is a standalone state management library, while React Redux Universal Hot Example is a full-stack boilerplate
- React Redux Universal Hot Example includes additional features like server-side rendering and hot reloading
- Redux focuses on core state management principles, while the example project demonstrates a complete application structure
Use Cases
- Redux: Ideal for large-scale applications requiring robust state management
- React Redux Universal Hot Example: Suitable for developers looking for a comprehensive starting point for universal React applications
Community and Maintenance
- Redux: Actively maintained with frequent updates and a large contributor base
- React Redux Universal Hot Example: Less frequently updated, serves more as a reference implementation
Get started with React, Redux, and React-Router.
Pros of react-redux-starter-kit
- More lightweight and focused on core React and Redux functionality
- Cleaner project structure with better separation of concerns
- Uses Webpack 2, which offers improved performance and features
Cons of react-redux-starter-kit
- Lacks universal/isomorphic rendering capabilities
- Fewer additional features and integrations out of the box
- Less comprehensive documentation and examples
Code Comparison
react-redux-universal-hot-example:
import React from 'react'
import ReactDOM from 'react-dom/server'
import serialize from 'serialize-javascript'
import Html from '../containers/Html'
const renderHtml = (store, assets, component) => {
// ... (additional code)
}
react-redux-starter-kit:
import React from 'react'
import ReactDOM from 'react-dom'
import createStore from './store/createStore'
import App from './components/App'
const store = createStore(window.__INITIAL_STATE__)
ReactDOM.render(
<App store={store} />,
document.getElementById('root')
)
The code comparison highlights the difference in rendering approach. react-redux-universal-hot-example includes server-side rendering capabilities, while react-redux-starter-kit focuses on client-side rendering with a simpler setup.
The web's most popular Jamstack front-end template (boilerplate) for building web applications with React
Pros of React Starter Kit
- More comprehensive and feature-rich, including GraphQL integration and CSS Modules support
- Better documentation and project structure, making it easier for newcomers to understand
- Regular updates and active maintenance, ensuring compatibility with the latest React ecosystem
Cons of React Starter Kit
- Steeper learning curve due to its more complex architecture and additional features
- Potentially overkill for smaller projects or those not requiring all the included features
- Less focus on server-side rendering compared to React Redux Universal Hot Example
Code Comparison
React Starter Kit:
import React from 'react';
import Layout from '../../components/Layout';
import Home from './Home';
const title = 'React Starter Kit';
function action() {
return {
chunks: ['home'],
title,
component: <Layout><Home title={title} /></Layout>,
};
}
React Redux Universal Hot Example:
import React from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
@connect(state => ({ user: state.auth.user }))
export default class Home extends React.Component {
render() {
const { user } = this.props;
return (
<div className="container">
<Helmet title="Home"/>
<h1>Welcome {user ? user.name : 'Guest'}!</h1>
</div>
);
}
}
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
â ï¸ DO NOT USE THIS!! â ï¸
Once upon a time, this repo helped a lot of people, but it's waaaay out of date. It's now more of a historical artifact of what React development looked like in 2015.
React Redux Universal Hot Example
About
This is a starter boilerplate app I've put together using the following technologies:
IsomorphicUniversal rendering- Both client and server make calls to load data from separate API server
- React
- React Router
- Express
- Babel for ES6 and ES7 magic
- Webpack for bundling
- Webpack Dev Middleware
- Webpack Hot Middleware
- Redux's futuristic Flux implementation
- Redux Dev Tools for next generation DX (developer experience). Watch Dan Abramov's talk.
- React Router Redux Redux/React Router bindings.
- ESLint to maintain a consistent code style
- redux-form to manage form state in Redux
- lru-memoize to speed up form validation
- multireducer to combine single reducers into one key-based reducer
- style-loader, sass-loader and less-loader to allow import of stylesheets in plain css, sass and less,
- bootstrap-sass-loader and font-awesome-webpack to customize Bootstrap and FontAwesome
- react-helmet to manage title and meta tag information on both server and client
- webpack-isomorphic-tools to allow require() work for statics both on client and server
- mocha to allow writing unit tests for the project.
I cobbled this together from a wide variety of similar "starter" repositories. As I post this in June 2015, all of these libraries are right at the bleeding edge of web development. They may fall out of fashion as quickly as they have come into it, but I personally believe that this stack is the future of web development and will survive for several years. I'm building my new projects like this, and I recommend that you do, too.
Installation
npm install
Running Dev Server
npm run dev
The first time it may take a little while to generate the first webpack-assets.json
and complain with a few dozen [webpack-isomorphic-tools] (waiting for the first Webpack build to finish)
printouts, but be patient. Give it 30 seconds.
Using Redux DevTools
Redux Devtools are enabled by default in development.
- CTRL+H Toggle DevTools Dock
- CTRL+Q Move DevTools Dock Position
- see redux-devtools-dock-monitor for more detailed information.
If you have the Redux DevTools chrome extension installed it will automatically be used on the client-side instead.
If you want to disable the dev tools during development, set __DEVTOOLS__
to false
in /webpack/dev.config.js
.
DevTools are not enabled during production.
Building and Running Production Server
npm run build
npm run start
Demo
A demonstration of this app can be seen running on heroku, which is a deployment of the heroku branch.
Documentation
- Exploring the Demo App is a guide that can be used before you install the kit.
- Installing the Kit guides you through installation and running the development server locally.
- Adding Text to the Home Page guides you through adding "Hello, World!" to the home page.
- Adding A Page guides you through adding a new page.
- React Tutorial - Converting Reflux to Redux, by Matt Star If you are the kind of person that learns best by following along a tutorial, I can recommend Matt Star's overview and examples.
Explanation
What initially gets run is bin/server.js
, which does little more than enable ES6 and ES7 awesomeness in the
server-side node code. It then initiates server.js
. In server.js
we proxy any requests to /api/*
to the
API server, running at localhost:3030
. All the data fetching calls from the client go to /api/*
.
Aside from serving the favicon and static content from /static
, the only thing server.js
does is initiate delegate
rendering to react-router
. At the bottom of server.js
, we listen to port 3000
and initiate the API server.
Routing and HTML return
The primary section of server.js
generates an HTML page with the contents returned by react-router
. First we instantiate an ApiClient
, a facade that both server and client code use to talk to the API server. On the server side, ApiClient
is given the request object so that it can pass along the session cookie to the API server to maintain session state. We pass this API client facade to the redux
middleware so that the action creators have access to it.
Then we perform server-side data fetching, wait for the data to be loaded, and render the page with the now-fully-loaded redux
state.
The last interesting bit of the main routing section of server.js
is that we swap in the hashed script and css from the webpack-assets.json
that the Webpack Dev Server â or the Webpack build process on production â has spit out on its last run. You won't have to deal with webpack-assets.json
manually because webpack-isomorphic-tools take care of that.
We also spit out the redux
state into a global window.__data
variable in the webpage to be loaded by the client-side redux
code.
Server-side Data Fetching
The redux-async-connect package exposes an API to return promises that need to be fulfilled before a route is rendered. It exposes a <ReduxAsyncConnect />
container, which wraps our render tree on both server and client. More documentation is available on the redux-async-connect page.
Client Side
The client side entry point is reasonably named client.js
. All it does is load the routes, initiate react-router
, rehydrate the redux state from the window.__data
passed in from the server, and render the page over top of the server-rendered DOM. This makes React enable all its event listeners without having to re-render the DOM.
Redux Middleware
The middleware, clientMiddleware.js
, serves two functions:
- To allow the action creators access to the client API facade. Remember this is the same on both the client and the server, and cannot simply be
import
ed because it holds the cookie needed to maintain session on server-to-server requests. - To allow some actions to pass a "promise generator", a function that takes the API client and returns a promise. Such actions require three action types, the
REQUEST
action that initiates the data loading, and aSUCCESS
andFAILURE
action that will be fired depending on the result of the promise. There are other ways to accomplish this, some discussed here, which you may prefer, but to the author of this example, the middleware way feels cleanest.
Redux Modules... What the Duck?
The src/redux/modules
folder contains "modules" to help
isolate concerns within a Redux application (aka Ducks, a Redux Style Proposal that I came up with). I encourage you to read the
Ducks Docs and provide feedback.
API Server
This is where the meat of your server-side application goes. It doesn't have to be implemented in Node or Express at all. This is where you connect to your database and provide authentication and session management. In this example, it's just spitting out some json with the current time stamp.
Getting data and actions into components
To understand how the data and action bindings get into the components â there's only one, InfoBar
, in this example â I'm going to refer to you to the Redux library. The only innovation I've made is to package the component and its wrapper in the same js file. This is to encapsulate the fact that the component is bound to the redux
actions and state. The component using InfoBar
needn't know or care if InfoBar
uses the redux
data or not.
Images
Now it's possible to render the image both on client and server. Please refer to issue #39 for more detail discussion, the usage would be like below (super easy):
let logoImage = require('./logo.png');
Styles
This project uses local styles using css-loader. The way it works is that you import your stylesheet at the top of the render()
function in your React Component, and then you use the classnames returned from that import. Like so:
render() {
const styles = require('./App.scss');
...
Then you set the className
of your element to match one of the CSS classes in your SCSS file, and you're good to go!
<div className={styles.mySection}> ... </div>
Alternative to Local Styles
If you'd like to use plain inline styles this is possible with a few modifications to your webpack configuration.
1. Configure Isomorphic Tools to Accept CSS
In webpack-isomorphic-tools.js
add css to the list of style module extensions
style_modules: {
extensions: ['less','scss','css'],
2. Add a CSS loader to webpack dev config
In dev.config.js
modify module loaders to include a test and loader for css
module: {
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader'},
3. Add a CSS loader to the webpack prod config
You must use the ExtractTextPlugin in this loader. In prod.config.js
modify module loaders to include a test and loader for css
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader')},
Now you may simply omit assigning the required
stylesheet to a variable and keep it at the top of your render()
function.
render() {
require('./App.css');
require('aModule/dist/style.css');
...
NOTE In order to use this method with scss or less files one more modification must be made. In both dev.config.js
and prod.config.js
in the loaders for less and scss files remove
modules
localIdentName...
Before:
{ test: /\.less$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
After:
{ test: /\.less$/, loader: 'style!css?importLoaders=2&sourceMap!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
After this modification to both loaders you will be able to use scss and less files in the same way as css files.
Unit Tests
The project uses Mocha to run your unit tests, it uses Karma as the test runner, it enables the feature that you are able to render your tests to the browser (e.g: Firefox, Chrome etc.), which means you are able to use the Test Utilities from Facebook api like renderIntoDocument()
.
To run the tests in the project, just simply run npm test
if you have Chrome
installed, it will be automatically launched as a test service for you.
To keep watching your test suites that you are working on, just set singleRun: false
in the karma.conf.js
file. Please be sure set it to true
if you are running npm test
on a continuous integration server (travis-ci, etc).
Deployment on Heroku
To get this project to work on Heroku, you need to:
- Remove the
"PORT": 8080
line from thebetterScripts
/start-prod
section ofpackage.json
. heroku config:set NODE_ENV=production
heroku config:set NODE_PATH=./src
heroku config:set NPM_CONFIG_PRODUCTION=false
- This is to enable webpack to run the build on deploy.
The first deploy might take a while, but after that your node_modules
dir should be cached.
FAQ
This project moves fast and has an active community, so if you have a question that is not answered below please visit our Discord channel or file an issue.
Roadmap
Although this isn't a library, we recently started versioning to make it easier to track breaking changes and emerging best practices.
- Inline Styles - CSS is dead
Contributing
I am more than happy to accept external contributions to the project in the form of feedback, bug reports and even better - pull requests :)
If you would like to submit a pull request, please make an effort to follow the guide in CONTRIBUTING.md.
Thanks for checking this out.
â Erik Rasmussen, @erikras
Top Related Projects
Set up a modern web app by running one command.
The React Framework
A JS library for predictable global state management
Get started with React, Redux, and React-Router.
The web's most popular Jamstack front-end template (boilerplate) for building web applications with React
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot