Using ES5 with Drupal 8

For core and contrib, the important and safe to use ES5 features

In fixing contrib javascript I mentioned that as a contrib maintainer or developer you could do a bit more than just run JSHint. This is because Drupal 8 will not support IE8, meaning that core and contrib are free to go crazy! The incredibly useful caniuse.com website holds extensive compatibility tables for the fancy new HTML/JS/SVG features in the works. But talking about ES5 specifically, the ECMAScript 5 compatibility table is what you're looking for to know what you can rely on.

For core and contrib, here is a peak at what's coming to a future near you.

Safe

By safe I mean that those are features that won't bite you horribly. Some of them are already used in Drupal 8 core or are in a patch that'll be committed soon enough.

"use strict"

This is actually enforced by JSHint — you know the thing that you should be running on your JS — while we're not relying on the advanced features of the strict mode it is used to make sure there are no leaking variable. I've seen too many strays variable in contrib and projects. To use, put "use strict"; at the top of the file-closure.

(function ($, Drupal, drupalSettings) {

  "use strict";

  // Your code.

})(jQuery, Drupal, drupalSettings);

Function.prototype.bind

It is the native version of the basic usage of jQuery.proxy().

Before

var handler = $.proxy(callback, this);

After

var handler = callback.bind(this);

Array.prototype.forEach

Looping is a rather large topic so we'll stick with the basics. Given the following array:

var valueList = [
  'a', 'e', 'i',
  'o', 'u', 'y'
];

Before

var i = 0;
var il = valueList.length;
for (; i < il; i += 1) {

}

After

function callback (value, index) {}
valueList.forEach(callback);

Object.keys

This one combined with forEach allow you to do painless filtered for each if we take the following object:

var snacks = {
  banana: 0,
  chips: 1000
};

Before

for (var snack in snacks) {
  if (snacks.hasOwnProperty(snack)) {

  }
}

After

function eatSnacks (snack) {}
Object.keys(snacks).forEach(eatSnacks);

And that looks much better than the first example. Giving a name to your function gives you extra info on what is it the loop is doing without having to comment it too much. Also makes profiling easier since you'll have data on the callback function.

Now you'll probably ask why not use jQuery.each in both cases? or even _.each. First it's native so there is no need for an extra library. I'm not talking about speed — if your bottleneck is how you do your loops, you don't need to read all this, otherwise go profile your DOM manipulations. jQuery each doesn't filter with hasOwnProperty which means that is some script on your page extends either Object.prototype or Array.prototype — on top of breaking jQuery — you're gonna have a bad time. Underscore does filter properly so it's fine using that if you have the library on the page anyway.

I still need IE8 support

Does Drupal 8 dropping IE: 6, 7, 8 means you can't use it in a market like china or big administrations where IE8 is still the default and supported browser?

IE8 module

The IE8 module was started to introduce IE8 compatibility back to Drupal 8 — in fact it was started to help take the decision to drop IE8. While the level of support is still undecided the goal is to allow people who develop for IE8 to be able to use Drupal 8. We'll see what that means when that time comes. For now you can use the ie8 tag in the issue queue to help up see what'll go wrong on IE8.

There is a lot more good stuff we can use such as localStorage, document.querySelector but those are DOM-related and have nothing to do with ES5 so expect a follow-up post on those.

Comments

Reply