sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.77k stars 4.14k forks source link

Space after conditional tag is erroneously gobbled up #6381

Open aral opened 3 years ago

aral commented 3 years ago

Describe the bug

The space in markup after a conditional is gobbled up. It should be left alone.

Logs

None

To Reproduce

<script>
  let truthy = true
</script>

<h1>Always{#if truthy} true{/if}!</h1>

https://svelte.dev/repl/4c6d1164f6434abaadf5c062b643d54c?version=3.38.2

Expected behavior

When truthy, the markup output should be:

<h1>Always true!</h1>

Instead, it is:

<h1>Alwaystrue!</h1>

This is true even if the text is surrounded by a tag, e.g.

<h1>Always{#if truthy}<span> true</span>{/if}!</h1>

When falsy, the output is as expected:

<h1>Always!</h1>

Workaround

Although not exactly equivalent, you can work around the issue by using a non-breaking space instead:

<h1>Always{#if truthy}&nbsp;true{/if}!</h1>

This will have the (possibly unwanted) side-effect of making your sentence not break at that point but it will maintain proper letter spacing.

If you can sacrifice a tiny bit of variance in proper spacing, you can also use an en space:

<h1>Always{#if truthy}&#8197;true{/if}!</h1>

Stacktraces

Not applicable.

Information about your Svelte project:

See REPL.

Severity

Quite fundamental when formatting HTML output. Encountered while creating a Mad Libs-style (sentence-style) form.

Additional context

Not applicable.

arxpoetica commented 3 years ago

This is likely actually a bug, even though it's been around since v3.0.0. See: https://svelte.dev/repl/4c6d1164f6434abaadf5c062b643d54c?version=3.0.0

However, since this behavior has been fairly long-standing, one could almost think of it as a breaking change. Not sure what to do, since it could break applications in the wild.

Note that white space at the end of {#if} statements is preserved: https://svelte.dev/repl/b161491bbf014f54a349f834e82c7d92?version=3.38.2 So if the thinking is that the whitespace trimming is intentional, it's not consistent.

One way or another this will likely lead to a breaking change if we want consistency.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

justuswilhelm commented 9 months ago

I am working on a breadcrumb list generator that can chain arbitrary lists of a > b > c and so on. The > is assigned only after the first element, so I need to use an each loop and test if the iteration index is > 0. If I don't purposefully insert a whitespace using an expression, the whitespace will be gobbled up. Furthermore, prettier formatting the svelte code to look like it should have a leading whitespace makes the issue even more confusing. Anyway, this is how I ended up fixing it:

<script lang="ts">
    interface Crumb {
        href?: string;
        label: string;
    }
    export let crumbs: Crumb[];
</script>

<div>
    {#each crumbs as crumb, ix}
        {#if ix > 0}
            <!-- workaround -->
            {" "}
            &gt;
        {/if}
        {#if crumb.href}
            <a href={crumb.href}>{crumb.label}</a>
        {:else}
            <span>{crumb.label}</span>
        {/if}
    {/each}
</div>