Here we are again talking about mixins :) There isn't actually an issue on mdn/content yet that will formally decide about mixins, so I'm opening this one. Fun fun fun!
Please also read https://github.com/mdn/browser-compat-data/issues/472 for prior discussions.
And if you are concerned about how inheritance structures (as opposed to mixins) are documented, then please read https://github.com/mdn/content/issues/1006.
So, observing mixins in the wild and deciding how to document them. I recently chatted to Rachel Andrew about this and here's what my take has been:
The idea is to document Aria attributes. A spec for them is here https://www.w3.org/TR/wai-aria-1.2/#AriaAttributes and the idl looks like this:
interface mixin AriaAttributes {
attribute DOMString? ariaActiveDescendant;
attribute DOMString? manymoreattributes;
}
Element includes AriaAttributes;
Now, as an MDN writer who uses WebIDL heavily to determine how and where to document things, you are not given a guideline where to document ariaActiveDescendant and friends, and so there are two options basically:
docs/Web/API/AriaAttributes/ariaActiveDescendantdocs/Web/API/Element/ariaActiveDescendantOption 1. exposes the mixin to the world of web developers and option 2. hides this abstraction.
I recommended option 2. and so why did I do that?
AriaAttributes anymore, it is now called ARIAMixin. Consequently, with option 1. the page would need to move to docs/Web/API/ARIAMixin/ariaActiveDescendant and BCD would need to be updated, etc. But why? It doesn't really matter to web developers because Element.ariaActiveDescendant is going to be there no matter where in the spec or in IDL it has been defined.On MDN, we can find API docs that do not hide the mixins however. Why is that? Example:
So, I guess the idea here is that mixins add features to multiple interfaces and so having to duplicate docs for every interface they appear on, should be avoided. Does that make sense, though? Mixins can disappear and be renamed still. Even in this case the docs make it quite confusing to the readers.
Feedback welcome.
My own natural inclination is the same as your, option (2) above; I guess the questions of duplication of content will be key to figure out implementability though.
I have always been an advocate of option 2. (I should note that while Chrome does use mixins in our IDL, we don't always use the ones listed in web specs. Rachel and I bumped into an example of this last week, which I can't seem to find at the moment.)
It seems to me that to do this properly, there should be some kind of inclusion mechanism for both MDN pages and BCD. I don't know what that needs to look like.
Hm, I searched Microsoft/TypeScript repo but couldn't find any reference there.
I wonder how they implement it.
Alternatively: Does Facebook's Flow has support for this ootb?
So requestAnimationFrame and cancelAnimationFrame used to be Window only methods, but it were recently been added to DedicatedWorkerGlobalScope (well both really) via the mixin:
interface mixin AnimationFrameProvider {
unsigned long requestAnimationFrame(FrameRequestCallback callback);
undefined cancelAnimationFrame(unsigned long handle);
};
Other cases I've seen document this in the mixin and then refer to it in Window say as "methods documented in other classes". What is it you see happening here - it gets documented in both places?
For reference: https://github.com/mdn/content/issues/1519
In the short term, yes. (I know. 😞). In the long term we need some kind of inclusion mechanism. This is the only way to keep information out of MDN that has no relevance to writing an actual script.
Thanks @jpmedley. We do "kind of" have page inclusion now via a macro - that might be able to pull specific sections for methods from mixin docs into relevant pages? That mechanism feels fragile to me though.
It would be lovely for a mixin to also be able to be a mixin in the docs :)
For now it would just be good to have a way forward that works for the majority of cases and that doesn't close the door on being able to address it in a better way in future. At least if we know where all the examples are, and they have been documented in a consistent way that should make it easier to convert them to some kind of inclusion mechanism in future.
I will highlights once I come across as I'm working. My open PRs for TextEncoderStream and TextDecoderStream both reference properties included via mixin.
For example: https://encoding.spec.whatwg.org/#interface-textdecoderstream includes TextDecoderCommon and GenericTransformStream. In this case I have documented these as if they were regular properties which is as option 2.
So ... if I am adding ARIAMixin, which was AriaAttributes to Element, for BCD does that mean adding all of these to the 9000+ line long Element BCD file?
So ... if I am adding ARIAMixin, which was AriaAttributes to Element, for BCD does that mean adding all of these to the 9000+ line long Element BCD file?
I've proposed a solution for BCD in https://github.com/mdn/browser-compat-data/issues/8929
I've made a proof of concept using HTMLHyperlinkElementUtils: https://github.com/mdn/content/pull/2046
I really like this proposal. I think it does what we've needed to do for a long time now. I also agree with the BCD approach outlined in mdn/browser-compat-data#8929. Having a separate file for the stuff defined in a mixin really does help make sense of it all in terms of the compat data.
For quite some time I've thought that we should define mixins in separate page sets, and then have some kind of clever way of slurping them into the actual pages we want readers to see, e.g. have a separate set of https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils pages, but then in the final build render separate https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement and https://developer.mozilla.org/en-US/docs/Web/API/HTMLAreaElement pages based on them.
However, as I think about the implementation of this more, I wonder if that would be worth the effort. You would still need separate descriptions, syntax, examples, BCD, etc. for the two different page sets, if you were doing it properly.
I am going to go and review some of @Elchi3 's proof of concepts now, to see if any issues present themselves. If not, I'd say let's write this up in the MDN meta docs, and move forward with this way of doing things.
I'm very happy to see mixins being phased out, but want to quote what I said about WindowOrWorkerGlobalScope in the BCD issue:
We could naively flatten these mixins and end up with
api.Window.fetch+api.WorkerGlobalScope.fetchinstead ofapi.WindowOrWorkerGlobalScope.fetch. However, I think we should treat these mixins as different from all the rest.It's an accident of how Web IDL works that the exposure set of interfaces like
Requestis defined using[Exposed=(Window,Worker)]while the exposure set of methods likefetchis defined usingpartial interface mixin WindowOrWorkerGlobalScope. In MDN documentation and in BCD, I think we should find a common way to represent the worker exposure. Many different approaches could work, but my first suggestion would beapi.WindowOrWorkerGlobalScope.fetch→api.fetchand working through the many consequences of that.However, I think it would be smart to set
WindowOrWorkerGlobalScopeaside in the mixin flattening, and sort it out in a later step, because the issues are very different.
Thanks @foolip, I agree to leave this out for now and worry about it later. I also assume there will be exceptions to our new mixin documentation convention because the Web is not defined very consistently :)
I've sent https://github.com/mdn/content/pull/2366 to update mixins in the MDN contribution docs according to the discussion here.
To-Do list for existing docs that need updates/refactoring/moving/deletion:
Unfortunately, I run into issues when moving pages around, so it is a bit slow going and hairy on the MDN side of things. We made some progress on the BCD side already, though. See https://github.com/mdn/browser-compat-data/issues/8929
Also, for mixins that exists for workers, it might be a bit more complicated and we're still figuring things out. However, for mixins that don't touch on the worker topic, docs and compat data are vastly improved thanks to this effort.
Many different approaches could work, but my first suggestion would be api.WindowOrWorkerGlobalScope.fetch → api.fetch and working through the many consequences of that.
That would resolve to a path like /api/fetch. Since I can call fetch() without reference to a global or instantiated object, that would work. But is that generally true of everything with WindowOrWorkerGlobalScope? I don't want to replace one thing that looks like a real code reference but isn't with another thing that looks like a real code reference but isn't.
Many different approaches could work, but my first suggestion would be api.WindowOrWorkerGlobalScope.fetch → api.fetch and working through the many consequences of that.
That would resolve to a path like /api/fetch. Since I can call fetch() without reference to a global or instantiated object, that would work. But is that generally true of everything with WindowOrWorkerGlobalScope? I don't want to replace one thing that looks like a real code reference but isn't with another thing that looks like a real code reference but isn't.
This is the right question to ask! For all of the methods on WindowOrWorkerGlobalScope, I believe invoking them directly as fetch() rather than self.fetch() is idiomatic. They are: atob(), btoa(), clearInterval(), clearTimeout(), createImageBitmap(), fetch(), queueMicrotask(), setInterval(), setTimeout().
For attributes, while they can be accessed directly, I think for at least these it's more idiomatic to access them via the global object, because it makes it clear they're not local variables: self.crossOriginIsolated, self.isSecureContext, self.origin.
Then there's caches and indexedDB, where I suspect there's more variation in style. I'd certainly write indexedDB.open(...), but the example uses window.indexedDB.open('toDoList').
On the URL, another option would be /api/Global_Objects/fetch, more analogous to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
I think that looking at the members of Window and WorkerGlobalScope will reveal more tricky cases. I think especially a method like window.resizeTo(), while it can be invoked as just resizeTo(), would not be great to give the same treatment as fetch().
That sounds like problems with how we need to explain them on actual pages. I've created an issue capture this.
FWIW, I think it would be a good idea to move these under Global_Obects.
Most helpful comment
I'm very happy to see mixins being phased out, but want to quote what I said about
WindowOrWorkerGlobalScopein the BCD issue: