Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2020: React v17, ES2020, Node.js v14 #3

Open
wants to merge 22 commits into
base: react-v15-2016
Choose a base branch
from

Conversation

i-like-robots
Copy link
Owner

@i-like-robots i-like-robots commented Mar 6, 2022

Scene setting: No toilet paper, washing hands, face masks, staying inside, everything over Zoom.

JavaScript

In 2016 we were dealing with a step change in JavaScript created by more than a decade of pent-up potential energy bursting out all at once in the ES6 spec. Since then JavaScript has continued to evolve but only drops a handful of features with each regular release.

The TC39 process was created in response to the massive and overwhelming changes brought by ES6. The TC39 committee now governs how new features are designed and added to the language (which is all done here) and new features which make it through to the final acceptance stage will be added to the next year's ECMA-262 specification.

The first annual spec release was for ES2016 and the additions were minor but it did pave the way for ES2017 by promoting async and await to keywords. Promises completely changed how we handled asynchronous - or might be asynchronous - code and async functions built upon these foundations to enable more comprehensible synchronous-looking code.

ES2018 gave us the spread operator for objects, ES2019 introduced the methods to flatten nested arrays and methods to turn iterable things into objects, and ES2020 brought nullish coalescing and optional chaining.

This iteration of the app takes advantage of many of these new features and like the switch from ES5 to ES6 many of them make for less and more readable code. But not only can the app logic be expressed more succinctly than it could before, it should also be more reliable because custom logic has been replaced with well behaved language features. All of the server side code has been refactored to use ES modules too, just like the front-end, but this is still being compiled to CommonJS because although ESM support arrived in Node.js v14 for all practical purposes it was unusable.

React

JavaScript may have received small incremental changes since 2016 but React introduced a completely new way of writing components. React v16.8 was a minor release but it came with an experimental implementation of "hooks" which would turn how to think about and compose component logic on its head.

The React hooks documentation leads with an underwhelming introduction to this significant new feature: "They let you use state and other React features without writing a class" to which I say "so what?" and "aren't functional components meant to be stateless?!"

But hooks are not simply an effort to rid the world of classes, they're intended to solve some real problems like preventing duplicated logic in lifecycle methods and enable more sharing and reuse of non-visual logic. The latter is compelling because reusing logic between class components is not always easy, higher-order components (HOCs) and render props work sort of fine but it can be confusing to see new props magically appear in your render method and composing multiple layers of them can quickly become a little scary 😨:

const Wrapped = withAuth(withRouter(connect(data)(Component)));

But it's not easy to switch to hooks, they're a new paradigm which requires a new mindset. Adding state to previously stateless things does feel magic, debugging closures which have become "stale" due to mismanagement of their dependencies is hard, and it is easy to get those dependencies wrong and find yourself inside an infinite loop. Hooks are esoteric, beyond the basics they are difficult to explain, and without help it's easy to find yourself battling a fractal of useRef(), useMemo() and useCallback() usage.

I initially found hooks strange to look at but quite easy to pick up, just like React itself back in 2014, but unlike the early versions of React which elevated my existing knowledge and enabled me to express my ideas quickly, I struggled to master hooks and can still stumble over them. I know many others have struggled to adopt them too, so whilst React remains well ahead of the pack developer satisfaction with it is dropping. I personally know more than a dozen developers who will no longer work with it at all.

On the plus side, hooks truly have enabled sharing and reusing component logic. Projects like react-use and React ARIA provide hundreds of hooks which solve all sorts of common problems.

This version of the app is built using React v17 and has been fully refactored to use hooks. I have not abstracted any logic into custom hooks to avoid breaking the diff.

Tooling

Over the years I've heard many criticisms of Webpack from all corners of web development. I've listened to people complain that it's too complicated or too slow and even once that it simultaneously does both too much and too little. Despite this in 2020 it was still easily the most popular JS bundler and Babel and its plugin ecosystem remained top of the pile for compiling too.

I understand why many developers don't enjoy working with Webpack and Babel, despite how useful they are. I know they can be slow and a pain and shipping a tiny React app like this requires installing at least 275 different packages. To avoid the headache of a modern JS toolchain many developers will reach for a boilerplate like Create React App which was downloaded over 7 million times in 2020 but this will install over 1300 dependencies which take up more than 300MB of disk space which is completely absurd for an app with less than 100KB of source code 🤯.

Whilst these heavyweights remain the most widely used and versatile by 2020 they were no longer always the default choice because a host of smaller, zero or low configuration tools were hitting the mainstream.

In 2017 the tiny Babel spin-off Sucrase was released which is able to compile all of the latest JavaScript sugar down to more widely compatible ES6. The Rust based SWC came in 2019 and it promised a 70x speed increase over Babel without requiring any configuration. And in 2020 we got the Go based ESBuild which can not only compile the latest JS all the way down to ES5 but bundle and minify it as well.

Rollup deserves an honourable mention here too, it's usage has increased exponentially since it was first launched but you may not have noticed because it's quietly doing the heavy lifting behind the scenes in tools like Vite, Snowpack, and Microbundle.

This version of the app uses ESBuild for compiling and bundling all of the code for the browser and compiling away the JSX and ESM on the fly for the server too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant