woutdp / live_svelte

Svelte inside Phoenix LiveView with seamless end-to-end reactivity
https://hexdocs.pm/live_svelte
MIT License
1.28k stars 53 forks source link

Unable to compose Svelte components with each other #151

Open nikfp opened 1 month ago

nikfp commented 1 month ago

I'm trying to get some composition going and I ran into an issue with importing one svelte component into another. This is the code I'm working with. The main component looks like this:

<script lang="ts">
    import TextInput from "./TextInput.svelte";

    export let live;

    let textInput = "";

    function handleForm() {
        live.pushEvent("validate-item", { name: textInput });
    }
</script>

<form on:change|preventDefault={handleForm}>
    <TextInput value={textInput} name="element" id="123456" />
</form>

And here we have the text input getting started.

<script lang="ts">
    export let value: string;
    export let name: string;
    export let id: string;
</script>

<div>
    <input
        type="text"
        {name}
        {id}
        bind:value
        class="mt-2 block w-full rounded-lg text-zinc-900 focus:ring-2
        sm:text-sm sm:leading-6 dark:bg-zinc-700 dark:text-zinc-100
        inlinedark:placeholder-zinc-300"
    />
</div>

When I add the text input in, I'm getting this error:

[error] ** (NodeJS.Error) TextInput is not defined

And I've tried several ways of getting the imports going, including the relative import show, importing from $lib, and importing relative to the elixir project root.

What am I missing? Is this something simple I should be approaching differently? I haven't been able to find an example of composing Svelte components inside a LiveSvelte project online.

woutdp commented 1 month ago

I've added your example to the example_project and it seems to work for me: https://github.com/woutdp/live_svelte/commit/f9d688960d169f329391ca2f09f729830b28df74

Also make sure of the following:

<form on:change|preventDefault={handleForm}>

Should probably be:

<form on:submit|preventDefault={handleForm}>

Because preventDefault only applies to submit.

Consider running the example_project, maybe it'll reveal the issue

ElijahJohnson5 commented 4 weeks ago

I am running into this same issue, it looks like to me that the generated server.js and app.js files are doing something incorrectly.

For example:

// svelte/Test.svelte
var Test2 = create_ssr_component(($$result, $$props, $$bindings, slots) => {
  return `<div data-svelte-h="svelte-wl5jh0">Test</div>`;
});
var Test_default = Test2;

// svelte/Test2.svelte
var Test2_exports = {};
__export(Test2_exports, {
  default: () => Test2_default
});
var Test22 = create_ssr_component(($$result, $$props, $$bindings, slots) => {
  return `<div>Test 3
  ${validate_component(Test, "Test").$$render($$result, {}, {}, {})}</div>`;
});
var Test2_default = Test22;

this code gets output in my server.js. To fix the undefined issue I can just change this line from: ${validate_component(Test, "Test").$$render($$result, {}, {}, {})}</div>; to ${validate_component(Test_default, "Test").$$render($$result, {}, {}, {})}</div>; everything works again.

Just figured it out you need "verbatimModuleSyntax": true in your tsconfig.json file

woutdp commented 4 weeks ago

@nikfp Does adding "verbatimModuleSyntax": true to the tsconfig.json fix it for you too?

nikfp commented 4 weeks ago

Give me the day to try it, I was exploring LiveSvelte on a branch that I'm not actively working on and I need to get something working in front of a coworker today. Once that pressure is off I can circle back.