Page MenuHomePhabricator

[EPIC] Enable gadget and user-script developers to use Vue and Codex
Open, LowPublic

Description

As a gadget or user-script developer, I want to be able to use Vue and Codex in my own projects without difficulty

One of the goals of adopting Vue.js for use in MediaWiki T241180 was to better support gadget and user-script developers. In particular, Vue's ability to provide a full set of features without a build step (something that on-wiki script authors will likely never have access to) was a selling point.

The goal of this task is for gadget/user-script developers to have a smooth and well-supported experience in using Vue.js and Codex in their own projects.

Related Objects

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Restricted Application added a subscriber: Aklapper. ยท View Herald TranscriptJul 27 2022, 3:35 PM

@Michael I understand you spent some time exploring how to use Vue.js-based gadgets. Would love to learn about any of your findings here โ€“ are there other things that need to be done to better support gadget authors which are not on the list up above?

@Michael I understand you spent some time exploring how to use Vue.js-based gadgets. Would love to learn about any of your findings here โ€“ are there other things that need to be done to better support gadget authors which are not on the list up above?

So far, I've only explored it in user scripts. There, the main challenge was how to import components from other files. Though that might be less of an issue when developing an actual gadget?
Also, class SFC not working so that one has to handle separately. Though I'm not sure if there is a way around that.

ldelench_wmf renamed this task from Enable gadget and user-script developers to use Vue and Codex to [EPIC] Enable gadget and user-script developers to use Vue and Codex.Nov 17 2022, 11:27 PM

My understanding is that Gadget authors cannot currently use the packageFiles feature of ResourceLoaderย โ€“ they are limited to just defining multiple scripts that get concatenated. While this is not a complete blocker for use of Vue or Codex, the experience would be much better if gadget authors could actually write .vue files and generally structure their code in a modular way.

So in addition to issues with the syntax checker, we may need to update the gadget definitions to support PackageFiles and .vue single-file components.

In the meantime, I think that gadget authors could use Vue's little-discussed ability to provide component templates as <script type="text/x-template"> tags on the page. For example, it's possible to do this:

// load this script tag on the page somehow first
<script type="text/x-template" target="my-component-template">
<h1>{{ message }}</h1>
</script>
// then initialize your component and use the script as its template, referencing its id
<script>
Vue.component( {
    // define data, methods, computed props as normal
    template: '#my-component-template'
} );
</script>

Ideally, gadgets should support the same content organization that's used in deployed code, ie. .vue files. We'd probably want to generalize our permission system a bit first, it has a bunch of hardcoded checks for .js pages that should apply to other pages containing executable code as well.

Another option would be to implement the template/CSS/JS portions of a Vue component as MCR slots, which would maybe allow more nuanced permission management, but MCR isn't quite ready for that. (Plus, Vue templates can include JS so it would only allow relaxed permissions for the CSS portion; so probably not worth the effort.)

Could we add to the checks for this epic:

  • "Hello World" Dialog example as user script and Gadget exists
    • The state of information about this use case is downright pathetic at the moment. Just having a completely basic "This is how a Gadget can display a Hello World dialog using Codex" example would be a dramatic improvement.
  • Gadgets and user scripts are first-class citizens
    • Current docs, status reports, roadmaps, detailed use cases etc. all talk exclusively about "MediaWiki and extensions"
    • All such contexts should address Gadgets and user scripts explicitly to make sure on-wiki users of Codex are first-class citizens and not an afterthought
  • Gadget- and user script-derived detailed use cases exist
    • For example, a settings or preferences dialog workflow for a Gadget (MW and extensions will use Special:Preferences, but this is not accessible to Gadgets so for them this is a common and primary need)
    • Or remote (other WMF) wiki editing of Wikidata data for this wiki's items: for example, Wikisource needs to provide a local Gadget to edit complex Books data for their hosted works on Wikidata. That's going to want something spreadsheet / data table-like UI-wise, with preferably built-in persistence. It's unlikely core or extensions will have this particular need.
    • And maybe Wikidata is a special case of something datatable-like that's backed with MW:API? Large parts of the Action API are going to give you data that is roughly compatible with a datatable-type display.
    • I'm sure there are lots of others out there once one actually acknowledges them
  • Codex has the richness of widgets and usability to be full replacements for jQuery UI and OOUI for Gadgets
    • There's an example somewhere of the number of lines of code it takes to show a simple dialog in OOUI vs. jQuery UI (let's just say OOUI doesn't look very good in the comparison and leave it at that). Most Gadgets and user scripts are going to be very narrow and focused tools that need a relatively rich library of UI widgets that can be composed with minimal complexity and boilerplate code.
    • Checking that Codex has equivalents for all the currently deployed jQuery UI and OOUI UI widgets, and that they can be used and composed in a simple straightforward way is going to be a good coverage check for Codex.
    • Replacements obviously do not need to be one-to-one, and in some cases definitely should not be. But for any current Gadget or user script using OOUI or jQuery UI widgets it should be possible to point at something in Codex and say "You should start migrating to that" and get approving nods rather than people backing away slowly.
    • The replacements don't actually have to be finished, of course, but sufficiently concrete for Gadget developers to start evaluating it, assessing functionality, and filing Phabs for missing pieces etc. Concrete enough that it's something one can start tracking ala. "This change just landed so now the Foo widgets support Blarfing, which means I can migrate my DWIM code to use Codex."

I've been waiting for OOUI to be a replacement for my jQuery UI-based Gadgets, and now I'm waiting for Codex to become usable. But I don't see any activity, at all, on Codex and on-wiki uses; not even minimal docs or a Hello World example. All code examples and docs assume I'm working in core or extensions, and as a Gadget developer I don't even feel like a second-class citizen yet: I'm a non-entity as far as the docs and examples are concerned. And I very much fear that that impression accurately reflects how much attention the relevant teams are paying to my use case...

I've been waiting for OOUI to be a replacement for my jQuery UI-based Gadgets, and now I'm waiting for Codex to become usable. But I don't see any activity, at all, on Codex and on-wiki uses; not even minimal docs or a Hello World example. All code examples and docs assume I'm working in core or extensions, and as a Gadget developer I don't even feel like a second-class citizen yet: I'm a non-entity as far as the docs and examples are concerned. And I very much fear that that impression accurately reflects how much attention the relevant teams are paying to my use case...

Hi @Xover, thanks for your comment. We (the WMF Design Systems Team) very much want to get to a point where Codex is useful for on-wiki Gadgets and Userscripts. You are correct that this has not been a priority in our work so far, but that is because we are still laying the groundwork for getting Vue and Codex working well in MediaWiki generally (in skins/extensions, etc). The library is also still in a pretty early stage โ€“ย the components that have been developed thus far are solid but there are many we still need to introduce (like a table of some sort). You can see a list of planned and potential future components here: https://www.mediawiki.org/wiki/Design_Systems_Team/Codex_Planned_Components. The Codex board on Phabricator (which is still being organized) also has columns for planned and proposed new components. For what currently exists, you can see documentation and interactive demos here: https://doc.wikimedia.org/codex/latest/

Here's my current understanding of where things are at as far as using Codex in on-wiki Gadgets is concerned:

  • vue and @wikimedia/codex are available in ResourceLoader as modules that you can require now (mw.loader.using( [ 'vue', '@wikimedia/codex' ] ), etc). We took care to ensure that the same names are used in RL and in NPM, so if you are running a development server or unit tests in Node.js, you can get the same libs you'd use on-wiki during development/testing (just specify the packages as devDependencies in package.json if you go that route). You'd also want to declare these dependencies in the gadget definition.
  • ResourceLoader supports .vue single-file components inside of a PackageFiles project with some caveats (see https://www.mediawiki.org/wiki/Vue.js/Guidelines). The Gadgets extension probably needs to be updated to allow .vue files in gadgets the same way we are currently handling them in MW extensions. I know that as of a few years ago there were issues writing ES6-style JS inside gadgets, but maybe that's not a problem any more?
  • As far as code organization is concerned, I'd recommend the following:
    • A top-level init.js file that serves as the PackageFiles entry point; this file would be in charge of mounting your Vue app to the appropriate part of the page, etc
    • An App.vue component (which gets mounted in the above file) that pulls in any other necessary components
    • Other components in single-file component (.vue) format. The script part should define module.exports = { /* vue component options */ }
    • Other stand-alone JS and CSS files as necessary. Styles could also live in <style> tags inside your component files (we have this working in MediaWiki extensions, including for LESS). The Gadgets extension might need some small updates to enable this as well.

So โ€“ย most of the pieces are present but we may need to make minor updates to enable use of .vue files in Gadgets, and of course everything then needs to be documented.

Your suggestion for a "Hello World" Dialog example is a good idea, and I think that's something we could get to relatively soon. Some of the other items you propose (Codex as full replacement for OOUI/jQuery UI) are works in progress but will take a while.

There's an example somewhere of the number of lines of code it takes to show a simple dialog in OOUI vs. jQuery UI (let's just say OOUI doesn't look very good in the comparison and leave it at that). Most Gadgets and user scripts are going to be very narrow and focused tools that need a relatively rich library of UI widgets that can be composed with minimal complexity and boilerplate code.

โ˜๏ธ Once we've removed the various technical blockers, I think that Codex will be a big improvement in this area. We want to provide both staff and community developers with a clean and intuitive way to define UIs. This was one of the original goals of the Vue.js RFC (T241180: RFC: Adopt a modern JavaScript framework for use with MediaWiki) from back in 2019.

There's an example somewhere of the number of lines of code it takes to show a simple dialog in OOUI vs. jQuery UI (let's just say OOUI doesn't look very good in the comparison and leave it at that). โ€ฆ

โ˜๏ธ Once we've removed the various technical blockers, I think that Codex will be a big improvement in this area. โ€ฆ

The comparison was in T155567, in the task description. ~20 lines of dense dense OOUI-specific code using moderately advanced inheritance, custom initializers, a window manager, etc. in order to do the equivalent of window.alert("Hello World!"). The equivalent jQuery UI example is three lines of simple and generic JS and three lines of bog standard HTML. It's so simple that one comment on the task (T155567#2958208) actually thought it was a trick!

Looking at T330350 I see ~90 lines, spread over three files, using a mix of syntaxes (html, css, js, and vue), moderately advanced framework-specific concepts, etc.

Granted this code is prompting for user input and doing something with the result rather than just display a dialog, and it's actually running code rather than just a static code example, but ~90% of those code lines also look like boilerplate that could be abstracted away.

Estimating the number of hours I will have to invest into Vue documentation and tutorials in order to be able to use this example code effectively is a somewhat scary number. Estimating the number of hours invested to be able to create something similar from scratch (because, say, my use case is just different enough that I can't just cut+paste+tweak this code) is beyond scary. I would need to have a pretty massive Gadget in mind in order to justify that investment, or an extremely large number of them to amortise the cost across. And for a lot of my use cases the code for the simple dialog will be larger or as large as the core functionality of the Gadget in terms of lines of code.

Without really evaluating that aspect specifically, I also worry that this will force me into writing the non-UI parts of the Gadget in Vue or using Vue patterns rather than generic JS (not to mention jQuery).

In other words, this appears to me to be a significant barrier to entry for most typical Gadget and user script developers (1โ€“5 gadgets, each of relatively low complexity and length, UI needs relatively simple and secondary to core purpose of gadget). Upside is probably that it enables entirely new use cases for Gadgets, and, presumably, that it'll be an actively supported and modern framework (which jQuery UI sure ain't, and OOUI arguably wasn't in practice).

But as with T155567 I think abstractions and simplifications for the long tail of on-wiki developers needs to go on the roadmap somewhere. Simple widgets that are simple to use for simple use casesโ€”"Hello World in three lines of code"โ€”and from which one can graduate to use the full power and expressivity once the needs justify the added complexity and learning curve.

And just as a ottomh ferinstance / strawman, what if every wiki page out of the box was a running Vue app inside which a Gadget, as a "plugin" to that app, could ask for a simple dialog or other basic UI widget? Analogous to having a MW-provided OOUI window manager and widget factory instead of each Gadget having to create and manage those themselves and individually. Can we put enough of the boilerplate and complexity prepackaged in the default execution environment that simple Gadgets can pretend to live in a simple world?

I'll respond in more detail on T330350 later, but it's now clear to me that the example gadget I wrote isn't the simplest possible thing and contains some advanced concepts. I think you're right that it should be simpler, and I can already think of some ways that it can be simplified. I'll take a stab at that soon.

Per T75714#8878539, we now have a promising-looking alternative for an ES6 (and beyond) syntax validator.

Another issue that came up in T330349 is that Gadgets don't support Less (which was a deliberate decision, see T56864#6153179). I talked to @Krinkle at the hackathon last week and he suggested that we could support Codex tokens in Gadgets by making them available as CSS variables (possibly with tree-shaking so that we only output the variables that are actually used).

Summarizing T330350#8822663 here: in addition to the feedback from T313945#8822617, we should:

  • Explain Vue-specific style/concepts and how all the code in the example gadget hangs together in code comments or on a wiki page
  • If anything from the example can be made generic, we should pull it out or upstream it into MediaWiki
  • Once there's a demo of a first gadget, a running version of it should be hosted somewhere (a Patchdemo, or wikitech, or mediawiki.org, or somewhere) and we should blog about it

@jsn.sherman and I were talking about using Codex in userscripts this week (since he recently wrote one).

Right now it's actually possible to do quite a bit (you can use all of Codex and most of the Vue.js API), but there is some friction because a bit of setup is required. This got me thinking about providing a basic scaffold that userscript authors could use as a starting point. Right now I think that scaffold would look something like this:

( function () {
    let myApp;

    // Define root component (your main interface)
    const rootComponent = {
        name: /* ... */
        template: /* ... */
        data: function () {
            return { /* ... */ }
        }
        // ... etc
    },

    // Set up Vue app and register any Codex components that you wish to use
    // see https://doc.wikimedia.org/codex/latest/components/overview.html 
    // for the full list
    mw.loader.using( [ 'vue', '@wikimedia/codex' ] ).then( ( require ) => {
        const { createMwApp } = require( 'vue' );
        const { CdxButton, CdxDialog } = require( '@wikimedia/codex' );
        myApp = createMwApp( rootComponent )
            .component( CdxButton )
            .component( CdxDialog );
    } );

    // Define a function that adds a container element and mounts app there.
    // A more complex version of this might create a new portlet link or 
    // otherwise integrate in the existing MW page UI
    function init() {
        const container = document.createElement( 'div' );
        container.setAttribute( 'id', '#my-userscript-app' );
        myApp.mount( container );
    }

    // Call the init function when page is ready
    mw.hook( 'wikipage.content' ).add( init );
}() );

I can add something like this to the Vue.js page on MediaWiki, but I thought I'd share it here first to see if there are additional ideas for improvement. (cc: @AlexisJazz โ€“ you were asking a while back about how to get a basic Codex widget on a page, so you may find this helpful)

A lot of the above is boilerplateย โ€“ it's conceivable that we could go a step beyond providing a copy-pastable code sample and expose some kind of function inside of MW that folks could call to set up Vue/Codex userscripts easily. It would be a function that would accept the following arguments:

  • Root component definition (a JS object; this is the main UI that you would be creating). This would need to include the template as a string, but any Codex components could be used here
  • List of Codex components to use in the userscript
  • Init function that controls how this app is set up on a given wiki page (appended to the DOM, controlled by a portlet link, etc)

Would this sort of thing be useful, or more trouble than it's worth?

Anyway, feedback is welcome. I also encourage folks interested in Codex userscripts to take a look at @jsn.sherman's example since it's a complete working widget.

Guides and examples similar to OOUI documentation (e.g. OOUI/Windows/Process Dialogs) and demos would be great.

Guides and examples similar to OOUI documentation (e.g. OOUI/Windows/Process Dialogs) and demos would be great.

Check out the Codex documentation site โ€“ย each component has its own page with interactive demos and corresponding code samples (including copy/pastable MW-compatible ones).

Check out the Codex documentation site โ€“ย each component has its own page with interactive demos and corresponding code samples (including copy/pastable MW-compatible ones).

I'm aware of that site, but I find it too complex for the uninitiated compared to the OOUI documentation on MW Wiki. I want not just fragments but examples of JS code that work on the fly so I can get the hang of it (of which revertrisk.js serves as one, but we could use more in a more "official" place like MW Wiki).