meteor / blaze

:fire: Meteor Blaze is a powerful library for creating live-updating user interfaces
http://blazejs.org/
Other
528 stars 115 forks source link

List of potential changes to Blaze #75

Closed mitar closed 3 years ago

mitar commented 8 years ago

Just a list of some ideas I have what we could change in Blaze to make it a bit better, keep the good parts and move on. Some of them might be breakable so we should see how to integrate this. Personally, I would like to see that we do just incremental changes. One thing to do that would be to introduce components. Then <template>s could be seen simply as a HTML fragments with placeholders you can reuse, without any logic. This is what I also started with Blaze Components.

But the new components (in contrast with Blaze Components) would have some changes. I will be making it a lit of comments for each of those so that community can upvote/downvote them.

Please write only ideas (and variations of existing ideas). If you want to discuss details of an idea implementation, process, roadmap, open a ticket for that particular idea (we can update then its comment here with a link to the ticket).

What are your ideas? What would you like to improve in Blaze?

mitar commented 8 years ago

You would have to explicitly declare which arguments a component is receiving (as a dict).

(Discussion: #108)

mitar commented 8 years ago

No implicit passing of a data context.

(Discussion: #113)

stubailo commented 8 years ago

I'd add inline event binding like react has, and get rid of the event map style.

(Discussion: #109)

mitar commented 8 years ago

The values of the arguments would be reactive, but not the whole data context (so we get immediately one level deeper equality comparison, instead of top-level data context which changes always).

(Discussion: #113)

mitar commented 8 years ago

You bind events inside a template (like Blaze Components), not using event maps (they should still be supported for trickier things).

(Discussion: #109)

mitar commented 8 years ago

We could offer easy way to cache results of reruns of reactivity and if it is the same, we do not have to continue.

(Discussion: #111)

mitar commented 8 years ago

We could be doing diff between new and old version of internal HTMLJS and then apply just changes (like virtual DOM), maybe this is already done, not sure.

(Discussion: #111)

mitar commented 8 years ago

Or use something like incremental DOM.

(Discussion: #111)

mitar commented 8 years ago

For that to work, we introduce a "pure" component which does not allow any mingling with jQuery inside (no $ selector available) and all changes are result of just result of helpers and stuff.

(Discussion: #111)

mitar commented 8 years ago

This is allows most things to do, the only reason I have to mingle with DOM is animations, so we should provide some way to do that.

mitar commented 8 years ago

Arguments to methods can still be list of arguments of keyword arguments, but keyword arguments get wrapped into a normal JavaScript object which is an instance of Spacebars.kw or something, so that it looks like options object or something, you do not have to care or you do about the fact that it is an instance of that prototype.

mitar commented 8 years ago

You get this object only when somebody really passed keyword arguments to your helper.

mitar commented 8 years ago

We deprecate #with and simple #each, but we simplify that all this is simply part of current scope, no fancy things of data contexts, lexical scopes, and so on, things would simple resolve just: is it in current scope, or is it a method on current component instance.

mitar commented 8 years ago

Components try to persist as long as possible, only their rendered HTML is being changed, only their arguments change in values (so you can keep state in them).

stubailo commented 8 years ago

Crazy idea: Add a way to write template code with a script tag inside the template itself.

(Discussion: #94)

mitar commented 8 years ago

When removing components we go from outside in, so that we might remove everything first, and not that we first remove inner elements, and then outside, and so on which takes a long time on route switching.

(Discussion: #111)

mitar commented 8 years ago

We introduce normal method calling inside helpers, so {{foo something(a) foo=bar}} (we can discuss exact syntax).

mitar commented 8 years ago

I'd add inline event binding like react has, and get rid of the event map style.

This is this:

You bind events inside a template (like Blaze Components), not using event maps (they should still be supported for trickier things).

It is already in Blaze Components. No? Or would you want something else?

mitar commented 8 years ago

Crazy idea: Add a way to write template code with a script tag inside the template itself.

I was thinking that we could have JS code and then simply top-level <template> inside same file. We would still have code and template split, but it could be in the same file. But yes, we could wrap the code into <script> to be more compatible with various IDEs.

(Discussion: #94)

caioreis commented 8 years ago

@mitar are you thinking in someway merge Blaze Components here? Or the ideia is to start implementing this stuff from scratch?

mitar commented 8 years ago

@mitar are you thinking in someway merge Blaze Components here? Or the ideia is to start implementing this stuff from scratch?

I do not know yet how we will implement this, but let's keep this issue on topic of ideas:

Please write only ideas (and variations of existing ideas). If you want to discuss details of an idea implementation, process, roadmap, open a ticket for that particular idea (we can update then its comment here with a link to the ticket).

stubailo commented 8 years ago

It is already in Blaze Components. No? Or would you want something else?

Sure, I meant add it to core. There are some things I don't personally like in BC, so I wouldn't want to use it just for this feature.

mitar commented 8 years ago

Sure, I meant add it to core. There are some things I don't personally like in BC, so I wouldn't want to use it just for this feature.

No, I mean, you want the thing which is also in Blaze Components, or something else? Because I also added on the list that those inline events (like in Blaze Components) should be go to core. But I am unsure if there is some extra detail of event handling which is not covered there.

stubailo commented 8 years ago

Yeah, I think it's about the same. I added my comment first though :P

mitar commented 8 years ago

Or should we keep template/logic be 1:1. While in Blaze Components they are split (easier to make it backwards compatible with Blaze, and easier to reuse same HTML with different logic), I must say I have never really reused the same template for multiple components. Keeping template/logic 1:1 is then easier because it is clearer what {{> Foo}} does.

So, should we keep template/logic 1:1?

stubailo commented 8 years ago

I think the right way to reuse templates should be like React does it - you make one template that has the logic, and then it can accept a logicless template as a parameter.

mitar commented 8 years ago

Importing modules. It would be great that {{> foo.Bar}} loads foo module and uses Bar symbol from it. Maybe we could allow relative imports as well.

The downside is that then Meteor imports would be {{> meteor.foo.Bar}. And that for local imports you would need to use relative imports always. But this could be as simple as {{> .foo.Bar}}.

mitar commented 8 years ago

I think the right way to reuse templates should be like React does it - you make one template that has the logic, and then it can accept a logicless template as a parameter.

So in our case you could also pass a template with logic, but it would just reuse the non-logic part?

mitar commented 8 years ago

For imports mentioned above. Should we then instead of {{> foo.Bar}} or {{> foo/Bar}}?

mitar commented 8 years ago

Or {{> 'foo/Bar'}} (because {{> foo}} would allow import what is in variable foo).

stubailo commented 8 years ago

So in our case you could also pass a template with logic, but it would just reuse the non-logic part?

No, I don't think we should ever separate a template from its logic.

For imports mentioned above. Should we then instead of {{> foo.Bar}} or {{> foo/Bar}}?

Maybe {{> Bar from './module'}} or something? I feel like sticking to import syntax from ES2015 is a good idea.

mitar commented 8 years ago

Maybe {{> Bar from './module'}} or something? I feel like sticking to import syntax from ES2015 is a good idea.

How you pass arguments to it? :-)

stubailo commented 8 years ago

"or something" 😛

I also feel like it's a good idea to put the imports at the top rather than inline.

mitar commented 8 years ago

Crazy idea then:

<script>
  import Bar from './module'
</script>

<template name="fooTemplate">
  {{> Bar}}
  {{hello}}
</template>

<script>
  class Foo extends fooTemplate {
    hello() {
      return "awesome";
    }
  }
</script>

(Discussion: #94)

mitar commented 8 years ago

And arguments:

<template name="fooTemplate">
  {{> Bar data=bar parent=this}}
</template>

<script>
  class Foo extends fooTemplate {
    giveMeSomething() {
      return "You";
    }
  }
</script>

In Bar:

class Bar extends barTemplate {
  hello() {
    return this.parent().giveMeSomething() + ": " + this.data();
  }
}

(Discussion: #94)

mitar commented 8 years ago

You could also do:

<template name="fooTemplate">
  {{#let Bar=require('./module').Bar}}
    {{> Bar}}
  {{/let}}
  {{hello}}
</template>

And:

<template name="fooTemplate">
  {{> require('./module').Bar}}
  {{hello}}
</template>

(Discussion: #94)

mitar commented 8 years ago

So maybe a simple way to do is that {{> symbol}} requires that symbol is a variable. It cannot really be a string anymore. Simply "symbol" is not a Blaze template so inclusion fails.

Now, that symbol you can import inside a template, or in the same module (JavaScript code in the same file is part of the same module).

So:

<script>
  import Bar from './module'
</script>

<template name="fooTemplate">
  {{> Bar}}
  {{hello}}
</template>

<script>
  class Foo extends fooTemplate {
    hello() {
      return "awesome";
    }
  }
</script>

Is simply compiled into:


import Bar from './module';

const fooTemplate = spacebarsCompiledTemplate();

class Foo extends fooTemplate {
  hello() {
    return "awesome";
  }
}

And for backwards compatibility we can make so that you can somehow easily enable (or disable?) that all templates defined are available as variables in a global scope of all templates. This could even be a global helper which returns that template. So instead of {{> fooBar}} resolving fooBar in a special way as a named template, it would simply search a scope for fooBar and global scope would contain a symbol, a reference to a template, with that name.

(Discussion: #94)

mitar commented 8 years ago

Another backwards compatible way could be have argument to a template named export, if is true, it exports a template and do not make it global, if is false it does not export a template, and if it is missing it is a global template (backwards compatibility).

<template name="fooTemplate" export="true">
  {{> Bar}}
  {{hello}}
</template>

(Discussion: #94)

mitar commented 8 years ago

Or even simpler, we introduce <component>, and components get export argument if you want to export them, otherwise they are local. (Or it could be that they are exported by default.)

And <component> could have all other backwards incompatible changes as well.

MiroHibler commented 8 years ago

Guys, wouldn't a discussion like this be more appropriate on Slack (or forum or hackpad), so we can attract more broader audience, not just the contributors (I'd guess not all Blaze users are also contributors to the code)?

I know @mitar feels very much at home here ;) but until we reach the execution point, with concrete tasks and issues, I think we should do such discussions somewhere else...

BTW, how relevant is this hackpad these days?

maxenceC commented 8 years ago

We could be doing diff between new and old version of internal HTMLJS and then apply just changes (like virtual DOM), maybe this is already done, not sure.

@mitar, Isn't this what ember did to their handlebars templates with the glimmer engine ? : https://github.com/tildeio/glimmer

From the readme :

Glimmer is a flexible, low-level rendering pipeline for building a "live" DOM from Handlebars templates that can subsequently be updated cheaply when data changes.

We could adapt it to blaze.

alexandesigner commented 8 years ago

BTW, how relevant is this hackpad these days?

I think there's a good discussion and a material that maybe we can explore.

We could adapt it to blaze.

@maxenceC, I like the idea... a while ago I suggested the Incremental DOM by knowing a little more and be relatively simpler, but maybe we could take a look at the Glimmer even the similarity with the Blaze who uses Spacebars.

mitar commented 8 years ago

Guys, wouldn't a discussion like this be more appropriate on Slack (or forum or hackpad)

I do not think so, because ideas tend to get lost there. And people cannot nicely upvote and downvote. I agree that Slack is great for ironing out bugs in real-time (like helping with why tests are failing), but one my main issue with MDG's development process was that things were designed and decided in closed sessions. And Slack to me is closed: if you are not online at the time a discussion is happening, it is more or less history and you will not find it later on.

GitHub is also great because even if people come around in a month they can still vote on things. And many of ideas here will be probably done in a year or two, so they have to stick around for a long time.

And hackpads again split attention of the community. They are great when you want to get some document out. Maybe useful when we will be working on a roadmap and concrete syntax/changes discussion.

Isn't this what ember did to their handlebars templates with the glimmer engine

It seems so.

We could adapt it to blaze.

I think it would be probably more work than worth. We already have most of the pieces available.

mitar commented 8 years ago

(But let's keep implementation details of ideas out of this ticket. So discussion on how we would implement diffing: using some library, doing it ourselves, and so on.)

tcastelli commented 8 years ago

Not sure if this is somewhere or can be achieved without the use of a global JSON.parse helper, but having simple objects as parameters would be great so no need for extra helper code.

eg: {{> tmp1 param1="hi" param2='{"a":8, "b":3}' }}

(Discussion: #5)

mitar commented 8 years ago

I do not see much difference from {{> tmp1 param1="hi" param2=(a=8 b=3) }}? Even less characters? See #5.

(Discussion: #5)

mitar commented 8 years ago

Let's have the discussion of details in its own issue. This one is mostly to have a list of all possible improvements and upvoting and downvoting.

LaughingBubba commented 8 years ago

If the long term view is to be a stand alone reactive view layer, independent of meteor, shouldn't the focus be on removing dependency or forking on minimongo & tracker?

Or is the view that blaze will always be wedded to meteor "classic"?

Just curious

mitar commented 8 years ago

No, moving to other system is definitely in plan, but we can still develop new features in parallel.

See #11 for NPM transition ticket, and #13 for the dependency, we first have to move Tracker and others to NPM. I think we need some champions of pushing those changed forward. And they also need a bit of help from MDG. But let's discuss there.

LaughingBubba commented 8 years ago

Thanks so the short answer is not any time soon to impact what I had in mind.

That's Ok, the reason is my best contribution is likely to be the voice of the n00b. So my plan was draft up a visual/schematic of how blaze works (with meteor) at a high level and then an anatomy of a simple blaze app. I know a lot of this is covered in the blazejs.org site but that's all is the written word. This is about keeping the learning curve as flat as possible.

Is that OK?