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

#84 - add displayName for @:jsxStatic components #86

Merged
merged 3 commits into from
Feb 27, 2018

Conversation

kLabz
Copy link
Contributor

@kLabz kLabz commented Dec 4, 2017

When compiled with -debug, add a displayName to functional components for use with external tools (enzyme, chrome dev tools, etc.).

Handled components include:

  • Component classes with @:jsxStatic meta
  • Static methods returning a ReactElement
  • Static variables with getter returning a ReactElement

Local vars, static vars (without getter) & instance fields are not handled -- they will still be displayed as "Unknown". It's because they are not constant so it's a lot more complex.

Output example, at the end of the generated js file:

components_Footer.render.displayName = components_Footer.render.displayName || "Footer";

This should be compatible with haxe-modular code splitting, but this has not been tested yet (I need to setup a sample project).

Cleanup: moved all jsxStatic-related code to react.jsx.JsxStaticMacro.hx

name: '__displayName',
access: [Access.AStatic, Access.APrivate],
kind: FieldType.FVar(null, macro {
untyped $i{classPath}.$jsxStaticField
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm afraid this won't be compatible with code splitting - what does the generated JS look like?

To work with Modular it should be added in static _init_ and the code should be a direct assignement:

com_Something.StaticField.displayName = 'StaticField';

Though we'd need to check but maybe this will work as well (in _init_):

if (com_Something.StaticField != null)
    com_Something.StaticField.displayName = 'StaticField';

Copy link
Contributor Author

@kLabz kLabz Dec 5, 2017

Choose a reason for hiding this comment

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

This adds assignements alongside tagComponent() output, at the end of the generated js:

components_Footer.__displayName = components_Footer.render ? components_Footer.render.displayName = "Footer" : false;
components_Link.displayName = "Link"; // From tagComponent()
components_Todo.__displayName = components_Todo.render ? components_Todo.render.displayName = "Todo" : false;

I'm not sure about code splitting, but it seems to work (or not to) like existing code. I'd need to check that.

Btw, direct assignement without untyped (or similar tricks) will not be possible, haxe won't add fields to functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok that would be compatible with code splitting.

@@ -295,6 +295,37 @@ class ReactMacro
return fields;
}

static function buildJsxStatic():Array<Field> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use a comment saying "Add a displayName to functional components"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure! :)

extraParams.hxml Outdated
@@ -0,0 +1 @@
--macro addGlobalMetadata("", "@:build(react.ReactMacro.buildJsxStatic())")
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes me sad.

And though it works I'm not sure this is the best approach: we'll have the same problem in other cases where we just use a functional component without using :jsxStatic:

function render() {
    return jsx('<FunctionalComp />');
}
static function FunctionalComp(props) {
    ...
}

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 agree.
Maybe this is one of several things that could be added in jsx macro, which might need a (partial?) rewrite to handle more complex features.

Copy link
Contributor Author

@kLabz kLabz Dec 6, 2017

Choose a reason for hiding this comment

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

I have a working prototype without extraParams, handled within jsx macro.
I'll clean things up a bit, factorize a little and try to find edge cases (local variables?).

The output will be a little different (but better imo), and still at the end of the generated code:

components_Footer.render.displayName = "Footer";
components_Todo.render.displayName = "Todo";

Edit:
Output will actually be like this, to allow user defined displayNames:

components_Footer.render.displayName = components_Footer.render.displayName || "Footer";

@kLabz kLabz force-pushed the feature/jsxstatic-displayname branch from 1d143df to cec106b Compare December 6, 2017 17:19
@kLabz
Copy link
Contributor Author

kLabz commented Dec 6, 2017

I updated the PR, using jsx macro as entry point instead of adding build macros.

@kLabz kLabz force-pushed the feature/jsxstatic-displayname branch from 018f1b9 to 98fad4a Compare December 7, 2017 16:41
@djaonourside
Copy link

Hello, gentlemen! Any chance this pr will be accepted?

@kLabz
Copy link
Contributor Author

kLabz commented Dec 29, 2017

This PR is ready imo, only waiting for @elsassph approval.
Could you please take a look when you have time to do so?

I had rewritten the PR description along with the feature itself, and your comments should have been handled.
The diff may seem heavier than it really is, because I moved some existing code to a dedicated class so that @:jsxStatic-related code do not polute JsxMacro.

@elsassph
Copy link
Contributor

Does it work if @:jsxStatic is applied to a sub-class of a module? e.g.

// Foo.hx
class Foo {...}

@:jsxStatic
class Bar {}

@kLabz
Copy link
Contributor Author

kLabz commented Dec 30, 2017

Yep.

I found a small issue with @:jsxStatic however: it breaks without giving a clear explanation (so ReactMacro breaks later) when used without any param. Should we send a proper compilation error, or default to some value? ('render', maybe?)

@elsassph
Copy link
Contributor

A default value could help but it may cause other issues and confusion if you have a non-static method of the default name...

@kLabz
Copy link
Contributor Author

kLabz commented Dec 30, 2017

The error would be the same if the field does not exist or if it is not a static method:

Class<X> has no field render

But an error is probably better indeed. Defaulting to "render" would save a few keystrokes but I agree that it is less safe. I'll add the compilation error message in this PR.

@kLabz
Copy link
Contributor Author

kLabz commented Dec 30, 2017

Added the compilation error if no param.

case WithParams(_, params): params.pop().getValue();
case NoParams(meta):
Context.fatalError(
"@:jsxStatic requires a param (name of the component's function)",
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe more like Parameter required for @:jsxStatic('name-of-static-function')

@kLabz kLabz force-pushed the feature/jsxstatic-displayname branch from ee020a3 to da00c23 Compare December 31, 2017 15:10
@djaonourside
Copy link

Hello, guys! Any chance these changes will be in haxelib version?

@kLabz
Copy link
Contributor Author

kLabz commented Feb 5, 2018

Anything else bothering you @elsassph? (btw, do you want me to squash?)

if (!hasBeenHooked)
{
hasBeenHooked = true;
Context.onAfterTyping(afterTypingHook);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does that work with compiler server?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't find a way to break it, do you have something specific in mind?

$ haxe --connect 9009 build.hxml --times -debug 
/git/haxe-react/src/lib/react/jsx/JsxStaticMacro.hx:153: afterTyping
/git/haxe-react/src/lib/react/jsx/JsxStaticMacro.hx:153: afterTyping
name           | time(s) |   % |     # | info
----------------------------------------
analyzer       |   0.090 |   9 | 30285 | 
filters        |   0.050 |   5 |     1 | 
generate       |   0.010 |   1 |     1 | 
  js           |   0.010 |   1 |     1 | 
haxelib        |   0.000 |   0 |     1 | 
macro          |   0.550 |  56 |   361 | 
other          |   0.080 |   8 |     1 | 
parsing        |   0.120 |  12 |   647 | 
server         |   0.010 |   1 |  8692 | 
  module cache |   0.010 |   1 |  8692 | 
typing         |   0.080 |   8 |  1116 | 
----------------------------------------
total          |   0.990 | 100 |     0 |

$ cat .build/klabz.js | grep displayName | wc -l
65

$ haxe --connect 9009 build.hxml --times -debug
name             | time(s) |   % |   # | info
----------------------------------------
analyzer         |   0.000 |   0 |  37 | 
filters          |   0.020 |  40 |   1 | 
generate         |   0.020 |  40 |   1 | 
  js             |   0.020 |  40 |   1 | 
haxelib          |   0.000 |   0 |   1 | 
other            |   0.000 |   0 |   1 | 
server           |   0.010 |  20 | 649 | 
  module cache   |   0.010 |  20 | 649 | 
    add modules  |   0.010 |  20 |   7 | 
    changed dirs |   0.000 |   0 | 628 | 
    check        |   0.000 |   0 |   7 | 
typing           |   0.000 |   0 |   1 | 
----------------------------------------
total            |   0.050 | 100 |   0 |

$ cat .build/klabz.js | grep displayName | wc -l
65

$ haxe build.hxml
$ cat .build/klabz.js | grep displayName | wc -l
35

$ haxe build.hxml -debug
/git/haxe-react/src/lib/react/jsx/JsxStaticMacro.hx:153: afterTyping
/git/haxe-react/src/lib/react/jsx/JsxStaticMacro.hx:153: afterTyping

$ cat .build/klabz.js | grep displayName | wc -l
65

@kLabz kLabz force-pushed the feature/jsxstatic-displayname branch from e5e3b42 to 1c6a346 Compare February 7, 2018 09:51
@kLabz kLabz force-pushed the feature/jsxstatic-displayname branch from 7e46690 to dc9ab98 Compare February 26, 2018 09:33
@elsassph elsassph merged commit 9755a24 into massive-oss:master Feb 27, 2018
@kLabz kLabz deleted the feature/jsxstatic-displayname branch January 17, 2019 08:53
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.

3 participants