- Flux using
- Redux Dev Tools
- Routing using
Universal Redux Router
- Server rendering
- Progressive enhancement
- Hot module reloading
- CSS Modules
- Style themes
- Testing Redux and React components
- Bundling using Webpack with
- Enforcing coding style with ESLint
Although this setup is far from simple or minimal, I have
purposefully avoided all but what I see as core for a large
project. For example, authentication and data fetching is
outside the scope of this starter kit.
mkdir new-project; cd new-project git clone [email protected]:colinmeinke/universal-js.git . npm install npm run build:dev npm run start:dev
/src directory is where all of the code for the app
The build process
npm run build:dev or
npm run build:pro
will compile this code and output it into the
Files that will be directly requested by the browser are then
copied into their appropriate directory within
There are two files in the root of the
These two files are the entry points into the app for their
server.js will listen for HTTP requests sent from a client
to the server. On receiving a request it will render the
response on the server and send it back to the client to
initialises in the browser. This will hydrate the app on the
client, and thereafter handle requests itself, removing the
need for additional requests to the server.
/src/common directory is where all of the shared code
lives for both server and client. This is the beauty of
/components directory also resides within the
directory. This is where all React components live. Both
presentational and container (those that connect to the Redux
store or have access to its dispatch method).
Each presentational component lives within its own
/components. The directory is named after
the component in question, e.g.
<Button /> would be:
Connecting components to the Redux store is done by adding a
file to the root of the
/components directory. This file is
also named after the component, e.g.
This structure means that all components can be imported into
any file as follows:
import Button from './components/Button';
The file importing the component does not need to know if it
is a presentational or a container component.
This is because of how imports resolve. It will first look
for a file within the
/components directory called
Button.js. If that does not exist, it will then look for the
index.js file within a directory called
|-- common |-- components |-- Button |-- index.js |-- base.css |-- Button.js
Terms, concepts and reasoning
I get worried when I see very complex things getting built,
building in the right way. It will fall back to what's
- Jeremy Keith
If progressive enhancement is an
aim, then we must provide the core experience of our app to
This necessitates that we render the same app on the server
as we might on the client. The response from the server should
kicks in. That's just a bonus!
Server-side rendering isn't just about progressive enhancement
and accessibility. It's also a huge win for performance and
If we are rendering the same experience on both
the server and the client, then it
follows that we should use the same language to build both.
When we use the same language for everything, it means we can
abstract common code and share it between environments. Huge
wins for maintainability, testing, cognitive load ... the list
goes on and on.
At its core, this is a
React app. React is how we
write our components, render the user interface and keep it in
sync with the state of the app.
React also makes
rendering on the server really easy.
We need a way to manage the state of our React components.
Flux is a
pattern that can be used to architect how state flows
through our app and how we update state.
However, Flux itself is only an idea. You can't download or
Redux is a Flux implementation. It is a library
that you can download or install.
It's beautifully simple and stores all app state in a single
It allows us to treat our user interface as a pure function,
which when passed identical state will always render identical
It also allows our state to be serializable, and therefore
storable or shareable. This makes the possibility of things
like undo, redo, debugging and cross-device syncing very
Universal Redux Router
CSS Modules allow you to write CSS that is locally scoped.
This means that a CSS file can use the same class names that
are in another CSS file without worrying about clashing. When
the CSS is output, each class gets a unique hash – no need to
rely on long-winded naming conventions like
Most importantly for me is that you can extract the CSS
written this way into an external style sheet. This means you
A downside for me was getting CSS Modules setup in the first
place to work how I wanted. For more comprehensive
documentation on how to setup CSS modules with Webpack, check
another repository of mine that describes exactly that.
With the right plugins installed PostCSS allows you to write
future CSS, and compile it to something that works on today's
browsers. This is its major strength for me – you can just
If we write all user interface as components, all of our CSS
can be split by component too.
I like to allow theming, giving each presentational component
base.css file and then overriding those styles with a
base.css typically contains base layout rules and a very
simple grayscale color palette.
The reason we don't have to care about browser support for the
Babel takes care of transpiling our
code to ES5. ES5 works on all modern browsers.
Everything that can be done on the command line, can be done
Here's a list of the some of the scripts I have setup:
npm run build:dev– build to run in a development
npm run build:pro– build to run in a production
npm run changelog– create or update a changelog.
npm run commit– create a
conventional commit message.
npm run lint– lint the code.
npm run start:dev– start the server in a development
npm run start:pro– start the server in a production
npm run test– run the tests.
Webpack is the powerhouse behind
the build scripts
npm run build:dev and
npm run build:pro.
through that file's dependencies, and its dependents'
dependencies, bundling all that code into an output file.
In your Webpack config, you can tell Webpack to run various
loaders on specific file types during bundle-time. For
the Babel loader to convert our ES2015+
features and syntax to regular ES5.
Loaders can be chained together, which can be very powerful.
For more information, check out the section on
entry points above.
Hot module reloading
Part of a great development environment is not having to
manually recompile your code and refresh your browser every
Hot module reloading
Maintaining a consistent coding style is important, especially
when there is more than one contributor.
This guides us through the process of writing a conventional
commit message by prompting us for various data about the
changes we have made.
As well as maintaining consistent commit messages across the
project, this can have other extremely useful benefits.
Help make this better
and pull requests gratefully received!
I'm also on twitter @colinmeinke.