Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate <script> with export and <script template-helpers> #547

Closed
mlrawlings opened this issue Jan 25, 2017 · 42 comments
Closed

Deprecate <script> with export and <script template-helpers> #547

mlrawlings opened this issue Jan 25, 2017 · 42 comments

Comments

@mlrawlings
Copy link
Member

mlrawlings commented Jan 25, 2017

We've decided to stop hijacking the script tag and use concise style tags that look like JS instead.

Deprecate <script> with export

Old:

<script>
   module.exports = {
      handleClick() {
         alert('hi!')
      }
   }
</script>

<button on-click('handleClick')>Click me!</button>

New:

class {
   handleClick() {
      alert('hi!')
   }
}

<button on-click('handleClick')>Click me!</button>

Deprecate <script template-helpers>

Old:

<script template-helpers>
   function sum(a, b) {
      return a + b;
   }
</script>

<div>The sum of 1 + 2 is ${sum(1, 2)}</div>

New:

static function sum(a, b) {
   return a + b;
}

<div>The sum of 1 + 2 is ${sum(1, 2)}</div>

Moving to an external file

One concern you may have is that with the <script> with export approach, the only change required to move a component to an external .js file was copy and paste. Admittedly, it's not quite that simple, but it's still really easy.

This template:

import sum from './helpers/sum';

class {
   handleClick(a, b) {
      console.log(sum(a, b))
   }
}

<button on-click('handleClick', 3, 4)>Click me!</button>

becomes these two files

component.js

import sum from './helpers/sum';

export default class {
   handleClick(a, b) {
      console.log(sum(a, b))
   }
}

index.marko

<button on-click('handleClick', 3, 4)>Click me!</button>

So we copied over and had to add an export statement. Still pretty simple.

@gilbert
Copy link
Contributor

gilbert commented Jan 25, 2017

What does moving static functions over to component.js look like?

@patrick-steele-idem
Copy link
Contributor

@mlrawlings Can you update this issue to also mention:

static {
  function myHelper() { ... }
  var foo = 'hello';
}

I wonder if it makes sense to recommend static { ... } because it makes it a little easier to move those functions how to a separate file if needed (only the block content needs to be copied out)

@patrick-steele-idem
Copy link
Contributor

patrick-steele-idem commented Jan 26, 2017

@mindeavor, @philidem and I had an impromptu discussion based on concerns raised in the Gitter chat room. The following proposal seemed to be liked by everyone:

static {
    function myHelper() {
         /* ... */ 
    }

    class ViewModel {
        constructor(data) {
            this.data = data;
        }

        get fullName() {
            return this.data.firstName + this.data.lastName;
        }
    }
}

component style lang="less" scoped {
    .foo {
        background-color: 'red';
    }
}

component class {
    onInput() { /* ... */ }
    handleButtonClick() { /* ... */ }
}

Reopening the issue for discussion. It's not too late to voice your approval or concerns.

@gilbert
Copy link
Contributor

gilbert commented Jan 26, 2017

Although I find that syntax ok, my ideal syntax would still be something like this:

<script marko>
import helper from 'library';

class Component {
    onInput() { /* ... */ }
    handleButtonClick() { /* ... */ }
}

function myHelper() {
     /* ... */ 
}

class ViewModel {
    constructor(data) { /* ... */ }
    get fullName() { /* ... */ }
}
</script>


<style lang="less" scoped>
.foo {
    background-color: 'red';
}
</style>

<div class="the-component">
    <h1>${ state.name }</h1>
</div>

@Eldar-X
Copy link

Eldar-X commented Jan 26, 2017

I think it's not readable and clear like old syntax. Example if you are newbie in marko world and you see

<script template-helpers>
   function sum(a, b) {
      return a + b;
   }
</script>

You can easy understand that some logical operations is happen in script tags but if you see

static function sum(a, b) {
   return a + b;
}

You can think someone try to write in output "static function ... etc". Also if you need to write really to output something like this you need to wrap this code and it's not intuitive.

I like marko html syntax and custom tags because it make me fill everything is standard with some extra power.

Another thing why i like html syntax is if i have already written code in html it's really easy to integrate with my project without any other efforts but otherwise result can be unexpected.

I don't like concise, mix syntax and maybe i am wrong.

@Hesulan
Copy link
Contributor

Hesulan commented Jan 26, 2017

@Eldar-X
You're certainly not alone in preferring standard over concise syntax. I personally prefer concise, but I do feel that the official documentation should use HTML syntax whenever possible.

@mindeavor @patrick-steele-idem
I much prefer using a separate tag rather than hijacking <script>. Even with the template-helpers or marko-init attribute, the first time I saw that it took a while to click. Someone new to Marko might not realize that it transforms top-level <script> and <style> tags, but when I see something like <static> or static { /* ... */ } I immediately recognize that it's special.

@patrick-steele-idem
I really like this proposal. Correct me if I'm wrong, but I'm assuming the HTML syntax would look like:

<static {
    function myHelper() { /* ... */ }
} />
<component class {
    onInput() { /* ... */ }
} />

Would <static> still accept body content like <script marko-init> did?

<static>
    function myHelper() { /* ... */ }
</static>

@gilbert
Copy link
Contributor

gilbert commented Jan 26, 2017

I think it's good and unsurprising that marko transforms <style> tags. I wouldn't want my styles to be inlined every time I use the component :)

If we really want to stay away from <script>, then we can use a different name instead:

<component>
import helper from 'library';

class {
    onInput() { /* ... */ }
    handleButtonClick() { /* ... */ }
}

function myHelper() {
     /* ... */ 
}

class ViewModel {
    constructor(data) { /* ... */ }
    get fullName() { /* ... */ }
}
</component>

My primary preference is to have a single tag for all my JS code if possible.

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 26, 2017

I think it's good and unsurprising that marko transforms <style> tags. I wouldn't want my styles to be inlined every time I use the component :)

@mindeavor I mostly agree (which is why this is the current behavior), but there is the concern that someone could be using Marko as a pure template language (without lasso, webpack, etc) — something we still want to support. Suppose you had a template like the following that you wanted to include in the <head> of many pages:

<title>${data.title ? data.title + ' | Marko' : 'Marko'}</title>
<link rel="icon" type="image/png" sizes="32x32" href="/public/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style>
    body { background:#f00; }
</style>

It would probably be surprising if your <style> tag didn't show up in the output.

I really like this proposal. Correct me if I'm wrong, but I'm assuming the HTML syntax would look like:

<static {
   function myHelper() { /* ... */ }
} />
<component class {
    onInput() { /* ... */ }
} />

@Hesulan Yes that would be the equivalent HTML syntax, but I don't think that's a good idea (and Patrick is talking about potentially making that invalid).

Would still accept body content like <script marko-init> did?

It does not with the current implementation, but that would be trivial to implement. It would require updating the syntax highlighter though.

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 26, 2017

I would like to point out that I prefer the HTML syntax, but I think it makes sense to use the concise syntax for these JS-like tags and other tags that don't directly affect the output, while still using the HTML syntax for tags that are actually involved in rendering the final HTML output.

<script> and <style> not ending up in the output HTML doesn't fit with the default expectation and for someone learning how to write a component, they will look up the documentation and follow what it says. I don't think there's some default expectation that putting something in a <script> allows you to create component methods that can be attached to elements - this idea is foreign to HTML and why we need something like Marko in the first place.

Regarding component class or component style, everything in the template is for the component. It is redundant to say component.

For someone who is new to Marko, I really find it difficult to believe that someone would look at the following and not understand what is happening. And I don't see how wrapping this in a <script> tag would make it any less intimidating.

image

@gilbert
Copy link
Contributor

gilbert commented Jan 26, 2017

@mlrawlings I generally agree with what you're saying. style {} is fine, and so is class in your simple example. Using curly brackets to differentiate between html tags and output is a good idea too.

The problem appears when you want something more than just a class. Specifically:

  • Where do I put imports?
  • Where do I put helper functions?
  • Where do I put static data?

class is not really a class, but a special tag that looks like JavaScript. The current answers are in the same vein: a special import tag, a special function tag, and a special static tag. Put this together with var, for, and probably others, and you've reached an uncanny valley of javascript-but-not-really-javascript syntax.

The reason I was ok with component class {} was that the word component immediately tells you something special is going on, to up your guard and not think you can write just any JavaScript code in this file.

Another proposal with these things in mind:

script {
  import helper from 'library';

  class Component {
    onInput() { /* ... */ }
    handleButtonClick() { /* ... */ }
  }

  var languages = ['js', 'css', 'html']

  function myHelper() {
     /* ... */
  }

  class ViewModel {
    constructor(data) { /* ... */ }
    get fullName() { /* ... */ }
  }
}

style {
  .count {
    font-size: 3rem;
    padding: 0.5rem;
    width: 3rem;
  }
}

<button on-click('handleButtonClick') />
<select>
  <option for(lang in languages) value=lang>lang</option>
</select>

@patrick-steele-idem
Copy link
Contributor

The "component class" is special and I believe it deserves to be moved up to the root. I think a block consisting of curly braces is a good indicator that the code is JS/CSS. Taking your example, I think the following reads really well:

marko-syntax

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 27, 2017

☝️ @patrick-steele-idem That does look nice.

Other thoughts

and not think you can write just any JavaScript code in this file.

@mindeavor I understand that concern and I could probably be convinced to dial back some of the JS tags introduced in v4, specifically class (for non-component classes) and function and probably invoke, maybe even assign and var — we could require them to be within a JS block where any JS is valid.

Beside the fact that I like the component's class definition at the top-level, I really think that within the static block (or script as you suggested - but I think static is the right term) that it should be "Just JavaScript™". You shouldn't have a special class Component that gets picked up in some magical way - that kind of stuff should happen in Marko land.

Here's my current thoughts on the list of "JS" tags we should support and their rational:

static { ... } to embed static javascript code

We need a way to have code that runs statically, that is once when the template is loaded and then is available every time the template is rendered. This beats <script marko-init> because this is not included in the output - see previous messages for more detail.

{{ ... }} to embed runtime javascript code (in the render method)

Currently we have var, invoke, and assign tags (and we added function and class in v4) but maybe we deprecate those? We also have scriptlets (<% ... %>), but sticking with our curly brace notation seems to make sense and using something that could be interpolated in both HTML and concise syntax. (This would actually be a language level thing, like scriptlets, not a tag).

class { ... } to define a component's class

Defining the component's class is somewhat special, and I don't think we should start modifying what you're expecting to be pure JS. Just by seeing class, it lets you know exactly what syntax is allowed inside the { ... } because it's a 1:1 match with JS. (This would be my argument against something like component {}).

style { ... } to define a component's style

We need a way to write styles and don't want to hijack the <style> tag.

import to pull in external helpers

For one, this is ES6 syntax, but we generate CommonJS require calls, so you wouldn't need any extra transpilation step. I also really feel like imports should be at the top outside of a block, but maybe that's not valid?

export to export data attached to the template

There are some legitimate cases where you might want to export some values from a template. The template lives in a marko_template variable that gets generated, but that shouldn't be manipulated directly, the export tag will do that for you. (Having this tag also is somewhat of an argument for import to make things balanced).

var

Do we need var? It already exists in v3 and we probably don't want to remove it at this point, right? I agree that it's kinda nice to not have to wrap var in { ... }, but the same could be argued for any JS statement, so where do we draw the line?

What about...

@patrick-steele-idem, @mindeavor What are your thoughts on this example?

import { CurrencyFormatter } from './formatters';

static {
    var format = new CurrencyFormatter('usd');
}

class {
    constructor(input) { ... }
    adjustPrice(index, amount) { ... }
}

{{ var products = state.products; }}

<table>
    <tr for(i, product in products)>
        {{ var name = product.name;
           var price = product.price; }}

        <td>${ name }</td>
        <td>${ format(price) }</td>
        <td on-click('adjustPrice', i, -1)>- $1.00</td>
        <td on-click('adjustPrice', i, +1)>+ $1.00</td>
    </tr>
</table>

@gilbert
Copy link
Contributor

gilbert commented Jan 27, 2017

@mlrawlings I think dialing back the JS tags is a great solution. Having a minimal number of them makes me a lot more comfortable explaining and promoting the idea to others.

I think I agree with all your points in tandem; your example suits well with me. The only confusion I foresee is people trying to import or require within static, but good error messages should be able to mitigate.

The special tag for runtime code makes a lot of sense when you compare it to the static tag; presenting them together makes them easy to explain.

If you don't mind a bit of bikeshedding... I think %{} would be a nicer than {{}}, since it parallels with ${} :)

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 27, 2017

If you don't mind a bit of bikeshedding... I think %{} would be a nicer than {{}}, since it parallels with ${} :)

Totally fine. I have some more thoughts to share on the stylistic front. And would like your opinion on some of these things.

One small issue I have with static { ... } is that it kinda seems as if the JS is scoped to that block, when in reality it's available throughout the template and even to the class.

If you look at the OP, static also supports an "inline" mode where you can have a single statement without a block:

static var foo = 123;

I'm curious what you think of this mode, but I like that it brings the statement up to the top level, but I still know that anything following the static keyword is just JS.

In any case, I wonder if we could have something that gives us a similar experience for the runtime JS. I still want something that could be (safely) interpolated within HTML.

import { CurrencyFormatter } from './formatters';

static var format = new CurrencyFormatter('usd');

class {
    constructor(input) { ... }
    adjustPrice(index, amount) { ... }
}

% var products = state.products;

<table>
    <tr for(i, product in products)>
        % var name = product.name;
        % var price = product.price;
        <td>${ name }</td>
        <td>${ format(price) }</td>
        <td on-click('adjustPrice', i, -1)>- $1.00</td>
        <td on-click('adjustPrice', i, +1)>+ $1.00</td>
    </tr>
</table>

In this case we would also support % { ... } for multiple statement if thats what you wanted to do.

Okay, so I used % in the example just because, but @patrick-steele-idem kinda hates the % symbol and I don't know that I really like it either.

We also looked at the following options:

Looks nice, kinda like a REPL prompt, but could be confusing with ${}:

$ var foo = 123;

// this has a space, so it's different than ${}
$ {
    var bar = 456;
}

Probably safe, but two characters:

$$ var foo = 123;

$$ {
    var bar = 456;
}

Also looks like a prompt, but ruins any hope of using markdown in a template:

> var foo = 123;

> {
    var bar = 456;
}

Only breaks nested blockquotes in markdown:

>> var foo = 123;

>> {
    var bar = 456;
}

For reference:

This is a block quote

This is a nested block quote 😢
This nested block quote has a space though and would still work (> >)

@gilbert
Copy link
Contributor

gilbert commented Jan 27, 2017

static one-liners seem good; the keyword conveys something different than plain JS is happening.

To be honest, I'm ok with drawing the line at var for JS tags, so long as documentation uses the <var /> form to avoid any confusion. If someone opts for writing concise syntax, they'll know that they're only stripping away some angled bracket characters, as opposed to writing plain JS.

With that said, I don't know if %{} (or $${} or whichever symbol chosen) needs a concise version. The current ${} certainly does not, and the only difference between it and the former is that the former outputs nothing.

@patrick-steele-idem
Copy link
Contributor

@mindeavor Really appreciate your input on this. I do think we will end up in a good place and I think we all are in favor of reducing the number of special tags.

With that said, I don't know if %{} (or $${} or whichever symbol chosen) needs a concise version.

Agreed. Whichever syntax we finally settle on, it will be the same for both concise and HTML.

We internally polled some devs at eBay and the following seems to be the most popular:

marko-component

@gilbert
Copy link
Contributor

gilbert commented Jan 28, 2017

Huh... I think I like it :)

@gilbert
Copy link
Contributor

gilbert commented Jan 28, 2017

Would a backslash \$ allow you to insert literal dollar sign characters?

@patrick-steele-idem
Copy link
Contributor

Would a backslash $ allow you to insert literal dollar sign characters?

Yup, that's what I am thinking and that is what we allow if you need to escape placeholders.

If you are good with it, then I propose we move forward with $ <code_block> and $${ <code_block> }.

If anyone has any last minute objections please let us know!

/cc @austinkelleher @philidem @mlrawlings @Hesulan @Eldar-X

@Eldar-X
Copy link

Eldar-X commented Jan 28, 2017

If we do, it will be a problem to put spaces after $ because most of our text editors can divide our code like this

<div>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris 
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 
Excepteur sint occaecat cupidatat non proident, sunt in culpa $
{
// What?
} qui officia deserunt mollit anim id est laborum.
<div>

Also i still think it should be at least for html version at least inside tags maybe like this

<$>
var myCode = true;
</$>

<{>
var myCode = true;
<}>

<${>
var myCode = true;
</}>

@Hesulan
Copy link
Contributor

Hesulan commented Jan 29, 2017

@patrick-steele-idem The only problem I see is that the $ ... would be parsed as a tag name in concise, but as text in HTML. I would prefer either <$></$>, or making that concise-only (in HTML you'd probably want to use $${ ... } instead anyway).

Other than that I like this proposal. Though I do feel it's important to mark this as a breaking change, since anyone previously using something like $${price} will now need to escape the first $.

@Hesulan
Copy link
Contributor

Hesulan commented Jan 29, 2017

Actually, now that I think about, I feel like it would be more intuitive if the behaviors of $${ ... } and <% ... %> were swapped (then $${...} would be a multi-line, multi-statement version of ${...}), but that might be too much of a breaking change.

Edit: Whoops, nevermind. For some reason I was thinking $${...} would replace static { ... }. Haven't had my coffee yet this morning.

@mikewoo200
Copy link

mikewoo200 commented Jan 29, 2017

  1. When this moves forward, will the deprecate state be eternal? Or is there a timeline to remove the old syntax? People tend to stick to the old syntax until forced to change. Will there be a migration tool?
  2. I guess this is not related to the syntax change, but is JS linting possible in JS embedded in marko file?
  3. I prefer a syntax that permits parsing such that we can still write easy-to-read, lint-able code (without changing a team's current JSLint/ESLint settings) - i.e., multi-lined object literal, usual indents, etc. For small JS, I am okay having it in marko; for larger JS, my preference is to put it in separate JS file. I'd want to be able to move the JS from marko to JS file without reformatting.
  4. I prefer a single way of doing things - syntax flexibility of doing the same thing tends to end up in multiple ways of writing code within the same code base - and leads to endless discussion in opinions.

@Hesulan
Copy link
Contributor

Hesulan commented Jan 29, 2017

@mikewoo200

  1. I'm not aware of anything in Marko that's ever been deprecated for too long without being removed, but with a change like this there will be plenty of deprecation notices. There will also be a migration tool sometime after v4 is released.

  2. That would depend on whether the linter you're using supports linting only a section of the file. Alternatively, you could lint the entire resulting .marko.js file.

  3. That's one of the main reasons for these changes; the way it's currently done doesn't make that easy, but the class { ... } syntax would.

@mikewoo200
Copy link

  1. What's a good linter than supports linting only a section of the file? We wouldn't lint.marko.js because it's a generated file that we don't check into our app codebase.

@patrick-steele-idem
Copy link
Contributor

@mikewoo200 this past week I looked into what it would take to support linting of embedded JS inside Marko. We can do it in Atom very easily, but I think the main goal will be to ensure that the JavaScript is valid. In the future, when Marko supports source maps we can apply linting to the entire compiled output to catch problems such as undefined variables and unused variables (this cannot be done on individual embedded JS fragments). With source maps we can map the linter warning back to the location in the original template file.

@gilbert
Copy link
Contributor

gilbert commented Jan 29, 2017

Here's another potential issue to discuss: Would any $ enter "js mode", or does the $ need to be the first non-whitespace character of its line?

Example:

<div>
  $ console.log('x')
  Price range is $ for this venue.
  Price range is $$$ for that venue.
</div>

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 29, 2017 via email

@patrick-steele-idem
Copy link
Contributor

patrick-steele-idem commented Jan 29, 2017

Both need to be at the start of the line or prefixed only by whitespace:

  • Single line: /^\s[$]\s/
  • Multiline /^\s[$]{2}\{/

@mikewoo200
Copy link

@patrick-steele-idem, for "valid JS" linting (unused, undefined, etc.), what you mentioned would work. But for style linting (spaces, indents) in the template, what can we do?

@patrick-steele-idem
Copy link
Contributor

@mikewoo200

But for style linting (spaces, indents) in the template, what can we do?

We could definitely come up with a way to enforce code style for embedded JS and Marko code as well. We'll probably need to explore that more after the v4 release.

@Hesulan
Copy link
Contributor

Hesulan commented Jan 30, 2017

@patrick-steele-idem I'm a little unclear on the exact behavior of $${ ... }. Is it the same as <% ... %>, or will you be able to return something from it to be inserted into the document? For example, would this:

<div>
    $${
        return result;
    }
</div>

do basically the same thing as <div>${result}</div>?

I'm also not sure that $${ ... } needs to be restricted to the beginning of the line. It makes perfect sense for $ ..., but why not allow this:

<div>$${
    /* ... */
}</div>

@mlrawlings
Copy link
Member Author

mlrawlings commented Jan 31, 2017

Copying thoughts from an internal discussion where we've decided $ <code> and $ { <code> } is the direction we're going to take.


So despite my initial reservations on $ { ... } I think this is the right approach.

It would only be allowed at the beginning of a line (/\s*\$ \{/):

$ var price = 5;
$ {
  var id = 0;
  function nextId() {
    return id++;
  }
}

Ambiguity has been the reasoning against this, but looking at it again, even without syntax highlighting, I think it is pretty clear (and it definitely looks nicer), and @scttdavs has pointed out that with proper syntax highlighting it would be made very clear (red $ vs blue $, for example).

screen shot 2017-01-30 at 9 35 49 pm

Part of the reason this makes sense is that we're already planning to allow {}, (), [], etc. to allow the expression to continue to the next line:

$ var foo = {
   bar: 1
}

But JS already supports a block statement, so we would actually have to special case $ to disallow $ { ... }.

And there is an issue with $${ ... } that could potentially end up with a confusing situation like this:

<span.price>
    $${price.toFixed(2)}
</span>

So in order to get what you want in this case (<span class="price">$5.00</span>), you would need to escape the first $:

<span.price>
    \$${price.toFixed(2)}
</span>

But if you actually wanted to output the multiline sequence (perhaps you're explaining how to use it), you need to escape the second $:

<code>
    $\${
        var price = 5;
    }
</code>

With the single $, escaping is straightforward:

<code>
    \$ {
        var price = 5;
    }
</code>

It's a fairly subtle difference, but I do think that it's only going to be an issue in one direction:

// I could see someone doing this
${
    var foo = 123;
    var bar = 456;
}

// I don't see this happening
<div>
    Hello my name is $ {name}.
</div>

In the above case, we're typically going to see multiple JS statements because we also allow the single line version:

$ var foo = 123;

So, if you accidentally forget the space for a multiline JS block, it will compile to:

out.w(escapeXML(var foo = 123;var bar = 456;));

That's going to be pretty easy to detect.

@Hesulan
Copy link
Contributor

Hesulan commented Jan 31, 2017

@mlrawlings I like that, though I'm not sure what you mean by "special case $ to disallow $ { ... }".

Here's my interpretation of the parser logic:

  • If the tag name is $, immediately begin parsing as a multi-line expression (which also tracks depth within {}, (), and [] pairs)
  • Continue until char === "\n" && depth === 0 (end of line and we're not inside a pair of brackets)
  • If the expression text spans multiple lines and begins with {, strip the opening { and closing }

If you need to enclose a multi-line tag's content in a javascript block statement, you'll simply need to use two pairs of brackets:

$ { /* begin script */ { /* begin block */
   /* ... */
/* end block */ } /* end script */ }

Optionally, the single-line syntax could also strip a single pair of surrounding brackets to avoid confusion.

@mlrawlings
Copy link
Member Author

@Hesulan What I meant is that the single line version, because we allow continuing, is also the multiline version. So If we wanted to have a different symbol (like $$) and didn't want the single $ to allow multiline, it would take more work.

Your logic is pretty much how I implemented it: marko-js/htmljs-parser@2195823#diff-61eec70114a46820c77ce5879a128729R658

I'm going to close this as the work has been completed. Thank you everyone for your feedback and help in reaching this point!

@jsumners
Copy link
Contributor

jsumners commented Feb 1, 2017

I'm late to the party, but I want to add my voice in support of not "concise" syntax. I do not think floating JS blocks are indicative enough of the code being associated with the template system. And as someone who abhors the "class" sugar, I'd be loath to use it solely for that reason. I would much rather see something like the following:

<marko-script>
module.exports = {
  handleClick: function (event) {}
}
</marko-script>

@gilbert
Copy link
Contributor

gilbert commented Feb 1, 2017

@jsumners I also dislike classes in general. However, the concept of a class fits perfectly with what a marko component is, and the class syntax is now officially part of the JS language. In marko's case, a class is the best tool for the job.

As I understand it, the only "floating JS blocks" marko 4 will support are class and import. I think this is reasonable, especially since they are so common (though I would push back against adding any more), and even then they are not really JS blocks, but tags. Real JS code blocks need to be written using either the static tag or the $ runtime tag.

@Hesulan
Copy link
Contributor

Hesulan commented Feb 1, 2017

@jsumners I don't completely disagree - it would be nice to have a more HTML-like syntax - but after digging through the compiler code and giving it a lot of thought I'm personally convinced in favor of class. Also keep in mind that <class {} /> (or <script> module.exports = ... </script>) is really just a convenience to avoid writing a separate component.js for small, simple components.

@patrick-steele-idem @mlrawlings On a related note, could <static> fall back to using body-text if the { /* ... */ } attribute is omitted? I think a lot of users would prefer that, and it would certainly ease the transition from <script marko-init>.

@patrick-steele-idem
Copy link
Contributor

@Hesulan static supports a block:

static {
  function myHelper() {
  }

  var foo = '123';
}

@Hesulan
Copy link
Contributor

Hesulan commented Feb 1, 2017

@patrick-steele-idem Yes, but could it fall back to parsing body-text if the block is omitted?

<static {
   /* ... */
} />
<static>
   /* ... */
</static>

@mlrawlings
Copy link
Member Author

On a related note, could fall back to using body-text if the { /* ... */ } attribute is omitted? I think a lot of users would prefer that, and it would certainly ease the transition from <script marko-init>.

Hmm... do we only do it for static, or everything? This might be a bad path to go down...

<!-- Not quite JS -->
<class>
    constructor() {
        this.state = { count:0 };
    }
    increment() {
        state.count++;
    }
</class>

<!-- Highjacking the style tag again :( -->
<style>
    button {
        background:#fff;
    }
</style>

<!-- the "concise" equivalent is technically a language construct, not a tag -->
<$ var foo = 123/>
<$>
    var foo = 123;
    var bar = 456;
</$>

<!-- I don't think I have any issues with these -->
<static var foo = 123/>
<static>
    var foo = 123;
    var bar = 456;
</static>

<!-- I *would* take issue with this -->
<static function sum(a, b) {
    return a+b;
}/>

<!-- These are fine -->
<import foo from "file"/>
<export var num = 2/>

@Hesulan
Copy link
Contributor

Hesulan commented Feb 1, 2017

@mlrawlings I only meant for <static>, and only in the way that's already used by <script marko-init> (which <static> is replacing). It wouldn't make sense for <class>, and I really don't like hijacking tags like <style>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants