Combined live/hot-reloading quickstart for Express.js/React
Switch branches/tags
Nothing to show
Clone or download

README.md

A "real-life" Express + React application quickstart

Express, React, BrowserSync, Webpack, Nodemon

Combined live/hot-reloading for Express.js and React.

Motivation

TL;DR

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.

Background

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.

That's why we still need to generate content on the server using tried & tested, fast, specialized template engines such as Pug, EJS, Vash, Dust, etc.

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.

Features

  • 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 webpack@2.1.x;
  • Seamless CSS reloading with browsersync.

Starting

  • In development mode: npm run dev, then edit code and enjoy the auto-reload magic on localhost:3000;
  • In production mode: npm run build, then npm start.

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.js to 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-db and 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 npm script if you're using Stylus with autoprefixer-stylus plugin or write your styles in plain CSS.
  • package.json contains simple npm scripts for running in development and production mode.
  • The quickstart provides a simple, yet efficient asset versioning mechanism based on package.json version: the static assets are served from a "virtual" root /static/x.x.x.x, where x.x.x.x is the package version. Just make sure to do an npm version bump as part of your deployment scenario (not provided here).
  • Efficient ES6 on the server with babel-preset-latest-minimal – configured in index.js.
  • 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 webpack.config.js.
  • On the server, the global.Promise is replaced with bluebird for performance reasons – this is configured in index.js. Simply remove it if you don't like the idea.

Contributing

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.

Credits

If you find this repo useful, don't hesitate to give it a star, spread the word or even endorse the author on LinkedIn.

License

ISC-licensed by Ionut-Cristian Florescu. Feel free to use and abuse.