The bleeding-edge saga

Rafael Campos
8 min readApr 1, 2018

--

Being a frontend developer in 2018 is hard but in a good way. Hundreds of possibilities, new libraries appear every day and it is up to us to choose the best among them.

I work on a Startup called Eventfly. We are a white label service for ticket sales on the web as well as mobile.

As the platform matured and more features were added, the complexities and shortcomings became very apparent: various CSS files scattered throughout the project, nested routes, an intricate system of actions, reducers, and reselectors, repetitions and underutilization of the components. Conclusion, a nightmare to maintain and a puzzle for new developers.

A complete refactor was in order. We needed to resolve the scalability and maintenance issues.

As soon as I was appointed by our CTO to lead the project, my head was already bubbling with a dozen of cool ideas, it’s time to choose:

So, we started to decide which libraries and frameworks would integrate the project:

React

That did not even get in the way, we would continue to use React. The benefits are numerous and there are hundreds of texts out there dedicated to presenting them, but I would like to highlight the componentization and the declarative way of programming as two fundamental aspects for the adoption of React.

Monorepo

We wanted all our web projects (institutional page, web ticket sales platform and our management platform for producers) to make a single environment, a monorepo.

Why a monorepo? Cohesion. The centralization of the project configuration and its dependencies was what made us to adopt the idea of implementing a single repository.

We had a W.O. in this dispute. We did not even consider Lerna, Yarn Workspaces was our choice.

We love Yarn (who does not ?!) and we get excited when we discovered its multi-project management system.

The implementation is simple: in the project root, we created a package.json, where we inform the workspaces:

“workspaces”: [“projects / *”, “common”]

Look at this *, this field also accepts glob patterns, sweet!

Now we just need a single yarn to install and link all dependencies, pretty neat!

Emotion Vs. Styled-Components

We no longer wanted to deal with a lot of CSS files, the lack of cohesion caused by them spread throughout the project, neither class overlays nor the damn important!.

Also, changing the CSS programmatically by linking to the props can be a nightmare, it would be nice if it were all JS, wouldn’t it? It turns out it can be all JS!

So, CSS-in-JS was another easy decision, but which library to adopt? Emotion or Styled-Components.

I voted for Styled-Components, but Felipe, our CTO and oracle when it comes to what technology to adopt (seriously, he must have some insider information because he usually predicts which technology will win the battle in the jungle that is the JS environment), he voted for Emotion.

And although in this case, the fight is still going on, with no apparent winner, Emotion is faster and by the time we decide, had a system of themes already implemented, which is very interesting for us, since we are a white label and we want that the customer could be free to style his app, making it unique.

Strongly-typed

I love JS. I learned to code with Python and even had my phase with Ruby and Kotlin, but I really fell in love with JavaScript, to be more specific, ECMAScript 6.

And I was accustomed to JavaScript’s dynamic types and my attempts to mitigate inconsistencies with the use of PropTypes, when the oracle, a.k.a. Felipe, asked me: “Why not use TypeScript?”.

My first reaction was rejection: “the simple adoption of TypeScript does not reduce errors”, “it creates more syntax noise and more lines of code increases the possibility of errors”, “the longer build time with the transpiling process”…

In addition, we have to remember that complex types are not generated automatically in an error-proof system, we are the ones who write them and in a dynamic system like ours, not always writing a type is an easy task and, finally, types are not checked at runtime.

But like the Dungeon Master in the Dungeons & Dragons TV series, Felipe launched the questioning and disappeared, which led me to hold the discussion to myself and question if all that rejection was not just me trying to keep myself in my comfort zone with my old friend JavaScript...

Two references in a single paragraph, this is getting very deep …

Well I decided to try and after some time I came to answer the question “why to use TypeScript” like this:

I see the TS as a form of documentation with superpowers. For example, when defining a function, we parameterize its possible parameters and what it returns, facilitating the life of another team member, or our future self; we have the integration with our IDE (VSCode rules!) we gain snippets and autocompletion, boosting productivity and eliminating the need to know the entire code base by heart; and we even got one last compile check.

Conclusion, The Dungeon Master got me there, let’s adopt TypeScript!

React-Styleguidist vs. Storybook

In this idea of monorepo and a file with the components shared between the projects, the adoption of a cataloging library and the visual test was our next topic.

In this match,we had two competitors: React-Styleguidist and Storybook.

The idea of the React-Styleguidist was incredible, just create a .md file for each component, it would automatically detect them, auto document the props, and complement the documentation with simple comments in the code.

It turns out that all this automation, in a project like ours, a monorepo with Typescript, began to generate a configuration need that was not as straightforward as we would have liked, what eventually led us to rethink its adoption and its replacement by the Storybook.

With the Storybook we created a folder called .storybook in each of the monorepo projects and in it we inserted the custom webpack settings:

.storybook / webpack.config.js

And config:

.storybook/config.js

We can also create a .babelrc file for each of the projects.

Server-Side Rendering

We are a sales platform; every second the customer waits to load the page translates into a loss of money for our customers.

In addition, we need Search Engine Optimization to improve their exposure.
Using React, an option that we found interesting, was to render the pages, at least the most important of them on the server. Then came the question: how?
I was studying the adoption of Next.js, but abandoning the React-Router was bothering me and the model of convention over configuration is not something that brings me good memories thanks to Rails.

It was then that I heard an episode of The React Podcast. Michael Jackson was talking to Jared Palmer about Palmer’s projects when he started talking about Razzle and After. And it was exactly what I wanted, the powers of Next with the possibility of maintaining the React-Router.

I talked to Felipe, thinking that that time I would finally surprise him and he replied: “I also think it’s a good idea to adopt After, in fact, I think I posted this in our slack some time ago.” Man, nobody surprises the oracle …

I started implementing Razzle / After, adjusting the settings to fit our monorep, with TypeScript, when Webpack v. 4 was released and talking to Felipe I commented that it would be nice if Razzle would soon adopt the new version. He told me that he had already talked to Palmer about it and that he had told him that maybe I could upgrade the lib.

Wow, contribute to an Open Source, with several plugins, that supports a number of libs and frameworks (there are 20 examples that could not break) … [Deep breath]

My PR, # 525, was merged and we got support for Webpack v.4, even before the create-react-app launched theirs (I know it’s silly, but I’m proud of it).

But Razzle still had to be set up, which given the particularity of our project, was not a simple task.

razzle.config.js (https://github.com/jaredpalmer/razzle#extending-webpack)

client.ts

Document.ts (https://github.com/jaredpalmer/after.js/blob/master/README.md#custom-document)

server/index.ts

We faced a limitation with the adoption of the After, it renders a Switch and we needed to render a Header on all routes.

The solution we found was to insert the Header into customRenderer, which has been transformed into a Higher-order function:

const customRenderer = (brand, containers, theme) => node => {
const App = (
<Provider inject={values(containers)}>
<EventflyThemeProvider theme={theme}>
{{
...node,
props: {
...node.props,
children: (
<Fragment>
<Header brand={brand} />
{node.props.children}
</Fragment>
),
},
}}
</EventflyThemeProvider>
</Provider>
)

State Management

“I do not think we should use Redux in this project,” said the oracle. Man, right now that I was comfortable with the RVA system (reducers, views, actions), I had already understood how to use reselectors and depended on a lot of middlewares …

And then the new ContextAPI has arrived and with it, Unstated.

The idea of encapsulating the logic of communication with the API and maintaining the state in components seemed to align with what we wanted in the project: reuse and simplicity.

Yeah, one more point for the Dungeon Master.

EventsContainer.tsx

Now, with the powers of Render Props, we can subscribe to this container and have access to its state and methods.

So far…

The refactor has already passed the institutional page and reached the web platform, where we must see the full power of this boilerplate in action.

Now, besides the elaboration of each of the components and organization of them on the pages, we also turn to the adoption of new patterns of components, such as compound components and render props.

In addition, we plan to turn the app into a PWA, with the help of the wokbox.

What I can say so far is that it has been an incredible process and that I feel that this project will comply with what we propose, that it was: easy to scale and maintain the code.

Thank you so much for joining me here and see you in the scenes of the next chapters, after all, a lot of new stuff is about to arrive!

--

--

Rafael Campos

Senior React Developer @SkipTheDishes, addicted to online courses and learning new technologies