How to closure compile but still provide interface API to uncompiled 'extensions'

49 Views Asked by At

I would like to compile an 'sdk' that is providing an API.

How could a compiled file provide an 'interface' that uncompiled extensions could use to plug into to compiled SDK?

Example:

API clients could include the sdk with

<script src='nn-skd'> (nn is the name of the sdk)

Here is the whole sdk

/**
 * @nocollapse
 * @const
 * @namespace
 */
var NN = {}

/**
 * @interface
 * @export
 */
NN.INode = function() {}
/**
 * @export
 * @return {number} 
 */
NN.INode.prototype.getMagic = function() {}

document.addEventListener("click",()=>{
  const node = /** @type NN.INode */ (window['specialNodeAddedByAPIClientOutsideOfTheSdk'])
  console.log(node.getMagic())
})

What I would expect here is to have a client that can put classes that "implement" INode into the window['specialNodeAddedByAPIClientOutsideOfTheSdk'] and the sdk could use this class.

Like for example the following uncompiled file:

NN.Node = class {
  getMagic() {
    return 4;
  }
}
window['specialNodeAddedByAPIClientOutsideOfTheSdk'] = new NN.Node();

But this will not work because the google closure compiled nn-sdk file will never call NN.Node#getMagic. It simply does not know about it. The compiled file looks like

(function() {
    var a = {},
        b = a.a,
        c = ["NN", "INode"],
        d = this;
    c[0] in d || !d.execScript || d.execScript("var " + c[0]);
    for (var e; c.length && (e = c.shift());) c.length || void 0 === b ? d[e] && d[e] !== Object.prototype[e] ? d = d[e] : d = d[e] = {} : d[e] = b;
    a.a.prototype.b = function() {};
    a.a.prototype.getMagic = a.a.prototype.b;
    document.addEventListener("click", function() {
        console.log(void 0)
    });
}).call(window)

where the console.log() is just 'void 0'.

How could I make this work. How could an compiled file provide an interface that uncompiled extensions could use to plug into to compiled SDK.

Update1:

Found a possible solution

console.log(node['getMagic']() || node.getMagic())

This makes sure that if the node is mangled and is inside the sdk than node.getMagic() will be called while if it is outside the sdk than node'getMagic' will be called.

Is this what I should be doing?

Update 2 and 3.

The approach above works until I try to extend and override a method with

NN.Node = class extends NN.INode {

and then

getMagic() {
super.getMagic()
}

in which case it is impossible to resolve the correct getMagic.

0

There are 0 best solutions below