JavaScript for people who knew JavaScript 15 years ago

I was assigned a project that used JavaScript everywhere, and I got a taste for how complex the landscape had become. And my experience is not uncommon - there are plenty of engineers with years of experience that are unsure of this "modern JavaScript" thing and/or can't find a way to approach it.

JavaScript for people who knew JavaScript 15 years ago

My first paid programming gig took place before the current millennium, and it involved a smattering of JavaScript. JS wasn't very hip nor capable back then - it was mostly used to alert, confirm, or occasionally decorate the browser status bar with a marquee of wavy ASCII lines (like ``'-.,_,.-'``'-.,_,.='``'-.,_,.-').

And cross-browser functionality was a nightmare.

It was a few years later that cross-browser frameworks started showing up, culminating in the 2006 release of jQuery. And for some, like me, that's where JavaScript stopped for the better part of a decade.

Sure, every now and then I would hear whispers of this Node.JS thing, but people weren't really using JavaScript to code server-side concerns, were they? That would surely be madness.

So imagine my surprise when I was assigned a project that used JavaScript everywhere, and I got a taste for how complex the landscape had become. And my experience is not uncommon - there are plenty of engineers with years of experience that are unsure of this "modern JavaScript" thing and/or can't find a way to approach it.

Well, I just had a Philly cheesesteak, so I'm not going anywhere for a few hours... let's go over the current state of JavaScript.

The language itself

JavaScript is standardized as ECMAScript (I will use "JavaScript" and "ECMAScript" interchangeably), and that standard is versioned, with multiple major releases over the last couple of decades. The ECMAScript I cut my teeth on was version 2 (which introduced try/catch), released in 1999. Most people who have done front-end work in the past 10 years are probably familiar with version 5 (which introduced JSON and strict mode), which was released in 2009.

Version 6 (ES6) was released in 2015 and since then there has been a release every year. These releases are tagged with the year number, not necessarily a major revision, although some people informally refer to ES2016 as ES7, ES2017 as ES8, etc.

Each update has added varying amounts of syntactical change to the language (and I'll cover some of these later (if there's interest) (maybe)), which introduces the question "how comprehensively do browsers handle all these new language features?"

Well, Chrome (for example) only completed its ES2016 support in May of 2018, and it's only one of two browsers to have such support. You could say that browser adoption is somewhat laggy. So how do you, as a developer, take advantage of newer language features while still maintaining support?

I'm glad you asked.


All major browsers have supported ES5 comprehensively for years at this point, so it's a safe bet that if our source code uses only ES5 language features it will work on all major browsers.

We write our source code in more modern JavaScript versions and lean on a transpiler to generate ES5-only syntax that can be used in any browser. "Transpile" comes from the Latin trans- meaning "change" and -pile meaning "newer, decent syntax into older, less flexible syntax".

A traditional compiler will take human readable source code as an input and will generate machine-executable code as an output. Transpilers take source code for Language A (in this case ECMA2018 or whatever) and output source code for Language B (in this case ES5).

The library I've used the most for transpiling is Babel. Babel has a pretty neat plugin system, so you don't specifically have to write your primary source code in, say, ES2018 - you can use ES2017 and add plugins for specific language features you like from ES2018. Or maybe invent your own language features and write plugins for those. I don't know, I haven't played around with it a ton. But the primary takeaway is "there's a library for that".

And the library itself is a good touchpoint for another couple of concepts: dependency management and automated build systems.

Dependency Management and Automated Build

Building by hand is just infeasible, so we tend to want things like 'build systems', unless they are make. So how does that look in JavaScript environments?

There are a few different options in modern JavaScript. I prefer npm, whereas others will want to use yarn. A couple of less-popular-now-but-they-had-their-heyday-a-few-years-ago options are grunt and gulp. I think yeoman is in there too somewhere? I'm not sure.

Anyway, each of these build systems will have some kind of plugin system or something that allows you to run tests, measure coverage, transpile, and package artifacts from the command-line or a CI/CD pipeline.

Most of these build systems will also maintain metadata for your project (much like maven or gradle), including a list of dependencies. Running (for example) npm install will fetch dependency packages (correctly versioned) from the main npm repository (or, if you've configured such, a local/personal/on-premises repository).

NOW LISTEN: Using the npm repository is a risk, because about once a year there's a compromised or malformed package that brings down half the internet. I'm not going to go over why or how to mitigate this risk, but I feel like it's important to be aware of it.

When your build system pulls these dependencies into your project it will install them in the ./node_modules directory relative to your project's top level directory. If your dependencies get whacky (out of sync, multiple conflicting versions, etc.) this is the directory you want to rm -rf.

There are two different categorizations for your dependencies: regular dependencies and dev dependencies. Regular dependencies are under the "dependencies" section of your package.json file, and will be included in any artifacts you generate. Dev dependencies are under the "devDependencies" section of the package.json file and won't be included in any artifacts you generate. Typically you'll use the dev dependencies category for things like testing frameworks, babel plugins, or other things that impact "how" you're building as opposed to "what" you're building.

More more more more more

There's always more, like "how does testing work" and "tell me about promises" or even "holy butts what's up with react-redux" but I'm over 1k words at this point and I'm starting to recover from that cheesesteak. Tell you what: if you think this article was valuable let me know and I'll write more.

Good luck out there, older seasoned engineers.