☀️ - React-Router
☀️ - Marko
A short rundown of the various technologies:
- Marko - Fast HTML rendering engine, into which we slot in our React-generated HTML
- MobX - Awesome state management library, makes it so easy I feel like I'm cheating somehow. State stores initialized on the server, altered by some actions depending on request, and then passed over to the client to continue its state-altering journey.
- ReactJS - Build views on the server according to state and then inject functionality into those already built views on the client, and continue calling MobX actions and re-rendering accordingly
- React-Router - A routing solution for ReactJS. Works great with server-side rendering too, catching all possible routes we may want to render.
Folder and Module Structure
||What's in it
Regular React components, main
App component and whatever else makes up the layout.
/svg - SVG React components. Placed directly in the code as if they were normal functional React components. Much easier to incorporate into layouts. They're usually very small in size (1-3kb) so it's not a data hog and means they load instantly with SSR too.
/routes - The React-Router defined routes for our app
A bunch of organised
.scss, Sass style modules. The main one,
entry.scss, is included in our
entry.js so webpack knows it's part of our client bundle (and hot reloading works because it becomes part of the "hot" bundle)
By using Webpack, when we compile for production, these styles are automatically extracted into a seperate styles.css file that we can include in the head of our html.
API functions (returning promises) that work on both client and server side using
These APIs are most likely only going to be called from MobX stores, since all our state is managed by them and it makes it very easy to reason about what we're doing if there are only a few endpoint actions (functions) we have to call on both client and server.
Pretty self explanatory, just constants to be used throughout the app. For now it's just different types of tabs. This allows us to think about certain parts of the UI as one, constant thing and therefore we can create things like language dictionaries that can be access according to a language constant and the UI constant but the components remain exactly the same.
For now there are no constants, as before there used to be some to keep track of tabs- that is managed by the different routes in React-Router now. BUT constants are still a very important part of an app's ecosystem in order to maintain consistency between things. It is left here as an empty folder to be expanded upon.
/stores - All the MobX stores in seperate modules, which are basically just classes with
@decorators to keep things neat. some of them access API files from above.
allStores.js - The only part of the code that feels too static too me, but required for the next step. We just bundle all the modules from the folder above into a single exported object. This enables what happens in the next file.
store-utils.js - Creating and hydrating stores (for now the only utils). It requires that we remember to put our stores in the imported
allStores.js above so they are included in the processes. Used on the server side first to create new stores (which are then used normally before the request returns), and then hydrated on the client side (taking the state that came from the server and mirroring it exactly on the client side MobX stores).
The most important crossover file. It has a
The entry point for our server. It makes use of
Our actual server file. It's a basic Koa server, makes use of some base middleware imported from the
/middleware folder and a router from
Take a look inside
/middleware/crossoverMiddleware.js to see how MobX state is first created, and then used to render our React at the end of a request.
The amazing part about Koa is its use of
async functions and using the
await key word for request/response streams. Makes things much easier to reason about, especially with our MobX stores also returning
async / await functions which themselves can be
await'ed. Take a look inside the router file to see it in action.
Within our server we make use of Pug as the view engine. We also serve files in the
/static directory thanks to some middleware which you can find in the
Or, even better (if you are using
To start the development server (which is what you want most of the time)
npm run dev
To start the production server is the usual
npm start, but the code has to be built first, so:
npm run build
Or for quick production testing
npm run build-start
Before deployment to a production server, your code should always be built first- so that the default
Some Extra Configuration Information
npm start can be used to spin up quickly.
I'm using the
npm run dev ) - as recommended.
The server code (and the React code which is used on the server) is then built into the
/built folder for production use (
npm start )