-
Notifications
You must be signed in to change notification settings - Fork 319
Make compatible with closure advanced compilation #374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Currently, compiling lit-element with the Closure compiler results in a clean build but a number of hard JS errors due to a few issues: - static methods being collapsed (i.e. removed entirely) - Object.hasOwnPropertyName() looking for static properties that have been rewritten by the compiler - static property initializers not being run when @exported The last issue is a compiler bug being tracked internally, but all three need to be worked around before this will compile and run cleanly. This includes all of the necessary fixes, including addressing the last issue by moving the Object.hasOwnPropertyName('_classProperties') check to _finalize(). This is necessary to ensure that _classProperties is defined before it's iterated in observedProperties on an element that has no properties. Another option for making _finalized and _classProperties public would be to move to checking this._finalized and this._classProperties and not needing to access them by name - I thought that was out of scope for this but would be happy to change to that style if reviewers prefer.
Fully support Closure compiler including ADVANCED_OPTIMIZATIONS
* uses `JSCompiler_renameProperty` where literal names are needed instead of using `@export` * The private `_classProperties` is no longer created by default. Instead `_ensureClassProperties` was added and is called to make sure that the specific class has its own storage for class properties. * Adds a test that ensure a subclass cannot alter a superclass. The condition tested here would only fail after merging #359. * optimization: ensures `LitElement` is marked as `finalized` so that it does not ever try to finalize.
Does this need docs changes? |
@katejeffreys No, it's just making the type annotations and constructions compatible with closure; no real user-facing considerations there. |
src/lib/updating-element.ts
Outdated
@@ -12,6 +12,14 @@ | |||
* http://polymer.github.io/PATENTS.txt | |||
*/ | |||
|
|||
/** | |||
* When using Closure Compiler, JSCompiler_renameProperty(property, object) is | |||
* replaced by the munged name for object[property] We cannot alias this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* replaced by the munged name for object[property] We cannot alias this | |
* replaced *at compile time* by the munged name for object[property] We cannot alias this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/lib/updating-element.ts
Outdated
@@ -200,29 +208,32 @@ export abstract class UpdatingElement extends HTMLElement { | |||
/** | |||
* Maps attribute names to properties; for example `foobar` attribute | |||
* to `fooBar` property. | |||
* @nocollapse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make it clear in here somehow why some properties need nocollapse and others don't? I assume properties that we use only via own property lookup, and not static inheritance, don't need nocollapse. That distinction might be subtle for maintainers w/o everyday Closure experience. Maybe comment the exceptions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, not related to hasOwnProperty
(that is dealt with by making sure we use JSCompiler_renameProperty
anywhere we use a property by name. It's working around ES6 compiler bugs -- and definitely deserve a comment.
I believe this is right:
- any static method needs @nocollapse to not be removed altogether
- static fields need @nocollapse to get their initializers
@rictic Does the above sound correct?
That said, similar to why Steve removed the initializer for _classProperties
, I'm not entirely sure why _attributeToPropertyMap
and properties
need initial values on UpdatingElement
either... will take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the simplest guidance is that all static methods and fields should have @nocollapse
in order to preserve correct semantics.
jscompiler started the perspective that there is no inheritance of static members, and that static members can be rewritten to global variables. These assumptions don't hold up well with ES6+ code, and work is underway to handle them more correctly, but for the time being @nocollapse
is the easiest way to tell it not to apply dangerous optimizations to them.
It's called @nocollapse
because we're asking for these members not to be collapsed down into global variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed initial values for _attributeToPropertyMap
and properties
as well.
Added comment block describing when @nocollapse is needed.
static createProperty(name: PropertyKey, | ||
options: | ||
PropertyDeclaration = defaultPropertyDeclaration) { | ||
/** @nocollapse */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised we need nocollapse here. Is it because of this
access? If so, seems like an unsafe optimization by Closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely unsafe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, all static methods need @nocollapse currently (closure bug workaround).
|
||
/** | ||
* Memoized list of all class properties, including any superclass properties. | ||
*/ | ||
private static _classProperties: PropertyDeclarationMap = new Map(); | ||
private static _classProperties?: PropertyDeclarationMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why remove the initializer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UpdatingElement
itself will never set anything into its _classProperties
(since it never has properties
); the set is created lazily during finalization on actual user subclasses
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can add a comment to that effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* Ensure this class is marked as `finalized` as an optimization ensuring | ||
* it will not needlessly try to `finalize`. | ||
*/ | ||
protected static finalized = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we initialize UpdatingElement.finalized to true too then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSCompiler_renameProperty
where literal names are needed instead of using@export
_classProperties
is no longer created by default. Instead_ensureClassProperties
was added and is called to make sure that the specific class has its own storage for class properties.LitElement
is marked asfinalized
so that it does not ever try to finalize.