Quantcast
Channel: 懒得折腾
Viewing all articles
Browse latest Browse all 764

State of the Art JavaScript in 2016

$
0
0

State of the Art JavaScript in 2016

Image “Question!” by Stefan Baudy, CC BY 2.0

So, you’re starting a brand new JavaScript front end project or overhauling an old one, and maybe you haven’t kept up with the breakneck pace of the ecosystem. Or you did, but there’s too many things to choose from. React, Flux, Angular, Aurelia, Mocha, Jasmine, Babel, TypeScript, Flow, oh my! By trying to make things simpler, some fall into a trap captured by one of my favorite XKCD comics.

Well, the good news is the ecosystem is starting to slow down. Projects are merging. Best practices are starting to become clear. People are building on top of existing stuff instead of building new frameworks.

As a starting point, here’s my personal picks for most pieces of a modern web application. Some choices are likely controversial and I will only give basic reasoning behind each choices. Keep in mind they’re mostly my opinion based on what I’m seeing in the community and personal experiences. Your mileage may vary.

Core library: React

The clear winner right now, is React.

  • Components all the way down makes your application much easier to reason about.
  • The learning curve is very flat. The important APIs fit would fit on one page.
  • JSX is awesome. You get all the power of JavaScript and its tooling when writing your markup.
  • It is the natural match for Flux and Redux (more on that later).
  • The React community is amazing, and produced many best of breed tools such as Redux (also more on that later).
  • Writing high quality data flow is much easier in large applications than dealing with 2 way data binding (eg: Knockout)
  • If you ever need to do server side rendering, React is where it’s at.

There’s plenty of monolithic frameworks like Ember, Aurelia and Angular that promise to take care of everything, but the React ecosystem, while requiring a few more decisions (that’s why you’re reading this!), is much more robust. Many of these frameworks, such as Angular 2.0, are playing catch up with React.

Picking React isn’t a technology decision, it’s a business decision.

Bonus points: Once you start working on your mobile apps, you’ll be ready for it thanks to React Native.

Application life cycle: Redux

This isn’t the final logo!

Now that we have our view and component layer, we need something to manage state and the lifecycle of our application. Redux is also a clear winner here.

Alongside React, Facebook presented a design pattern for one way data flow called Flux. Flux largely delivered on its promise of simplifying state management, but it also brought with it more questions, such as how to store that state and where to do Ajax requests.

To answer those questions, countless frameworks were built on top of the Flux pattern: Fluxible, Reflux, Alt, Flummox, Lux, Nuclear, Fluxxor and many, many more.

One Flux-like implementation eventually caught the community’s attention, and for good reasons: Redux.

In Redux, almost all of the moving parts are pure functions. There is one centralized store and source of truth. Reducer functions are responsible for manipulating data that makes up the store. Everything is much clearer than in vanilla Flux.

More importantly, learning Redux is a snap. Redux’s author, Dan Abramov is a fantastic teacher, and his training videos are fantastic. Watch the videos, become a Redux expert. I’ve seen a team of engineers go from nearly zero React experience to having a production ready application with top notch code in a few weeks.

Redux’s ecosystem is as top notch as Redux itself. From the nearly magicaldevtool to the amazing memoization utility reselect, the Redux community got your back.

One thing to be careful is the natural instinct to try and abstract away the Redux boilerplate. There’s good reasons behind all those pieces. Make sure you tried it and understand the “why” before trying to blindly improve on it.

Language: ES6 with Babel. No types (yet)

Avoid CoffeeScript. Most of its better features are now in ES6, a standard. Tooling (such as CoffeeLint) is very weak. Its community is also rapidly declining.

ES6 is a standard. Most of it is supported in the latest version of major browsers. Babel is an amazing “pluggable” ES6 compiler. Configure it with the right presets for your target browsers and you’re good to go.

What about types? TypeScript and Flow both offer ways to add static typing to JavaScript, enhancing tooling and catching bugs without needing tests. With that said, I suggest a wait and see approach for now.

TypeScript tries too hard to make JavaScript like C# or Java, lacking on modern type system features such as algebraic data types (and you really want those if you’re going to do static types!). It also doesn’t handle nulls as well as Flow.

Flow can be much more powerful, catching a wider variety of bugs, but it can be hard to setup. It’s also behind Babel in terms of language features and has poor Windows support.

I’ll say something controversial: Types are not nearly as critical to front end development as some will have you believe (the whole argument will have to be in a future blog post). Wait until the type systems are more robust and stick to Babel for now, keeping an eye on Flow as it matures.

Linting & style: ESLint with AirBNB

Another clear winner ESLint. With its React plugin and awesome ES6 support, one could not ask for more of a linter. JSLint is dated. ESlint does what theJSHint + JSCS combo does in a single tool.

You do have to configure it with your style preferences. I highly recommendAirBNB’s styleguide, most of which can be enforced via the ESlint airbnb config. If your team is the kind that will argue on code style, just use this style guide as gospel and the end all be all of arguments. It isn’t perfect, but the value of having consistent code is highly underestimated.

Once you’re comfortable with it, I’d suggest enabling even more rules. The more that can be caught while typing (with an ESlint plugin for your favorite editor), the less decision fatigue you’ll have and the more productive you and your team will be.

Dependency management: It’s all about NPM, CommonJS and ES6 modules

This one is easy. Use NPM. For everything. Forget about Bower. Build tools such as Browserify and Webpack brings NPM’s power to the web. Versioning is handled easily and you get most of the Node.js ecosystem. Handling of CSS is still less than optimal though.

One thing you’ll want to consider is how to handle building on your deployment server. Unlike Ruby’s Bundler, NPM uses wildcard versions, and packages can change between the time you finish coding and you start deploying. Use a shrinkwrap file to freeze your dependencies (I recommend using Uber’s shrinkwrap to get more consistent output). Also consider hosting your own private NPM server using something like Sinopia.

Babel will compile ES6 module syntax to CommonJS. You’ll get a future proof syntax, and the benefits of static code analysis, such as tree shaking when using a build tool that supports it (Webpack 2.0 or Rollup).

Build tool: Webpack

Unless you fancy adding hundreds of script tags to your pages, you need a build tool to bundle your dependencies. You also need something to allow NPM packages to work in browsers. This is where Webpack comes in.

A year ago you had a lot of potential options here. Your environment, such as Rails’ sprockets could do it. RequireJS, Browserify and Webpack were the JavaScript based solutions. Now, RollupJS promises to handle ES6 modules optimally.

After trying them all, I highly recommend Webpack:

  • It is more opinionated yet can be configured to handle even the craziest scenarios.
  • All main module formats (AMD, CommonJS, globals) are supported.
  • It has features to fix broken modules.
  • It can handle CSS.
  • It has the most comprehensive cache busting/hashing system (if you push your stuff to CDNs).
  • It supports hot reload out of the box.
  • It can load almost anything.
  • It has an impressive list of optimizations.

Webpack is also by far the best to handle extremely large SPA applications with built in code splitting and lazy loading.

Be warned that the learning curve is brutal! But once you get it, you’ll be rewarded with the best build system available.

But what about Gulp or Grunt? Webpack is much better at processing assets. They can still be useful if you need to run other kind of tasks though (usually you won’t). For basic tasks (such as running Webpack or ESlint), I recommend simply using NPM scripts.

Testing: Mocha + Chai + Sinon (but it’s not that simple)

There are a LOT of options for unit testing in JavaScript, and you can’t go wrong with any of them. If you have unit tests, that’s already good!

Some choices are Jasmine, Mocha, Tape and Ava and Jest. I’m sure I’m forgetting some. They all have something they do better than the rest.

My criteria for a test framework are as follow:

  • It should work in the browser for ease of debugging
  • It should be fast
  • It should easily handle asynchronous tests
  • It should be easy to use from the command line
  • It should let me use whatever assertion and mock library I want

The first criteria knocks out Ava (even though it looks awesome) and Jest (auto-mocking isn’t nearly as nice as it sounds, and is very slow anyway).

You can’t really go wrong with Jasmine, Mocha or Tape. I prefer Chai asserts because of all available plugins and Sinon’s mocks to Jasmine’s built in construct, and Mocha’s asynchronous test support is superior (you don’t have to deal with done callbacks). Chai as Promised is amazing. I highly recommend using Dirty Chai to avoid some headaches, though. Webpack’smocha-leader let’s you automatically run tests as you code.

For React specific tooling, look at AirBNB’s Enzyme and Teaspoon (this isn’t the Rails based Teaspoon).

I really enjoy Mocha’s features and support. If you want something more minimalist, read this article about Tape.

Utility library: Lodash is king, but look at Ramda

JavaScript doesn’t have a strong core of utilities like Java or .NET does, so you’ll most likely want to include one.

Lodash is by far the king and contains the entire kitchen sink. It is also one of the most performant, with features such as lazy evaluation. You don’t have to include the whole thing if you don’t want to, either: Lodash lets you include only the functions you use (pretty important considering how large it has become). As of 4.x, Lodash also natively supports an optional “functional” mode for the FP geeks among us.

If you’re into functional programming, however, take a look at the fantasticRamda. If you decide to use it, you might still need to include some Lodash functions (Ramda is focused on data manipulation and functional construct almost exclusively), but you’ll get a lot of the power of functional programming languages in a JavaScript friendly way.

Http requests: Just use fetch!

Many React applications don’t need jQuery at all anymore. Unless you’re working on a legacy application or have 3rd party libraries that depend on it, there’s no reason to include it. That means you need to replace $.ajax.

I like to keep it simple and just use fetch. It’s promise based, it’s built in Firefox and Chrome, and it Just Works ™. For other browsers, you’ll need to include a polyfill. I suggest isomorphic-fetch, to ensure you have all your bases covered, including server side.

There are other good libraries such as Axios, but I haven’t needed much beyond fetch.

For more details about why promises are important, see my post onasynchronous programming.

Styling: Consider CSS modules

This is an area I feel is lagging behind. SASS is the current go to, and node-sass is a great way to use it in your JavaScript project. That said, I feel it’s missing a lot to be a perfect solution. Lack of reference imports (a way to import just variables and mixins from a file, without duplicating selectors) and native URL rewriting makes it harder than needed to keep things lean and clean in production. node-sass is a C library, and will have to be kept in sync with your Node version.

LESS does not suffer from these issues, but has fallen out of favor due to lacking many of SASS’ features.

PostCSS is much more promising, allowing you to kind of “make your own CSS processor”. I’d recommend using it on its own, or even in ADDITION to your preferred processor for things such as AutoPrefixer instead of importing a big library like Bourbon.

One thing worthy of attention though, are CSS modules. CSS modules prevents the “cascading” part of CSS, allowing us to keep our dependencies explicit, and prevents conflict. You’ll never have to worry about overriding classes by accident or having to make ultra explicit names for your classes. It works great with React, too. One drawback: css-loader with CSS modules enabled is REALLY slow, so if you plan on having hundreds of kilobytes of CSS, you may want to avoid it until it gets better.

If I was to start a large project from scratch today, I’d probably just use PostCSS along with pre-compiled versions of my favorite CSS libraries.

Regardless of what you choose, you may want to look at my post on CSS performance with Webpack, especially if you go with SASS.

Universal (Isomorphic) JavaScript: Make sure you need it.

Universal or Isomorphic JavaScript refers to JavaScript that can be used on both the client and the server. This is primarily used to pre-render pages server side for performance and SEO purpose. Thanks to React, what was once only the realm of giants such as Ebay or Facebook is now within reach of most development shops. It is still not “free” though, adding significant complexity and limiting your options in term of libraries and tooling.

If you are building a B2C (Business to Customer) website, such as an e-commerce website, you may not have a choice but to go that route. For internal web or B2B (Business to Business) applications however, that kind of initial performance may not be required. Discuss with your product manager to see if the cost:benefit ratio is worth the trouble.

The API: There’s still no true answer.

It seems everyone lately is asking themselves what to do for API. Everyone is jumping in the RESTful API bandwagon, and SOAP is a memory of the past. There are various specifications such as HATEOAS, JSON API, HAL, GraphQLamong others.

GraphQL gives a large amount of power (and responsibility) to the client, allowing it to make nearly arbitrary queries. Along with Relay, it handles client state and caching for you. Implementing the server side portion of GraphQL is difficult and most of the documentation is for Node though.

Netflix’s Falcor looks like it will eventually give us a lot of what GraphQL/Relay offers, with simpler server requirements. It is however only a developer preview and not ready for prime time.

All the well known specifications have their quirks. Some are overly complex. Some only handle reads and don’t cover update. Some stray significantly from REST. Many people choose to make their own, but then have to solve all the design problems on their own.

I don’t think any solutions out there is a slam dunk, but here’s what I think your API should have:

  • It should be predictable. Your endpoints should follow consistent conventions.
  • It should allow fetching multiple entities in one round trip: needing 15 queries to fetch everything you need on page load will give poor performance.
  • Make sure you have a good update story: many specifications only covers reads, and you’ll need to update stuff sometimes.
  • It should be easy to debug: looking at the Chrome inspector’s network tab should easily let me see what happened.
  • It should be easy to consume: I should be able to easily consume it with fetch, or have a well supported client library (like Relay)

I haven’t found a solution that covers all of the above. If there is one, let me know.

Consider looking at Swagger to document your API if you go the standard RESTful path.

Desktop applications: Electron.

Electron is the foundation of the great Atom editor and can be used to make your own applications. At it’s core, it is a version of Node that can open Chrome windows to render a GUI, and has access to the operating system’s native APIs without a browser’s typical security sandboxing. You’ll be able to package your application and distribute it like any other desktop application, complete with an installer and auto-updates.

This is one of the easiest ways to make an application that can run on OSX, Windows and Linux while reusing all the tools listed above. It is well documented and has a very active community.

You may have heard of nw.js (formerly node-webkit) which has existed longer (and does almost the same thing), but Electron is now more stable and is easier to use.

Take a look at this great boilerplate to play around with Electron, React and hot reload. You’ll probably want to start from scratch if you’re serious about making your own application so you understand how all the pieces work.

Who to follow and where to learn more?

This is a place where I’m falling short, but on Twitter I follow the following people:

While there’s many more worth noting, those people retweet almost anything worth looking at, so they’re a good start.

Consider reading Pete Hunt’s Learning React. Follow the order!

Dan Abramov published the Getting started with Redux video series. I can’t overstate how amazing it is at teaching Redux.

Dan also published his own list, and it’s probably better than mine.

Mark Erikson’s collection of React/Redux links is an ever growing gold mine.

Read Removing user interface complexity, or why React is awesome to get a walkthrough of how React is designed and why.

If you don’t need it, don’t use it

The JavaScript ecosystem is thriving and moving quickly, but there’s finally an end at the light of the tunnel. Best practices are no longer changing constantly, and it is becoming increasingly clear which tools are worth learning.

The most important thing to remember is to keep it simple and only use what you need.

Is your application only 2–3 screens? Then you don’t need a router. Are you making a single page? Then you don’t even need Redux, just use React’s own state. Are you making a simple CRUD application? You don’t need Relay. Are you learning ES6? You don’t need Async/Await or Decorators. Are you just starting to learn React? You don’t need Hot reload and server rendering. Are you starting out with Webpack? You don’t need code splitting and multiple chunks. Are you starting with Redux? You don’t need Redux-Form or Redux-Sagas.

Keep it simple, one thing at a time, and you’ll wonder why people ever complained about JavaScript fatigue.

Did I miss anything?

And there you have it, my view of the current state of JavaScript. Do you think I forgot an important category? Do you think I’m objectively wrong on one of these choices? Do you recommend something else? Let me know!



Viewing all articles
Browse latest Browse all 764

Trending Articles