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:
@@ -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" ],
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user