How Do We Even JS? (The Components of Nylas's Javascript Stack)

Javascript fatigue has been extremely prevalent over the past few years, making it really difficult to choose from the enormous pool of tooling and framework options without high levels of anxiety.

Fortunately, it’s 2017 already, and smarter people than I have already made a lot of these choices.

While the primary codebase at Nylas is written in Python, we’ve been building with Javascript for a while, and we’ve grown with it; we have a large codebase where you can find Coffeescript, plain old ES5, ES6, React, JSX, CJSX(I know, WTF?), along with many flavors of Flux, Redux and observable-based architectures.

Dependencies are saved to package.json by default without having to add the--save flag.

The killer feature, IMO, is running custom scripts without having to preface them with run. Say you have the following script in your package.json:

// Your package.json

"scripts": {

"win": "node ./scripts/win.js",

},

To run that script with npm, you’d have to type: npm run win. But with yarn, you just need to type: yarn win. It feels so nice.

(Bear in mind, npm v5 was recently released with many of the goodies that yarn provides, like lockfiles, better perf, and a nicer CLI. You might want to use it, too!)

create-react-app

We’ve been writing React for a while, so we wanted to continue using it in our projects. However, starting a React project that uses modern Javascript from scratch is nontrivial because it requires A LOT of configuration:

webpack(or browserify, or rollup, or brunch, or…) to generate builds to ship to the browser. That in itself requires lots of configuration.

babel to transpile your code. Italso requires a lot of configuration. Plus, knowing what Javascript features you are using in your code that need to be transpiled so they can run in the browsers you want to support, making sure you polyfill the right things depending on browsers you are targeting(e.g. Promise, fetch),and more that we probably haven’t realized yet.

eslint to lint your code

More that I’ve probably forgotten

Then tying it all together!

BUT, as I mentioned, it’s 2017 already, and thank the GODS create-react-app exists. With a single command, you can scaffold a React application that comes preconfigured with webpack, babel, eslint, a dev environment that’s ready to go with automatic reloading, scripts to generate optimized production builds, etc.

yarn global add create-react-app

create-react-app dope-af

# ✨~magic~✨

cd dope-af

yarn

yarn start # Start development server

yarn build # Create optimized production build

Additionally, it comes with an excellent User Guide with information on pretty much anything you might want to do.

You can get pretty far with just create-react-app , but if you reach a point where you need to modify the configuration that comes out of the box, you can run the eject command to manually manage the configuration.

There’s a couple of things that I found are missing from the default configuration, like #2310, but luckily the community is really active, and I believe these will be included without having to eject.

jest

create-react-app comes out of the box with jest configured as its test runner. In this post we won’t cover how we write tests using jest, but suffice to say, it’s dope AF. This talk convinced me: https://www.youtube.com/watch?v=PvabBs_utr8

eslint

With create-react-app, eslint comes preconfigured with sensible defaults. If you want to extend it, you just need to write a custom .eslintrc file:

// .eslintrc

{

"extends": "react-app",

"rules": [

"prefer-const": "warn" // custom rules

]

}

Your code will be linted by default when you run yarn start or yarn build, but you can also add a custom script:

yarn add --dev eslint@3.19.0 # Same version that create-react-app uses

// Your package.json

"scripts": {

"lint": "eslint ./src ./scripts",

},

flow

flow is a static type checker for Javascript. There are numerous arguments for and against a static type checker, but after we grew an immense Javascript codebase here at Nylas, the value of types became more and more apparent, especially for core abstractions and highly used modules in a codebase.

One good thing is that flow supports gradual typing, which means that type annotations are not required everywhere. That means that if you’re prototyping or writing something you know is likely to change, you don’t need to use types, but if you’re writing a core module in your codebase, you can lock it down with types. Types can be beneficial because:

they give us more confidence when making changes or refactors

they serve as documentation(which wont become stale, unlike comments)

they prevent a lot of unnecessary unit tests that we usually end up writing just to check types

create-react-app does not enable flow by default, but, of course, the user guide specifies how to do it: Adding Flow

There’s one extra thing we did when configuring flow, and it was changing it to report type errors as eslint errors:

That’s useful because if you already have eslint configured in your editor you won’t need an extra editor integration for flow. It also applies for other tools that you’ve already configured with eslint. E.g., we use Phabricator at Nylas for code review, and we’ve already integrated it with eslint, so we didn’t have to write a new integration for flow.

prettier

prettier is a Javascript code formatter. What that means is that it’s a program that takes your javascript code as input and then outputs that same code, but formatted. The code will be formatted in a standard way it so it all“looks” the same—i.e., uses the same rules for spacing, where to place newlines, and so on.

It’s great because:

You won’t spend time manually formatting code as you write it. You can just write the ugliest code imaginable, and as long as it’s valid code, prettier will automagically make it, well, prettier.

You have a fast and automated way of formatting code, so all of the code in your repo will look the same, which makes it way easier to read and follow.

You won’t get into fights about how code should be formatted since it’s all just offloaded to the tool, regardless of how people want to write it.

create-react-app doesn’t have a section on prettier, but that’s why we’re here! Here’s how we configured it:

We defined a custom prettier script: yarn prettier. When run, it will read any code that is not inside the build/ directory and write it back correctly formatted. It also includes some basic configuration options for prettier.

We wantedeslint to report any formatting errors detected by prettier. To do that, we added eslint-plugin-prettier and enabled it in our plugins and rules section:

"plugins": [

"flowtype-errors",

"prettier"

],

"rules": {

"flowtype-errors/show-errors": 2,

"prettier/prettier": ["error", {

"singleQuote": true,

"trailingComma": "es5"

}],

"prefer-const": "warn"

}

One thing to note is that we had to duplicate our prettier configuration in this file(😢) and in our package.json because prettier doesn’t currently support configuration files.

Finally, eslint includes several formatting rules itself, but given that we are using prettier, we don’t want eslint to complain about formatting rules that prettier will handle. To achieve this, we added eslint-config-prettier, which will disable any eslint rules that affect formatting. In order to enable it, we added these extra extensions:

"extends": [

"react-app",

"prettier",

"prettier/flowtype",

"prettier/react"

],

And that’s it! Our basic prettier workflow works in the following way:

Write code

Try to submit a diff

Our diff tool reportsprettier errors via eslint

Run yarn prettier

Submit diff! 🎉

You can also have a tighter integration by adding prettier to your editor so it formats your code as you type or as you save your file, so you don’t ever have to explicitly run yarn prettier. However, editor integrations are a topic for another post.

And that’s how we JS here at Nylas!(Or at least how we’re trying.)

Finally, I wanted to call out and thank everyone who has spent time building and contributing to these awesome tools, which, in my humble opinion, are making Javascript development in 2017 a lot more fun.