Make sure to actually use yarn to install the main-packages, otherwise the packages.json#resolutions property will not be used and @babel/helpers would not get overruled

Overruled @babel/helpers to fix how initializers play with decorated properties. Thus circumventing the imperformant and lengthy code being generated by babel in the non-legacy option.
This commit is contained in:
2019-11-05 21:11:01 +01:00
parent 5ca9bec93a
commit 72f38c1137
47 changed files with 5004 additions and 80 deletions

View File

@@ -2,7 +2,7 @@
"presets": [
],
"plugins": [
[ "@babel/plugin-proposal-decorators" , { "decoratorsBeforeExport": true }],
[ "@babel/plugin-proposal-decorators" , { "legacy": true }],
[ "@babel/plugin-proposal-class-properties", { "loose": true } ],
[ "@babel/plugin-proposal-private-methods", {"loose": true } ],
[ "@babel/plugin-proposal-optional-chaining" ],

View File

@@ -1,43 +1,56 @@
import {render} from "../vdom";
/** Helper class to mark an initializer-value to be used on first get of a value**/
class InitializerValue{ constructor(value){ this.value = value; } }
/**
* The decorators proposal has changed since @babel implemented it. This code will need to change at some point...
* THIS IS TOTALLY FIGGIN BROKEN!! valueMap used to be just value, but it turns out is not unique amongst decorated props.
* (it appears to be run once per class definition, and thus multiple instances would share the same value-reference)
*/
export function State() {
return function decorator(target){
let key = target.key;
let descriptor = target.descriptor;
let valueMap = new WeakMap();
return function decorator(target, key, descriptor){
let {get: oldGet, set: oldSet} = descriptor;
let valueKey='__'+key;
// Add a getter/setter or replace if they're already there with something that intercepts it (this gets a whole lot easyer in the new proposal if i'm not mistaken)
descriptor['get'] = oldGet || (function(){
return valueMap.get(this)
});
descriptor['set'] = function(newValue){
let oldValue = descriptor.get.call(this);
if(newValue!==oldValue){
valueMap.set(this,newValue);
this.markDirty && this.markDirty();
// Rewrite the property as if using getters and setters (if needed)
descriptor.get = oldGet = oldGet || function(){
let val = this[valueKey];
if(val instanceof InitializerValue){
this[valueKey] = val = val.value.call(this);
}
if(oldSet) return oldSet.call(this, newValue);
return val;
};
// CAUTION: this is dangerous. We need intend to conver regular fields to get/set methods here.
delete descriptor.writable;
oldSet = oldSet || function(newVal){
this[valueKey]=newVal;
return newVal;
};
// Overwrite the setter to call markDirty whenever it is used
descriptor.set = function(newValue){
let result = oldSet.call(this, newValue);
this.markDirty && this.markDirty();
return result;
};
// Update the descriptor to match with using getters and setters
target.kind = 'method'; // update to get and set if need be..
delete descriptor.writable;
// CAUTION: this is again dangerous, the initialize function should be called right before the constructor, but after it was fully defined.
if(target.initializer){
valueMap.set(target, target.initializer(target));
delete target.initializer;
// Catch usage of initial value or initalizers
if(descriptor.value){
Object.defineProperty(target, valueKey, {
writable: true,
value: descriptor.value
});
delete descriptor.value;
}else if(descriptor.initializer){
Object.defineProperty(target, valueKey, {
writable: true,
value: new InitializerValue(descriptor.initializer)
});
delete descriptor.initializer;
}
return target;
return descriptor;
}
}

View File

@@ -2,21 +2,16 @@
* The decorators proposal has changed since @babel implemented it. This code will need to change at some point...
*/
export function defineElement(tagName, options) {
return function decorator(target) {
// Queue defining element in a finisher, because apparantly thats how the non-legacy decorator proposal works (again, new proposal will be different...)
target.finisher = (finishedTarget)=>{
// Register the tagName as a custom-element with the browser
window.customElements.define(tagName, finishedTarget, options);
// Define the chosen tagName on the class itself so our vdom.render-function knows what DOM-Element to create
Object.defineProperty(finishedTarget, 'tagName', {
value: tagName,
writable: false,
enumerable: false,
configurable: false
});
return finishedTarget;
};
return target;
return function decorator(targetClass) {
Object.defineProperty(targetClass, 'tagName', {
value: tagName,
writable: false,
enumerable: false,
configurable: false
});
// Register the tagName as a custom-element with the browser
window.customElements.define(tagName, targetClass, options); // Define the chosen tagName on the class itself so our vdom.render-function knows what DOM-Element to create
return targetClass;
};
}