alpinejs-devtools icon indicating copy to clipboard operation
alpinejs-devtools copied to clipboard

Track custom events being `$dispatch`-ed

Open HugoDF opened this issue 5 years ago • 9 comments

This is again inspired by Vue.js Devtool's "events" tab, obviously Alpine.js doesn't use synthetic events or emit events to communicate between components.

~~Instead we should register a top-level listener for events being dispatched with $dispatch (which we can detect) eg. we can read @click="$dispatch('my-custom-event') which means we should listen to 'my-custom-event' at the top-level (using document.addEventListener) and then report their contents in a tab.~~

Any thoughts/ideas limitations you can think of @ryangjchandler @Te7a-Houdini ?

We probably want a new panel for this.

Update 1

With Alpine latest we can overwrite $dispatch and instrument it (see https://github.com/amaelftah/alpinejs-devtools/issues/48#issuecomment-732133163):

It turns out that it's possible to overwrite a magic property 👀 , so we can inject some code that will replace $dispatch and send debug info on call 👍 https://codepen.io/hugodf/pen/xxOvqpg

Note on this: we should check that the suggested $dispatch function override works the same as regular Alpine one, one thing that might be different is which element dispatchEvent is being called on

Update 2

Overwriting $dispatch doesn't behave the same as Alpine implementation see https://codepen.io/hugodf/pen/GRjKgNO?editors=1111 the overriden $event.target is not correct (it's the root of the component, not the element from which $dispatch is called).

A way to get this to work is to monkey-patch dispatchEvent with something like this:

const _dispatchEvent = EventTarget.prototype.dispatchEvent;
EventTarget.prototype.dispatchEvent = function(...args) {
  // send a message to devtools
  // `this` is the element from which `$dispatch` is called
  // `args[0]` is the event name, `args[1]` is the options (including `options.detail`)
  console.log(this, args);
  
  return _dispatchEvent.apply(this, args);
}

This has the advantage of not being Alpine.js specific (eg. if custom events are sent from vanilla JS) + not locking us into a minimum Alpine version.

HugoDF avatar May 09 '20 17:05 HugoDF

Here's the relevant code in Alpine, if we can hook into CustomEvent or el.dispatchEvent that could work

https://github.com/alpinejs/alpine/blob/3c3e8b801a7b00a982dd54290cf656f051e915d9/src/component.js#L369

HugoDF avatar Nov 23 '20 11:11 HugoDF

When you say hook in, do you mean monkey-patching the prototype?

ryangjchandler avatar Nov 23 '20 12:11 ryangjchandler

When you say hook in, do you mean monkey-patching the prototype?

Pretty much hahaha

Otherwise we would have to read the DOM and parse custom event names since I don't think you can just register a catch-all event handler for it.

Other ways we could go is a change in the Alpine side which detects devtools and integrates that way or maybe overwriting the $dispatch magic property somehow?

HugoDF avatar Nov 23 '20 12:11 HugoDF

When you say hook in, do you mean monkey-patching the prototype?

Pretty much hahaha

Yeah, I think that could work. Would just be a case of extending EventTarget.dispatchEvent and checking that the element in question has a parent or itself with __x property?

ryangjchandler avatar Nov 23 '20 12:11 ryangjchandler

I think we should do the page -> devtools communication refactor first.

ryangjchandler avatar Nov 23 '20 12:11 ryangjchandler

@ryangjchandler Agreed re- the refactor.

It turns out that it's possible to overwrite a magic property 👀 , so we can inject some code that will replace $dispatch and send debug info on call 👍

https://codepen.io/hugodf/pen/xxOvqpg

Other interesting note is that $dispatch basically doesn't need to be in core any more 😂

HugoDF avatar Nov 23 '20 12:11 HugoDF

@HugoDF Legendary, hadn't even thought about that.

ryangjchandler avatar Nov 23 '20 13:11 ryangjchandler

It turns out that it's possible to overwrite a magic property 👀

Oh nice! We can implement both $refs and $dispatch both now :D

KevinBatdorf avatar Nov 27 '20 13:11 KevinBatdorf

It turns out that it's possible to overwrite a magic property 👀

Oh nice! We can implement both $refs and $dispatch both now :D

well see this update

Overwriting $dispatch doesn't behave the same as Alpine implementation see https://codepen.io/hugodf/pen/GRjKgNO?editors=1111 the overriden $event.target is not correct (it's the root of the component, not the element from which $dispatch is called).

HugoDF avatar Nov 27 '20 14:11 HugoDF