Search code examples
javascriptecmascript-6babeljsbrowserifyecmascript-5

Babel 7 not transforming builtin subclasses properly


Babel version: 7.6.0

I am working on a JavaScript widget meant for browser use, but it depends on a library built for NodeJS ( edtf.js ). Particularly, it extends the Date builtin in this file.

So far, it seems to work on all modern browsers I have tested it with. But to make sure it is bulletproof to older ones, I thought of Babelifying the edtf library. Here is the browserify configuration from my Gruntfile.js:

browserify: {
  development: {
    src: [
      "node_modules/edtf/index.js"
    ],
    dest: './dist/js/edtf.js',
    options: {
      browserifyOptions: { standalone: 'edtf' },
      transform: [["babelify", {
        "presets": ["@babel/preset-env"], "plugins": [["@babel/transform-runtime", {"helpers": false}]]
      }]]
    }
  }
},

After a lot of tinkering, this configuration at least does not trigger any error when the resulting javascript file is loaded on the page, but as soon as I start using the library it breaks with this error:

edtf.js:3040 Uncaught TypeError: this is not a Date object.
   at Date.getUTCFullYear (<anonymous>)
   at Date.get (edtf.js:3040)
   at Date.toEDTF (edtf.js:2960)
   at Date.value (edtf.js:5696)
   at new Date (<anonymous>)

A previous SO answer correctly points out that builtin subclasses are only partially supported by Babel, according to their documentation, and suggests using the transform-builtin-extend plugin, which is sadly unmaintained for 2 years and only suits Babel 6.

Shouldn't the transform classes work for that? I tried including it in my config, but it changed strictly nothing.

Anyway, if anyone has any advice on how to move forward, here is the github branch to try it for yourself, simply run npm install, npm run build and open the index.html file in your browser. Any recommendation is welcomed: I am not married to the Babel idea, but I want to make sure that I can safely use this edtf library and have it working on the majority of browsers.


Solution

  • The fundamental problem is that you can't subclass Date using only ES5 and earlier features. It simply doesn't work (like Error and Array).

    If you need to use your code transpiled to ES5 or earlier, you'll have to modify your class so it doesn't try to subclass Date. (For instance, use a Date instance as a member instead and forward the method calls on...)