2

For the following JavaScript code, how can I write it in ReasonML?

class HelloWorld extends HTMLElement {
  constructor() {
    super();
    // Attach a shadow root to the element.
    let shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `<p>hello world</p>`;
  }
}

I could not find any documentation on writing classes in ReasonML? I cannot use plain objects/types as I need to extend from HTMLElement class which doesn't work with ES style classes.

I have looked into this existing question - How to extend JS class in ReasonML however, it is a different thing. To write web component, we need to extend HTMLElement and must call it with new keyword. ES5 style extension mechanism doesn't work.

Harshal Patil
  • 17,838
  • 14
  • 60
  • 126
  • 1
    Possible duplicate of [How to extend JS class in ReasonML](https://stackoverflow.com/questions/46454098/how-to-extend-js-class-in-reasonml) – Yawar Jan 08 '19 at 18:16
  • @Yawar, I don't think it is a duplicate. It is specifically about extending native `HTMLElement` class for web components. – Harshal Patil Jan 09 '19 at 04:18
  • Hi Harshal, if you are extending a JavaScript class, my linked answer is, as far as I know, the only way. I also mentioned in my linked answer that you must do two things: extend in the class in `[%%bs.raw ...]`; and then bind to it from Reason side. Binding to it, e.g. the constructor function, will allow you to have Reason output the necessary `new HelloWorld()` call. – Yawar Jan 09 '19 at 15:41
  • Btw I just updated that answer to show the binding explicitly, hope that helps. – Yawar Jan 09 '19 at 16:04
  • Thank you @Yawar. I read your updated answer. It works but loses goodness of reason. The whole point of doing this exercise is to write stencil.js like web component compiler with a beauty of reasonml. – Harshal Patil Jan 10 '19 at 05:58
  • Hi Harshal I've opened a discussion about this in the Reason forum, we can continue there if you like :-) – Yawar Jan 10 '19 at 15:00

1 Answers1

4

You can't. Not directly at least, since BuckleScript (which Reason uses to compile to JavaScript) targets ES5 and therefore has no knowledge of ES6 classes.

Fortunately, ES6-classes require no special runtime support, but are implemented as just syntax sugar, which is why you can transpile ES6 to ES5 as shown in the question you link to. All you really have to do then, is to convert this transpiled output into ReasonML:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var BaseElement = (function (_super) {
    __extends(BaseElement, _super);
    function BaseElement() {
        _super.call(this);
    }
    return BaseElement;
}(HTMLElement));

And depending on what specific class-features you actually need, you can probably simplify it a bit.

glennsl
  • 28,186
  • 12
  • 57
  • 75
  • Thanks for the information. I thought so. I tried this already. However, it doesn't work with `HTMLElement` class when extending for web components. It needs to be called with `new` keyword. I just updated my question. – Harshal Patil Jan 09 '19 at 04:27
  • Interesting. I think @Yawar's answer in the duplicate question suggesting to use `bs.raw` is the only way to go about it then. You'll probably also have to output es6 instead of commonjs. – glennsl Jan 09 '19 at 09:47
  • Yes, that seems to be the case. Unfortunately, I loose the goodness of reason and bs. – Harshal Patil Jan 10 '19 at 05:56