prepack
prepack copied to clipboard
Add DOM shims
The community is eager to have shims for DOM, if prepack team invests in documenting what needs to be done, how to do them, and split this into smaller tasks.
Will something like this work?
https://github.com/mohsen1/prepack-assume-browser-globals/blob/master/index.js
Obviously not every global is a function and I need to fix that.
That's a good start, but it probably won't be so easy. For example, this would still fail for nested methods window.history.back()
and window.document.createElement()
.
And then we also need to define types of return values. For example, document.querySelector()
returns a DOM Element or undefined. If it's an Element, it also has its own methods and properties, which can also return another Element (e.g. el.parentElement
), and so on.
This is going to be a lot of work. I'm tempted to look for workarounds and hacks.
@deltaidea Can https://github.com/Microsoft/TypeScript/blob/master/lib/lib.dom.d.ts help us in some way? Typescript have quite good type definitions.
The Flow typing of the DOM (https://github.com/facebook/flow/blob/v0.44.1/lib/dom.js) is also of interest for this, as we may want to be able to generate models from Flow typed APIs for React Native. The Flow typing does seem to be a lot shorter and may be less complete.
I think @sebmarkbage has though the most about the web use case, maybe he had some ideas.
I think it is interesting to narrow down which cases cause side-effects and which might read from a JS provided object that needs to preserve ordering.
For many other things we might get away with making it fully abstract for most use cases.
This is an example of where it is important to know something about the DOM implementation itself rather than just the structure of it:
let obj = {x: false};
document.body.addEventListener('foo', function (e) {
if (obj.x) {
console.log('foo');
} else {
console.log('bar');
}
}, false);
document.body.dispatchEvent(new Event('foo'));
obj.x = true;
document.body.dispatchEvent(new Event('foo'));
Prepack will have to know that there is an intermediate state of obj.x
that needs to be represented here.
I don't know how common it is to have any such scenarios of synchronous events but there might be other similar cases that are synchronous that we'll have to know about.
Using the JSDOM library can tell us a lot more about these implementations than Flow/TypeScript types can.
here's how those typescript definitions are generated: https://github.com/Microsoft/TSJS-lib-generator
Here are some more examples of patterns that Prepack has trouble encoding right now.
let options = {};
options.passive = false;
document.body.addEventListener('click', function() {}, options);
options.passive = true;
window.addEventListener('click', function() {}, options);
options = {};
options.prototype = Object.create(HTMLElement.prototype);
document.registerElement('x-foo', options);
options.prototype = Object.create(HTMLElement.prototype);
document.registerElement('x-bar', options);
Note how the options
object is read by native code and at different times during initialization.
Hi team, is there anything new on this side?
It would be nice to have a place to track progress, or some kind of a workaround for now @hermanventer
We are swamped with non DOM related work right now, so there is nothing specifically happening on this front. If there are specific issues that are blocking you from doing something in this area, please add new issues.
I hope to write some documentation for Prepack a bit later on this year.
@hermanventer, the main problem is that it seems like it's impossible to compile any existing or new web application using prepack right now. Each time there would be some DOM operation, or browser API call that makes the process fail. That is very unfortunate, considering the fact that prepack might be the future of JS optimization. People should be able to test and evaluate it already, I think.
The second point is -- why not just make every unsupported API call an abstract unknown value right now? Yeah, it will disallow lots of optimizations, but it won't crush the process. Also, as far as I understand --abstractEffectsInAdditionalFunctions can be used to optimize the bodies of functions, right?
Anyways, thanks for your time! I see the barrage of issues you have, but I think that prepack is worth some attention, therefore people have to be able to play with it, without it crashing on them. May be I am just missing some stupid option that makes it happen, in that case I am sorry!
I'm afraid that we are all going to have to be very patient with Prepack. Getting to the point where it can usefully run on real browser based applications is going to take a lot of very hard work and a long time. Taking short cuts will result in something that works only for some ill defined subset of JavaScript and only up to a point.
Right now, Prepack can deal with initialization code (global code) in environments that we can easily model and about which we can make restrictive assumptions. We are hard at work to go beyond that, but the war will be won in a long series of small, hard won victories.
Some previous work on analyzing JavaScript has already highlighted just how difficult things become once you try to support all of JavaScript and you have to deal with untyped call backs. The conclusion reached in those efforts was that, in the end, the analyzer knows nothing much. Since this is a good description of a typical browser based web app, it makes sense for us to set our sights on gains that are more attainable in the short term.
That said, if Prepack actually crashes for some input (i.e. a false invariant or a runtime exception, we'll be glad to hear about it particularly if you have a way to reproduce it). The expected behavior of Prepack is that it should give you a nice error message telling you that your program is not suitable for the current state of Prepack. We have quite a bit of work to do on that front as well.
@hermanventer, thanks for your descriptive answer! It's nice to hear that people are hard at work writing this wonderful project.
By the way, I think we should add a place where all the implemented APIs are tracked, shouldn't we?