A lot has happened in 2017, and it can be a bit overwhelming to think about. We all like to joke about how quickly things change in frontend engineering, and for the last few years that has probably been true.
At this risk of sounding cliché, I’m here to tell you that this time it’s different.
Frontend trends are starting to stabilize — popular libraries have largely gotten more popular instead of being disrupted by competitors — and web development is starting to look pretty awesome.
In this post, I’ll summarize some of the important things that happened this year in the frontend ecosystem with an eye toward big-picture trends.
Crunching the numbers
It’s hard to tell when something is the next big thing, especially when you’re still on the last big thing. Getting accurate usage data for open source tools is tricky. Typically we look in a few places:
- GitHub star counts are loosely correlated with a library’s popularity, but people often star libraries that look interesting and then never return.
- Google Trends is helpful for seeing trends at a rough level, but doesn’t offer data with enough granularity to accurately compare a particular set of tools.
- Stack Overflow question volume is more of an indication of how confused people are using a technology rather than how popular it is.
- NPM download stats is the most accurate measure of how many people are actually using a particular library. Even these might not be totally accurate since this number also includes automatic downloads like those done in continuous integration tools.
React 16 was released in September, bringing with it a complete rewrite of the internal core architecture without any major API changes. The new version offers improved error handling with the introduction of error boundaries as well as support for rendering a subsection of the render tree onto another DOM node.
The React team chose to rewrite the core architecture in order to support asynchronous rendering in a future release, something that was impossible with the previous architecture. With async rendering, React would avoid blocking the main thread when rendering heavy applications. The plan is to offer it as an opt-in feature in a future minor release of React 16, so you can expect it some time in 2018.
After eight beta releases and six release candidates, Angular 4 was released in March. The key feature in this release is ahead of time compilation — views are now compiled at build-time instead of render time. This means that Angular apps no longer need to ship with a compiler for application views, reducing the bundle size significantly. This release also improves support for server-side rendering and adds many small “quality of life” improvements to the Angular template language.
Over the course of 2017, Angular has continued to lose ground compared to React. Although the release of Angular 4 has been a popular release, it is now even farther away from the top spot than it was at the beginning of the year.
NPM downloads of Angular, React, and Vue
2017 has been a great year for Vue, allowing it to take its place as a premiere frontend view framework alongside React and Angular. It has become popular because of its simple API and comprehensive suite of companion frameworks. Since it has a template language similar to Angular and the component philosophy of React, Vue is often seen as occupying a sort of “middle ground” between the two options.
There has been an explosion of growth in Vue in the last year. This has generated a considerable amount of press and dozens of popular UI libraries and boilerplate projects. Large companies have started to adopt Vue — Expedia, Nintendo, GitLab among many others.
At the beginning of the year, Vue had 37k stars on Github and 52k downloads on NPM per week. By the middle of December, it had 76k stars on Github and 266k downloads per week, twice as many stars and five times as many downloads.
This still pales in comparison to React, which had 1.6 million downloads per week in the middle of December according to NPM Stats. One can expect Vue to continue its rapid growth and perhaps become one of the top two frameworks in 2018.
TL;DR: React has won for now but Angular is still kicking. Meanwhile, Vue is surging in popularity.
Shared Memory and atomic operations are a hugely significant feature that hasn’t gotten a lot of notice. Shared Memory is implemented using the SharedArrayBuffer construct, which allows web workers to access the same bytes of a typed array in memory. Workers (and the main thread) use atomic operations provided by the new Atomics global to safely access this memory across different execution contexts. SharedArrayBuffer offers a much faster method of communication between workers compared to message sending or transferrable objects.
As of December 2017 they are supported by all major browsers, and Edge starting with v16. Node does not currently support web workers, so they have no plans on supporting Shared Memory. However, they are currently rethinking their worker support, so it’s possible that it might find its way into Node in the future.
All major browsers now support WebAssembly, with Chrome support arriving in May, Firefox in March, and Edge in October. Safari supports it in their 11th release, which ships with MacOS High Sierra and an update is available for the Sierra and El Capitan releases. Chrome for Android and Safari Mobile also support WebAssembly.
None of these projects are production-ready and their APIs are changing frequently. Given the desire for compiling JS to WebAssembly one can expect these projects to gain momentum as WebAssembly becomes more popular.
There are already a lot of really interesting WebAssembly projects. There is a virtual DOM implementation targeting C++, allowing to create an entire frontend application in C++. If your project uses Webpack, there is a wasm-loader that eliminates the need to manually fetch and parse .wasm files directly. WABT offers a suite of tools that allow you to transform between the binary and text WebAssembly formats, print information about WASM binaries, and merge .wasm files.
TL;DR: WebAssembly will change everything eventually, but it’s still pretty new.
Yarn introduced lock files which allowed for reproducible builds across different machines and an offline mode that allowed users to reinstall packages without an internet connection. As a result its popularity exploded and thousands of projects started using it.
NPM responded with a massive v5 release which significantly improved performance and overhauling the API. Yarn responded with introducing Yarn Workspaces, allowing first-class support for monorepo package management similar to the popular Lerna tool.
There are now more options for NPM clients than just Yarn and NPM. PNPM is another popular option, billing itself as “fast, disk space efficient package manager”. Unlike Yarn and NPM it keeps a global cache of every package version ever installed which it symlinks into the node_modules folder of your package.
TL;DR: NPM has adapted quickly to Yarn’s surge in popularity, both are now popular.
There has always been a desire to solve some of the lower-level problems with CSS that make it difficult to use it in concert with component-based development. Particularly, the global namespace makes it difficult to create styles that are isolated within a single component. Keeping CSS in a different file than the component code means that smaller components take up a larger footprint and require two files to be open in order to develop.
CSS Modules augments normal CSS files by adding namespaces that can be used to isolate component styles. This works by generating a unique class name for each “local” class. This has become a viable solution with the widespread adoption of frontend build systems like Webpack, which has support for CSS Modules with its css-loader. PostCSS has a plugin to provide the same functionality. However, with this solution CSS remains in a separate file from component code.
“CSS in JS” was an idea introduced in a famous talk in late 2014 by Christopher “Vjeux” Chedeau, a Facebook engineer on the React development team. This has spawned several influential libraries making it easier to create componentized styles. By far the most popular solution has been styled-components, which uses ES6 tagged template literals to create React components from CSS strings.
TL;DR: PostCSS is the preferred CSS preprocessor, but many are switching to CSS-in-JS solutions.
There has been innovation in the module bundler space not related to Webpack. While it remains popular, developers have complained about the difficulty in configuring it correctly and the wide array of plugins required to get acceptable performance on large projects.
We see this in the transition from Angular to React / Redux and from SASS to PostCSS. Webpack and the bundlers and task-runners before it were all decentralized solutions with many plugins.
In fact, Webpack and React share similar complaints in 2017 for nearly the same reasons. It makes total sense that people would desire a “batteries included” solution for bundling as well.
Rollup generated a considerable amount of attention before the release of Webpack 2 in 2016 by introducing a popular feature known as tree shaking, which is just a fancy way of saying dead-code elimination. Webpack responded with support for Rollup’s signature feature in its second release. Rollup bundles modules differently than Webpack, making the overall bundle size smaller but at the same time preventing important features like code splitting, which Rollup does not support.
In April the React team switched to Rollup from Gulp, prompting many to ask why they chose Rollup over Webpack. The Webpack team responded to this confusion by actually recommending Rollup for library development and Webpack for app development.
TL;DR: Webpack is still by far the most popular module bundler, but it might not be forever.
Although this trend has existed for the last few years, it’s picked up pace in 2017. TypeScript is now the third-most loved language according to the 2017 Stack Overflow Developer Survey (Flow didn’t even garner a mention).
Reasons often cited as for why TypeScript won include: superior tooling (especially with editors like Visual Studio Code), linting support (tslint has become quite popular) larger community, larger database of third-party library type definitions, better documentation, and easier configuration. Early on TypeScript got automatic popularity by virtue of being the language of choice for the Angular project, but in 2017 has solidified its usage across the entire community. According to Google Trends, TypeScript grew twice as popular over the course of the year.
TL;DR: TypeScript is winning against Flow.
Redux continues to be the preferred state management solution for React projects, enjoying 5x growth in NPM downloads throughout 2017:
Mobx is an interesting competitor to Redux for client-side state management. Unlike Redux, MobX uses observable state objects and an API inspired by functional reactive programming concepts. Redux in contrast was heavily influenced by classic functional programming and favors pure functions. Redux can be considered a “manual” state manager in that actions and reducers explicitly describe state changes; MobX in contrast is a “automatic” state manager because the observable pattern does all of that for you behind the scenes.
MobX makes very little assumptions about how you structure your data, what type of data you’re storing, or whether or not it’s JSON-serializable. The above reasons makes it very easy for beginners to start using MobX.
Unlike Redux, MobX is not transactional and deterministic, meaning you don’t automatically get all of the benefits Redux enjoys with debugging and logging. You can’t easily take a snapshot of the entire state of a MobX application, meaning that debugging tools like LogRocket have to watch each of your observables manually.
It’s used by several high-profile companies like Bank of America, IBM, and Lyft. There is also a growing community of plugins, boilerplates, and tutorials. It’s also growing really fast: from 50k NPM downloads at the beginning of the year to a peak of 250k NPM downloads in October.
Because of the aforementioned limitations, the MobX team has been hard at work at combining the best of both world of Redux and MobX in a project called mobx-state-tree (or MST). It’s essentially a state container that uses MobX behind the scenes to provide a way to work with immutable data as easy as working with mutable data. Basically, your state is still mutable, but you work with an immutable copy of this state referred to as a snapshot.
There is already a plethora of developer tools that help debug and inspect your state trees — Wiretap and mobx-devtools are great options. Because they operate in a similar way, you can even use Redux devtools with mobx-state-tree.
TL;DR: Redux is still king, but look out for MobX and mobx-state-tree.
There are now many client and server implementations to choose from. Apollo is an popular client and server choice, adding comprehensive cache controls and integrations with many popular view libraries like React and Vue. MEAN is a popular full-stack framework that uses GraphQL as an API layer.
Within the last year the community behind GraphQL has also grown immensely. It has created server implementations in over 20 languages and thousands of tutorials and starter projects. There is a very popular “awesome list”.
React-starter-kit — the most popular React boilerplate project — also uses GraphQL.
TL;DR: GraphQL is gaining momentum.
Also worth mentioning…
While it has been possible to use threads in Node using the node-webworker-threads package and by interfacing with lower-level languages, Napa makes this seamless with the rest of the Node ecosystem by adding the ability to use the Node modules system from inside worker threads. It also includes a comprehensive API for sharing data across workers, similar to the newly released shared memory standard.
The project is Microsoft’s effort to use bring high-performance architecture to the Node ecosystem. It’s currently used by the Bing search engine as part of its backend stack.
Given that it has the support of a major company like Microsoft, you can expect long term stability. It will be interesting to see how far the Node community goes with multithreading.
The trend in recent years has overwhelmingly been an increase in the importance of and complexity of build tools. With the debut of Prettier, code formatting is now a popular addition to a frontend build pipeline. It bills itself as an “opinionated” code formatter designed to enforce a consistent coding style by parsing and reprinting it.
While linting tools like ESLint have long been able to automatically enforce linting rules, prettier is the most feature rich solution. Unlike ESLint, Prettier also supports JSON, CSS, SASS, and even GraphQL and Markdown. It also offers deep integration with ESLint and many popular editors. Now if we could just agree on semicolons, we’d be alright.
Experience your Vue apps exactly how a user does
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.
LogRocket: Full visibility into your web and mobile apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
Get set up with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID
Install LogRocket via npm or script tag.
LogRocket.init()must be called client-side, not server-side
- (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- NgRx middleware
- Vuex plugin