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

Riot next - roadmap to v4 #2283

Closed
17 tasks
GianlucaGuarini opened this issue Mar 5, 2017 · 125 comments
Closed
17 tasks

Riot next - roadmap to v4 #2283

GianlucaGuarini opened this issue Mar 5, 2017 · 125 comments

Comments

@GianlucaGuarini
Copy link
Member

GianlucaGuarini commented Mar 5, 2017

Roadmap proposal for the future riot major release:

(this list just a draft and it's going to grow)

  • Complete rewrite of the compiler simplifying the sourcecode allowing also sourcemaps
  • Fix all the yield issues introducing the use of <slot> deprecating the <yield>
  • Make the use of riot-observable optional
  • Remove this.tags from the tags instances in favor of ref Unify this.tags functionality #2360
  • Automounted components deprecating the riot.mount method
  • Add support for shadow DOM or at least support the :root selector instead of :scope
  • Make the tags options explicit avoiding to pick per default all the custom tags attributes
  • Avoid the use of riot.csp in favor of a simpler solution
  • Cleanup the readme file removing dead links to tutorials or old riot stuff
  • Simplify the mixin logic avoid the use of es6 classes and functions instances
  • Remove the shouldUpdate method in favor of a smarter DOM updates strategy
  • Drop IE9/10/11 support
  • Use new ES6 features like Proxies and template strings
  • Drop the use of each={ items } in favor of each={ item in items }
  • Reduce the source code simplifying a lot the api
  • Update the api simplifying the core methods arguments handling
  • Prefer a functional approach over the current objects extension strategy

We will track the progress here

✌️

@sourcegr
Copy link
Contributor

sourcegr commented Mar 5, 2017

some more points to consider

  • Introduce one-time computed parameters, that do not change across updates. This can be accomplished with something like {= parameter =} and could be computed right before the mount event.
<div data-is="my-tag" bgcolor="red" mytitle="this is my name" productprice="30"></div>
<my-tag>
  <div style="background-color:{= opts.bgcolor =}">
    <h2>Page title: {= opts.mytitle =}</h2>
    <p>Product Price (Including VAT): {= (opts.productprice * CONST_VAT_PERCENT).toFixed(2) =}</p>
  </div>
</my-tag>

It is obvious that a lot of re-computation could be avoided, resulting in much faster overall experience

see also #2144

@sourcegr
Copy link
Contributor

sourcegr commented Mar 5, 2017

  • allow HTML to be inserted, by using some special syntax like {! unescaped !}.

I believe we should avoid the {{ unescaped }} format because {{ ... }} is used by many back-end templating engines, like laravel's blade.

@fabien
Copy link
Contributor

fabien commented Mar 6, 2017

I would like to see some rudimentary support for transitions/animation, in the form of deferrable/async (Promise based) control of mount and unmount (perhaps even update).

Something along these lines, perhaps:

willMount() {
  return Promise.delay(500)
}

willUnmount() {
  return Promise.delay(500)
}

willUpdate() {
  return Promise.delay(500)
}

@sourcegr
Copy link
Contributor

sourcegr commented Mar 6, 2017

@fabien could you elaborate on this a little more?

@fabien
Copy link
Contributor

fabien commented Mar 6, 2017

@papas-source I'll try ... is this more clear (at the expensive of being a bit contrived)?

function fetchData() {
  // Code to fetch data asynchrously
  return promise
}

function performTransition(transitionName) {
  // Promise is resolved once transition completes
  return promise
}

willMount() { // called after the root is mounted, but before the mount event is fired
  return fetchData().then(function(data) {
     this.data = data
     this.update()
  }).then(function() {
     return performTransition('fadeIn')
  })
}

willUnmount() {
  return performTransition('fadeOut')
}

willUpdate() { // called after shouldUpdate, but before update event fires
  return performTransition('slideOut') // hide before update
}

didUpdate() { // called after update (but before updated event is fired - will wait)
  return performTransition('slideIn') // show once fully updated & rendered
}

@jakubrpawlowski
Copy link

I like all the ideas and upcoming features Gianluca. Please do not forget that many of us choose Riot over Vue due to size-first approach. The day Riot grows over 14KB my dreams will be crushed. Thank you in advance for staying committed to minimalism!

@GianlucaGuarini
Copy link
Member Author

@jakubrpawlowski actually my idea is to drop the size of the lib down to 3kb again but we will see I just need time to work on it stay tuned

@sourcegr
Copy link
Contributor

sourcegr commented Mar 6, 2017

And something else, that is actually on the @tipiirai list of new features, and is a must have. Actually, I believe that it will make Riot a trully magnificent tool for creating reusable components.

The <yield> tag should run on parent context where the code resides and can contain complex constructs like loops and custom tags.

@aggre
Copy link

aggre commented Mar 8, 2017

I think that Shadow DOM is the optimal answer for component based UI.
By trying component development like Riot using HTML Template, I'm thinking about what is necessary for Riot.

It is like this:
https://jsbin.com/moviqek/edit?html,js,output

@davidtai
Copy link

davidtai commented Mar 9, 2017

Hi! Riot is shaping up great.

We've been using Riot or a long time in our
projects and have even built a framework on top
of it. An issue our team runs into (especially while integrating third party
widgets) is converting everything to use riot's synchronous updating scheme.
Not everything converts nicely so we usually end up pushing a lot of
unnecessary updates or having to hack our way out of infinite update loops (most off the shelf widgets from our experience don't play nice with riot).

In addition, having multiple sources of streaming data, ajax requests, or waiting for
promises (such as with animations) can cause performance issues when updating.

I'm wondering if anyone has thoughts one way or another about adding the
ability to support scheduling asynchronous batched updates like React setState and
Vue's nextTick?

@rbatistajs
Copy link

Please add custom directive/attribute.

@GianlucaGuarini
Copy link
Member Author

GianlucaGuarini commented Mar 10, 2017

@davidtai I am not sure about all your performance concerns since you are using riot@2 in your components. Have you tried upgrading? Riot@3 is about 5x faster than the previous releases

@rongxike
Copy link

how's about "requiretags" ? something like requirejs ?
a full heavily requirejs is not needed, but at least we can have something easier to reference the tag files.

Ex:

<script src='test1.html' type='riot/tag" ></script>
<script src='test2.html' type='riot/tag" ></script>
<script src='test3.html' type='riot/tag" ></script>
...

<test1 />
<test2 />
<test3 />

<script>
  riot.mount('*');
</script>

We can have

<test1 />
<test2 />
<test3 />
<script>
  riot.mount('*', {
     tags: ['test1.html', 'test2.html', 'test3.html']
  })
</script>

@Joylei
Copy link
Contributor

Joylei commented Mar 11, 2017

@rongxike

it's already there: riot.compile()

riot.compile('SOME_URL', function(){
   riot.mount('*')
})

or multiple urls

riot.compile(['url1','url2','url3'], function(){
    riot.mount('*')
})

@jakubrpawlowski
Copy link

Not everyone is on Gitter so I will just repost here a link that @richardtallent mentioned:
https://medium.com/@WebReflection/hyperhtml-a-virtual-dom-alternative-279db455ee0e#.j7ea4ao27

@sourcegr
Copy link
Contributor

@jakubrpawlowski it is allready in the todo list, see the first post by @GianlucaGuarini

;)

@richardtallent
Copy link

Everything sounds good, with one exception -- dropping IE11 support. I use Riot on an intranet application, and while all of my users have Chrome available, IE11 is their default browser, so I can't drop support for it. I'd hate to get left behind on v4.

In corporate environments, Windows 7 and 8 are still common and likely won't go away until 2020 and Edge is only available on Windows 10, so IE11 is as high as those environments can support.

If the concern is IE11's lack of ES6 features, please keep in mind that over 50% of mobile browsers are still Android Browser 4/5 and iOS 9, which also have minimal ES6 compatibility.

I do all of my tag compilation server-side, so feeding the output of gulp-riot to babel isn't a problem as long as the resulting javascript runs in IE11.

@jakubrpawlowski
Copy link

I hear you, but punishing users of modern browsers (especially the ones on mobile) isn't fair either. Best solution imo would be optional pluggable polyfill for projects that need to support fetchless browsers as seen here (tip 8): https://hackernoon.com/10-things-i-learned-making-the-fastest-site-in-the-world-18a0e1cdf4a7#.19shthvx4

@davidhewitt
Copy link

davidhewitt commented Mar 16, 2017

Will the yield / slot scope be changing to the parent tag's scope? I see yield in point 2 on the list but it's not clear to me if the scope is determined an issue or not. :)

@sourcegr
Copy link
Contributor

sourcegr commented Mar 16, 2017

@davidhewitt this is labeled, discussion, so we are free to share our own views/thoughts for the upcoming release

As you can see I made a comment about that :)

Feel free to upvote for it - allthough there is no guaranties that upvoted comments will pass ;)

EDIT: I linked to one other comment, the link is fixed now

@davidhewitt
Copy link

Ah cheers I did scan the thread but failed to read the quote in our post. Upvoted!

@PascalLeMerrer
Copy link

Droppping IE11 support would be a big problem for me. I work for a big company which just dropped IE8 in favour of IE11 and FF, for internal applications. It was a big move, as there are hundreds of them. In fact it's not totally finished yet, and wont be before a few months. If Riot V4 does not offer any solution to support IE11, I won't be able to use it any more for my professional projects :(

@foximoxi
Copy link

foximoxi commented Mar 16, 2017

How about some inheritance between tags (events, methods, variables)?

<parent>
<script>
doSth() { }
</script>
</parent>

<child::parent>
<script>
this.doSth();
</script>
</child::parent>

@GianlucaGuarini
Copy link
Member Author

GianlucaGuarini commented Mar 17, 2017

@PascalLeMerrer of course there will be ways to support ie11 but not in the riot core. I would like to make riot4 completely web components compliant providing a simpler API with some utils web components don't provide yet. I guess the new riot compiler will output kind of Custom Elements scripts

@planeguy
Copy link

@PascalLeMerrer @GianlucaGuarini I'm good with a standards-compliant riot as long as there's a good, clear way to polyfill for ie11 (I'm in the exact same boat as you Pascal). What stuff would we need to bring ie11 up to snuff for riot4?

@GianlucaGuarini
Copy link
Member Author

I decided that the foundation for the new riot major release will be the compiler and I am working a new draft release https://github.com/riot/compiler/tree/next

@syuilo
Copy link
Contributor

syuilo commented Mar 21, 2017

+1 for dropping IE 9/10/11 support,
If you need IE 9/10/11 support, you can continue to use riot v3.x.

@MartinMuzatko
Copy link
Contributor

Our company already gave up on IE 9 and below.

@GianlucaGuarini
Copy link
Member Author

@StarpTech discussing about browsers support when we don't have released either a pre pre pre alpha release of our new rewrite is worthless. Please let's wait until we will have something concrete to test ;)

@icetbr
Copy link

icetbr commented Jun 30, 2017

Hi, I'm just a bystander in the JS frameworks arena since I haven't coded front end JS in a while, but here some thoughts regarding mostly aesthetics I guess.

I think this is how a v4 tag is going to look like

<tag>

  <myTag onclick={doStuff}></myTag>

  <script>
  
  import myTag from 'myTag.tag'

  export default {
	
    doStuff() {
    }	

  }

  </script>

</tag>

This is how a JS first approach might look like. And if you use ${} as delimiters, you get auto IDE integration (syntax highlight is easy to get, some IDEs have language injections by default)

import myTag from 'myTag.tag'

export default {

  template: `
    <myTag onclick={doStuff}></myTag>
  `,

    doStuff() {
    }	

}

And here it is in markojs (components are auto discovered, no import required)

<myTag onclick=('doStuff')></myTag>

class {

    doStuff() {        
    }

}

@nodefish
Copy link

nodefish commented Jul 5, 2017

FYI it appears one of the big limitations of HyperHTML is reordering. I don't trust browsers to do competent diffing on huge lists if you change the order of the items. This is one area that riot v4 would need to handle in a custom way. I could be wrong, but I don't think HyperHTML does "smart" diffing of lists (as it's focused on pushing template literals to the DOM and lets the browser handle it).

edit: Or not! It seems hyperHTML.wire may in fact take care of list item tracking/reordering: https://github.com/WebReflection/hyperHTML/blob/master/GETTING_STARTED.md#rendering-multiple-nodes.

Also: @GianlucaGuarini @aMarCruz This might be interesting: https://github.com/joshgillies/hypercomponent

@joshgillies
Copy link
Contributor

joshgillies commented Jul 5, 2017

@nodefish I was actually going to ask what the issue was you were seeing with reordering. But it seems like you've uncovered the secret sauce since originally posting the above! Hint: hyperHTML.wire. :)

Fact is if you manage your wires correctly you get node reuse for free, so as far as I'm concerned reordering becomes a non-issue.

With regard to hypercomponent I'm really close to publishing v3 which implements a class based API - https://github.com/joshgillies/hypercomponent/tree/v3

@aMarCruz
Copy link
Contributor

aMarCruz commented Jul 6, 2017

ES6TL are excellent for a generic use, but they are very limitated for things like

<div attr={ a > 1 ? `foo${a}` : 'bar' }/>

The riot parser is the base that can handle this and is (almost) already done.

I'm now working on a "render" builder and a fork of hyperHTML v0.15.2 (ported to TypeScript) that will allow to emit HTML based in markers (like {= "<p/>" }) instead of the surrounding context.

All this will be part of a completely new codebase with a simpler API and more oriented towards the compilation (lighter runtime) which should give us a much better performance.

Regarding the low-level engine for the rendering I don't now... maybe I'll experiment with Inferno or snabbdom or some other framework yet, but the idea is performance w/ security and stability, keeping the riot syntax as much as possible.

This is a lot of work and time (we are all volunteers :)), but we are already on the way.

@nodefish
Copy link

nodefish commented Jul 6, 2017

@aMarCruz You can do nested template literals with Outer ${Inner} so it's not necessarily a problem if you wrap everything in a template literal. So your example in hyperHTML style would be

render`<div attr=${ a > 1 ? `foo${a}` : 'bar' } />`

Of course that's different from the riot style (which I personally prefer). Honestly I think using a pre-existing rendering backend is a smart decision at this point. The JavaScript ecosystem has way too many people rolling their own things.

@aMarCruz
Copy link
Contributor

aMarCruz commented Jul 6, 2017

@nodefish actually, the code emitted for the previous fragment with my working "compiler" is something like this:

render: function (state) {
  riot.__$render(
    [
      ['<div attr="',  '"></div>'],
      riot.__$toStr( state.a > 1 ? 'foo' + state.a : 'bar' )
    ]
  )
}

where riot is a small runtime for tests, riot.__$render is hyperHTML, and riot.__$toStr is a guard for falsy output

So yes, it is possible to use ES6 TL, but I think the new parser is more convenient.

@WebReflection
Copy link

WebReflection commented Jul 8, 2017

riot.__$render is hyperHTML

nope, nopity nope.

If I read that correctly, ['<div attr="', '"></div>'] is always different from ['<div attr="', '"></div>'] which is the main strength of hyperHTML, the bit not everyone understood.

Following the ABC behind hyperHTML

let previous;
function tag(chunks) {
  if (!previous) previous = chunks;
  console.log(previous === chunks);
}

tag`<div attr=${1}></div>`; // true
tag`<div attr=${2}></div>`; // true

@WebReflection
Copy link

WebReflection commented Jul 8, 2017

Moreover, in hyperHTML this works already:

render`<div attr="${ a > 1 ? `foo${a}` : 'bar' }"></div>`;

Not a single issue, you just need to follow the 2.5 rules of hyperHTML. In this case: attributes in quotes, that's literally it!

@WebReflection
Copy link

screenshot from 2017-06-20 09-05-19

@aMarCruz
Copy link
Contributor

aMarCruz commented Jul 8, 2017

@WebReflection thanks for your excelent work and support.
I understand the comparisson of statics is by reference (by hash for FF), in the final version of riot v4 it must be cached in the Tag instances.

Regarding the above rules the riot compiler will emit what is necessary for hyperHTML to work as intended given the riot own rules (quoting unquoted attributes values, expanding selfclosing tags, and so on).

In riot 3, all expressions generate raw text or values, not HTML. In v4 the expressions will generate text (textContent) or HTML (maybe other custom tag instances identified by the data-is property).

So, to allow expressions as text as unique content of an element, the compiler will append an space to the static part: <p>{ expr }</p> => [ ["<p>", " </p>"], expr ].

For expressions generating HTML a prefix is required (ex: =).
To allow mixed text and html expressions we need to pass all to hyperHTML as a single value, sanitizing text expressions before the innerHTML injection: <p>Title: {text} - {= html }</p> => [ ["<p>", "</p>"], "Title: " + sanitize(text) + " - " + html ].

Maybe I'm wrong on some concepts, I'm very new to hyperHTML and the compiler is WIP. Right now I'm focused on the JS part and I have not started the complete tests, but would be very happy to have your support in the implementation of the engine (maybe by email or slack).

@WebReflection
Copy link

I'd be happy to help but it looks like you're implementing a JSX transformer ...or something similar. @kentaromiura already worked on something similar, maybe he can help too.

@aMarCruz
Copy link
Contributor

aMarCruz commented Jul 8, 2017

@WebReflection yep, we can see the riot compiler as something like that :) Thanks.

@babakness
Copy link

I'm the first guy out there to say IE sucks. But IE11 is like 12% global market share as it was shipped with Windows 10.

@aMarCruz
Copy link
Contributor

@babakness ,
bad thing to have to support the only browser without basic ES6, but I agree and the use of IE11 is too high to ignore it, especially in companies that still use Win7.

@kazzkiq
Copy link
Contributor

kazzkiq commented Jul 13, 2017

In my experience, companies that have IE11-enabled systems are those open about which browser their employees use. Most of the issues remain in IE8/WinXP/Vista/7 from companies who are stuck in time (which make a big chunk of corporative market, sadly).

@sourcegr
Copy link
Contributor

sourcegr commented Jul 13, 2017

You can use the :scope pseudoclass

<my-tag>
  <h1>Hi!</h1>
  <style>
    :scope {display:block; background:red; width:33%};
    h1 {color:#00f;}
  </style>
</my-tag>

example

@nodefish
Copy link

OK, now I feel stupid. I wasn't aware of that. Thanks!

@sourcegr
Copy link
Contributor

@nodefish, no worries!!! It happens to me every day!

@coffeebite
Copy link

I'd like to propose lazy/asynchronous component loading and mounting. E.g. I have a tag called my-settings. Users don't change their settings often so it is not rendered most of the time. But I have to download and compile it nonetheless in case it is shown.

I'd like a system where, upon the first instance of <my-settings> in the DOM, riot can request the component definition from a predefined URL and mount it on demand.

@WebReflection
Copy link

But I have to download and compile it nonetheless in case it is shown.

This is not true with hyperHTML because it supports asynchronous chunks (Promises) so that views for specific sections/components can be asynchronous too and loaded on demand.

viper-news as example, which is the fastest HNPWA these days, does that.

Those import(...) are brought by Webpack

@evaisse
Copy link

evaisse commented Sep 22, 2017

Definitely agree with florian registering animation and retain events on dom update is only thing missing for me right now.

I would love seeing that kind of animation stuff being done in riot without heavy use of .unmount() or creating custom tags. Just by adding some custom events to a dom node :

<random-number-list>
  
  <div class="app">
    <div class="block" animation={ myAnimationHandler } each={ num in numbers }>
      { num }
    </div>
  </div>
  
  <script>
    var self = this,
        count = 6;
    
    this.numbers = [];

    // using a string to get a default css-driven animation with conventions based animations (like react/vue/angular/...)
    // .animated-number.animated-number-enter/.animated-number-leave/.animated-number-update
    this.myAnimationHandler = "animated-number";
    // using a function to manage dom node lifecycle with animation
    this.myAnimationHandler = function () {
      
      return {
        onMount: () => true,
        onUpdate: () => true,
        onBeforeRemove: () => new Promise()
      };
      
    };
    
    function setState() {
      var i, number;

      for (i = 0; i < count; i++) {
        if (Math.random() < 0.5) {
          number = Math.ceil(Math.random() * 12);
          if (number > 9) number = null;
          self.numbers[i] = number;
          self.update();
        }
      }

      setTimeout(setState, Math.random() * 250 + 250);
    };
    
    this.on('mount', setState);
  </script>

</random-number-list>

It's clearly something impossible to achieve in a simple way or with any mixin in the current versions.

@damusix
Copy link
Contributor

damusix commented Oct 20, 2017

How about importing styles?

<my-tag>
    <h1> ... </h1>
    <script>
        import marked from 'marked';
    </script>

    <style>
        import 'my-tag.css';
    </style>
</my-tag>

Or alternatively
<style src='my-tag.css'></style>

Maybe even assume .css and just src='my-tag'

To keep things separate for when a component's style becomes too large. This would be amazing with postcss.

@bcartmell
Copy link

CSS imports already work. See proper syntax at MDN

@damusix
Copy link
Contributor

damusix commented Oct 23, 2017

@bcartmell Sure but will Riot import this and parse it through its CSS parser? How would standard css @import work when I'm using a compiler like rollup babel or postcss where there I can't depend on a fixed path and want to use css variables?

@bcartmell
Copy link

@damusix Yes, Riot will parse it if provided a pre-processor (less is supported by default). The <style> tag in your tag file needs to specify type. Why can't you depend on a fixed path for your files? You should know where your src and dist files are. You should review the documentation at http://riotjs.com/api/compiler/ and start a new question if you still need help, but let's move this out of the 'roadmap to v4' thread.

@dharmax
Copy link

dharmax commented Oct 25, 2017

i'd like to kindly ask what is the up to date roadmap - features and timelines - of this wonderful library. i got lost among all these posts :-)

@GianlucaGuarini GianlucaGuarini mentioned this issue Jan 7, 2018
12 tasks
@GianlucaGuarini
Copy link
Member Author

closing this issue in favor of #2515 thanks anyone for the great feedback

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

No branches or pull requests