Building production ready prototypes
For last few years I have experimented with creation of UI implementation that would give me more relation to more advanced process and data management in backend and also improve business needs and logic relation in what we are building.
My job being designing and developing both ends, being able to relate back end to front end fully, or almost 1–1, means a lot (if not everything).
At the end, what came as a bonus of this solution concept is quick prototyping with prototypes which can be reused in building real thing, and ability to easier provide business with ability to AB test, switch features, redesign and implement something ad-hoc.
Problem
Looking at what most of UI implementations looked 2–4 years ago, we have seen no progress in understanding the core issue… There were better and better tools, giving us more automation or simplicity or covering more compatibility cases, but none gave us free simplification and ability to have lowest common denominator in terms of building blocks of front end features.
There was (and mostly still is) always single point of convergence for every aspect of UI — CSS,HTML and JS… Of course, there is a folder with all the CSS/SCSS/LESS (maybe finely separated and BEM organized and that, but still separated from all other stuff), folder where we keep all the templates and folder where we keep all our JS. At some point it all gets meshed up together and gets merged and minified. With new tools and approaches, JS went furthest to provide context of relation between the pieces, but html stayed in loosely coupled templates or separately written stuff and CSS was always global… until recently new tools provided us with a way to do it little better.
So, we mostly had separation of technologies in our UIs, not separation of concerns. Even when ReactJS came as a bearer of hope for real separation of UI modules, there were stuff missing, mostly conceptually.
2–3 years ago, I started building new UI stack around React and webpack, with the idea of designing something to fit modern development and general computer science standards. I was designing it to be UI piece of NodeJS driven system I was building for Vast.com I worked for at that time. I have built hive-like platform that hosts several applications of the same purpose using only one NodeJS server but with different visual and functional features that can be turned on and off . I needed ui to support this high level of resource sharing, customizability and general control over features and all that with high reuse factor.
I wanted to have isolated pieces, easy replaceable, replicable and sharable blocks that I could build, kick around, mess with and discard … and not care.
Also, was more and more interested, and worked on micro services based backends with CQRS + event sourcing as dominant concepts and idea was to make it all in-line philosophy-wise.
Pursue for a solution
I am going to make sure to provide you with concepts and ideas of particular solutions, not with best practices in creating them… I am also going to give you rough review of options to use in achieving it as well.
Wishlist:
- Self sufficient UI module — containing look and feel and logic. It would also be good that it is safe from mess potentially coming from the outside.
- Good separation of styles, DOM and interactions/applicative stuff inside module
- Ability to utilize global data handling as in line with CQRS principles as possible
- Ability to write it in most up to date syntax in JS and CSS
- Ability to always have highly customizable build with some (NodeJS) API that can provide us with dynamic builds and server side rendering.
- Live reload/HMR feature
- Give as much as possible portable code (for React Native in this case)
Evolution through practical application
Here is where I got so far as a result of applying and reiterating for last 2+ years on multiple projects of various sizes. Stuff I am going to show here are one of the factors of success my teams had in delivering various apps and features in different technologies (in the backend) in recent years.
Approach
In any engineering job it is important that you know what your parts are and how they come together… Modules and assemblies and little bits and pieces that make the whole… I do not have spectacular new component categorization for you nor I got new hype train for you to jump on — I got polished UI modules concept I wanna share.
Enter UI modules
React’s two basic parts are JS logic (which is mostly pure JS) and virtual DOM (which is, basically, very sophisticated data-driven HTML engine) . Looking from traditional web dev perspective, these are JS and HTML of your new app… you just need the CSS to complete the circle.
So, here is what I came up with as an optimal solution:
Here is your footer component. Ideally, It should hold all things footer in it — HTML, JS(if any) and CSS. So, the index.js is convergence point and it includes footer.jsx as a render (DOM) component, footer.jsx then uses footer.css to apply footer specific styles. Here is what the code looks like in practice:
import React from 'react';
import DOM from './footer.jsx';
export default class Footer extends React.Component {
constructor(props) {
super(props);
this.view = DOM;
}
render() {
return this.view();
}
}
I do agree that this should be stateless component, but this is for example purposes, so imagine that it has more “meat”.
And here is your JSX:
import React from 'react';
import styles from './footer.css';
import Logo from '../logo';
export default function() {
return (
<footer className={styles.container}>
<Logo />
<h1 className={styles.title} >This is footer!</h1>
<div className={styles.allRights}>
© 2017 Tessier-Ashpool All rights reserved
</div>
</footer>);
}
and CSS:
.container {
margin: 30px auto;
width: 97%;
lost-utility: clearfix;
}
.title {
margin: 20px auto;
}
.allRights {
clear: both;
display: block;
padding-top: 65px;
font-size: 16px;
padding-left: 10px;
}
Here is what makes this concept shine. As you can see, your JSX is well separated outside of JS, and can even be programmatically loaded depending on a use case (for AB testing purposes for example), same goes for CSS. It is all well separated from outside world as well which means full control of internal styles, and their naming. Every component can have its .container, .title etc class since CSS Modules are providing us with good specificity providing mechanism.
This is what you get as an output for footer opening html tag:
<div class="footer__container___1gSYe">
CSS Modules mean that each of your modules (css files) that get into this system (every css file related to specific ui module), gets parsed in a way that every class gets a name build from its file name, class name and hashed combination of these — getting to, for example .[filename]__[class name]_[first 5 chars of hash], you can configure it how ever you want. This is why every class is called like style.[class name].
When done like this, you have full comfort of logical verboseness when writing your modules and when it gets built, it is delivered to the browser in form that provides infinite specificity for your css.
You can, of course, do general/global styles, by just wrapping something in :global{}.
In the example above you can se how easy these modules fit together, since there is logo module loaded in footer… but that is out-of-the-box react thing, and that is beauty of it.
Webpacking
In this stack, like any other modern JS stack, there is build system, and in this case in particular it is Webpack. Looking at what it does, Webpack is not just a build system, it is providing us with easy implementation of some core concepts of solutions described here and carries some bonuses with it.
I’ll just highlight three things — handling of require and import, building css and HMR.
Handling of imports
Webpack has concept of loaders, each file included anywhere where webpack gets (require, import, url() in CSS…) has to have handler defined for its filetype (based of extension or name — it is handled by regex), so you can manipulate content pretty well, including inlining images under some size and such.
Parsing CSS
Take a look at mentioned loader setup for CSS that provides us with CSS modules:
{
test: /\.css$/,
use:[{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules:true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
loader: 'postcss-loader'
}
]
}
Any tutorial for technologies used is out of the scope of this article, but I think that above is providing good illustration on how good webpack api is, and how easy it is to implement this advanced thing. This is how css gets parsed and how import style from 'some.css'
gets registry of classes into style variable. style becomes {container: 'footer__container__Y56cF'}
…
There is another benefit of this approach, and that is ability of multi-style and multi-dom UI modules with dynamical swap between different variations. I know you can find tons of uses for this and it deserves article of its own so I will work on it and provide a link here when done.
HMR — hot module replacement
HMR is another great development feature that just plain makes your life easier and likable again… Instead of reloading whole page, it swaps piece of code that changed in your memory, making everything react to change you made in code almost instantly… like magic.
Bonus — NodeJS API
Webpack provides NodeJS API which allows us to rebuild on the fly, serving JS files dynamically.
I used it to compile couple variations of my js code on the fly and store it in memory-fs, this code was then served through single API endpoint picked by some criteria (it can be localization for instance).
This also allowed me better control when I was building delivery system for complex search widgets that were getting delivered to partner site (this was also quite easy with ui modules built like this). Additionally, I was able to implement awesome debug features utilizing this.
Data
Web apps love data, and you love data, everything s connected by the data, we need data and we need it available everywhere… That is why we have internet and smart phones.
On the other hand our app needs data provider as well, and smart one, one of a kind that will give us the most flexibility.
This is the last, but not the least important piece of this concept — everything should be decoupled, which, in this case, for me means event driven workflow and it all should receive data through subscription, which means that moving stuff around or removing it entirely would not cause breaks or need to change anything. When you take something out event listeners just stop receiving dispatched events and there is no one looking at the data, but in general it is all fine.. No data ever cried for not being consumed ;)
disclaimer: This part is rough overview of features and abilities, not in any way designed to teach you much about how redux works and how you should use it in our app. That is what code examples provided at the end are for.
Redux, what else
MobX, Relay and GraphQL, Jumpsuite(altho it is redux tbh), Flux, RxJS, ReactJS’s own state, they are all good choices… When I started building this, first version was using ReactJS state for data store, and it worked out perfectly. Then I upgraded to Redux.
Obviously, the most popular option is Redux, altho being known for its tiresome nature, it wins on brood force of great set of features… and social marketing. Just kidding, I think its documentation, support and presence are unparalleled, except by react itself… and community is managed great.
In short, Redux is my data container. They define it as predictable state container, which means that it has events and data (which is meant to be your app’s state) and that events mostly transmit and influence data, but data is all at the same place, in one big blob and little pieces of that blob are related to parts of your app and get changed by methods that are called reducers and are connected to events and a blob is not actually a blob, but na observable or something similar… you can subscribe to its changes, or, more precisely, your app can.
You probably understand enough to know that there are reducers that are in charge of setting data, that data is in one central place and that it is all event/action driven, which is enough to read this. You have to know that reducers are pure functions and, yes, it is exactly like event sourcing with short term memory.
Redux is in charge of all the data app contains, it’s data container is provided to the app using react-redux provider that wraps the whole app… In this case app is represented by router which is main entry point for the app. Store is redux store:
const App = ({ store }) => (
<Provider store={store}>
<Router history={ hashHistory }>
<Route path="/" component={ HomePage }></Route>
<Route path="/docs" component={ DocPage }></Route>
<Route path="/examples" component={ ExmplPage }></Route>
</Router>
</Provider>
);
Redux store is built from reducers and middlewares using redux’s createStore()
method that just combines any number of these together to form data store.
let store = createStore(
appDataReducers,
applyMiddleware(sagaMiddleware)
);
As you can see apart form reducers, I use redux-saga middleware to handle async stuff.
Data usage
General rule of a thumb here is that every module has its reducer and that modules that need async actions (data fetches mostly) also have their own separated sagas that are triggered by related actions.
Our modules are each subscribed to their specific data endpoint in the store (that is handled by its reducer), so data flow is complete.
Stack
View and glue — React
ReactJS is used to build views and contain modules, its virtual-dom + reactive state combination is unrivaled compared to any out of the box solutions. It provides nice API, is battle tested, community supported and has great documentation…
Style — PostCSS + CSS Modules
PostCSS is swiss army knife of styles, preprocessors and browser compatibility. It is collection of JS libraries that manipulate CSS and allow you to build your own CSS preprocessor from little functionality modules. From autoprefixer and nice simple and super efficient grid system to future CSS specification syntax etc. It can be set to perform any set of CSS tasks for you (like pinging caniuse and figuring out your set of prefixes you need) and you can make its syntax as rich as you want (manually pick features like nesting, imports, mixins, etc). PostCSS is a must for any future web UI project.
[Post CSS website](http://postcss.org/
CSS Modules are like primer for styling, the hard base to which we apply all the nice stuff — it will improve your BEM to undreamed maximum height of unlimited specificity and give you as much developer experience improvement.
Knowledge — React + saga
All the truth is out there sometimes, but in this case it is all in the global event driven state container, Redux, giving us easy and well controlled access to all the data app has and all the data app needs.
To be able to fully follow reactive — event sourcing CQRSish architecture that we want to use everywhere these days, we have to complement Redux event controlled state store with something to handle sagas (or in common tongue translation — anything that lasts more then “done immediately”), which are mostly ajax calls in this kind of apps. For this, I recommend redux-saga:
Webpack — packing stuff up
Packaging and transpiling is done through Webpack, and the most exciting pieces in this solution are highly dependent on webpack’s great seamlessness in implementing complex ways stuff is loaded and parsed:
Other pieces
- React router — great client side router, project had some problems around year hand half ago, but now they are again at the top.
- Axios — Great AJAX library — I plan to use fetch api from now on, but for now it turned out to be great..
- Jest — test test test, test everywhere. Facebook vastly improved their web testing framework giving it speed, more power, integrated code coverage reporting and making it another piece of their web+mobile stack that helps you write all the apps.
Recently
Last couple years, this stack is being used in many new apps and webpages. It has been further tested on crazy use cases and has proven to provide high level of efficiency/reusability when building React Native app based of it.
My wishlist seems to be all checked.
Code example — repo
For more context (or just some reading material), here is the repo containing boilerpate for UI development using this approach:
I have tons of stuff going on in there, and will write additional articles about some of them, but it is mostly useful to see how described stack looks at the present moment after seeing decent amount of battles and even more coffee. Repo itself is rather a playground, but with some docs and comments.
I am making sure that it is all well documented so who ever wants can go in and see if what is there can help you as much it helped me.
If you are ready to take it and cleanup the shell reusing patterns it is even ready to be used in any serious project. Apart from discussed above it has in it solutions for:
- Production and development builds
- Testing
- Coverage reports
- Build analytics
- Serving app in simple web server
- Checking for updates
Comments