Svelte: Prop initialization in web/standalone components

Created on 15 Mar 2019  Â·  26Comments  Â·  Source: sveltejs/svelte

Today I created a small, self-contained standalone/web-component in svelte and stumbled across the following behaviour:

In my component, i declare a few properties like so:

export let zip = null;
export let radius = 10;

I then create/bundle the component with rollup, include and use it in my webpage:

<html>
<head>
<script src='bundle.js'></script>
</head>
<body>
<my-component zip="12345" radius="15></my-component>
</body>

Then, in the component I wanted to use the defined props in the onMount-Hook to set additional parameters for a call to an external API. The result from this call should then be displayed by the component. But at that point in the lifecycle, they are just undefined or have their initial default values. Only after the second, third, n-th beforeUpdate-Hook they get their external values passed down, as can be seen on this screenshot:

image

Basically it does one complete lifecycle for each defined prop. I somewhat fixed the problem of the missing values by encapsulating everything in a $-block, but that creates subsequent calls to the external API for each prop.
At that point I didn't know if I did something wrong, or if this is somewhat expected for web-components to do. If not, then that should be fixed so that all prop-values are correctly set in onMount.

Versions from package.json:
"npm-run-all": "^4.1.5",
"rollup": "^1.2.2",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^4.0.1",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"sirv-cli": "^0.2.3",
"svelte": "^3.0.0-beta.7"

custom element has pr

Most helpful comment

I see this issue has 2 open PR's is this going to be finalized anytime soon? It kind of makes creating web components from svelte unusable atm

All 26 comments

Update on this, the problem is the execution order of sveltes onMount-handler in relation to the web components attributeChangedCallback and connectedCallback. I added some console.logs in the source code, to get a glimpse on the order of execution. As you can see, onMount gets called first, then the attributeChanged-callbacks and finally connected.

image

I think it would make more sense to call onMount last in the case that the component is a standalone/web component - if this is possible at all. Tested this with [email protected]

Same problem here. Been banging my head against the wall for several hours. I see a prop in the template but can't access it from onMount - it's undefined. Moreover, I get warnings of type was created without expected prop 'title'.

Here's my HTML:
<site-message title="hello"></site-message>

Here's my Svelte:

<script>
  import { onMount } from 'svelte';
  export let title;
  onMount(() => {
    console.log(title); // undefined
  })
</script>

<svelte:options tag="site-message"/>
<div>{title}</div>

Does anyone know what might be wrong?

As I mentioned before, it's the load order in which the props get processed in a standalone component. Basically onMount is called too early resulting in undefined props. I also came across the was created without expected prop-error, but "fixed" it by giving my props some default values and then checking in my logic if those values were overwritten.

In a nutshell, what I did to fix my problems was 1) ditch onMount in my custom components 2) use <svelte:window on:load={customOnLoadHandler} /> were customOnLoadHandler is just a normal async-function within my component. When this runs, all the props that were set are initialized/overwritten from the defaults and I can access the API I wanted to call, without calling it multiple times. Yes, it is a bit hacky, but it works for now until this is resolved or there is a better solution.

@thepete89 that did a trick, although it feels a bit clumsy. Do you also get warnings of type was created without expected prop 'title'. in console.log? The only way to get rid of them is to set default values for props, but this also doesn't feel right.

@timonweb as I wrote in my last comment, I had the same issue and also "fixed" it by giving them default values. Yes, it doesn't feel right, but it's the only way at the moment to get rid of that error.

@thepete89 @timonweb I'm still getting the same issues you guys are getting.
Was there anything that either of you did to fix it, other than the above described workaround?

@pbastowski nah, I didn't like this workaround and dropped Svelte for now, will wait for better times.

@timonweb I'm also leaning towards not using Svelte to create web-components until this issue is resolved.
The worst issue I encountered is that slots within my Svelte app's components no longer work properly when I wrap it in a web-component. This is a complete deal breaker, unfortunately. Pity.

Feel free to open some PRs to fix the issues you are encountering.

@antony There seems to be a PR present for the slot issue already https://github.com/sveltejs/svelte/pull/3136

@pbastowski nice - have you tried it? can you confirm that it works?

@antony I have just tested it with my test project and it does indeed work as expected.

That is, the slot content from index.html is passed into App.svelte and renders correctly.

App uses Input.svelte, which also has a slot and that slot's contents are rendering as expected.

Based on my limited testing, it would appear that this PR has indeed fixed the broken slot problem.

Nice. I'd recommend you go to the PR and add your findings there / working
code sample there, or maybe just link this issue - as it will speed things
up when it comes to merging it.

Sadly I don't have the access to do so but I know this will be useful to
those who do :)

Thanks

On Sun, 18 Aug 2019 at 10:12, pbastowski notifications@github.com wrote:

@antony https://github.com/antony I have just tested it with my test
project and it does indeed work as expected.

That is, the slot content from index.html is passed into App.svelte and
renders correctly.

App uses Input.svelte, which also has a slot and that slot's contents are
rendering as expected.

So, it would appear that this PR has indeed fixed the broken slot problem.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/sveltejs/svelte/issues/2227?email_source=notifications&email_token=AABVORKVPGOCZ3COHPA76UTQFEG67A5CNFSM4G65UU5KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4Q32YI#issuecomment-522304865,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AABVORLISXDQHKF5FXOOXF3QFEG67ANCNFSM4G65UU5A
.

>


ꜽ . antony jones . http://www.enzy.org

@antony done

@thepete89 Apologies for hijacking this issue with slot problems. This issue was originally discussing prop initialization problems, which are still there.

@Rich-Harris I contacted you last week regarding issues with Svelte components wrapped in a web-component. I noticed you were on Twitter recently asking about web-components, so, perhaps it is a good time to revisit this issue as well? I was going to create a new issue, but this one does the job perfectly.

@pbastowski no problem, was not around until yesterday so I had no time to answer your question. svelte:window and default values was the only thing I did to fix the issue with the prop-initialisation.

Funny thing is, if my webcomponent gets injected asynchronously (say via jQuery oder other DOM-Manipulations in vanilla JS) then i HAVE to use onMount because svelte:window on:load won't work in that case. So it would really make things easier if onMount would behave like it should in either case.

One way I do to workaround the issue is to wrap my onMount callback in a setTimeout.

<script>
  import { onMount } from 'svelte'

  export let foo

  onMount(() => {
    setTimeout(() => {
      console.log(foo) // work
    }, 0)

    console.log(foo) // undefined
  })
</script>

It's completely hacky, I would like to know if there's a fix planned?

@RomainLanz have you tried await tick()?

What'up guys? I have the same issue. I start to use svelte to build web components, but props in wc don't work

Not to throw shade on Svelte, but in the end, I dropped Svelte for web components and started using Lit-Element, so far the ride is pretty smooth. Here's a good resource: https://open-wc.org/

Oh shoot, yeah I'm having problems here too. Any fix in the works for this?

I've been digging into this to try to get Svelte custom components to play nicely with other frameworks that create an element before binding properties. The issue is that the constructor of the compiled custom element runs init() immediately, but the browser doesn't call attributeChangedCallback until after instantiation, and if you have after-creation bindings being added (from outside) they also happen too late.

I've been working on a fix in the compiler which I think solves the problem, by deferring the call to init() until connectedCallback, i.e. it will only build the component once it is added to the DOM — except if you pass options into the constructor (like would happen if you're manually instantiating it in JavaScript rather than including it in some HTML); in that case it initialises straight away. If you manually assign any properties before init is called, it keeps track of those too.
The result is that (as far as I can tell so far) the events happen in the right order; at least the tests are passing.

I should have a PR ready to go in the next few days.

For anyone looking for a temporary solution to this problem, this is what I'm doing:

import { onMount, tick } from 'svelte'

onMount(async () => {
  await tick()
  myProp1 = myProp1 || defaultValue1
  myProp2 = myProp2 || defaultValue2
})

...Then I just make sure that all my $: reactive statements also check whether the values are initialized or not. It's hacky, but it avoids the double render.

I see this issue has 2 open PR's is this going to be finalized anytime soon? It kind of makes creating web components from svelte unusable atm

Got hit by this issue too, and it’s unfortunately a blocker for releasing a component in my case.

yeah - this one's painful :/

Was this page helpful?
0 / 5 - 0 ratings