sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.81k stars 4.24k forks source link

Trim whitespaces before control structures and variables #6540

Open Kapsonfire-DE opened 3 years ago

Kapsonfire-DE commented 3 years ago

Describe the problem

Fixes #6486

Describe the proposed solution

PHP Template Engine Twig solves it by adding a - to the curly braces

{{-variable }} removes whitespaces before the variable/control structure

{{ variable -}} removes whitespaces after the variable/control structure

combining both remove the whitespaces in front and end

Take a look at: https://symfony.com/blog/better-white-space-control-in-twig-templates

Similiar solution for svelte could be nice as well

Alternatives considered

dont write whitespaces in your code - but makes the code ugly ;-)

Importance

nice to have

dummdidumm commented 3 years ago

This would be a breaking change because right now there's no requirement to have a whitespace between the brackets and the code. This makes it ambigouus to the minus sign.

Kapsonfire-DE commented 3 years ago

What about ~

the only use case i know is to invert Bits and I guess nearly no one would use it in template/html code and for these who need it could use (~var)

{~variable} trimmed before variable

{~variable~} trimmed before and after variable

{variable~} trimmed aftervariable

Prinzhorn commented 3 years ago

the only use case i know is to invert Bits and I guess nearly no one would use it in template/html code and for these who need it could use (~var)

It's still a breaking change.

I like the idea. White space issues in Svelte come up frequently and there is no one-size-fits-all solution to make every use-case happy (I still have to fight inline-block with font-size: 0 because of that...). And this is a suggestion I like very much.

Liquid does essentially the same https://shopify.github.io/liquid/basics/whitespace/ But for Twig and Liquid it's easier to find a syntax because they only have a single type of open/close tag.

If the Svelte team thinks this is a viable solution to the white space issues, then let's find a syntax. It also needs to work for {-#if} or {-:else:} etc. and the minus is ugli.

{expression}
{#if}
{:else}
{/if}
{#each}
{/each}
{#await}
...

This would be a breaking change

I've seen this argument a number of times (e.g. in https://github.com/sveltejs/svelte/issues/6373), maybe it's time to plan for a v4? But I know absolutely zero about future plans for Svelte and if that's on the horizon. I think avoiding breaking changes at all cost slows innovation and might result in awkward APIs.

I personally would even be fine with a {@ltrim} / {@rtrim} (self-closing) tag or similar. Like a control character you can place somewhere and have the leading or trailing white-space remove. But that's also kind of ugli and verbose.

Example: currently my Host.svelte (that renders a host with different parts colored) looks like this (prettier is now smart enough to not introduce whitespace between the spans). I cannot use font-size:0 hack because the component needs to adjust to the inherited size depending on the context.

<span class="host"
  >{#if subdomain}<span class="subdomain">{subdomain}</span>.{/if}{#if sld}<span class="sld">{sld}</span>.{/if}<span
    class="tld">{tld}</span
  ></span
>

It could become this if both if-blocks would trim leading and trailing whitespace, with whatever syntax we end up.

<span class="host">
  {#if subdomain}
    <span class="subdomain">{subdomain}</span>.
  {/if}

  {#if sld}
    <span class="sld">{sld}</span>.
  {/if}

  <span class="tld">{tld}</span>
</span>

But I think there are enough examples of why this is needed in other issues already :sweat_smile:

@Kapsonfire-DE do you have an example where trimming of an {expression} block is actually needed and cannot be done via nearby control blocks? The Liquid docs have one but it's completely made up and not necessary to even have that whitespace in the first place. Because for all other tags it should be easier to find a backwards compatible syntax.

Edit: I was just thinking that if something like this is introduced it would make things even better than expected. Because then by default all white-space could be 100% preserved as they appear in the HTML without touching it at all. It could be treated like any other content. This would make everything much more explicit than what Svelte is currently doing. And the white space can also be trimmed in the compile step. But of course keeping white-space 100% in-tact would be breaking because preserveWhitespace would be completely removed.

Kapsonfire-DE commented 3 years ago

In fact I dont have a example where a control block won't work - but this is a solution where it works against the concept of writing short code.

To make the code not breaking, this could be a flag-enabled feature, which are default off, in start template default on. So it won't break current projects..... But i agree to your statement: I think avoiding breaking changes at all cost slows innovation and might result in awkward APIs.

The ~ gives a similiar feeling like a minus, its short and nearly no one will be affected by it, and if someone is - he can easily refactor in less than a minute... The control blocks for trimming will make the code more noisy and verbose.

dummdidumm commented 3 years ago

What would this give us that hugging open/close tags can't?

<span>{#if foo}
  etc
{/if}</span>

If it's "only" about "this looks ugly in certain cases", then that sounds like a case for better formatting, which is the job of prettier-plugin-svelte .

Prinzhorn commented 3 years ago

What would this give us that hugging open/close tags can't?

Like I said this discussion is not new, there are plenty of arguments to be made #3080, #189

But skimming through those the proposed solution here would put us in jsx territory where you need {' '} for an actual space. But jsx is also somewhat popular. Edit: I think {' '} would be even rarer than in jsx with this solution.

If it's "only" about "this looks ugly in certain cases"

I think code readability and things like cyclomatic complexity are not about looks, but maintainability. Also consistency (see example below).

then that sounds like a case for better formatting, which is the job of prettier-plugin-svelte .

This is an interesting way to look at it. But prettier cannot offer a one-size-fits-all solution in the same way the compiler itself cannot. Because there are different problems. I'll post one more example to illustrate a point, but I think the other issues will contain much better and in depths examples.

Let's take this as an example (formatted by prettier):

<div>
  {#each list as item}
    {#if item.foo}
      <div>{item.foo}</div>
    {/if}

    {#if item.bar}
      <div>{item.bar}</div>
    {/if}
  {/each}
</div>

Works as expected. But once we're talking about inline-block prettier would have to (know to) turn this into:

<div><!--
-->{#each list as item}<!--
---->{#if item.foo}<!--
-----><div>{item.foo}</div><!--
--->{/if}<!--

--->{#if item.bar}<!--
-----><div>{item.bar}</div><!--
--->{/if}<!--
-->{/each}
</div>

which looks a lot like what I've been doing 10 years ago in PHP to render a inline-block list. The alternative would be to completely change the code to let it hug. But I'd rather have consistently formatted code and a way to also control white-space, which the proposal here would (kind of) give us.

I think if there was an easy and straight forward solution it would have already happened :smile:

baseballyama commented 3 years ago

What do you think about my opinion? (Maybe this is almost the same as @Kapsonfire-DE)

this could be a flag-enabled feature, which are default off, in start template default on.

My opinion is that users can set the option to compilerOptions if they want to remove useless whitespace from output's HTML.

In my understanding, if a user wants to output whitespace, a user should mention &nbsp in HTML. (And at the same time, break line also should mention <br>)

So I think in many cases, whitespace is just noise. (or should be noise.) But this idea also will be breaking changes. That's why I thought that this feature should implement as a compiler option. (Default is disabled.)

And the good point of this idea is that users can maintain readability. Users can avoid from ugli and verbose.

Thank you for reading!🎉 And I hope someone will comment on this idea.🧐

Kapsonfire-DE commented 3 years ago

whitespaces and   are not the same there are several cases where its handled differently

pre-tag :empty and many more

baseballyama commented 3 years ago

Ahhh right... (I forgot to think about pre tag ...) Thank you for sharing the information.