Skip to content

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

Merged
merged 10 commits into from
Jan 10, 2019

Conversation

sorvell
Copy link
Member

@sorvell sorvell commented Dec 15, 2018

  • 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 Ensure user accessor is never overridden #359.
  • optimization: ensures LitElement is marked as finalized so that it does not ever try to finalize.

rickcnagy and others added 4 commits November 13, 2018 21:03
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.
@sorvell sorvell added this to the 1.0.0 milestone Dec 15, 2018
@ghost
Copy link

ghost commented Jan 8, 2019

Does this need docs changes?

@sorvell sorvell requested a review from justinfagnani as a code owner January 8, 2019 22:58
@kevinpschaaf
Copy link
Member

@katejeffreys No, it's just making the type annotations and constructions compatible with closure; no real user-facing considerations there.

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -200,29 +208,32 @@ export abstract class UpdatingElement extends HTMLElement {
/**
* Maps attribute names to properties; for example `foobar` attribute
* to `fooBar` property.
* @nocollapse
Copy link
Contributor

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?

Copy link
Member

@kevinpschaaf kevinpschaaf Jan 10, 2019

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.

Copy link
Contributor

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.

Copy link
Member

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 */
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely unsafe

Copy link
Member

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove the initializer?

Copy link
Member

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

Copy link
Member

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.

Copy link
Member

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;
Copy link
Contributor

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinpschaaf kevinpschaaf merged commit 231eb95 into master Jan 10, 2019
@kevinpschaaf kevinpschaaf deleted the closure-advanced branch January 10, 2019 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants