So in this post, I just wanted to share the latest setup I have found working when I start a frontend project. Nothing revolutionary here, this won't be news, and at times you might disagree with my views. But on the other hand that might make you curious about something you haven't heard of, or find the last push to finally try this stuff everyone has been talking about.
But for new projects, I now always use Typescript - the clear winner of the js types battle, and a very pleasant subset to use. It is so good and actually easy that I rarely code without it, even on a technical interview test or when coding a micro app to track my newborn daughter's diapers. So good that I started to refuse jobs when they don't use typescript, as I don't want to go back to refactoring hell. Pretty strong move from a guy that was saying he "did not believe in it" a bit over three years ago.
Anyone saying such things hasn't probably used it, or only barely. But just give it a real try and you will see the enormous amounts of problems it solves. Not only does it imposes good standard practice and replace the chain of transpiling, but it also gives you the beautiful IDE intelliscence, the thing that boosts your productivity tenfold and provides strong confidence in your code. This is not the perfect silver bullet, you still have to test your code. But never again did I have to fry my brain while deciding to change the signature of one function: my IDE would tell me straight that it needed refactoring in ten different files.
The intellectual and time investment is small - or at least to get started and use basic types and inference - but the payoff is unfathomable before feeling it in everyday life.
So bottom line: I use TypeScript for frontend projects, and I strongly believe you should, too.
div with id
There are but three frameworks widely enough used today, and one of them is used way more than the other two, for, I believe, very good reasons. I won't launch into a comparison of them, whatever suits your boat, contract, abilities, etc... For me, having tried all of them, I go React all the way. If you have never tried it, or still think that it's arcane and complicated, I'd invite you to type
npx create-react-app myApp --typescript in your terminal and see what fun it is to start a new React project. I actually start all my (non-SSR, see below) projects with
create-react-app it has a perfect blend of opinions and freedom. I never feel any needs to eject.
React is pushing new ideas and practices. I would recommend following those as they steam from a simple yet powerful understanding of recurring pains in a coder's ass. React is truly elegant at heart. So there is no excuse not to use the latest features, like hooks and context, and keep moving as they get released.
To be honest, it's been a year that I haven't written a class component - and for the best!
Finally, typescript plays extremely well with React, an elegant way to type props and state.
So bottom line: I use React, with the latest features.
You are feeling that I am taking no risk here, just following the classic hype? Well, I am going to do it again!
You don't always have a say in the API the backend team is choosing. But when it's early enough (or when I also work on the backend team) I always try to push in the GraphQL direction.
GraphQL, in terms of services rendered, would be the Typescript of API. It changed the way I worked as a React front end coder and made it so much better that I wish to never go back to REST. For those who haven't heard much more of it than the name, I could start describing it as what would your rest endpoint look like if you made a particularly complex query system to select each field you want returned - plus each field of any relations, for any level of nesting. And that it would also self-document, self validate, generates a playground to test it and allow you to load the typescripts types for any query in a single CLI command. So, yeah, pretty good.
It is always a good attitude to say about it (like about anything) "well, it depends on your project if you should choose it are not". But as far as my front end experience goes, I haven't met one situation, however small, where Graphql was not a good fit.
Once you understand you should separate the data management (backend) from the UI generation (front end), and as you have a powerful language working on the browser, it makes good sense to have it manage the whole site or app. And thus Single Page Apps where born. Every React/Vue/Angular/Whatever project will need some routing to map (declaratively, remember) the URLs to this or this component/page.
For this task, the safe React bet is React Router. It's mature, well maintained, kind of too big to fail. And now with propper hook API, it is getting better than ever.
But I would like to submit another powerful library (that I hope will keep being updated): Hook Router. Its API is very elegant, simple to reason about, and way less verbose than the leader I talked about. I would recommend it absolutely, weren't there some little issues that still have to be ironed out (trailing slash management, for example, is a small detail that tells you: maybe not mature enough).
Bottom line: I would love to use Hook Router, but still am turning to React Router for professional projects. To be continued.
CSS are a pain. Because they rely on arbitrary namings that don't get type-checked; because they rely on a global scope and you can declare some class as many times as you want - making it easy to overload some rules, and hard to debug. And because they involve different professionals with different concerns and technical mindset (from designer to integrators to coders).
Many options here, CSS-in-js have just come out of the lush booming phase, as some stuff seems to start fading in the distance, others to slowly become mainstream. I have been trying quite some of them in the latest years, from basic CSS modules to Jss, Styletron or Radium.
But to me and many others, the big API winner is Styled-Components. It's elegant, fast, let's you write real CSS while injecting anything from the js in the form of a string template. Componentalizing and reuse are flawless. It's a bit of a change compared to a big stylesheet with atomic naming convention, so your integrator will have to adapt, and start working in the codebase - however, as it is still regular (sa|le|c)css, the shift is not too big to make.
As much as I enjoy Styled-Components, I think Emotion even comes ahead. They offer the same API than SC, but adds some other niceties, like the
CSS prop, and play way better with SSR in my experience.
When building a front end application, coding the UI elements is a big part of the work. As a coder is not a designer (he might think he is - but he's not) and that you might want to spend your time to more interesting problems, using a UI kit is always a big win - for a quick POC, even for production use when the product is fairly generic.
There are just so many of them out there that you can't check them all out. Some seem mature and beautiful, others just kinds of bla. The key for me is: a nice API on the component props, beautiful styles, a large variety of components and proper styling abilities so that I can adapt the kit to my own design - or a client identity, and save everyone a lot of time and money.
I tried Material UI (one of the biggest in the field), Semantic UI, Evergreen, Blueprint, Atlaskit, Ant Design, the One from Uber and even React-Bootstrap (well, a long time ago). I must admit that I am a big geek of those and is always on the lookout for a new best solution.
Material UI was a direct dislike. Their theming system is - to my taste - painful and weird. I had a better story with Ant Design, but again, their sass theming system is far from ideal (see the section before) plus it was kind of buggy to set up with SSR.
But sooner this year I stumbled upon Chakra Ui, and until now it checks all the boxes. Carefully made, nice looking, varied, and most of all: it's built with Emotion and follows the Styled System Theme Specification for theming, which is extremely nice to use. Every component exports all the useful CSS attributes so that you can add a margin here or there without needing the
style prop or adding CSS.
And on top of that, someone did https://openchakra.app/, a visual editor with Chakra Ui that produces React code. Not a big believer in those visual editors in general, but it's worth checking out.
Bottom line: use whatever makes you happy, but I will keep starting up my projects with Chakra Ui, and you should check it out if you haven't yet.
This is the time to bring up sate management. Once your app is well componentized, well decoupled, you start wondering how to inject, update and react to some global variables. The user data, for example, that are repeated in many discreet places - or a list of posts, the number of stars, the state of the UI, menu, top bar buttons, etc...
Since the introduction of the context API in React, you can inject a state - and have your components react to it - on any level of the tree. However, such a simple state sharing can become very messy: you quickly discover that debugging this shared state is often really difficult. The other essential thing that lacks in the
context+state or reducer hook solution is the notion of selectors: when your shared state changes, all the components that listen to this state gets rerendered - and if this state was an object, you cannot link the component to specific keys of it. So your component gets rerendered every time any key changes, even though it doesn't use it. Of course, you can use memoization to temper the problem, but it becomes quite messy.
The big, golden standard in global state management is, of course, Redux. Brought to us by Our Dan Who Art In Facebook, it combines flux design, immutability and good practices with an excellent debugging experience - and even a chrome extension to follow every step of your state changes. For me, it shines in big projects when many different developers work on the same app. If you do React you should know Redux, as you will have to use it sometime in your career.
However Redux is not without its faults. The main one would be the developer experience. Redux is not hard to understand or to set up, but it requires a lot of boilerplate code. It's extremely verbose - and this verbosity is sometimes a strength - but it feels tedious to use time and again. Adding async actions (you always need async actions) demands to add thunks or sagas, to your Redux setup - and it's more stuff to write.
So, when building an app with Apollo, you don't need to store your data in a global state - which makes the bulk of Redux use - but only rely on Apollo queries, and let the magic happen. This is one of the boons of Graphql, and why it is so good to front-end coders. Should I add that there is a very good chrome extension to watch and debug your cache? Apollo offers many other features, but this is beyond this humble piece.
But then what about the data that doesn't come from the API? Ui states, for example? It's likely to be a small amount. However, even for this, I feel reluctant to use either a simple context state either the full Redux machinery.
Apollo offers a way to use their cache for any data you want, even local ones, and it can seem like a good fit for the task. However, it feels very strange to declare graphQL types, mutations and queries for simple state updates. I tried it but ended looking elsewhere.
For me the solution came from this very pleasant (and vegan) library, Easy-Peasy. It uses redux and Immer under the hood, but leverages react hooks and context API to provide for a very intuitive system. You build an object with your data and your actions (and type it with TS) and get a Provider on one side, some hooks on the other, that are selectors to actions or values. So, the best of everything: simple API, hooks ready, typescript ready, multiple global states are possibles, you get real selectors and - best of all: you have access to the Redux debug tool for a perfect debugging workflow.
So bottom line: I use Apollo cache for server-sent data, and Easy-Peasy for the rest - or almost all the rest, see the next section.
So, forms. At some point, it's difficult to manage one
useState per field on your page. Then there is validation, that involves clean/dirty detection, error messages, rules, etc... Once you work on one form, you understand the underlying complexity of doing it properly.
So we want a library to do it. And one that is simple, not too bloated, and hook-ready. Well, there is one just here: React Hook Form. It's elegant, powerful, simple. And, how good, there is a page in Chakra Ui documentation on how to implement Hook Form with it. Doesn't it feel like everything fits together?
Hook Form is my last piece for the state management triangle. I use it on every creation/edition page and plug it straight with apollo queries/mutations.
Bottom line: React Hook Form
For this, you need to serve the bots a fully built version of your site. As everyone knows, you have two ways to achieve this. Either you build the whole site on the server before sending it to any client (including bots) and let js then manage it from the browser - this is SSR (server-side rendering); Or, you render the site only when a bot asks for it, on the cloud, with some headless chrome instance doing the work - and this is called pre-rendering.
So which one to use?
Here it depends on the project. But doing full SSR involves many tricks, and changing an existing codebase to enable it is a real pain. From my experience, doing prerendering is most of the time easier to build, mainly because it abstracts the rendering question from the react codebase. So then this is not a front-end concern, but an architecture/back end problematic. There are a few docker images that will do Prerendering out of the box if the team ever asks.
When it comes to full SSR, there is one major framework that does it well, it's Next.js. My complaints with it are only related to the routing system: they follow the file system for it, and I didn't leave PHP behind to go back to this convention hell. Otherwise, coupled with Apollo, it's very efficient, and they have good code-splitting out of the box.
The last time I built SSR I used another tool called Razzle, that felt more elegant at the time. If Razzle is very promising, it is not as well maintained as it is not backed by any company, and support is lagging a bit. Worth having a look, but for professional take-no-risk project, go with Next.
Bottom line: For SEO and bots only, I'd say go with prerendering. SSR for end-user means gaining a bit of a better experience only on the first render of the site. It is some work for not so much gain.
When your site is not very big or doesn't update that often, you may be interested in static rendering. That means SSRing all the pages your site contains in one pass, and serve everything from a static hosting then. No need for backend or API - at least not for your end-users - as all the data you need are included in the site at rendering time.
This is not limited to the front end, by the way. I static render an API of French synonyms that is huge (35000+ JSON documents) but will probably never renders another time.
I am no expert on the subject, but I very much dislike the leader of the field, Gatsby, for their weird data loading API. For my needs, I tend to favor either Next (the SSR framework has a pretty neat static rendering feature) or React Static, which is extremely versatile.
Bottom line: for a blog or a simple presentational site - where data is no changing much - static rendering makes good sense. You can have a look at React Static for the most natural DX I could find.
There are other things that I don't have the energy to start about now. For example, I recommend integrating Storybook as early as you can for any codebase beyond the odd side project, especially if some UI coding is involved - will save you a world of pain.
We could address testing - or the project's files organization. But that will be for another time.
Before leaving you, I wanted to stress how tiring it can feel to have new tools to learn, and how small the payoff can seem before you experience it yourself. This is a natural attitude. We learned once to adapt, to grow around the problems we had until we don't even see them anymore. But they are still here. When someone tells us "this lib is awesome, it solves this and this" and we think "I already have solutions for that" - well maybe we should give it a try. Remember how Jquery seemed once all we needed to build anything, and how we would never ever go back to it now that we worked with JS frameworks?
Photo by Lachlan Donald on Unsplash