5

I am looking for a Svelte "Delegating Lazy Loading" component to another "real" component. This component should be transparent to the user who shouldn't know there is this "proxy" :

  • lazy-load the delegate (using a callback which dynamically import a js module)
  • Supports slots (slots should be forwarded to the delegate when it's ready)
  • Supports events (by forwarding subscriptions to the delegate)

I don't think it's possible now because no api is exposed for slots forwarding or events forwarding. Maybe a hack by implementing in js the same internal interface has a svelte component ?

Edit

I am looking for this kind of magic method:

I have an Heavy component, which I want to load asynchronously

Heavy.svelte:

<div on:click>
  <slot {secret}/>
  <slot name="footer"/>
</div>

<script>
  let secret = 'huhu';
</script>

I want to be able to export this component like this :

module.js

import { lazy } from './lazy.js'; // magic method

export let Heavy = lazy(async () => (await import('./Heavy.svelte')).default)

a consumer can then use Heavy without knowing it has been wrapped in this "high order" lazy component. this consumer doesn't have to handle/knowing anything about the asynchronous behavior of this wrapper :

Consumer.svelte

<Heavy on:click={() => console.log("clicked")} let:secret>
  <div>{secret}</div>
  <div slot="footer">Footer</div> 
</Heavy>

<script>
  import { Heavy } from './module.js';
</script>

I have a "working" solution, which doesn't support "let", doesn't support named slots, and doesn't support events..

2
  • Could you please clarify exactly which interface and behaviour do you expect? With a usage example, for instance Commented Jul 3, 2020 at 8:48
  • @illright I have updated my question with your suggestion. any idea ? :) Commented Jul 3, 2020 at 16:57

1 Answer 1

2

The best I can do. bind:* doesn't work, slots and events seem to work.

Wrapper.svelte

<svelte:component this={cpn} {...slotsProps} {...$$restProps} bind:this={instance}/>

<script>
    import { get_current_component } from 'svelte/internal';
    
    export let provider;
    
    const slotsProps = {"$$slots":$$props.$$slots, "$$scope":$$props.$$scope};
    const self = get_current_component();
    
    let cpn;
    let instance;
        
    provider().then(result => cpn = result);
    
    $: if (instance) {
        for (let [type, listeners] of Object.entries(self.$$.callbacks)) {
            instance.$on(type, (e) => {
                listeners.forEach(l => l(e));
            });
        }
    }

</script>

lazy.js

import Wrapper from './Wrapper.svelte';

export function lazy(provider) {
    return function(opts) {
        opts.props = {...opts.props, provider };
        return new Wrapper(opts)
    }
}

module.js (usecase example)

import { lazy } from './lazy.js';

export let Heavy = lazy(async () => (await import("./Heavy.svelte")).Heavy);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.