In all seriousness, the pragmatic approach for the enterprise developer writing code that runs in an ES3 environment, using ES3 tools, is to simply write ES3 code for production. All the while, I suppose, you can dream of the day that support for ES3 browsers can be dropped and modern ES5 or ES6 native code can be written instead. Of course, an enterprise dev has to wait for older browsers to die off, a longish engagement in the enterprise, for sure. So, day dreaming of the future can be a long venture in the enterprise.
I’ve personally never elected to use a comprehensive polyfill or a compile step to produce ES3 production code from ES5 or ES6 code. I’ve polyfilled a thing or two, but for me, I’ve never been able to overcome the complexity or overhead associated with a comprehensive polyfill or compiling routine (i.e. create ES3 production code from from ES5 or ES6 source code). The caveats, additional polyfills, limited usage, and incomplete features have mostly kept me at bay. For example, just go read all of the details around using ES6 feautres by way of the new 6to5 compiler.
But, not everyone shares my views. And, certainly not everyone’s threshold for additional complexity, or risk versus reward, is the same. So for the purpose of this article, I’m going to assume that, unlike me, you have decided that you want to use non-ES3 features from future specifications in an ES3 code base (note: I am not talking about polyfilling third-party code).
console.log(Array.from(new Set([1, 2, 3, 2, 1]))); // => [1, 2, 3] console.log('*'.repeat(10)); // => '**********' Promise.resolve(32).then(console.log); // => 32 setImmediate(console.log, 42); // => 42
The drop-in polyfill we just looked at, like it or not, adds newer features to ES3 environments at runtime. It will do so by any means necessary. If that’s not what you want, then you have another option. The core.js project also offers an opt-in polyfill that gives you newer features, but these features can optionally be used by invoking the features individually. This is similar to what you’d expect from libraries like lo-dash that offer one global value (e.g.
_) which all features hang on.
To opt-in ES5 and ES6 features in your code, you can include the library.js file from core.js. You can then use newer ECMAScript features as needed by writing code accessing method features hanging of the ‘core’ global. Similar to what you see in the code example below (code example from core.js).
var log = core.console.log; log(core.Array.from(new core.Set([1, 2, 3, 2, 1]))); // => [1, 2, 3] log(core.String.repeat('*', 10)); // => '**********' core.Promise.resolve(32).then(log); // => 32 core.setImmediate(log, 42); // => 42
ES5 and ES6 standard features can’t be directly compiled into ES3 code (i.e. using old features to write newer, equivalent, features). Doing so would greatly limit the actual features that could be translated. What is plausible is to use a pre-compiling step to compile ES6 code to ES5 code and then use the drop-in shim.js polyfill to get you the final mile to ES3.
To do this use you could use the new 6to5 transpiler and create a pre-compile build task using gulp that turns ES6 into vanilla ES5. Then, according to the 6to5 documentation, to get a full ES6 runtime environment you’ll also need to prep the runtime with the regenerate runtime, shim.js, and ES6 module loader polyfills (note: I am using client/shim.js from core.js, which includes support for ES3).
An HTML file containing 6to5 compiled code might look something like the following:
<!DOCTYPE html> <html> <body> <script src="runtime.js"></script> <script src="client/shim.js"></script> <script src="es6-module-loader.js"></script> <script> System.parser = '6to5'; //set es6-module-loader.js to use 6to5 //6to5 compiled code here </script> </body> </html>
About the only way you’d be totally safe to use a third-party tool in an ES3 environment is if the third-party code directly supports your exact polyfills/compiler. Otherwise, this can be a rather frustrating and timely assumption. Remember, all this hacking of new features into old environments comes with some caveats, complicated gotchas, and opinions. You shouldn’t assume a third-party has dealt with these caveats and gotchas as you would (or have), unless you can confirm they align with your environment exactly. If what I’m saying is lost on you, just keep in mind that third-parties likely don’t test ployfills or compiled output. It’s mostly the case that third-party code requiring ES5+ parsing will assume a real ES5+ environment.
If I wasn’t the author of this article and just a reader, I’d be asking myself, “Why are you telling me how to use newer features but not giving it a glowing recommendation?” This is a good question.
Header image courtesy of hackNY.org