Skip to content
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

Component constructors cannot be new-ed #2970

Closed
nolanlawson opened this issue Aug 2, 2022 · 15 comments
Closed

Component constructors cannot be new-ed #2970

nolanlawson opened this issue Aug 2, 2022 · 15 comments
Labels

Comments

@nolanlawson
Copy link
Contributor

nolanlawson commented Aug 2, 2022

Description

import Component from 'x/component'

lwc.createElement('x-component', { is: Component })

new Component() // throws "Illegal constructor"

Maybe this is working as designed, but it seems a bit surprising (at least to me).

Steps to Reproduce

Expected Results

No error thrown

Actual Results

Screen Shot 2022-08-01 at 4 16 05 PM

Version

LWC 2.21.1

Possible Solution

Use lwc.createElement instead.

@git2gus
Copy link

git2gus bot commented Aug 2, 2022

This issue has been linked to a new work item: W-11533536

@nolanlawson
Copy link
Contributor Author

Updated the description, I was wrong about CustomElementConstructor. Forgot that you can't new those until the elements are defined.

@jmsjtu
Copy link
Member

jmsjtu commented Aug 4, 2022

If this is the intended design should we add a KA and a section to the OSS / SFDC dev guides?

@nolanlawson
Copy link
Contributor Author

I think it may be intentional but I'm not 100% sure. @caridy might know.

@caridy
Copy link
Contributor

caridy commented Aug 4, 2022

It is intentional. Basically, what should be the result of new Component()? Should that return an element? it can't be, because that's not exactly a custom element constructor. should that return a component instance then? yes, but what can you do with a component instance? and how do you create the associated element? and what will be the tagName of the associated element? A component to function needs to have a 1-1 relationship with an element, otherwise it is useless.

@nolanlawson
Copy link
Contributor Author

@caridy Thanks, that makes sense. I guess in my head, I was thinking that lwc.createElement() is roughly analogous to customElements.define(), so in that way, you "should" be able to do new Component() after the element has been defined, because it does have a tag name associated with it, and it's registered in customElements.

I'm not totally convinced this is something we need to support, though. That's why we have CustomElementConstructor.

@caridy
Copy link
Contributor

caridy commented Aug 4, 2022

I'm not totally convinced this is something we need to support, though. That's why we have CustomElementConstructor.

Exactly, you don't do new Component() instead you do new Component.CustomElementConstructor(), and of course, you must register it before you do that, and as a result, you get an element.

@nolanlawson
Copy link
Contributor Author

Probably a different aspect of the same issue: you can manually create an element called x-foo that has already been claimed by LWC, but the element will not be upgraded. #2984

@caridy
Copy link
Contributor

caridy commented Aug 11, 2022

Well, with #2724 that's not longer observable... so creating x-foo that was claimed by LWC via a pivot is not visible to user-land code, so for them creating that element will NOT upgrade it and will not give you any hint that it is indeed already registered, and a definition after that will in fact upgrade the manually created element.

@nolanlawson
Copy link
Contributor Author

Pivots are still observable, just not 100% observable. If you do element.constructor.toString() you won't get HTMLElement() { [native code] } as you would with a non-upgraded element, so it is observable that it's a custom element. However, it won't be upgraded in the sense that it has a shadowRoot, has reactive properties, etc.

@caridy
Copy link
Contributor

caridy commented Aug 12, 2022

element.constructor.toString() should never be native code if the element is a custom element. I don't understand.

@nolanlawson
Copy link
Contributor Author

My point is that if we do this:

  1. Create a scoped element (within LWC) named x-foo
  2. Outside of LWC, someone calls document.createElement('x-foo').constructor.toString(), which returns 'class extends HTMLElement {\n}'
  3. Whereas if x-foo were never defined, then it would return 'function HTMLElement() { [native code] }'

So in that sense, the pivots are "observable."

@caridy
Copy link
Contributor

caridy commented Aug 18, 2022

I see! maybe we can make it a class considering that in IE11 that's the case anyways... so we can target the path of patching to use a class instead of an actual function. What do you think?

@nolanlawson
Copy link
Contributor Author

@caridy I'm not sure I understand. We already do use a class, not a function:

CE = class LWCUpgradableElement extends RendererHTMLElement {

We can discuss offline if it's easier. 🙂

@jmsjtu
Copy link
Member

jmsjtu commented May 7, 2024

This is a duplicate of #3202

@jmsjtu jmsjtu closed this as completed May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants