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

JSX second null argument compatibility fix #772

Closed
wants to merge 1 commit into from

Conversation

avesus
Copy link
Contributor

@avesus avesus commented Aug 20, 2015

Babel and other JSX compilers pass 'null' value as second argument
to m() function if there is no attributes in element specified.
Added check for 'null' to support JSX compilers transparently.

NOTE that passing children elements as arguments is already supported.

args[i - 1] = arguments[i];
}
// JSX compatibility with 'null' {pairs} argument
var args = Array.prototype.slice.call(arguments, (pairs === null ? 2 : 1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: just set i to pairs === null ? 2 : 1. Otherwise, you're creating a perf regression.

(Chrome and Firefox both don't usually like it when you pass the arguments object as an parameter. This is one case.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I'll fix it.
On Sat, Aug 22, 2015 at 9:53 AM Isiah Meadows notifications@github.com
wrote:

In mithril.js
#772 (comment):

@@ -49,9 +49,9 @@ var m = (function app(window, undefined) {
*
*/
function m(tag, pairs) {

  •   for (var args = [], i = 1; i < arguments.length; i++) {
    
  •       args[i - 1] = arguments[i];
    
  •   }
    
  •   // JSX compatibility with 'null' {pairs} argument
    
  •   var args = Array.prototype.slice.call(arguments, (pairs === null ? 2 : 1));
    

Nit: just set i to pairs === null ? 2 : 1. Otherwise, you're creating a
perf regression.

(Chrome and Firefox both don't usually like it when you pass the arguments
object as an parameter. This is one case.)


Reply to this email directly or view it on GitHub
https://github.com/lhorie/mithril.js/pull/772/files#r37693412.

Babel and other JSX compilers pass 'null' value as second argument
to m() function if there is no attributes in element specified.
Added check for 'null' to support JSX compilers transparently.

NOTE that passing children elements as arguments instead of Array is already supported.
@avesus
Copy link
Contributor Author

avesus commented Aug 24, 2015

@lhorie is this useful?

@avesus
Copy link
Contributor Author

avesus commented Aug 28, 2015

Actually supporting null second argument to m() makes Babel to compile JSX directly into beautiful Mithril code! I use this PR in my project and things work like a magic. I prefer pure JS code, but my partner reads better JSX templates, and working on a personal project late night allows to move on not "parsing" opened and closed braces and not counting commas.

I think that lot of Mithril supporters hate JSX. But transparently supporting it makes Mithril ultra-popular.

Shure, transparently supporting of JSX and some onfocus/onblur preserving parts for editboxes makes Mithril obsolete React.

@dead-claudia
Copy link
Member

Not everyone in the Mithril community hates JSX, or we wouldn't have MSX.

On Fri, Aug 28, 2015, 09:41 Ivan Borisenko notifications@github.com wrote:

Actually supporting null second argument to m() makes Babel to compile
JSX directly into beautiful Mithril code! I use this PR in my project and
things work like a magic. I prefer pure JS code, but my partner reads
better JSX templates, and working on a personal project late night allows
to move on not "parsing" opened and closed braces and not counting commas.

I think that lot of Mithril supporters hate JSX. But transparently
supporting it makes Mithril ultra-popular.

Shure, transparently supporting of JSX and some onfocus/onblur preserving
parts for editboxes makes Mithril obsolete React.


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

@avesus
Copy link
Contributor Author

avesus commented Aug 28, 2015

Guys from the MSX team said that they will deprecate MSX in favor of Babel,
if I understand them right.
On Fri, Aug 28, 2015 at 5:42 PM Isiah Meadows notifications@github.com
wrote:

Not everyone in the Mithril community hates JSX, or we wouldn't have MSX.

On Fri, Aug 28, 2015, 09:41 Ivan Borisenko notifications@github.com
wrote:

Actually supporting null second argument to m() makes Babel to compile
JSX directly into beautiful Mithril code! I use this PR in my project and
things work like a magic. I prefer pure JS code, but my partner reads
better JSX templates, and working on a personal project late night allows
to move on not "parsing" opened and closed braces and not counting
commas.

I think that lot of Mithril supporters hate JSX. But transparently
supporting it makes Mithril ultra-popular.

Shure, transparently supporting of JSX and some onfocus/onblur preserving
parts for editboxes makes Mithril obsolete React.


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


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

@dead-claudia
Copy link
Member

I was talking about part of the community, not the MSX compiler itself. I
still like this patch, by the way.

On Fri, Aug 28, 2015, 10:44 Ivan Borisenko notifications@github.com wrote:

Guys from the MSX team said that they will deprecate MSX in favor of Babel,
if I understand them right.
On Fri, Aug 28, 2015 at 5:42 PM Isiah Meadows notifications@github.com
wrote:

Not everyone in the Mithril community hates JSX, or we wouldn't have MSX.

On Fri, Aug 28, 2015, 09:41 Ivan Borisenko notifications@github.com
wrote:

Actually supporting null second argument to m() makes Babel to compile
JSX directly into beautiful Mithril code! I use this PR in my project
and
things work like a magic. I prefer pure JS code, but my partner reads
better JSX templates, and working on a personal project late night
allows
to move on not "parsing" opened and closed braces and not counting
commas.

I think that lot of Mithril supporters hate JSX. But transparently
supporting it makes Mithril ultra-popular.

Shure, transparently supporting of JSX and some onfocus/onblur
preserving
parts for editboxes makes Mithril obsolete React.


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


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


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

@avesus
Copy link
Contributor Author

avesus commented Aug 28, 2015

insin/msx#13 (comment)
Note that MSX will be deprecated as soon as the next version of Mithril is released, as a change has been made which allows you to make full use of Babel's JSX transpiler instead. Babel will pass any children as additional arguments, so you'd need to use this signature instead to put children into an array.

But he's not mentioned that secondary null argument is the problem while. Because talk was about upcoming next version.

}

if (isObject(tag)) return parameterize(tag, args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: shouldn't pairs be sent as-is as well to parametrize, in the form of the first part of args? Something like this?

for (var args = [], i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}

if (isObject(tag)) return parameterize(tag, args);
if (pairs === null) args.shift();

It's a breaking change otherwise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should review all cases:

/// Base Mithril cases:
// arguments.length === 1, pairs is undefined
m('div')
// arguments.length === 2+, pairs is Object, next arguments is undefined or Array (the single third argument) or one or more functions
m('div', {id: '1'}, ...)
// arguments.length === 2, pairs is Array
m('div', [m('div')])
// arguments.length === 2+, pairs is function, as next arguments should too
m('div', m('div'))
// arguments.length === 2+, pairs is String
m('div', 'Hello')

JSX emitter always emits function call with 2 or 3 arguments. In case of absent pairs, it emits null instead.
So for JSX, cases are following:

m('div', {})
m('div', null, m('div'))
m('div', {}, m('div'))

So, if second argument is null, Mithril just could consider that second argument is not second, but third one.
I'll fix the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This solution would suffice, right?

function m(tag, pairs) {
    var i = 1; 
    // Fix JSX style passing
    if (arguments.length > 2 && pairs === null) {
        i = 2; 
        pairs = arguments[2];
    }
    for (var args = []; i < arguments.length; ++i) {
        args.push(arguments[i]);
    }
    if (isObject(tag)) return parameterize(tag, args);
    // ...
}

@dead-claudia
Copy link
Member

@avesus Please add unit tests for this. Here's what I see is needed with this (at least):

  1. m(component, args, "foo") and m.component(component, args, "foo"), when the controller is called, should both call it with args and "foo"
  2. m(component, null, args) and m.component(c1, null, args) when the controller is called, should both call it with null and args (i.e. they should be passed verbatim).
  3. m("div", null, "body") and m("div", "body") should return an equivalent node.

@avesus
Copy link
Contributor Author

avesus commented Aug 28, 2015

@IMPinball not shure why consider m.component(c1, null, args) in tests. Could you explain?

Tests are very important part, I hope to write them on the next week. Have a nice weekend, thanks for the good peer review!

@dead-claudia
Copy link
Member

@avesus

  1. You can never test code too much.
  2. See my line comment explaining where the current PR could lead to unexpected behavior with components.
var Foo = {
  view: function (ctrl, opts) {
    opts = opts || {}
    var children = [].slice.call(arguments, 2).map(function (value, i) {
      return m('div', 'Index: ' + i, 'Body: ', value)
    });
    return m('div', [opts.header || "A list"].concat(children))
  },
};

// This will weirdly throw an error in the view itself.
m(Foo, null, [m('span', 1)]);
``

@avesus
Copy link
Contributor Author

avesus commented Sep 10, 2015

@IMPinball sorry for my long wait. After dive deep into Mithril's source code and meeting with s-n-a-b-b-d-o-m (with dashes to not promote it here like an ad) I wonder about alternatives.
Is Mithril really slower by 20 times to the s-worded alternative and how to make it faster? Also, I like modular approach but it is not Mithril' choice :-(. So, my motivation right now becomes much lower after discovering the alternative. But less and faster is not necessary better. Thus I still consider Mithril as important candidate as the base for my projects.

But my aaannnsweeeer could be very slow henceforth.

Feel free to bring this task to completion. I'l write when (if) come back!

@dead-claudia
Copy link
Member

@avesus You mind redoing this against next? It's an easy patch, although breaking for a single case.

@dead-claudia
Copy link
Member

Closing due to inactivity. If you feel this should still be done, please feel free to file a new issue and/or pull request. 😄

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

Successfully merging this pull request may close these issues.

2 participants