Choosing Vanilla JavaScript in 2016

ECMAScript’s latest spec makes a compelling case for developing without heavy libraries or frameworks.

Update 1: This article is targeted at front-end devs that work in the browser, so my definition of “vanilla” JavaScript includes other APIs like the DOM (as the original vanilla-js.com site does.) I apologize for the confusion this might have caused.

Update 2: I buried the lede a little so I want to make it clear that I’m advocating here for responsible library use. As the subtitle mentions, my aim is to get people using heavy libs and frameworks to reevaluate their needs in light of new features added to ECMAScript and the web platform. Sorry for the confusion!


I’ve always loved the idea of Vanilla JavaScript, or the use of JavaScript without relying on heavy libraries or frameworks. Where I work, we make use of the following front-end technologies:

  • jQuery for cross-browser DOM manipulation, animations, and AJAX
  • Twig.js for HTML templating
  • RequireJS for package and dependency management
  • Less for large-scale CSS management

I thought it’d be an interesting thought experiment to see which of these could be replaced by pure-JavaScript equivalents.

The browser landscape is better than ever. Chrome and Firefox have accelerated release schedules and seamless update processes, and Microsoft has pledged that they want Edge to go the “evergreen” route too (though it’s debatable if they’re there right now.) The only outlier is Safari, but that topic has been beaten to death by this point.


The basics: querySelectorAll and Promises

These are the oldest and most widely-implemented feature on this list, but they’re worth mentioning as part of the modern JavaScript coder’s toolbox.

For newbie coders and those who use jQuery mostly for DOM wrangling, document.querySelector and document.querySelectorAll get you 90% of the way towards jQuery’s Sizzle selector engine. Past that, the DOM isn’t nearly as nice as jQuery makes things, but it’s far better than it was even a few years ago.

Who has it?

It’s weird to say, but Promises are somewhat old-hat as far as this list goes. At time of writing, Chrome has had them for 15 whole versions!

var message = new Promise(function (resolve, reject) {
getMessage(function (success, message) {
if (success) {
resolve(message);
} else {
reject(message);
}
});
});
message.then(function (message) {
message += 'For the win!';
displayMessage(message);
});

Code complexity-wise, it’s easy to hang yourself with all the rope that Promises give you, but they simplify so many use-cases that it’s easy to see why their spec was fast-tracked.

Who has it?

  • Chrome 33+ / Opera 20+
  • Firefox 29+
  • Edge 12+
  • Safari 7.1+

Easy AJAX with the Fetch API

It’s no secret that using XMLHttpRequest just… sucks. The sequel is better, but still woefully ugly.

What is the Fetch API? At a high-level, it’s AJAX implemented as Promises. You know, like how jQuery works.

XMLHttpRequest Level 2:

var xhr = new XMLHttpRequest();
xhr.open('GET', '/user/1', true);
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
var user = JSON.parse(xhr.responseText);
}
};
xhr.send();

jQuery:

$.ajax('/user/1')
.done(function (data) {
var user = data;
});

Fetch:

fetch('/user/1')
.then(function (response) {
return response.json();
})
.then(function (data) {
var user = data;
});

Who has it?

  • Chrome 42+ / Opera 29+
  • Firefox 39+

Microsoft has indicated they intend to implement the Fetch API this year. I couldn’t find any info on when Safari might implement it.


HTML templating with <template> and ECMAScript 2015 template strings

The HTML5 <template> tag has been around for a few years and is fairly well-known and implemented. Elements inside a <template> tag are considered inert and do not get rendered or instantiated. The pattern is that your JavaScript will clone the elements inside when it wants to render them:

<template class="hello-template">
<div class="hello">
Hello, world!
</div>
</template>
<script>
var helloTemplate = document.querySelector('.hello-template');
var helloDiv = document.importNode(helloTemplate.content, true);
document.querySelector('body').appendChild(helloDiv);
</script>

It’s a little verbose but still useful when you have bits of reusable markup in your document. But what if you have bits of reusable markup in your code? Template strings to the rescue!

var firstName = 'Andrew';
var lastName = 'Wizard';
var fullName = `<div class="full-name">
<em>${firstName}</em> <strong>${lastName}</strong>
</div>`;
document.querySelector('body').innerHTML = fullName;

Template strings are useful for a bunch of reasons:

  1. They allow multi-line strings in JavaScript without hacks.
  2. They allow easier variable use without concatenation.
  3. The ${} substitution syntax can also evaluate any JavaScript expression, for instance 1 + 2.

I haven’t played with template strings as much as I’ve wanted to, but I imagine it wouldn’t be hard to make a vanilla JavaScript equivalent of Handlebars. It’d be a server-side script that takes HTML files with ${} substitutions, wraps them in backticks (`), and outputs them as JavaScript modules (see the next section) ready for immediate use.

(Update: Some have commented that this could leave you open to XSS, which is what I get for not playing around with it as much as I’d like! Make sure you thoroughly vet your web apps for security holes, especially when using newer technologies.)

This is as close as browsers have ever come to native, external HTML templates, and every major browser supports it! I’m really excited about this part of the stack.

Who has it?
Everybody has the <template> tag. As for who supports template strings:

  • Chrome 41+ / Opera 28+
  • Edge 12+
  • Firefox 34+
  • Safari 9.0+

Package management with ECMAScript 2015 modules

Modules are the biggest reason I decided to write this article. (Although I’m cheating since they probably won’t be ready for use this year.) There are two types of JavaScript modules today:

Native JavaScript modules take features from both and because of that they’re very robust.

import square from 'math';
console.log(square(12)); // 144

How does that song go again?

  • You import a single method or an entire module.
  • You can designate a default export method.
  • You can export classes.
  • You can name imports whatever you like.

I feel like modules will be one of the biggest advances for JavaScript development in a long time. Aside from native dependency management being great on its own, the syntax is just far cleaner than AMD/RequireJS.

Some great reading on this exciting new tech:

Who has it?

Nobody! Yet at least. The modules spec was included in ECMAScript 2015, but browsers have been slow to tackle it. Last I heard, the holdup seems to be consternation over how the module loader should behave. Hopefully we start to see some implementations later this year — they’re behind a feature flag in V8 (used by Chrome, Opera and Node.js) and Microsoft has pegged it as a feature coming soon to Edge.


On the style side: CSS variables

Not JavaScript, but still worth mentioning in a discussion about cutting out potentially-unnecessary technologies. CSS variables are the main selling point of CSS preprocessors such as Less and Sass. Like the other tools in this article, they have other helpful features, but for my uses CSS variables are the biggest draw. Without variables, maintaining a large-scale CSS codebase quickly becomes a headache.

:root {
--main-bg-color: #0099cc;
}
.header {
background-color: var(--main-bg-color);
}

That’s why I’m so excited to have them natively. The syntax is uglier than Less and Sass, and vanilla CSS doesn’t have nested clauses (justifiably, in my opinion), but it doesn’t matter. I can easily see myself forgoing Less/Sass entirely in future projects now.

Compared to preprocessors, native CSS variables also have the benefit of being fully live-editable in the Dev Tools, which Chrome has already implemented.

Who has it?

  • Chrome 49+
  • Firefox 31+
  • Safari 9.3+

Microsoft has indicated that CSS variables are a “low” priority for Edge at this time.


Conclusion

It’s up to each developer (or engineering team) to decide whether the network cost, performance hits, and technical debt of third-party libraries and frameworks are worth their ease of use. That has always been and will continue to be the case. My goal today was to point out that very soon, pure JavaScript will be good enough for the entirety of the modern front-end stack. I’ve personally never been more excited to be working in this space. Thanks for reading!

If you like this article, please recommend it by clicking the heart icon and by upvoting it on Hacker News and Reddit. :D


Andrew is a software developer in Boston. Opinions in this article are his own and do not necessarily reflect that of his employer, Nanigans. Who, btw, are hiring!