10000 API for creating views in packages · Issue #3752 · atom/atom · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Mar 3, 2023. It is now read-only.

API for creating views in packages #3752

Closed
benogle opened this issue Oct 8, 2014 · 21 comments
Closed

API for creating views in packages #3752

benogle opened this issue Oct 8, 2014 · 21 comments

Comments

@benogle
Copy link
Contributor
benogle commented Oct 8, 2014

If we plan to deprecate the space pen View class, we need a story for what folks can move to. Some kind of system that interoperates with custom elements. Something that UI heavy packages like settings view and fnr can use.

  • Maybe it looks like space pen (space-pencil)?
  • Maybe it's react?

We need to do more thinking.

@benogle benogle changed the title View system for packages API for creating views in packages Oct 8, 2014
@benogle benogle mentioned this issue Oct 8, 2014
21 tasks
@philipgiuliani
Copy link
Contributor

Is that really required? What if the packages also would just extend HTMLElements as views? I recently rewrote my package witch HTMLElements instead of using SpacePen and it worked great.

@benogle benogle self-assigned this Oct 9, 2014
@benogle
Copy link
Contributor Author
benogle commented Oct 27, 2014

After discussion and tinkering, we have a direction. The goal is a view system that uses the browser's built in mechanisms as much as possible, embracing new tech like custom elements and Object.observe. Much will be borrowed from Polymer.

We're encouraging a Model/View approach. Models are just plain objects. e.g. This is a fine model:

Model = {
  message: 'Find in Buffer'
}

A model class:

class FindModel
  message: 'Find in Buffer'
  constructor: ->

Views are custom elements with an HTML template. Templates support Polymer's template data-binding.

We'll provide a registerElement method from a new module called element-kit. It is basically a wrapper around document.registerElement with slightly cleaner syntax.

Example: Find panel

screen shot 2014-10-27 at 11 14 15 am

Model

class FindModel
  message: 'Find in Buffer'
  constructor: ->
  search: (text) ->
    # do search on current editor

A custom element view:

{registerElement} = require 'element-kit'

Template = require('../templates/find.html')
FindElement = registerElement 'my-find',
  createdCallback: ->
    @appendChild(Template.clone())
    @rootTemplate = @querySelector('template')
    @input = @querySelector('atom-text-editor')

    @classList.add 'tool-panel', 'panel-bottom', 'padded'

    atom.events.add this, 'button', 'click', -> @confirm()
    atom.events.add this, 'core:confirm', -> @confirm()

  confirm: ->
    @model.search(@input.value)

  getModel: -> @model
  setModel: (@model) ->
    # setup the data binding
    @rootTemplate?.model = @model

And the template in ../templates/find.html

<template bind="{{}}">
  <div>{{message}}</div>
  <div>
    <atom-text-editor mini></atom-text-editor>
    <button class="btn">Search</button>
  </div>
</template>

Registration. We need to tie the View to the Model with the view provider system:

atom.workspace.addViewProvider
  modelConstructor: FindModel
  viewConstructor: FindElement

Invocation. Create the model, then attach a panel:

@model = new FindModel
@panel = atom.workspace.addBottomPanel item: @model

@mark-hahn
Copy link
Contributor

Very powerful. It is a shame it is so much more complex.

On Mon, Oct 27, 2014 at 11:31 AM, Ben Ogle notifications@github.com wrote:

After discussion and tinkering, we have a direction. The goal is a
view system that uses the browser's built in mechanisms as much as
possible,
embracing new tech like custom elements and Object.observe. Much will be
borrowed from Polymer https://www.polymer-project.org.

We're encouraging a Model/View approach. Models are just plain objects.
e.g. This is a fine model:

Model = {
message: 'Find in Buffer'
}

A model class:

class FindModel
message: 'Find in Buffer'
constructor: ->

Views are custom elements with an HTML template. Templates support
Polymer's
template data-binding
https://www.polymer-project.org/docs/polymer/template.html.

We'll provide a registerElement method from a new module called
element-kit.
It is basically a wrapper around document.registerElement with slightly
cleaner syntax.
Example: Find panel

[image: screen shot 2014-10-27 at 11 14 15 am]
https://cloud.githubusercontent.com/assets/69169/4796694/32a4d8de-5e05-11e4-87c8-ee25d4b0cd49.png

Model

class FindModel
message: 'Find in Buffer'
constructor: ->

A custom element view:

{registerElement} = require 'element-kit'
Template = require('../templates/find.html')FindElement = registerElement 'my-find',
createdCallback: ->
@appendChild(Template.clone())
@RootTemplate = @querySelector('template')
@input = @querySelector('atom-text-editor')

@classList.add 'tool-panel', 'panel-bottom', 'padded'

atom.events.add this, 'button', 'click', -> @confirm()
atom.events.add this, 'core:confirm', -> @confirm()

confirm: ->
getCurrentEditor().scan(@input.value)

getModel: -> @model
setModel: (@model) ->
# setup the data binding
@RootTemplate?.model = @model

And the template in ../templates/find.html

{{message}}
Search

Registration. We need to tie the View to the Model with the view provider
system:

atom.workspace.addViewProvider
modelConstructor: CrappyFindModel
viewConstructor: CrappyFindElement

Invocation. Create the model, then attach a panel:

@model = new CrappyFindModel@panel = atom.workspace.addBottomPanel item: @model


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

@batjko
Copy link
Contributor
batjko commented Oct 27, 2014

I like the resemblance of Polymer in this. Google are pushing that thing pretty badly and it's well thought out to really become big. Also, everything that uses a web components approach is probably the right way forward.

@benogle
Copy link
Contributor Author
benogle commented Oct 27, 2014

It is a shame it is so much more complex.

@mark-hahn can you elaborate? There are definitely more distinct entities: a model, a view, a template, and registration. But overall, UIs built with this should be simpler. Data binding will remove a bunch of logic, and the view should have very little logic, just calling things on the model.

@mark-hahn
Copy link
Contributor

I was just comparing it my usual spacepen view, object model, and jquery
binding. If I was building a large app, like Atom itself, the complexity
would be needed. But most packages are a simple panel at most. Can I still
use my simple spacepen?

On Mon, Oct 27, 2014 at 12:33 PM, Ben Ogle notifications@github.com wrote:

It is a shame it is so much more complex.

@mark-hahn https://github.com/mark-hahn can you elaborate? There are
definitely more distinct entities: a model, a view, a template, and
registration. But overall, UIs built with this should be simpler. Data
binding will remove a bunch of logic, and the view should have very little
logic, just calling things on the model.


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

@benogle
Copy link
Contributor Author
benogle commented Oct 27, 2014

Space pen is going away, so something like this will be the only way.

2 ways to simplify:

  1. It is possible for us to get rid of the registration step by integrating it with the element registration
  2. you dont need the model if you dont want it. You can insert the view as a panel like this:
view = document.createElement('my-find')
@panel = atom.workspace.addBottomPanel item: view

@mark-hahn
Copy link
Contributor

It is possible for us to get rid of the registration step

That would be nice. I noticed in the docs that the state serializer used
registration at some point in the past. I have just been taking state
objects in the activate and returning them in serialize and it works
great. Simplicity is the greatest virtue. :-)

Space pen is going away

That's a shame. The barrier to entry for new package developers will
jump. It's not so much the amount of code but the learning curve. This is
definitely beyond the skill level of the typical web designer and Atom is
supposed to be attracting web designers.

So that means I will have to rewrite the views on my 12 packages. I guess
that is to be expected since I knew Atom was unstable

I have but one request. Please think through carefully what benefits
package writers will get with this new scheme. Don't use the new Chrome
features because they are cool.

On Mon, Oct 27, 2014 at 1:55 PM, Ben Ogle notifications@github.com wrote:

Space pen is going away, so something like this will be the only way.

2 ways to simplify:

  1. It is possible for us to get rid of the registration step by
    integrating it with the element registration
  2. you dont need the model if you dont want it. You can insert the
    view as a panel like this: coffee view =
    document.createElement('my-find') @panel = atom.workspace.addBottomPanel
    item: view


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

@benogle
Copy link
Contributor Author
benogle commented Oct 29, 2014

So that means I will have to rewrite the views on my 12 packages. I guess that is to be expected since I knew Atom was unstable

I suppose I should clarify. You can still use space-pen as a library dependency, but we will no longer include it in the atom exports, and we will likely not make any changes to it.

I have but one request. Please think through carefully what benefits package writers will get with this new scheme. Don't use the new Chrome features because they are cool.

I took this as an opportunity to collect my thoughts over the last few weeks into a bit of text. This new system will be a net positive for everyone. Even in small packages, the resulting code should be simpler.

Data binding is a huuuge dev speedup

If you've ever used data-binding in a webapp but it is amazing in its ability to speed up the dev process and reduce logic. No longer will we need to write logic to update the view like this or like this. Just set a property on an object and watch it from the template. An interesting example is making a view toggle when clicking a checkbox. All that's necessary is this:

model = { showIt: false }
<label>Show it? <input type="checkbox" checked="{{ showIt }}"></label>
<template if="{{ showIt }}">Shown via `if`</template>

Another example: Note how this space-pen view has more cruft than an element using template bindings. The space-pen view needs to set the text and class in multiple places (there's even a bug in there because of it!).

The learning curve should not be any steeper than space-pen. Take a look at this template file exercising all the binding features, it's only 60 lines of html! (see the corresponding model for context)

Performance

space-pen is slow for several reasons, notably it is not efficient in creating the markup. This new system uses the browser's mechanisms directly. @kevinsawicki noted large speedups when switching from space-pen views to custom-elements and using only native browser APIs (on tree-view, status-bar, and tabs).

I've run some benchmarks. Creating and appending 1000 elements with template bindings shows a ~35% gain over space-pen. Creating and appending 1000 elements with a template and no bindings shows a 95% gain over space-pen:

screen shot 2014-10-29 at 4 19 20 pm

The bindings are run async, so the impact to startup time should be that of the NO bindings case.

Less Cruft

We rely on jQuery which does a bunch of things we dont need because we know the platfom. jQuery's big win is a consistent API across all browsers, with some sugar here and there. The browser APIs are getting good (node.classList.add(), etc.) and we're only one platform, so a system papering over them is unnecessary.

We made up space-pen, which is pretty unlike any other view system out there. It has its own behavior and quirks which a package author needs to learn. The new system is just DOM APIs.

The Future

Overall, we're preparing for the future. We're betting that the API's eventually baked into chrome will be The Best Way to write views. We're betting that, eventually, libraries like jQuery and backbone and angular and space-pen will be obsolete.

This is just the foundation. We've written it in a minimal way initially on purpose — we're only providing the html require and registerElement. This gives us the option to expand later if necessary without deprecation and removal.

@mark-hahn
Copy link
Contributor

I'm still concerned about coding effort for small packages. The problem is overhead. You cheated on the first space-pen versus template bindings example. You didn't include the file ../templates/benchmark-element.html which is needed to duplicate the space-pen functionality. Without the html the space-pen code smaller than the new code.

Having two files instead of one is a PITA. I've never had to deal with an html file so far in Atom package development. This is a big step backwards. Even if I have to deal with crufty old html I can still put it in the same single view file, right?

The coffeescript html representation in space-pen is awesome, much like coffeescript itself, and I hate to lose that. The outlet feature is especially cool. There is an npm module teacup that works in a similar way to create html in coffeescript (side note: I wrote the predecessor to teacup).

Performance of markup has been a zero issue in my packages so far. They usually have no more than a dozen elements. The 35% gain you quote is not impressive especially since the space-pen rendering is a whopping 357 microseconds. And this usually only happens once when the package is activated.

eventually, libraries like jQuery and backbone and angular and space-pen will be obsolete.

Not in my lifetime, if ever, although I'm quite old.

Remember I am only considering package developers like me. I have no doubt these changes are awesome for the core rendering. Also note that I realize this has to be done. But keeping an easy route for package developers is paramount in my mind. Maybe I'll take a stab at making some tool to create everything easily for dummies.

@thomasjo
Copy link
Contributor

Performance of markup has been a zero issue in my packages so far. They usually have no more than a dozen elements. The 35% gain you quote is not impressive especially since the space-pen rendering is a whopping 357 microseconds

First of all there is a massive difference between 357 microseconds and 357 milliseconds (ms), three orders of magnitude to be exact 😜

Joking aside, while you might think this win is small, consider the total number of views that might be in play with a fully configured Atom environment with dozens of third-party packages on top of the core ones. Also the views in packages should (ideally) be created and destroyed whenever necessary/possible to reduce memory footprint etc, so a speedup here is a huge win in the overall perceived performance of Atom.

Also separating things into multiple files should make everything more manageable in the long run — separation of concerns. This also leads to small wins such as being able to more easily reuse views, and compose views from smaller partial views.

I for one, love these changes, and I guess there's a reason why the concept of model binding etc. keeps getting reinvented about every 10 years (fourth time now?) in one form or another. It's generally a nice concept once things reach a certain level of complexity within a system, but it does demand a bit more of the developer though, that part I do agree with.

@mark-hahn
Copy link
Contributor

First of all there is a massive difference between 357 microseconds and 357 milliseconds

I assumed the print-out shown was the total of the 1000 runs. Which is it? I'm pretty sure it is microseconds since there is no way that amount of code could take 1/3 of a second.

@benogle, I realize I have been representing the opposition of change here. I hope I'm not just knee-jerking a reaction to change as I suggested one might knee-jerk an acceptance of cool new features.

How big is the It's Alive!!! package going to be now? It would be really useful to see the new version.

@mark-hahn
Copy link
Contributor

I have thinking a lot about this (way too much) and I think my problem isn't the semantics as much as the syntax. I see this native html as noisy, hard to read, too much typing, and too many files. jQuery and space-pen had some useful features to hide that kind of cruft.

Is it possible there could be a space-pen sequel that does for the new html/bindings what the original space-pen did for the old html? This would be of general interest to all web developers, not just Atom, so there must be something happening in this direction somewhere. If not I'll have to put my coding where my mouth is and try to come up with some ideas.

BTW, I'm having a problem understanding this ...

Template = require('../templates/find.html')

Since when can you require an html file?

@thomasjo
Copy link
Contributor

Since when can you require an html file?

Since 82267c0 😃

@mark-hahn
Copy link
Contributor

I have been on a rant and I apologize. I said that this was right for Atom core and now I realize packages have to exactly match core.

P.S. Separation of concerns has nothing to do with files. Separating html by putting it at the top of the view file is a great separation. To me keeping the view in one file is a great feature. A view is really a kind of single concern when compared to a model.

@thomasjo
Copy link
Contributor

P.S. Separation of concerns has nothing to do with files. Separating html by putting it at the top of the view file is a great separation. To me keeping the view in one file is a great feature. A view is really a kind of single concern when compared to a model.

Agreed, but encouraging separate files also encourages the separation of concerns (at least more so than now). That being said, I do still believe you can inline your views if you prefer that approach. Although it will likely not be as "pretty".

@nathansobo
Copy link
Contributor

We won't be using SpacePen in core, but I see no problem with people continuing to use it if it's a good fit for their packages. We'll need to make a couple slight breaking changes to enable it to keep working in packages without support from core, but the library should continue to work indefinitely.

@benogle
Copy link
Contributor Author
benogle commented Oct 30, 2014

We've all talked about this and decided 2 things: the injection of globals via polymer isnt something we want to support long term, and it doesnt exactly fit in with the API freeze (it's additive). We plan to revisit this when we're into 1.0 initiative and can spend more time on it.

For now, @nathansobo is updating space-pen to be forward compatible and used outside of core. We will have a period of time between the freeze and 1.0 where our a recommendation for view code will range from vanilla custom elements to space-pen.

The stuff I outlined here is at https://github.com/atom/elmer and https://github.com/benogle/template-explore for future reference.

@mark-hahn
Copy link
Contributor

@nathansobo https://github.com/nathansobo is updating space-pen to be
forward compatible and used outside of core.

Awesome. Thanks.

On Thu, Oct 30, 2014 at 2:29 PM, Ben Ogle notifications@github.com wrote:

We've all talked about this and decided 2 things: the injection of globals
via polymer isnt something we want to support long term, and it doesnt
exactly fit in with the API freeze (it's additive). We plan to revisit this
when we're into 1.0 initiative and can spend more time on it.

For now, @nathansobo https://github.com/nathansobo is updating
space-pen to be forward compatible and used outside of core. We will have a
period of time between the freeze and 1.0 where our a recommendation for
view code will range from vanilla custom elements to space-pen.

The stuff I outlined here is at https://github.com/atom/elmer and
https://github.com/benogle/template-explore for future reference.


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

@thedaniel
Copy link
Contributor

I opened #5756 with a high-level overview of where we're at today and started a list of options. I'm closing this issue in favor of that one, in the interest of starting fresh with the current thinking & requirements.

@lock
Copy link
lock bot commented Jan 23, 2019

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 as resolved and limited conversation to collaborators Jan 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants
0