sveltejs / svelte

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

Syntax changes #1318

Closed Rich-Harris closed 6 years ago

Rich-Harris commented 6 years ago

Update 12 April

Most of these decisions are fairly settled at this point — you can see a summary here.

Original issue follows:


I've referred to this obliquely in other issues, Gitter, etc, but haven't quite got to the point of starting a proper discussion about it.

Essentially, for version 2 I'd like to move away from the Mustache-esque template syntax to something a bit lighter and more modern, which boils down to using one curly brace instead of two:

<h1 class={myClass}>Hello {name}!</h1>

The success of JSX has proved that the second curly is unnecessary. Moreover, a lot of people — particularly those who have been exposed to React — have a visceral negative reaction to double curlies, many of them assuming that it brings with it all the limitations of crusty old languages like Mustache and Handlebars, where you can't use arbitrary JavaScript in expressions.

We would also put an end to this sort of thing — component properties being typecast — at the same time. (See #657).

Quoted attributes

At present, Svelte allows you to quote attributes and properties for the sake of your syntax highlighter:

<Widget x={{y < z ? }}>this generally breaks highlighting</Widget>
<Widget x="{{y < z ? }}">this generally breaks highlighting</Widget>

I'd suggest that we keep that behaviour, so as not to force people to adopt additional tooling (which doesn't yet exist anyway). The same goes for directive arguments — these would be unchanged.

Control flow

It's less clear what to do about if/else/elseif, each, and await/then/catch. We could of course do this...

{#if foo}
  <p>foo!</p>
{else}
  <p>not foo!</p>
{/if}

...though part of me feels like we're just continuing to accept the premise of Handlebars, and that there's a more natural approach waiting to be discovered. Just for the sake of argument:

#if (foo) {
  <p>foo!</p>
} else if (bar) {
  <p>bar!</p>
} else {
  <p>neither foo nor bar!</p>
}

<ul>
  #each (cats as cat) {
    <li><a target='_blank' href={cat.video}>{cat.name}</a></li>
  }
</ul>

#await (promise) {
  <p>wait for it...</p>
} then (answer) {
  <p>the answer is {answer}!</p>
} catch (error) {
  <p>well that's odd</p>
}

Maybe that makes you want to barf, I don't know. But I'd be very interested to hear everyone's ideas.

Keyed each blocks

I'm in favour of replacing @name with by name, as discussed in #703 — it has some clear advantages.

Triples

Triples could arguably be unchanged — if anything, the increased distinction between {text} and {{{html}}} is a good thing. Or we could go in a totally different direction like <{html}>. Eager to hear thoughts.

Static tags

364 — briefly discussed, but never acted upon: the idea of adding syntax for declaring tags static, as a way of saying to the compiler 'this will never change after the initial render, don't worry about generating update code'. Would be nice if whatever choices we make preserve that possibility.

Escaping

If you needed a literal { character in your markup, you could always do {'{'}. (This is how it's done in React.) Or you could do &#123;, which is pleasingly easy to remember. Does there need to be some method of escaping beyond that?

Migrating

All this stuff should come with an simple, completely automated way to upgrade an existing template. There could be a CLI tool, and the REPL would detect old templates and show an 'upgrade' button.


Obviously we shouldn't rush into anything. But changes like these are best made earlier on in a project's lifecycle, so I'm eager to hear what people think so that we can start making some progress. Thanks!

ansarizafar commented 6 years ago

All Ideas presented here are very reasonable. Particularly I like Static Tags and control flow syntax changes the most.

PaulMaly commented 6 years ago

Actually, I feel no pain with current, mustache-like, syntax. Maybe because I work with it in Ractive and worked even before Ractive.

But I always thought that if Svelte will change its syntax to something new, it will more look like ES6 Template Literals:

<h1 class="${myClass}">Hello {name}!</h1>

But in this case, we need to decide which syntax will be for blocks:

${if foo}
  <p>foo!</p>
{else}
  <p>not foo!</p>
{/if}

If there are any serious reasons to not use this standard, well, then it's completely up-to-you.

Btw, I also personally like Dust-syntax: https://github.com/linkedin/dustjs/wiki/Dust-Tutorial

dxlbnl commented 6 years ago

I like it, single/double braces sometimes trips when switching between svelte and react. I'm unsure about what to think of the control flow syntax, but I think I like the style closest to js the most. using curly braces to denote blocks feels most natural. But maybe not in html style templating.

jacwright commented 6 years ago

the limitations of crusty old languages like Mustache and Handlebars, where you can't use arbitrary JavaScript in expressions

Currently you can't use arbitrary JavaScript expressions everywhere you would like to. We could simplify the compiler code by having one expression parsing path instead of each directive and binding using it's own. For example, transitions require an object literal when it could be desirable to use a member, setting the options on data. There are issues to solve, such as methods being pulled from helpers in bindings but pulled from the public component API in events. However, this is a digression from the topic of this issue and should be discussed in more depth elsewhere if it has any merit. My apologies.

For the rest:

TehShrike commented 6 years ago

Exciting stuff! :smiley: I'm positive on these changes, and excited about decreasing the curlies.

The #if (foo) { syntax seems fine to me, but no strong preference for it versus the current syntax. I'm not currently capable of imagining something superior and new, but I'll keep my eyes open.

Is there any reason not to use backslashes to escape curlies? \{

Maybe going down the route of any escape characters at all would be confusing, and people would start expecting things like \n to work.

tomcon commented 6 years ago

1) Curly: Go from two down to one throughout Svelte. Easier to understand and clear for v2 imo 2) Keyed each blocks: prefer "key name" rather than "by name". Shows purpose clearly 3) Triples: as is 4) Static tags: @TehShrike suggestion at component level seems good, otherwise [[wontChange]] or maybe even simply enclosing in backticks {`wontChange`}? looking forward to it!

Rich-Harris commented 6 years ago

I always thought that if Svelte will change its syntax to something new, it will more look like ES6 Template Literals:

I wondered about that. But as you mention, the control flow makes it tricky, because it's not really a template literal — it's a DSL. I thought perhaps it's better to have something that's explicitly different, than something a bit 'uncanny valley'.

👍 for {#if} and 👎 for #if {

Am by no means wedded to that second idea — I came up with it more or less as I was typing it. Just want us to have a think about whether there is a better solution than {#if ...}, and if there isn't then that's fine too.

Is there any reason not to use backslashes to escape curlies? \{

I had the same question earlier and googled 'react escape curly braces' and landed here: https://github.com/facebook/react/issues/1545. Feels like a slippery slope.

Re static tags, I'm not suggesting that they should be part of these initial changes, just that we don't prevent ourselves from doing it in future. Static-ifying stuff at a component level could be done, but it doesn't address this sort of thing:

{{#each dynamicList as item}}
  <p>[[item.name]]</p>
{{/each}}

Tag-level and component-level aren't mutually exclusive though, we could do them independently.

thgh commented 6 years ago

Things that I miss most from Vue:

<!-- Bind expression to attribute with `:` -->
<h1 class="some-static-class">Hello!</h1>
<h1 :class="someClassExpression">Hello!</h1>

<!-- Bind event handler with `@` and pass event as first param. -->
<h1 @click="greet">Hello!</h1>

<!-- Event handler options -->
<button @click.prevent="greet">Hello!</button>
<:Window @keydown.esc="close"></:Window>

What bothers me most from Svelte:

<!-- I want to bind the value of this custom input just like I would bind to normal input -->
<input bind:value="query" /> <!-- works -->
<search-input bind:value="query" /> <!-- doesn't work :/ -->

Proposal for double binding:

<search-input ::value="query" />

For templating, I don't mind the handlebars. It's familiar for Vue and Angular users. I have never regretted keeping logic in my templates to a minimum. So I don't agree with the "visceral negative reaction" argument.

RyanZim commented 6 years ago

IDK about doubles vs. singles, but #if (foo) { looks horrible to me. Triples are fine as they are IMO.

PaulMaly commented 6 years ago

@Rich-Harris I've an idea, why not use a unified scheme for all things:

{:sign[:key][:expression]}

For example:

<h1 class="{=myClass}">Hello {=name}!</h1>

Control flow

{#if foo}
  <p>foo!</p>
{:else}
  <p>not foo!</p>
{/if}

<ul>
  {#each cats as cat}
    <li><a href="{=cat.video}">{=cat.name}</a></li>
  {/each}
</ul>

{#await promise}
  <p>wait for it...</p>
{:then answer}
  <p>the answer is {answer}!</p>
{:catch error}
  <p>well that's odd</p>
{/await}

Keyed each blocks

<ul>
  {#each cats as cat, key}
    <li><a target='_blank' href="{=cat.video}">{=cat.name}</a></li>
  {/each}
</ul>

Triples

<div>{&html}</div>

Static tags

<div>{~text}</div>

Escaping Seems, using obligatory signs parser able to ignore brackets without appropriate sign after that.

Possible signs: {= } - escaped interpolation {& } - unescaped interpolation {~ } - static interpolation

{# } - start of block {: } - sub-block {/ } - end of block

Most likely, the signs have to be others, it's just an example. The main ideas - use single scheme with the equal parsing rules:

  1. use single brackets
  2. start sign is signaled about what will be it's parsed
  3. following expression depends on sign

As I could imagine, the unified scheme should simplify parsing. Correct me if I'm wrong.

p/s Sorry for verboseness, you said that you're very interested to hear everyone's ideas.

burningTyger commented 6 years ago

single curlies are fine with me. As for the blocks I'd prefer {#if ... style. Yet I like vue's v-if= attribute style a bit better. It's more concise and you don't actually need another set of closing directives.

Conduitry commented 6 years ago

I like the single curlies for interpolation. Using them for {#if} etc. also seems fine to me. The other #if { syntax does indeed make me barf a little for some reason. I don't have strong opinions about triple tags, those can stay at three braces probably.

For static tags, iirc Angular 1.something introduced one-time bindings, where the value inside the {{ }}s would begin with a colon. So {{:foo}} would cease updating in the document once foo had a non-undefined value. I like this a bit better than square brackets, which it seems will make escaping a bit more of a hassle. (I don't tend to use brackets or braces too much in regular old html, but I probably use square brackets more.)

As for escaping: For some reason I wasn't thinking about the &#123; possibility. I think that works well enough, and doesn't produce the additional unnecessary code that {{'{'}} does. I think just mentioning that in the docs would suffice.

jacwright commented 6 years ago

I've used if and each attributes in frameworks. It simplifies the syntax, but I've really enjoyed Svelte's blocks not being element-bound. Plenty of times I've had to add a <span> tag to employ an if, but with Svelte I don't need to.

I like @PaulMaly's idea, but I would like it if the "default" sign was = to simplify. Anything that isn't an escaped interpolation would require a sign. And you could use = if you wanted to be explicit.

Conduitry commented 6 years ago

I just gave @PaulMaly's suggestions a proper re-read, and they are interesting. I like the succinctness but I'm also concerned about this resulting in punctuation salad. (Insert Perl joke here.) Perhaps some middle ground - which I realize is unhelpfully vague.

PaulMaly commented 6 years ago

@jacwright @Conduitry Thanks,

I would like it if the "default" sign was = to simplify. Anything that isn't an escaped interpolation would require a sign. And you could use = if you wanted to be explicit.

Agree. I just tried to show the main idea. But, if obligatory using of signs would help with a literal { characters without any workarounds I think it reasonable price too.

I like the succinctness but I'm also concerned about this resulting in punctuation salad. (Insert Perl joke here.) Perhaps some middle ground - which I realize is unhelpfully vague.

Yep, it's just a number ideas but seems we already have some of those things like {#if ...} and {/if}. So maybe it's just some kind of unification.

trbrc commented 6 years ago

I applaud the effort to simplify things for 2.0! The current syntax feels sprawling and ad hoc.

The general approach that @PaulMaly suggested looks like a good idea to me. You can remember a simple rule like "everything inside curlies is Svelte specific stuff", and then look up details as needed as you go.

The specifics are of course infinitely bikesheddable. To reduce punctuation salad, maybe common interpolation could simply be {myVar}, and special cases could be marked with readable words like {unescape myVar} and {static myVar}. It is easier to google "svelte js unescape" than "svelte js {&" or "svelte js {{{".

I think blocks could also be simplified to just use reserved words, like {if condition1} <A /> {elseif condition2} <B /> {endif} or similar. If additional punctuation is needed for syntactic disambiguation or clarity, it might be a good idea to harmonize it with directives and special components too, which are currently marked with colon. So maybe {:if condition}, {:static myVar}, etc.

On the general topic of simplifying syntax in a breaking way, I would like to recall #878 and #1069. Remove the poorly motivated special syntax for declaring dependencies of computed properties, so the <script> tag just uses standard, valid Javascript. It is an unnecessary gotcha that you can't use higher order functions or simple references in this part of the component.

shancarter commented 6 years ago

+1 for new control flow #if {...

+1 for <{html}>

arxpoetica commented 6 years ago

Oh man...

Please, please, PLEASE keep the normal quotation inline as you mention above regarding tooling: <foo bar="{baz}"> etc. It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML.

Can we also bikeshed on stuff like <:Window/> tags, etc? That little colon after an opening brace doesn't parse well with many current tooling systems. I know you like it's easily identifiable difference from "normal" HTML for good easy to distinguish reasons. But why not just capitalize and call these components reserved?

<Window/>

The parser can throw an error if one uses a reserved component namespace.

I too like @PaulMaly's notation as well as the recommendation elsewhere to allow {=foo} and {foo} as the same.

arxpoetica commented 6 years ago

Oh, also, I agree:

👍 for {#if} and 👎 for #if {

ansarizafar commented 6 years ago

I think blocks could also be simplified to just use reserved words, like {if condition1} {elseif condition2} {endif} or similar.

To reduce punctuation salad, maybe common interpolation could simply be {myVar}, and special cases could be marked with readable words like {unescape myVar} and {static myVar}.

I like these ideas. We can also consider this #1322 for V2.

subpx commented 6 years ago

What happens when a new framework becomes really popular and starts using double curlies?

PaulMaly commented 6 years ago

Can we also bikeshed on stuff like <:Window/> tags, etc? That little colon after an opening brace doesn't parse well with many current tooling systems. I know you like it's easily identifiable difference from "normal" HTML for good easy to distinguish reasons. But why not just capitalize and call these components reserved?

👍+1

Btw, we already have one reserved tag: <slot>. It looks like very similar - special, reserved tag.

stalkerg commented 6 years ago

For my opinion Mustache syntax, it's ok and makes changes this only by taste reasons it's a bad idea. We only begun made collections of components, I don't want to think about porting all this. If we talk about syntax I like more http://www.makotemplates.org/ way or maybe ES6 template strings syntax. %if expression: and %endif is the best 👍

opus131 commented 6 years ago

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

stalkerg commented 6 years ago

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

If I remember right too many things locked on the internal handwritten parser. For real good approach, we can use something like Flex/Bison but I don't know about JS in this case.

hperrin commented 6 years ago

Since we already have special "HTML" tags like <:Window>, would it be reasonable to make all control structures into special tags?

<:if myVar>
  <span>Something</span>
<:else />
  <span>Something else</span>
</:if>
<ul>
  <:each myArray as el>
    <li>{el}</li>
  </:each>
</ul>

That makes a clear distinction between things that control the DOM structure (<:thing>) and things that output text ({thing}).

It also has the benefit of being quite readable in editors: screen shot 2018-04-06 at 9 06 16 am

Rich-Harris commented 6 years ago

Oh my, I wasn't expecting so much feedback! Thanks everyone, this is fantastic.

@hperrin's idea is pretty cool. You get auto-completion as a nice bonus! The self-closing <:else /> is a bit awkward though, and the same would be true for <:await...> — I wonder if it should be like this instead:

<:if myArray.length>
  <ul>
    <:each myArray as el, i>
      <li>{el}</li>
    </:each>
  </ul>

  <:else>
    Nothing in the array
  </:else>
</:if>

<:await promise>
  <p>loading...</p>

  <:then value>
    <p>the value is {value}</p>
  </:then>

  <:catch error>
    <p>oops! {error.message}</p>
  </:catch>
</:await>

Maybe it's too weird having else (and elseif) inside if, and maybe it would interact badly with certain tooling (@arxpoetica can you be more specific on that point?). Curious to hear what people think.

@arxpoetica

It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML

I don't totally follow this point — <input type=range min=0 max=100 > is valid HTML — the quotes are entirely optional for attributes without spaces as of HTML5 😀

@thgh the Svelte equivalent for those Vue idioms is this — I'm not sure I understand what the drawbacks are? (These are more flexible and explicit IMHO, and barely any extra characters.)

<h1 class="some-static-class">Hello!</h1>
<h1 class={{someClassExpression}}>Hello!</h1>
<h1 on:click="greet(event)">Hello!</h1>

For the event modifier stuff see #1088. Bindings on custom elements is something we should support, I don't think we currently have an issue for it though.

@PaulMaly that's a really strong proposal, thanks. Agree with the other comments the {= is probably unnecessary and could just be {. @trbrc makes a great point about searchability.

@opus131

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

In theory yes. The compiler really only needs the source string and an AST. If we properly formalised and documented the Svelte AST format, then we could allow anyone to build their own parser. I think the costs of doing so are more human than technical though — having a single canonical template language is better from the point of view of documentation, tutorials, Stack Overflow, shareable components, etc.


So, consolidating everyone's input so far, my read is that the current front-runner is something like this...

  • {expression} — replaces {{expression}}
  • {#if expression} — replaces {{#if expression}}
  • {:else} — replaces {{else}}
  • {/if} — replaces {{/if}}

...with the following possible additions:

  • {static expression} (though this doesn't allow static if/each/await expressions)
  • {unescape expression} — replaces {{{expression}}}. Or maybe {html expression}?

But a last minute challenger has entered the race:

<:if foo>
  <p>foo!</p>
</:if>
hperrin commented 6 years ago

Regarding static tags, we could use another special tag:

<:Static>
  Hello, {user.name}. Even if you update your name, I'll still call you by the old one!
</:Static>

Also, -1 for <{html}>. (It will definitely confuse editors.) +1 for keeping {{{html}}}

jacwright commented 6 years ago

Regarding @hperrin's suggestion, the simple case works for HTML parsing in browsers. Will more complex expressions hurt that at all?

<:if myHelper() !== some.value && foo.bar.length>
  Foo is true!
<:else />
  Foo is false. :(
</:if>

I like it. But I'm leaning to {#if}, possibly because it stands apart more, possibly because I'm more used to that syntax in Svelte.

RyanZim commented 6 years ago

I'm personally not a huge fan of <:if..., for two reasons:

  1. I forsee this highlighting very poorly in some editors.
  2. It doesn't stand out from the rest of the template; it's a conditional, not an element.
PaulMaly commented 6 years ago

I completely agree with @RyanZim. Also seems @arxpoetica suggested to replace this <:Tag /> syntax with just regular reserved tags like <slot> and it's also a good idea. So, I suppose that main reason for this variant (Since we already have special "HTML" tags) is almost out of the race.

Personally, I've one more reason not to vote for this variant - I remember the time when I used PHP in my work. PHP was designed to be injected in HTML conveniently, but first thing what we did before starting a project - choosing template engine. Because of this:

<ul>
<?php if(!empty($todo)):?>
<?php foreach ($todo as $item):?>
  <li>
      <input checked="<?=$item['done']?>">
      <?=$item['body']?>
  </li>
<?php endforeach;?>
<?php else:?>
   <li>No todos</li>
<?php endif;?>
</ul>

Too many angle brackets, you know. This one looks much better (Smarty Template Engine):

<ul>
{foreach $todo as $item}
  <li>
      <input checked="{$item.done}">
      {$item.body}
  </li>
{foreachelse}
  <li>No todos</li>
{/foreach}
</ul>
hperrin commented 6 years ago

It looks like @RyanZim's first point is valid in Sublime Text. screen shot 2018-04-06 at 11 52 16 am

VS Code and Atom look fine. screen shot 2018-04-06 at 11 52 06 am screen shot 2018-04-06 at 11 51 51 am

One big bonus in all of them, though, is the matching tag highlighting.

hperrin commented 6 years ago

I translated a big component of mine, and after seeing how botched it looks in Sublime, I'm taking back my own vote for <:if>. 😭 It's too bad too, cause it highlights really well in VS Code. Better than {#if}.

hperrin commented 6 years ago

Regarding renaming the special tags from <:Name> to <Name>, I think that's a really bad idea. It invites name collisions in the future. If beginning the tag name with a colon breaks a lot of tools, we can pretend it's a namespace, and choose something simple, like "s":

<s:Window ... />
PaulMaly commented 6 years ago

@hperrin We already have reserved <slot> tag which basically comes from Web Components standard current revision. So, there won't be a problem to have a few additional reserved tags.

constgen commented 6 years ago

Would anybody like to replace each (cats as cat) with for (cat of cats) to be more EcmaScript-like. May be not replace but add an alternative.

tivac commented 6 years ago

I'm against <:if> style tags due to how ungainly they are to type.

Finger DX is important.

Rich-Harris commented 6 years ago

So, looks like <:if ...> is out. It was a nice idea!

Seems folks are generally on board with {expression}, {#if expression}, {:else} and so on. Think we're probably at the point where we can exclude that from further bikeshedding.

I realised that {static expression} and {unescape expression} or {html expression} aren't as practical as we first thought, because of ambiguities about how to parse them:

{html (expression)} <!-- could be CallExpression or prefixed ParenthesizedExpression -->
{html + whatever} <!-- could be BinaryExpression or prefixed UnaryExpression -->

So we either need to choose sigils for those cases, or prefix the keywords, e.g.

{=html expression}

I think prefixing is better, but have no strong opinion about which special character would make most sense (except a mild aesthetic preference for characters with vertical symmetry, and a suggestion that we avoid < and & because they have special significance in HTML and will cause highlighting weirdness).

I agree with @hperrin about names for special components — I don't think it's wise to have <Window> and <Component> etc. <slot> is different precisely because it's an element with special meaning in HTML, and Svelte slots behave like 'real' ones do.

@constgen Have wondered about that. The reason I think it's probably best not to is that we can currently use indexes (each cats as cat, i) and for (cat, i of cats) would be odd. Also, there's no good place to put by name or key name. I'm generally against having multiple ways of doing the same thing, since it creates anxiety about which is the 'right' one and what the differences are between them.

We're almost there! Think we basically just need to figure out the HTML/static tags thing.

arxpoetica commented 6 years ago

Whew I am so relieved <:if ...> didn't land. 👍 Those little colons right after the angle brackets really mess with my current tooling.

@Rich-Harris

It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML

I don't totally follow this point — is valid HTML — the quotes are entirely optional for attributes without spaces as of HTML5 😀

Yes, but curly braces aren't considered serializable. So keeping the quotes allows for tooling that tries to serialize.

I agree with @hperrin about names for special components — I don't think it's wise to have and etc. is different precisely because it's an element with special meaning in HTML, and Svelte slots behave like 'real' ones do.

I definitely understand the point about it being intentional to separate it from regular components and HTML. So let's just stick on the discussion similar to <:if ...> about the colons in <:Window/> and <:Head/> messing with environment tooling.

I like @hperrin's recommendation to simply prefix it:

<s:Window ... />

That immediately solves the tooling problem. I could get behind that. It also makes it feel even a tad more intentional, i.e., that s: means something. It's a namespace. This actually goes well with the whole component marketplace idea, not to veer the discussion too far afield, but we've talked about namespacing before, and this fits with that. Hell, it could even be <svelte:Window/> but I like the shorter <s:Window/> more.

For that matter, maybe <s:*> ought to be the official namespace for all Svelte marketplace components.

Please can we do something other than <:Window/>? Pretty please???

image

ansarizafar commented 6 years ago

{#if expression}, {:else}

Multiple prefixes # : = will confuse new users. In my opinion We should use the same prefix everywhere or If possible completely avoid them {if condition}... {else}...{/if} etc.

PaulMaly commented 6 years ago

@ansarizafar I believe that developers able to remember a few prefixes. The unified schema would simplify parsing process.

Possible prefixes, I guess: {~foo} {?foo} {=foo} {%foo} {^foo} {*foo} {@foo}

arxpoetica commented 6 years ago

{🍔foo}

hperrin commented 6 years ago

If we did want to avoid prefixes all together, we could emulate one advantage of the <:if> syntax by clearly separating control structures from output. Maybe something like:

{if textIsSafe}
  <span>{{{text}}}</span>
{else}
  <span>{{text}}</span>
{/if}

So single curly brace means a control structure, double curly brace means escaped output, and triple curly brace means unescaped output.

tomcon commented 6 years ago
So, consolidating everyone's input so far ... 
{expression} — replaces {{expression}}
{#if expression} — replaces {{#if expression}}
{:else} — replaces {{else}}
{/if} — replaces {{/if}}

...with the following possible additions:
{static expression} (though this doesn't allow static if/each/await expressions)
{unescape expression} — replaces {{{expression}}}. Or maybe {html expression}?

{:else} — replaces {{else}} personally not keen on {:else}/{:elseif} and can't see any reason why we need to change what we have already i.e. {else}/{elseif}. Plus extra awkard typing + not a good look imo

Now that we are going to one curly brace, we have a space we can use, why not: {{static expression}} 2 braces {{{unescape expression}}} 3 braces, stay as is + it is significant to do this, so it is good to stand out On the other hand, maybe we should move away from 2 braces completely, can foresee problems in people migrating and accidentally making things static.....?

if we were to go down the prefix route then <sv: or <sve: as in \<sv:Window> \<sve:Window>??

trbrc commented 6 years ago

Maybe it's too weird having else (and elseif) inside if

This actually looks like a good idea to me (regardless of <if ...> vs {if ...}). There is something awkward about the Handlebarsian syntax for if/else blocks:

{{#if user.loggedIn}}
    <a href='/logout'>log out</a>
{{else}}
    <a href='/login'>log in</a>
{{/if}}

The pair of {{if ...}} {{/if}} blocks are similar to HTML, but what is going on with that {{else}} dangling by itself in the middle? HTML either uses pairs of tags enclosing some content, or self-closing tags when there is no additional content. The sandwhiched else breaks those rules. Having it as its own nested block inside the if fixes it.

Another fix would be more like @Rich-Harris's first proposal in the thread, which avoids the closing /if altogether.

I realised that {static expression} and {unescape expression} or {html expression} aren't as practical as we first thought, because of ambiguities about how to parse them:

{html (expression)} <!-- could be CallExpression or prefixed ParenthesizedExpression -->
{html + whatever} <!-- could be BinaryExpression or prefixed UnaryExpression -->

Good point! OTOH, we might treat them as reserved keywords and simply not allow data to use those names. At the moment, the compiler will not allow expressions where the data is called "class", "default", "for", etc, so there are already limits on what you data can be called.

thgh commented 6 years ago

If there has to be a prefix, I would strongly vote for ${foo}. Don't invent new prefixes 😃

I'm not sure I understand what the drawbacks are? (These are more flexible and explicit IMHO, and barely any extra characters.) <h1 class={{someClassExpression}}>Hello!</h1>

I like that handlebars can contain expressions, it makes total sense. But the fact that handlebars can output objects feels awkward, e.g. <SomeComponent data="{{someObject}}" />. I thought HTML only allows strings in attribute values.

PaulMaly commented 6 years ago

@thgh, seems it’ll look strange with Store properties: ${$foo}

stalkerg commented 6 years ago

ok, looks like you seriously decided to change syntax... I have only one wish: the finish of this action should be syntax plugins for VSCode/Atom/Sublime. And of course I can help with VS Code but it's should be part of the Svelte2 milestone.

RoryDuncan commented 6 years ago

Just another opinion in the fray:

Personally, I feel one of the strongest arguments svelte has is made by the original post by @Rich-Harris , discussing svelte apps as Web Components. The further it strays from it's initial ply of interopability, the more of an argument it is for someone to use a more fleshed out framework.

Which leads me to believe the ideal situation would be Web Components with standard JS tokens in the raw. That is, without any mustache-like tokens nor svelte-specific ones.


<SubComponent />

if (foo) {
  <SubComponent />
}
else {
  <SubComponent />
}

<SubComponent />

But, I don't know of the feasibility of it, so my vote would go towards ${if foo} style as an alternative.

TL;DR: the less Domain Specific Language aspects of svelte, the better.

ansarizafar commented 6 years ago

Ideal situation would be Web Components with standard JS tokens in the raw. That is, without any mustache-like tokens nor svelte-specific ones.

I completely agree with @RoryDuncan