preactjs / preact

⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.
https://preactjs.com
MIT License
36.63k stars 1.95k forks source link

Preact + Custom Element Side Effects #39

Closed c58 closed 8 years ago

c58 commented 8 years ago

Hi! I'm trying to use Preact as React replacement in my mobile app. But it seems that Preact does not support Web Components used inside "render". Web Components is used from OnsenUI framework.

I think that i know why it does not work. Preact uses vdom-dom diffing algorithm, React uses vdom-vdom. Onsen's web components changes a DOM (trying to change) and Preact is thinking that it is not right and it's deny it.

Is there any solution with Preact? Thanks.

developit commented 8 years ago

@c58 - very interesting. Have you tried this with the beta version? (Currently 3.0.1)

To help me investigate, what are you seeing happen - for example: do the web components get instantiated, but their attributes are not set?

Thanks!

c58 commented 8 years ago

@developit unfortunately, 3.0.1 does not work too. I've made an example to test it out. https://github.com/c58/preact-webcomp-test

In src/index.js just uncomment Preact part and comment React part and see the difference.

developit commented 8 years ago

Perfect, will take a look. Will be interesting to see if this is related to Shadow DOM polyfills.

c58 commented 8 years ago

@developit i've fixed minor mistake in the example. The issue is still there.

developit commented 8 years ago

It looks like the way Onsen instantiates CustomElements.js (from the Polymer project) is causing it not to use Shadow DOM at all. This means things like <ons-page> moves all of its children into a different parent element, which seems like the kind of things Preact can't really account for. I'm doing some testing to see how React can do the initial render without issue here, but I think a subsequent re-render would still mess things up for either framework. Will get back to you shortly.

c58 commented 8 years ago

The same thing happened with mithril. About re-rendering: with react no issues at all. I have tried to change a content in ons-page and ons-toolbar – content re-rendered as expected.

5 февр. 2016 г., в 18:14, Jason Miller notifications@github.com написал(а):

It looks like the way Onsen instantiates CustomElements.js (from the Polymer project) is causing it not to use Shadow DOM at all. This means things like moves all of its children into a different parent element, which seems like the kind of things Preact can't really account for. I'm doing some testing to see how React can do the initial render without issue here, but I think a subsequent re-render would still mess things up for either framework. Will get back to you shortly.

— Reply to this email directly or view it on GitHub.

developit commented 8 years ago

@c58 I came up with a test that shows that React behaves the same way after initial render. The reason Preact and Mithril both remove ons's elements on initial render is because they build the DOM imperatively, whereas React initially uses a static HTML snapshot inserted via innerHTML to do so.

However, this means that changing the structure of the DOM using React will still cause issues.

Really this boils down to what Preact (and React) are designed for: they are designed to constantly morph the DOM into a known state. You simply specify the desired DOM structure, and the work of mutating the DOM to look correctly is done for you.

I've published my React example to a fork for you to look at, it shows that after 1s a DOM structure change within <ons-page> causes the same degradation visible via Preact & Mithril.

I'm definitely still open to working on this, but I think the issue here is a lot more specific than Web Components: It's specifically integrating VDOM libraries with code that expects to be able to destructively mutate the DOM.

You can see a fairly complex example of how to account for this if you view the source of preact-mdl. Essentially, there is a wrapper placed around render() that tries to "backport" outside DOM mutations into the VDOM structure in order to preserve them. However, I have not yet found a good way to account for "injected" layers using this technique - where children appended to an element are forcibly moved into a different parent outside the control of Preact.

c58 commented 8 years ago

Yes, you are right, it does not work :( I will create an issue in OnsenUI repository.

UPDATE: I think it is already exists https://github.com/OnsenUI/OnsenUI/issues/985

developit commented 8 years ago

On the positive side, thanks for letting me know about Onsen :)

I'm testing out Polymer + Preact as well to see if there are issues.

developit commented 8 years ago

Closing for now, will revisit.

tconroy commented 7 years ago

Hey there, I'm running into an issue with a custom WebComponent not working when React is swapped for preact-compat. It seems to render on the initial view, but not subsequent views (IE, first page in a SPA app works, second page does not). Was there ever any workaround or resolution to this?

running

    "preact": "7.2.0",
    "preact-compat": "3.14.1",
developit commented 7 years ago

Hi @tconroy - would you be able to open a new issue in the preact-compat repo with a few details of your setup? It doesn't seem related to this issue, since side effects have been fully supported in Preact since 6.x.

tconroy commented 7 years ago

@developit Sure thing. Apologies, I should have posted there first. Hoping to get this resolved :)

H-Plus-Time commented 7 years ago

Looks like the 'renders once, subsequent renders don't work' issue remains whether or not preact-compat is present :-S. I'm running:

    "preact": "8.1.0",
    "preact-router": "2.4.1",
    "wc-loader": "1.1.3"

After switching routes, the element (paper-input, vaadin-grid in this case) is still there in DOM (all attributes intact), but shady DOM is toast (as to why my setup defaults to shady dom despite browser support... ¯_(ツ)_/¯ ).

tconroy commented 7 years ago

@H-Plus-Time I'm having a similar experience. FWIW my components are using the v1 spec ( not v0 ).

@developit -- is there any info I/we can provide to make debugging this easier/simpler?

developit commented 7 years ago

this might come down to removing component recycling, which is already likely to happen for other reasons. preact just creates DOM elements via createElement(), there's no special behavior for WC's so there isn't really a place to workaround. I'll try to ping you when I have something published without component recycling.

tconroy commented 7 years ago

Sounds good @developit! I have a strong feeling that that is the issue -- although unfortunately my knowledge of web components is a bit limited.

If you would like me to test out a pre-release version to see if it fixes the issue on my end toss me a message and I'd be more than happy to report my findings.

Cheers!