A "real-life" Express + React application quickstart
Combined live/hot-reloading for Express.js and React.
While a simple, webpack-only based development scenario is perfectly suited for building SPAs, building multipage applications or websites require a different, more elaborated approach.
While most React tutorials and quickstarts are focused exclusively on building SPAs (single-page applications), in real life your React application will often be running as part of a "classic" multipage application / website.
There's been lots of talk recently about server-side rendered React components or even about building your entire website as a client-side application. But rendering React components on the server is still unacceptably slow (as of December 2016), especially for websites that need to handle lots of traffic.
Also, we still need our server-generated content to be available and parsable by search engines. Admittedly, Google became smarter in regards to interpreting and client-side generated content, but it's not safe to completely rely on it, and other search engines are not so powerful yet.
Also, the webpack-based hot-reloading solution provided by most tutorials and available quickstarts completely ignore the API your application is connecting to. But in real-life not all projects are developed by multiple teams; sometimes there's a single full-stack developer or team writing the entire codebase for an app or website, including the webpage templates, client-side JS code and server-side APIs.
Trying to use webpack hot-reloading for template-generated pages and API endpoints is possible to a certain degree, but it feels like trying to fit a square peg in a round hole: it requires you to structure your code in a certain way and make use of unsafe artifacts such as
require cache busting, and it often results in FOUC when applying CSS changes.
Hence the need of a functional, truly general-purpose hot-reloading approach integrating the best of all worlds.
- Restart / full-page reload on server-side code change using nodemon and browsersync;
- Full-page reload on template change using browsersync's watch mechanism;
- Smart HMR on client-side code change using email@example.com;
- Seamless CSS reloading with browsersync.
- In development mode:
npm run dev, then edit code and enjoy the auto-reload magic on
- In production mode:
npm run build, then
Notes & Customizations
- For demo purposes, server-side views are generated with Vash template engine, but you can use Pug, EJS, or anything else, as long as you make the necessary amendments in
dev.jsto instruct the browser to reload when one of your views changes.
- A very simple/non-scalable JSON persistence mechanism based on lowdb and underscore-db is used as a server-side "database", for demo purposes. Make sure to
npm uninstall -S lowdb underscore-dband replace with an appropriate data persistence layer.
- A very simple gulp scenario is used for the sole purpose of transforming SCSS with node-sass and applying autoprefixer transformations with sourcemaps support in a single step. You can adapt it according to your own needs, or even fully replace it with a simple
npmscript if you're using Stylus with autoprefixer-stylus plugin or write your styles in plain CSS.
npmscripts for running in development and production mode.
- The quickstart provides a simple, yet efficient asset versioning mechanism based on
package.jsonversion: the static assets are served from a "virtual" root
x.x.x.xis the package version. Just make sure to do an
npm version bumpas part of your deployment scenario (not provided here).
- Efficient ES6 on the server with babel-preset-latest-minimal – configured in
- In development mode, webpack-dev-middleware and webpack-hot-middleware are running as browsersync middlewares. This way we end up keeping the main Express application uncluttered by development-related code.
- Webpack babel-loader is using stage-2 and react presets and react-hot-loader@3 – configured in
- On the server, the
global.Promiseis replaced with bluebird for performance reasons – this is configured in
index.js. Simply remove it if you don't like the idea.
PRs are welcomed, but keep in mind this is just one of the many quickstart alternatives available in the wild, and it's not intended to cover all possible use-cases (or yours in particular).
Before raising issues or asking for help
I'm getting lots of questions from people just learning to do web development or simply looking to solve a very specific problem they're dealing with. While I will answer some of them for the benefit of the community, please understand that open-source is a shared effort and it's definitely not about piggybacking on other people's work. On places like GitHub, that means raising issues is encouraged, but coming up with useful PRs is a lot better. If I'm willing to share some of my code for free, I'm doing it for a number of reasons: my own intellectual challenges, pride, arrogance, stubbornness to believe I'm bringing a contribution to common progress and freedom, etc. Your particular well-being is probably not one of those reasons. I'm not in the business of providing free consultancy, so if you need my help to solve your specific problem, there's a fee for that. If you understand that and wish to employ my services, don't hesitate to drop me a line on my GitHub email account.