cujojs / wire

A light, fast, flexible Javascript IOC container

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

properties interfering with after advice

skiadas opened this issue · comments

I ran into the following weird situation, that I managed to narrow down to the following. Imagine the following wire spec:

define({
  anotherResource: 'hi there!',
  sidebar: {
    create: 'workspace',
    after: { 'app.getWorkspace': 'render' }
  },
  app: {
    create: 'app',
    ready: 'getWorkspace',
    properties: { oops: { $ref: 'anotherResource' } }
  },
  $plugins: [ 'wire/aop', 'wire/connect' ]
});

The 'workspace.js' module simply returns a constructor function for objects with one method, called 'render'. Similarly, 'app.js' returns a constructor function for objects with one method, called getWorkspace. They each have a console.log in them.

Now what should be happening with the above code, I believe, is that when things are wired up, I would be seeing both console.logs. However, only getWorkspace fires up.

If we comment out the "properties" line, then both app.getWorkspace and sidebar.render fire up.
If we put the after clause in the app section instead, as:

after: { 'getWorkspace': 'sidebar.render' }

Then that works fine with or without the properties.
If the properties are in the sidebar instead, then that works fine as well regardless where the "after" clause goes.

To make things even crazier, if both sidebar and app have "properties", then after works fine regardless of where it is.

So the problem seems to be focused on "after" advices in a very specific case:

  1. component1 does not have properties
  2. component2 does have properties
  3. component1 has an after advice of the form: after: { 'component2.method1': 'method2' }

In this case the advice does not appear to get triggered.

Seems like a bug to me, or am I missing something?

I'm having another problem that may or may not be related. It appears a "connect" i'm trying to perform is not working as expected, as in not at all. It sort of works earlier in the wire process, namely when I link my connect to a method that gets triggered with a "ready", it works, but when I link it to a method that is triggered by a Backbone.Router route change, it doesn't.

What's the best way to troubleshoot these connection problems? Or any way really? I feel like stumbling in the dark at the moment, wire/debug doesn't seem to provide enough info on that part.

You original case is very odd indeed, and certainly sounds like a bug. I'll try to reproduce it and let you know what I find.

As for debugging connections, yeah, it's a bit trickier than it should be right now, unfortunately. We've slowly been making progress in that area. For example, we've recently improved handling of connection cycles by allowing component references to be resolved earlier, and by detecting cycles that simply cannot be resolved (thus creating deadlock), and failing loudly/informatively in those cases.

It'd definitely be cool to find more ways to debug and/or visualize connections and connection failures.

A little more on this: It seems if I use the "after" advice as:

after: {
    component2: {
        'method1': 'method2' 
    }
}

That seems to be more likely to work, than after: { 'component2.method1': 'method2' }. Hope that helps troubleshoot this.

Very strange indeed. Those two cases are effectively equivalent. The latter simply splits the string and then behaves like the former. My time was pretty much consumed with other things this week, but I got back to wire-related things today, so hopefully on Monday I can look into this.

As for Backbone.Router, it's likely a problem with it capturing/binding a direct reference to the function. I'm not sure what we can do there, other than deal with it via a wire plugin that allows more controlled usage of Backbone routing in wire.

Yeah a wire plugin will be the way to go for routing in general eventually. Backbone.Router isn't really doing much anyway, should be easy to reproduce its functionality.

I have a workaround for now, where Backbone.Router links routes to private methods of it, which simply turn around and call public methods. So I have something like:

routes: {
   'structure/:id': '_getStructure'
}
_getStructure: function(id) {
   this.getStructure(id)
}
getStructure: function(id) {
    // Other components can connect to this method
}

An extra function call, and a tad kludgy, but it works ;).

But yeah the "after" problem is bizarre to say the least. I haven't had time to look at it either.