-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Generic support for third-party data objects inspection (ImmutableJS, BackboneJS, etc) #469
Conversation
- Do not call calculated properties on prototype chain
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks! If you are contributing on behalf of someone else (eg your employer): the individual CLA is not sufficient - use https://developers.facebook.com/opensource/cla?type=company instead. Contact cla@fb.com if you have any questions. |
If this PR will be accepted, I will implement support for ImmutableJS data structures as well. Not that big deal. |
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
+1 big time. Can save a lot of hassle. |
+1 too, integration is important |
I like the idea, but not the magic property Disclaimer: I don't really know how react devtools hooks work, so this is more of a pseudo-code than something usable: // inside Backbone:
if (__REACT_DEVTOOLS_GLOBAL_HOOK__) {
const { addInnerStateInspector, } = __REACT_DEVTOOLS_GLOBAL_HOOK__
if (typeof addInnerStateInspector === 'function') {
addInnerStateInspector(function inspectBackboneModel(possiblyModel){
// is this a Backbone Model?
const isInspectable = possiblyModel instanceof Backbone.Model
return {
isInspectable,
value: isInspectable ? possiblyModel.attributes : undefined, // this is the value to show
}
})
addInnerStateInspector(function inspectBackboneCollection(possiblyCollection){
// is this a Backbone Collection?
const isInspectable = possiblyCollection instanceof Backbone.Collection
return {
isInspectable,
value: isInspectable ? possiblyCollection.models : undefined, // this is the value to show
}
})
}
} |
This code below behaves exactly in the same way, works faster, and framework developer doesn't need to know anything specific about dev tools hooks. if (__REACT_DEVTOOLS_GLOBAL_HOOK__) {
Object.defineProperty( Backbone.Model.prototype, '_innerState', {
get : function(){
return this.attributes; // That's internal key-value hash.
}
});
Object.defineProperty( Backbone.Collection.prototype, '_innerState', {
get : function(){
return this.models; // That's an array of models
}
});
} The decision, whenever it should or shouldn't be guarded with REACT_DEVTOOLS_GLOBAL_HOOK check, is entirely on framework developer. In the real framework it looks like a one-liner, So, what exactly is the benefit in making it more complex? |
@gaperton the benefit is prevention of false positives. Any object can have a property called My solution guarantees interop and prevents accidental false positives. You want to have that kind of certainty in order for your tools to be reliable. |
👍 |
@elektronik2k5 I don't think that such a dramatic increase of the complexity as in your proposal (not to mention that it will work dramatically slower) worth potential benefits of avoiding the risk of occasionally overlapping name in the class member. As there are way cheaper ways to mitigate such a risk. For instance, rename the property
I don't see the solution yet. Just the proposal. But you're welcome to proof its superiority by actually implementing it and creating the PR. |
That's a good idea, in fact. |
@elektronik2k5 From another hand, why not. Just changed an API a bit, so it actually looks much nicer than the usage of raw Updated PR description. // inside Backbone:
if (__REACT_DEVTOOLS_GLOBAL_HOOK__) {
const { addInnerStateInspector } = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (typeof addInnerStateInspector === 'function') {
addInnerStateInspector( Backbone.Model, x => x.attributes );
addInnerStateInspector( Backbone.Collection, x => x.models );
}
} |
+1 |
Guys, please, respond. We need these three issues to be fixed. |
React team is currently busy with rewriting React itself (facebook/react#7925). We recognize it's annoying but we just don't have the capacity to review big changes right now. If this was implemented as support built in on existing JS primitives (e.g. iterables) instead of adding APIs it would be easier to review. Most people who need Immutable (or other) support wouldn't guess that they need to also install a special hook for it to work. So I don't think it's a very good long term approach. |
Dan, people who need Immutable support will just see Immutable stuff
working. They don't need to install any hooks. That API is for framework
developers.
Regarding iterables, there's PR based on them. It's harder to review as the
changes are far more complex, it introduces N^2 complexity instead of
linear (and it is important for large SPA), raises questions like how it
will works in projects requiring transpiration to ES5 (IE support is still
required), and have huge troubles iterating through key-value maps as the
key is not accessible.
And overall approach looks really weird if you would like to customize
appearance of something which is not a collection. Something like Date, for
instance. There are no natural reasons to make it iterable.
…On Fri, Jan 27, 2017 at 6:39 PM Dan Abramov ***@***.***> wrote:
@gaperton <https://github.com/gaperton>
React team is currently busy with rewriting React itself
<https://www.youtube.com/watch?v=aV1271hd9ew> (facebook/react#7925
<facebook/react#7925>). We recognize it's
annoying but we just don't have the capacity to review big changes right
now.
If this was implemented as support built in on existing JS primitives
(e.g. iterables) instead of adding APIs it would be easier to review. Most
people who need Immutable (or other) support wouldn't guess that they need
to also install a special hook for it to work. So I don't think it's a very
good long term approach.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#469 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAcp1g-ro5zcU09pNHmPQAJej-VWtNW8ks5rWoA9gaJpZM4LbS3J>
.
|
Maybe I misunderstood you, but is there a corresponding PR for Immutable that has been reviewed and approved by its maintainers? I'm open to merging this if there is a broad agreement on the hooks between library maintainers but I haven't seen this yet. |
I will implement support for ImmutableJS if this PR will be accepted. Of
course, I'm not going to start a campaign of convincing all the framework
developer to use the API which is not implemented, nor I'm going to fix any
framework in advance just to see this PR to be rejected later. That's too
much, Dan.
…On Fri, Jan 27, 2017 at 7:02 PM Vlad Balin ***@***.***> wrote:
Dan, people who need Immutable support will just see Immutable stuff
working. They don't need to install any hooks. That API is for framework
developers.
Regarding iterables, there's PR based on them. It's harder to review as
the changes are far more complex, it introduces N^2 complexity instead of
linear (and it is important for large SPA), raises questions like how it
will works in projects requiring transpiration to ES5 (IE support is still
required), and have huge troubles iterating through key-value maps as the
key is not accessible.
And overall approach looks really weird if you would like to customize
appearance of something which is not a collection. Something like Date, for
instance. There are no natural reasons to make it iterable.
On Fri, Jan 27, 2017 at 6:39 PM Dan Abramov ***@***.***>
wrote:
@gaperton <https://github.com/gaperton>
React team is currently busy with rewriting React itself
<https://www.youtube.com/watch?v=aV1271hd9ew> (facebook/react#7925
<facebook/react#7925>). We recognize it's
annoying but we just don't have the capacity to review big changes right
now.
If this was implemented as support built in on existing JS primitives
(e.g. iterables) instead of adding APIs it would be easier to review. Most
people who need Immutable (or other) support wouldn't guess that they need
to also install a special hook for it to work. So I don't think it's a very
good long term approach.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#469 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAcp1g-ro5zcU09pNHmPQAJej-VWtNW8ks5rWoA9gaJpZM4LbS3J>
.
|
Just to remind you - currently Date shown as empty object, attempt to
access objects with "get" properties throws exceptions, and there is no way
to make custom framework's object to look good at all. Community live with
these problems for more than half a year. They make Dev Tools almost
unusable on anything but small examples.
I see nothing harmful in introducing the experimental dev tools hook API.
What can go wrong with it, Dan? :)
…On Fri, Jan 27, 2017 at 7:10 PM Vlad Balin ***@***.***> wrote:
I will implement support for ImmutableJS if this PR will be accepted. Of
course, I'm not going to start a campaign of convincing all the framework
developer to use the API which is not implemented, nor I'm going to fix any
framework in advance just to see this PR to be rejected later. That's too
much, Dan.
On Fri, Jan 27, 2017 at 7:02 PM Vlad Balin ***@***.***> wrote:
Dan, people who need Immutable support will just see Immutable stuff
working. They don't need to install any hooks. That API is for framework
developers.
Regarding iterables, there's PR based on them. It's harder to review as
the changes are far more complex, it introduces N^2 complexity instead of
linear (and it is important for large SPA), raises questions like how it
will works in projects requiring transpiration to ES5 (IE support is still
required), and have huge troubles iterating through key-value maps as the
key is not accessible.
And overall approach looks really weird if you would like to customize
appearance of something which is not a collection. Something like Date, for
instance. There are no natural reasons to make it iterable.
On Fri, Jan 27, 2017 at 6:39 PM Dan Abramov ***@***.***>
wrote:
@gaperton <https://github.com/gaperton>
React team is currently busy with rewriting React itself
<https://www.youtube.com/watch?v=aV1271hd9ew> (facebook/react#7925
<facebook/react#7925>). We recognize it's
annoying but we just don't have the capacity to review big changes right
now.
If this was implemented as support built in on existing JS primitives
(e.g. iterables) instead of adding APIs it would be easier to review. Most
people who need Immutable (or other) support wouldn't guess that they need
to also install a special hook for it to work. So I don't think it's a very
good long term approach.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#469 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAcp1g-ro5zcU09pNHmPQAJej-VWtNW8ks5rWoA9gaJpZM4LbS3J>
.
|
Could you send a fix for that in particular? It shouldn’t be hard to detect a native Date.
Why? Could we also fix this by doing whatever Chrome DevTools is doing for them? It doesn’t seem like this would require custom hooks either.
The reason I’m asking is it is much harder to get support from libraries than from us. I would like to see Immutable maintainers to at least agree to an RFC proposal (you don't have to send a PR) before proceeding with this. Since you approach this as a generic solution that requires library opt-in it makes sense to first get some feedback and commitment from library authors on the API. If you think Immutable maintainers won't accept this PR unless we also merge its support, doesn't it raise any issues about the approach itself? |
The fix for Date currently relies on While it can be done, I don't understand why do you think it's beneficial to rewrite the code in the way that it would be hard to do the same thing for any other data type. Including RegExp, byte arrays, files, etc. What exactly is the benefit in not exposing an API which make the fix for Date looks trivial? |
Good question, Dan. Here's the ticket about it. #390 |
Seems like it has a proposed solution: #390 (comment).
Right—the difference is that unlike the solution with a new API, it's easy to merge because we don't need to agree on the API, only on the implementation.
Once you add an API you can't easily break it as people come to rely on it. I'm not convinced this is the best API, or even that a public-facing API for injecting monitors is desirable. I agree though that native JavaScript objects that commonly appear as props should be rendered well. |
Dan, I have no idea will they accept it or not. Regarding ImmutableJS, as I said - I will implement support for it and create the corresponding PR. If the PR we are discussing will be accepted. Being framework developer myself, I'm trying to make developer's life better. And I see absolutely no harm, even potential one, in adding experimental API to the dev hook. Even if ImmutableJS maintainers will decide to reject my PR fixing an appearance in Dev Tools, what wrong will happen? This PR is +75/-8 lines of code or so, what are we talking about? Is an idea to expose the hook bad by itself? Why? Will it stop anyone to add inspections for iterables? No, it's a good idea as well. So what? |
Seems like it has a proposed solution: #390 (comment)
<#390 (comment)>
.
Maybe. It also looks like it still doesn't work in dev tools, and you're commenting in the PR which already contains such a solution (just 75 LOCs) :) Is it bad, or what?
Right—the difference is that unlike the solution with a new API, it's easy to merge because we don't need to agree on the API, only on the implementation.
Yes. Thing is that we're not discussing an API for some reason. Didn't even
started.
Once you add an API you can't easily break it as people come to rely on it.
Oh, yeah, it's terribly important, no doubts. Did you look at the API? Can you suggest better API for the purpose than that?
```javascript
addInnerStateInspector( Backbone.Model, x => x.attributes );
```
Or, than that? Which fixes another annoying ticket, and can be an example how an appearance of other built-in types can be fixed.
```javascript
addInnerStateInspector( Date, ( x : Date ) => ({
local : `${ x.toDateString() } ${ x.toTimeString() }`,
iso : x.toISOString(),
timestamp : x.getTime(),
});
```
Is there anything wrong with the API? Confusing? Hard to use? Too restrictive? Too specific? Too much typing? So, what's wrong with it? Any suggestions to make it better?
And don't forget, that we are talking about an API of esoteric thing - `__REACT_DEVTOOLS_GLOBAL_HOOK__`. There will be few people who rely on it. Data framework developers. And there will be much more people who will practically benefit from the capability to customize object representation in Dev Tools.
|
I think that it is extremely unlikely a library like Backbone or Immutable would add React-specific hook support. For this reason, this change won't benefit most users anyway. I also think that the implementation is a bit hacky (e.g. what is Hacky code is fine if it's worth it, but this just seems to adds complexity that we need to understand and maintain in the future, for little gain, as only a tiny portion of our users will know about the hooks (since, as I said earlier, I don't believe either Backbone or Immutable will add such hooks, based on my experience with open source). A generic solution like #459 seems like a better way to achieve these goals. I’m sorry I couldn’t help more. I’m still happy to take PRs fixing specific cases without exposing new APIs (e.g. to fix Dates). |
I'm sorry, but it's me who couldn't help more. Given the quality of the discussion here (where you practically avoiding discussing the matter of the topic and ignoring answers), it's highly unlikely that I will spend any more time contributing to the Dev Tools and any other of your repos. Take care. |
I’m not sure I fully understand what you are referring to. It seems like this PR would only be useful if you could persuade maintainers of Immutable or Backbone to add such hooks. I’m not avoiding anything, I’m just claiming this won’t happen, and you haven’t given any arguments to counter this. I’ve never seen Immutable/Backbone/etc adding view library-specific hooks, and React is not in some sort of unique position to dictate such integrations. What about Angular, Ember, Vue, Preact, etc? It doesn’t make sense for Immutable or Backbone authors to make special concessions for React. If you think it does please explain how this will happen. Talk to those maintainers, invite them to this discussion, demonstrate that you can coordinate this effort. It is your proposal after all. I don’t want to merge something without at least a basic plan, which you have not provided. Your proposal is basically “let’s merge and see what happens”. My answer is that this won’t work—not because I’m avoiding or ignoring you, but because it rests on unrealistic assumptions. I explained why they are unrealistic right above. If you don’t agree please let me know via counter-arguments rather than via assuming bad faith behavior on my end. Thanks! |
@gaearon - @gaperton is a known problematic contributor and we've had issues with him before in other projects. The group of people who commented are all from the same Facebook group where he ranted about it - and you're being the responsible adult here. I know you know this - but I just thought it's worth to have someone else say this out loud. Rock on. |
Oh, yes, I am :). I don't remember we ever intersected in any project, Benjamin, but I do perfectly remember that I blocked you on FB for continuous personal insults :). Let's fix it on github as well. |
Going to lock this thread as it doesn’t seem very productive.
Cheers! |
General problem is that sometimes developers are using data objects which are more sophisticated than raw JS objects and arrays. Typically, these objects are represented as some facade class at the top level holding an actual state inside. Navigating through such an objects in props as well as in state is clumsy and the property inspector is almost unusable.
There is a number of issues on this topic (#83, #52). And there was an attempt to solve it in the PR specifically for ImmutableJS: #149
In this PR I attempt to solve the problem in the way that it would be easy for data framework developers to customize the appearance of data objects in the inspector. I'm doing it to make NestedReact models and collections look good in the inspector, but it's trivial to do it for any other data library including ImmutableJS (which I can do as well to resolve that pool of duplicate issues as soon as this PR will be accepted).
Idea is to attach state inspector functions to the object's prototype, which will take an object instance and return plain JS object or array (whatever is appropriate for the particular case). Whenever an object has state inspector it will be used to transform its state. Using BackboneJS as an example, something like this needs to be done to make models and collections look good:
Another example -
Date
instances currently appears as an empty object (#388). Which is fixed by this PR in the following way:This API can be used internally to improve the appearance of built-in JS classes, by data framework developers to make their custom classes appear well, and by regular developers as well.
In the case of the more sophisticated data structure, the corresponding raw JS representation can be calculated inside of the inspector functions and memorized in the data object's instance (which will work perfectly in case of ImmutableJS).
P.S.: One more issue this PR resolves (#390) is an exception being thrown when you're trying to inspect an object with
get prop(){...}
calculated properties defined on the prototype.