Monday, January 9, 2017

Re: Vue GWT: Vue.JS integration for GWT 2.8


I'm no longer sure that would work. Even if I prefix my "to-go-in-data {}" fields in the Java class with $ so as to signal VueGwt to only put these properties in data {}, Vue monitors the properties defined in data {} recursively. So if I have a field which is OK to go in data {} but the object kept inside this field itself has fields which should not be monitored by Vue, there is no way to tell Vue not to do so... Just look at Vue's state.js & observer.js code...

Indeed the Data model is watched recursively. But this is not too much of an issue in my opinion as long as you don't have recursion in the objects you use in your data model. The way Vue.JS watch data model is by using native JS getter/setter overrides, so if you don't use a property there is not much performance cost (except setting those getter/setter).

I think the "return JSON.parse(JSON.stringify(data));" trick that you do in VueGwtTools.js has to go. 
For one, this call completely disconnects the original set of fields in data {}, from the ones that Vue will monitor. So I'm not sure that the current VueGwt implementation monitors the correct fields at all?

Also, a copy of the data {} is anyway required in Vue.js only when you register a new Vue component (as opposed to just instantiating a new Vue instance): https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
Perhaps the misunderstanding and the mismatch comes from how you register a new component. In  your example, you do it like this:
@JsType  public class RootComponent extends VueComponent  {      public RootComponent()      {          // ChildComponent is registered to be used in our RootComponent          this.registerComponent(new ChildComponent());      }  }

In Java and also with your approach where data {}, props {} methods {} and all are flattened in a single Java object, it would feel much more natural if you do it like this:
@JsType  public class RootComponent extends VueComponent  {      public RootComponent()      {          // ChildComponent is registered to be used in our RootComponent          this.registerComponent(ChildComponent.class);      }  }

... and then VueGwt should map a JS function to the Vue "data" property which function should instantiate a fresh instance of the ChildComponent class, ending up with a separate data {} copy for each new component instance, as is required.
(It is another topic how to do this reflective instantiation of the component with GWT anyway. Perhaps you need a Factory pattern here, in the absence of reflection in GWT?)


For the JSON.stringify call, as you said it disconnects the properties from the actual instance. We could provide two choice (common data model for all components instance, or a factory to get an instance of data model for each component). But no matter what the data properties will get disconnected from the component instance you create to register it.

It is because the Java "Components" are not so much components and more templates for Vue.JS. For example their constructor is never called when a new Component is constructed, only once when registered. So indeed the properties you manipulate on the Java side are not the one you end up manipulating in your JS component.

It's similar to what happens with regular Vue.JS. You usually declare your "data" object (or function returning new instance of data) and next to it the methods.
If in your data you have a property "hello", in your component methods you do "this.hello", but the "this" at the moment of declaration is going to be your component instance with it's own data when your component will be instantiated.

So in the Java Component, the "this.hello" you do, even though in the Java code it references the hello attribute of your Component class, at runtime it won't be, it will just be a hello attribute on a Vue instance created by Vue.

So I totally agree with you when you say it would feel way more natural to pass the Class to register the component. This will be how it works if we use Annotations (because as you said, we can't create instance on the fly with GWT :(). Components could even be abstract, to show that they should not be instantiated directly.

 
That would be nice. I have no experience with annotation processors myself, unfortunately. I think Angular2-Gwt uses this approach, isn't it? Perhaps you can contact the Angular2-Gwt maintainer for further info on the subject.

But then: even with that approach you have the "recursion" problem I mentioned at the top of my reply (Vue.js traversing all properties in data {} recursively), isn't it?

Yes it's indeed how they do it. I'll make sure to ask them some advice :).
And yes we would still get the recursivity issue. It would indeed be a limitation compared to what you can do in Java (meaning not being able to have recursive data structure). I don't think that would be that big of an issue but I guess it depends on your app data model.

If you have a data model with lots of reference (like a User, reference a UserRepository that reference everything etc...), then indeed exposing the User in the component Data would make Vue observe the whole User repository in each component. But you would have exactly the same issue in vanilla Vue.JS, this is why they recommend in documentation for the objects in the component to be simple.

Thank you again for all your remarks :), I really appreciate your feedback!

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment