What's in The Box?
There's a trivial example application in Breko-hub to help you explore the features.
There's a FooRoute
component showing how to pre-load data on both server and client render (the prefetch). The FooRoute
loads data unique to the client (the defer) which replaces the universally loaded data.
There's a BarRoute
component showing how to pre-fetch route data with a promise-action.
An API to support the BarRoute
's data needs.
There's a /private
route doing a redirect on both client and server with a flash message. The flash message is then automatically removed using a redux-saga.
The FlashMessage
component gives an example of action -> reducer
flow. A saga removes messages after a delay (or by clicking remove). The FlashMessages component uses a Block Element Modifier (BEM) utility for managing class names in combination with CSS-modules.
There's a dispatch call in src/app/entry.js
to show how to broadcast actions to a socket. A small socket server hosted within the app is (on the same port) forwarding any broadcast actions.
The test/functional/client/client-render.test.js
file has tests for routes.
Description
The .env
file
Breko-hub uses settings in your run-time environment, such as PORT
, NODE_ENV
and DEBUG
. When developing, it's nice to use a .env
file. The app loads an environment from your .env
file to give you quick and convenient control when developing.
The .env
file is untracked. This is important as environments contain sensitive information!
ES Imports
In Breko-hub, babel treats ./src/
as the default import root.
Using absolute require calls improves portability and clarity. No-one enjoys writing ../../../
and in a large application its important to give hierarchy to units of code. These two factors fight each other. By making ./src/
the default import root, you require any file without needing a relative path.
For example:
// inside `test/functional/client/client-render.test.js`
import App from '../../../src/app/components/App'
// becomes
import App from 'app/components/App'
Babel-root-imports resolves modules according to a configurable project route. Use a prefix of ~
to your import string if you need to require from above ./src/
.
For example:
// inside `test/functional/client/client-render.test.js`
import '../../../package.json'
// becomes
import '~/package.json'
Head and Body Script Loading
A big performance factor for an application is the load time. CSS links contribute to this load time because of their large filesize. One quick improvement is to defer loading of styles for below the fold or progressive enhancement. Asynchronous asset loading is a great performance gain.
There're intentionally, 2 entry points for this application, body
and head
. This is to give the developer more control of their scripts location on the server render. The bodyStyles
array loads CSS asynchronously after the DOMContentLoaded
event.
The CSS to JS correspondence in applications are not perfect. It wouldn't be strange for JS required in the body build to require a CSS file suitable for the head.css
bundle. You configure this in src/server/middleware/renderRouteContext.js
by moving the available assets into the different arrays. The ExtractTextPlugin
grabs any CSS into the head bundle from the body build if it's common to both.
Whilst developing, CSS-modules are not caught by the ExtractTextPlugin
configuration for CSS hot reloading on the client.
CSS Modules
You import any SCSS or CSS into a client JS file. The file extension /.module.s?css/
instructs Webpack to import the file as a CSS-module. This gives more clarity to each CSS file and some flexibility when managing styles.
Engine
npm: "v3.x"
node: "v5.x"
This project uses the above versions of npm and node. It's advised to use the same engine when using this boilerplate.
It doesn't work to develop, build, test or serve on Windows... if you want to make PRs for windows, please do!
Thanks For Ideas!
This boilerplate is shamelessly reusing some ideas from: