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

Let's choose a view framework for docs, generated packages, etc. #5756

Closed
thedaniel opened this issue Feb 26, 2015 · 132 comments
Closed

Let's choose a view framework for docs, generated packages, etc. #5756

thedaniel opened this issue Feb 26, 2015 · 132 comments
Labels

Comments

@thedaniel
Copy link
Contributor

@thedaniel thedaniel commented Feb 26, 2015

(This is an attempt to restate #3752, explain the current position and present options)

A blessed view system for Atom

We're in an interesting place with respect to generating views in packages and core. We wrote space-pen and used it heavily, but ultimately decided to discontinue using it for new views (though some base views still use space-pen we are no longer recommending it). So now we find ourselves in an unfortunate position of using the DOM APIs directly, and suggesting package authors do the same, choose a framework themselves, or ╮(. ❛ ᴗ ❛.)╭ - Not a great place to be, and makes it hard to write docs with nice examples.

We used React in the editor component for six months or so, and it was a good experience, but it has a bit of a learning curve.

We experimented with a few things inspired by React and Polymer, and have done some research on 3rd-party view frameworks, but haven't come to a decision. As we work on better docs for the run up to 1.0, we have to start taking this seriously.

Requirements

  • Embrace modern browser features (custom elements, Object.observe, etc) as much as possible
  • It absolutely does not pollute the global namespace
  • Data-binding preferred to imperative updates if templates are used
  • View model / MVVM-style separation of rendering and logic
  • No dependencies on jQuery-like helper libs
  • Small learning curve
    • somewhat self-explanatory when used in docs examples
    • in other words, most web developers will be able to recognize the concepts that are applied without reading a book on it

Contenders / experiments

  • React
  • Etch - a library for writing HTML-based view components that provides the convenience of a virtual DOM while at the same time striving to be minimal, interoperable, and explicit - written by @nathansobo and @maxbrunsfeld
  • rivets for templating+data binding plus some basic JS object glue for Atom
  • television - "Television aims to cleanly integrate the virtual DOM approach of React.js into HTML 5 custom elements." - an experiment from @nathansobo
  • virtual-dom this library is used by television, but could be a component in a similar solution that accomplishes the above goals.
  • elmer - An experiment from @benogle based on Polymer's template binding
  • vue.js - simple, component-based, simple & small
  • Something custom, delightful & new from your friends the Atom team (but we don't reallllly want to maintain another view frameowrk)

Want to help?

One way to help speed this along is to do some experimentation with using your favorite framework in a package. See https://github.com/benogle/template-explore as an example package using https://github.com/atom/elmer.

A couple questions I would try to answer with the package:

  • How does it handle model/DOM updates? Data-binding? Imperative + virtual-dom like react?
  • How does it handle events? i.e. How do I bind a click handler to an element?
  • Can it work with Object.observe and not it's own model system?
  • Does it inject any globals?
  • How does it interact with web components, both in terms of creating new ones and using existing components written using different frameworks?

Discuss

We're interested in hearing the pros and cons of the various ways we can satisfy the items listed under requirements, recommendations for solutions we don't have listed, and questions about the reqs and how and why we arrived at them.

Also, I encourage @atom/core and maintainers to edit the Contenders section in the issue body as more come in, and let me know if I missed / misstated anything in Requirements

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 26, 2015

That is good news. There was a vacuum for new package developers.

On Wed, Feb 25, 2015 at 6:38 PM, Daniel Hengeveld notifications@github.com
wrote:

(This is an attempt to restate #3752
#3752, explain the current position
and present options)
A blessed view system for Atom

We're in an interesting place with respect to generating views in packages
and core. We wrote space-pen https://github.com/atom/space-pen and used
it heavily, but ultimately decided to discontinue using it for new views (though
some base views still use space-pen
https://github.com/atom/atom-space-pen-views we are no longer
recommending it). So now we find ourselves in an unfortunate position of
using the DOM APIs directly, and suggesting package authors do the same,
choose a framework themselves, or ╮(. ❛ ᴗ ❛.)╭ - Not a great place to be,
and makes it hard to write docs with nice examples.

We used React in the editor component for six months or so, and it was a
good experience, but it has a bit of a learning curve.

We experimented with a few things inspired by React and Polymer, and have
done some research on 3rd-party view frameworks, but haven't come to a
decision. As we work on better docs for the run up to 1.0, we have to start
taking this seriously.
Requirements

  • Embrace modern browser features (custom elements, etc) as much as
    possible
  • recognizable markup (allow users to write 'normal HTML')
    • data binding preferred to imperative updates if templates are used
      • View model / MVVM-style separation of rendering and logic
  • Easy for developers to replace with another preferred library
    • this implies not polluting the global namespace
      • No dependencies on jQuery-like helper libs
  • Small learning curve
    • somewhat self-explanatory when used in docs examples
    • in other words, most web developers will be able to recognize the
      concepts that are applied without reading a book on it

Contenders / experiments

Discuss

We're interested in hearing the pros and cons of the various ways we can
satisfy the items listed under requirements, recommendations for solutions
we don't have listed, and questions about the reqs and how and why we
arrived at them.

Also, I encourage @atom/core https://github.com/orgs/atom/teams/core
and maintainers to edit the Contenders section in the issue body as more
come in, and let me know if I missed / misstated anything in Requirements


Reply to this email directly or view it on GitHub
#5756.

@steelbrain
Copy link
Contributor

@steelbrain steelbrain commented Feb 26, 2015

I am using vanilla-jsx, it supports JSX but it spits out native HTML Elements so it's performant and lightweight

@gilbert
Copy link

@gilbert gilbert commented Feb 26, 2015

Mithril.js saved JavaScript for me. Like many others frameworks/libraries it uses a virtual DOM, but most importantly it's just JavaScript. No JSX, no OOP, no arbitrary html-ish templating languages. Once you learn its five or so core methods, you're free to think and do anything JavaScript without Mithril getting in the way.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 26, 2015

no arbitrary html-ish templating languages

I think there should be a blessed template syntax as per the "recognizable
markup" requirement. I want to be able to easily read other package's
code.

IMHO it should be a simple noise-free template syntax like that of
space-pen.

On Wed, Feb 25, 2015 at 8:02 PM, Gilbert notifications@github.com wrote:

Mithril.js http://lhorie.github.io/mithril/index.html saved JavaScript
for me. Like many others frameworks/libraries it uses a virtual DOM, but
most importantly it's just JavaScript. No JSX, no OOP, no arbitrary
html-ish templating languages. Once you learn its five or so core methods,
you're free to think and do anything JavaScript without Mithril getting in
the way.


Reply to this email directly or view it on GitHub
#5756 (comment).

@thedaniel
Copy link
Contributor Author

@thedaniel thedaniel commented Feb 26, 2015

IMHO it should be a simple noise-free template syntax like that of space-pen.

This conflicts with the second requirement listed - I personally am strongly against anything like space-pen's syntax, or HAML, and I believe the rest of the team either doesn't feel strongly, or prefers that if we use templates at all we do data binding + templates similar to Polymer: https://www.polymer-project.org/docs/polymer/databinding.html

I'll let them chime in, but I wouldn't get your hopes up for something space-pen-like.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 26, 2015

I personally am strongly against anything like space-pen's syntax, or HAML

I don't see how Atom could bless coffeescript and not Space-Pen syntax. They are one and the same.

I know we have to use an existing solution so there probably won't be such a syntax available but I would certainly argue for matching coffeescript if we could.

@benogle
Copy link
Contributor

@benogle benogle commented Feb 26, 2015

recognizable markup (allow users to write 'normal HTML')

This is definitely not a requirement. Television, for example is more space-pen-like (and even more react like, minus the jsx). I personally like the markup better than the code-like definition, but it's not a requirement.

Easy for developers to replace with another preferred library; this implies not polluting the global namespace

The global namespace issue is a super hard requirement. Not really for ease of switching, but for playing nice with other versions of the framework, and with other frameworks.

We basically want the option of more than one framework to be used as a dep. That way we're relatively future proof. When the next react or whatever comes along, we can use it by including it as a dependency.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 26, 2015

The television link is a 404.

@benogle
Copy link
Contributor

@benogle benogle commented Feb 26, 2015

@mark-hahn it should work now. Sorry about that

@thedaniel
Copy link
Contributor Author

@thedaniel thedaniel commented Feb 26, 2015

Perhaps I let my opinions leak into the requirements - we're evaluating some options that don't use normal markup in their templates. I still think it's very prudent from a docs perspective but I'll move it out of the issue body and into "thedaniel's suggestions in the comments" since it's not actually a hard requirement.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 26, 2015

Television looks awesome. It looks cleaner and less-noisy than space-pen. And the custom element handling seems simple, even to a luddite like me. I think it would be accessible to beginners.

@lhorie
Copy link

@lhorie lhorie commented Feb 26, 2015

Mithril's out of the box syntax is very similar to virtual-dom/television, but you can also get HTMLy syntax via MSX (basically the same thing as React's JSX) if curly braces are important.

There's also SugarTags for a different flavor of code-like definitions.

@lee-dohm
Copy link
Member

@lee-dohm lee-dohm commented Feb 26, 2015

I like the template+data-binding approach. I think it would be awesome if the template language was pluggable so if people wanted something more HTML-like, they could have it, closing tags and all. And if they wanted something simplified a la HAML/Jade/Slim, they could have that too.

@benogle
Copy link
Contributor

@benogle benogle commented Feb 26, 2015

If anyone out there is interested, one way to help speed this along is to do some experimentation with using your favorite framework in a package. See https://github.com/benogle/template-explore as an example package using https://github.com/atom/elmer.

A couple questions I would try to answer with the package:

  • How does it handle model/DOM updates? Data-binding? Imperative + virtual-dom like react?
  • How does it handle events? i.e. How do I bind a click handler to an element?
  • Can it work with Object.observe and not it's own model system?
  • Does it inject any globals?
@nathansobo
Copy link
Contributor

@nathansobo nathansobo commented Feb 26, 2015

  • How does it interact with web components, both in terms of creating new ones and using existing components written using different frameworks?
@benogle
Copy link
Contributor

@benogle benogle commented Feb 26, 2015

I added a section in the body about helping out and answering these questions.

@nathansobo nathansobo self-assigned this Feb 26, 2015
@lee-dohm
Copy link
Member

@lee-dohm lee-dohm commented Feb 26, 2015

@benogle
Copy link
Contributor

@benogle benogle commented Feb 26, 2015

I'm taking a look at Vue.

❤️ Thanks. I briefly looked at it to see if it supported Object.observe, but iirc it didnt right now, and was not clear how to hack it in.

@lee-dohm
Copy link
Member

@lee-dohm lee-dohm commented Feb 26, 2015

🙇 You're welcome. This is my opportunity to dig deeper into the DOM and rendering, so I figured I'd give it the good ol' college try. I'm currently running into unsafe eval issues, but I'll take another crack at it later tonight.

@wmertens
Copy link

@wmertens wmertens commented Feb 28, 2015

Things that make me prefer React:

  • largest community of the proposed options
  • battle-tested with constant focus on performance
  • good dev tools: chrome devtools extension, webpack hotloader support etc.
  • JSX is optional and you can use television-like syntax as well
  • Plays well with immutability; statelessness gives you almost-free undo management and can really speed up your page draws while maintaining a simple concept for the code. For an example, see Goya (written in clojurescript on top of React) and the code it needed for undo management.
    • Note that if you embrace statelessness you don't need Object.Observe, or am I mistaken?
@Zireael07
Copy link

@Zireael07 Zireael07 commented Feb 28, 2015

Focus on performance? Me likey.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 28, 2015

This framework is for packages and almost no package has any performance
issues.

On Fri, Feb 27, 2015 at 11:03 PM, Zireael07 notifications@github.com
wrote:

Focus on performance? Me likey.


Reply to this email directly or view it on GitHub
#5756 (comment).

@wmertens
Copy link

@wmertens wmertens commented Feb 28, 2015

@mark-hahn Hmmm, I have like 40 packages installed. A lot of small slowdowns also results in a large slowdown... So I think that potential performance should be weighed as well.
For example, if I go to the dev tools timeline and record, I get a ton of timers fired and redraws every second, even though nothing changed and nothing is active. The timers are mostly from minimap which seems to poll the dom every 0.1s but doesn't turn off the polling when a pane is not active (I'll open a bug).
I'm just armchair programming here, but if immutability were used, the minimap would be only dependent on the editor text and the window position. Whenever either changes, it can re-render (and it would have both old and new versions available for diffing). No polling would be needed then.

@nathansobo
Copy link
Contributor

@nathansobo nathansobo commented Feb 28, 2015

@abe33 Would you consider switching mini-map to use atom.views.pollDocument to coordinate polling with the editor? It's currently an experimental API and it would be nice to get some external feedback on it. There's also atom.views.readDocument and updateDocument for coordinating reads and writes which may be of interest.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Feb 28, 2015

. A lot of small slowdowns also results in a large slowdown...

I'm arguing that slowdowns aren't caused by the framework when the package is only working on a small part of the DOM, like a half-dozen divs.

I get a ton of timers fired and redraws every second, even though nothing changed and nothing is active.

If this is true then there should be a core API to consolidate these. I have asked before for the presenter to be able to be used by packages.

@Hurtak
Copy link

@Hurtak Hurtak commented Jan 6, 2016

How about starting some official 'todoMVC' repo for atom packages. One specific simple package would be developed in several frameworks/libraries, atom devs would then be able to evaluate what suits best to beginners, and potential package developers would see how to develop packages in their favorite framework

@kanekotic
Copy link

@kanekotic kanekotic commented Jan 6, 2016

@mark-hahn I agree that using only DOM calls is painful. But i also agree with @lee-dohm and @mnquintana and the flexibility of using different frameworks, but i think the knowledge to help in the different ones should reside in the community it will probably become a burden.
I think the atom package generator should offline continue as is just a simple thing that explains how to start, and maybe extended with an extra option that will clone base projects based on a selected framework, that will allow the flexibility of selecting a framework.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Jan 6, 2016

todoMVC would be perfect since it has become the standard go-to demo app. It would need to be tweaked to somehow fit into atom instead of the standard web page.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Jan 6, 2016

an extra option that will clone base projects based on a selected framework,

I don't see why the sample projects @leedohm wants couldn't be loaded as projects.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Jan 6, 2016

It was worth it for the flexibility, I could do all sorts of optimizations specific to linter there

I can't imagine any optimization that couldn't be done with a framework, particularly vue, which is what I use.

@steelbrain
Copy link
Contributor

@steelbrain steelbrain commented Jan 6, 2016

@mark-hahn We have to handle cases with ~5k error messages in one panel, we have to keep a pool of DOM elements and re-use them in both panel and bubble and for that we have to design the message elements to be disposable + reusable.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Jan 6, 2016

we have to design the message elements to be disposable + reusable.

Actually, vue components would be perfect for that. I'm not saying you
should use vue, just that you underestimate what good frameworks are
capable of.

On Wed, Jan 6, 2016 at 1:10 PM, Steel Brain notifications@github.com
wrote:

@mark-hanh We have to handle cases with ~5k error messages in one panel,
we have to keep a pool of DOM elements and re-use them in both panel and
bubble and for that we have to design the message elements to be disposable

  • reusable.


Reply to this email directly or view it on GitHub
#5756 (comment).

@paulpflug
Copy link

@paulpflug paulpflug commented Jan 6, 2016

@mark-hahn We have to handle cases with ~5k error messages in one panel, we have to keep a pool of DOM elements and re-use them in both panel and bubble and for that we have to design the message elements to be disposable + reusable.

I did exactly that with vue already, of course you can't use the built in for loop, though.
(I used a list of entries which change their text and position on scrolling, each entry is a vue component and so the logic of the list and the entry is seperated)

But back on topic: I would prefer something other than todoMVC or a modified todoMVC which uses something of the atom api at least

@steelbrain
Copy link
Contributor

@steelbrain steelbrain commented Jan 6, 2016

@mark-hahn I evaluated several options including view frameworks but linter messages caching is complicated than you think, consider this

class MessageView {
  constructor() {
    this.rootElement = getRootElement()
    this.nameElement = getNameElement()
    this.typeElement = getTypeElement()
    this.messageElement = getMessageElement()
    this.rootElement.appendChild(this.nameElement)
    this.rootElement.appendChild(this.typeElement)
    this.rootElement.appendChild(this.messageElement)
  }
  attach(message) {
    if (message.name) {
      this.messageElement.textContent = message.name
    } else this.messaegElement.setAttribute('hidden', 'true')
    ... same for type ...
    if (message.hasLink) {
      // create link outside of pool, costy
      this.messageElement.appendChild(getMessageLink())
    }
  }
}

Now the difficult thing here is that the structure of each component is different, some are divs, some are spans, some are hyperlinks. Any generic caching technique would never be able to give us results that I can get this way. I can create generic message element view objects and attach and detach messages from them

@mnquintana
Copy link
Member

@mnquintana mnquintana commented Jan 6, 2016

I think a TodoMVC-esque example package for Atom is a great idea, but I agree with @paulpflug that it shouldn't literally be TodoMVC, but rather something that makes significant use of the Atom API.

@mark-hahn
Copy link
Contributor

@mark-hahn mark-hahn commented Jan 6, 2016

@steelbrain, I'm too lazy to argue by writing vue samples. I remain convinced though that it can be done with vue in an elegant way. You haven't presented anything to sway me, not that you should care.

Anything turing complete could do it but we'd have to compare final results to really get a good comparison.

@kanekotic
Copy link

@kanekotic kanekotic commented Jan 6, 2016

@mnquintana maybe something that will use the API and could be an adapt is a 'find TODO comments' on the editor.

@paulpflug
Copy link

@paulpflug paulpflug commented Jan 6, 2016

@steelbrain I believe, what you would need is something similar to clusterize.js and I'm sure you could implement and adapt it to your use case in nearly any view framework - only a matter of time ;)

@kierans
Copy link
Contributor

@kierans kierans commented Jan 7, 2016

I agree with @mnquintana that an examples need to showcase the Atom API, as well as have several different UI widgets to show what's possible.

@willnwhite
Copy link

@willnwhite willnwhite commented Jun 2, 2016

Whilst this has been going on, I started to just write functions in my code to create and append elements. It reminded me of HyperScript:

var h = require('hyperscript')
h('div#page',
  h('div#header',
    h('h1.classy', 'h', { style: {'background-color': '#22f'} })),
  h('div#menu', { style: {'background-color': '#2f2'} },
    h('ul',
      h('li', 'one'),
      h('li', 'two'),
      h('li', 'three'))),
    h('h2', 'content title',  { style: {'background-color': '#f22'} }),
    h('p',
      "so it's just like a templating engine,\n",
      "but easy to use inline with javascript\n"),
    h('p',
      "the intension is for this to be used to create\n",
      "reusable, interactive html widgets. "))

I'm a big fan of the HTML-like nesting. I will try it out on my package.

@k33g
Copy link

@k33g k33g commented Jun 10, 2016

Hello 🌍 , cc @thedaniel
I'm starting some quick experiments with Atom and UI:

With RactiveJS

http://www.ractivejs.org/

Learning curve is small, abs Ractive is pleasant to use

export default class MyPlugInView {

  constructor(serializedState) {
    this.element = document.createElement('div');

    let myForm = new Ractive({
      el: this.element,
      template: `
      <div>
        <p>{{greeting}}, {{recipient}}!</p>
        <div on-click="activate">{{message}}</div>
      </div>
      `,
      oninit: function () {
        this.on( 'activate', () => { // fooo
        });
      },
      data: {
        greeting: 'Hello world',
        message: 'Click me!'
      }
    });
  }
  serialize() {}
  destroy() {
    this.element.remove();
  }
  getElement() {
    return this.element;
  }
}

With HTMLElement (Custom Element and VanillaJS)

For small codes, to my mind it's enough: Custom Elements with Classes

Nothing but does the work for small tests

'use babel';

class Small extends HTMLElement {
  constructor() { super(); }
  createdCallback() {}
  attachedCallback(){}
  template(data) { return `<div></div>`; }
  html(data) {
    this.innerHTML = this.template(data);
    this.events(data);
  }
  init(data) {}
  static of(tagName, data) {
    let Element = document.registerElement(tagName, this);
    let instance = new Element()
    instance.init(data)
    instance.html(data)
    return instance
  }
}
export default Small;

And then I use it like that:

'use babel';

import Small from './small';

class MyForm extends Small {
  constructor() { super(); }
  template(data) {
    return `<div>
      <h3>${data.message}</h3>
      <form>
        <input type="text" placeholder="${data.placeholder}"/>
        <button>Click Me!</button>
      </form>
    </div>`;
  }
  events(data) {
    this.querySelector('button').addEventListener('click', (e) => {
      let value = this.querySelector("input").value;
      this.querySelector("h3").innerHTML = value;
    });
  }
  init(data) {
    console.log('Inititialize ...', data)
  }
}

export default class MyPlugInView {
  constructor(serializedState) {
    this.element = document
      .createElement('div')
      .appendChild(
        MyForm.of('my-form', {message:'Hello world!', placeholder:'???'})
      )
  }

  serialize() {}
  destroy() {
    this.element.remove();
  }
  getElement() {
    return this.element;
  }
}
@RobertBColton
Copy link

@RobertBColton RobertBColton commented Jun 17, 2017

+1 There really needs to be some normalization of view frameworks for package authors. People want to be able to do things in a way that they know won't break in the future.

@kanekotic
Copy link

@kanekotic kanekotic commented Jun 20, 2017

@RobertBColton I agree, but in any case is difficult, i think the rendering framework is not an issue in general.
My concern is becoming the fact that the liberty of rendering is adding dependencies in a per plugin bases. I would like to really se something different as use what is internal to atom so we don't have a mix of instances and resources being used, so performance and resource usage becomes better.
In any case this thread is 2 years old and we have not got to any agreement neither here or the forum.
So my vote is to just get to use whatever DOM is being used internally in atom.

@kolya-ay
Copy link

@kolya-ay kolya-ay commented Jun 20, 2017

Is the open issue means that relaying on etch isn't still a done deal?

@nathansobo
Copy link
Contributor

@nathansobo nathansobo commented Jul 3, 2017

At this point we use manual DOM manipulation, Etch, and React in the GitHub package. I think that's as close as we'll come to a specific endorsement, but we'll remain committed to being agnostic and giving package authors freedom of choice. Baking any view framework into Atom core other than the raw DOM APIs that come with the browser is a liability we're not prepared to take on any time soon.

@lock
Copy link

@lock lock bot commented Mar 31, 2018

This issue has been automatically locked since there has not been any recent activity after it was closed. If you can still reproduce this issue in Safe Mode then please open a new issue and fill out the entire issue template to ensure that we have enough information to address your issue. Thanks!

@lock lock bot locked and limited conversation to collaborators Mar 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.