The Growth team has been working on migrating existing software (mentee overview module on Special:MentorDashboard, T300532) and creating new projects (Impact module on Special:Homepage, T222310).
While working on those projects, we've periodically reached out to Design-System-Team colleagues and received useful feedback and code review comments (thank you!). That has mostly happened in the context of fairly narrow questions. This task is to request a high-level review of our Vue code, how we've used Codex components. The reason for doing that is that there aren't many examples to draw upon in the MediaWiki ecosystem, so it's hard to know if we're doing things the best way.
Some goals for this review:
- ensure we're following best practices and latest guidance, per the product development best practices playbook
- see if there are areas to improve our code
- identify components that could be upstreamed from GrowthExperiments code
- document pain points in working with Codex / Vue in MediaWiki
I could see this audit working in a few ways:
- a synchronous meeting, 1:1 with a DST engineer and one or more Growth engineers to walk through code and talk through what we built
- write up questions/notes asynchronously to allow more time from DST engineers to look through the GrowthExperiments codebase
- a combination of the above
I'm optimistically hoping this would be a ~2 hour time commitment from both sides.
If this doesn't fit into your schedules this quarter, that's not a problem, but if it does, let us know how you'd like to move forward with something like this.
GrowthExperiments Vue modules
Module name / script path | Link to code | Notes |
ext.growthExperiments.Homepage.NewImpact | Browse code | Used in Special:Homepage |
ext.growthExperiments.MentorDashboard/MentorDashboard | Browse code | Used in Special:MentorDashboard |
vue-components | Browse code | Bucket for Vue re-usable components and utils |
Review questions
Question | Context | Possible actions |
How to prevent an undefined property inside an SFC template that can go to production? | The patch User impact: add disabled and unactivated state introduced an undefined variable when creating a new component: NoEditsDisplay.vue. Inside the template tag there's a property bind using "mode" variable: :size="mode !== 'desktop' && 'sm'" which is undefined. | The error could had been caught with a unit test but a a linting error should be also possible and avoid bugs in non-tested components |
What's the recommended practice for writing and loading styles for both server and client? | Growth Team built a skeleton interface for the user impact module to improve the javascript and data loading experience (T321675: NewImpact: Create skeleton loading state). Styles from the client components were reused and some ad-hoc styles were added for the markup rendered on the server (see patch User impact: add skeleton markup while JavaScript loads). The goal is to build interfaces that present some minimal content while javascript loads. | Design Systems Team is working on CSS-only versions of Codex components that can be loaded in advance of JS initialization, something we hope to have ready soon. For components developed by Growth, it's not ideal but you could move LESS styles into separate files and then ensure that the styles get loaded on the server. This is the approach that Structured Data followed when developing MediaSearch. Finally, this seems like a possible new feature to consider adding to ResourceLoader: RL is already pulling out the styles from Vue components, so maybe we can enable loading them independently from JS. In general it would be great to allow addModuleStyles to work with any RL module, whether it also has a JS portion or not. |
What would be the best setup for reusing interfaces between desktop and mobile? | GrowthExperiments Special:Homepage contains several JS modules (some using OOUI some Codex) that can be enabled based on different configurations. The modules have a consistent appearance across mobile and desktop sites. On mobile the content is rendered inside an overlay provided by MobileFrontend. Advice on how to reuse interfaces across modules in the same Special page and across different special pages is appreciated. The current setup creates a new Vue mwApp for each platform. The components are then tweaked based on an injected property. Working on a functional setup of vue-router with some mobile navigation system could be helpful. Also for having several "views" on the same page and avoid the mount boilerplating. | I would recommend trying to solve this problem in CSS as much as possible. Say you need slightly different styling on a component based on the mode property of the top-level app (overlay vs regular mode, etc). Instead of passing the mode throughout layers of components or using provide/inject, would it be possible to just write your component CSS so that a different set of styles come into play when the outer App or Layout component (which is aware of the "mode") adds a different CSS class? For example, inside your Scorecard component, you could write some nested LESS rules that only apply when the parent element has an .mode--overlay modifier class. |
How to consistently display OOUI and Codex icons and fonts? | GrowthExperiments features mix OOUI and Codex interfaces. Having a consistent way to display icons and fonts will help to create consistency while the two libraries coexist | I think the answer here is to increase reliance everywhere on the Codex design tokens. Some work is currently underway to make it easier to use them inside MW skins and extensions (see T325237). |
How to allow portability of GrowthExperiments Vue components? | Allowing portability of GrowthExperiments components to other contexts like Codex or an automated documentation tool could be helpful. Is there a Vue "recipe" that GrowthExperiments could adopt and would facilitate: (a) upstream of components to Codex (b) Autogenerated documentation with a vite or similar | Growth could consider developing its Vue components in an external library (outside of MW) similar to how Codex is developed. This would allow a couple of benefits: components could be written in a standard way, you could use Typescript and other front-end build tools like Vite; you could compile your components for use inside of MW but also deploy a stand-alone documentation site using something like Vitepress, and you could split out your CSS styles into a separate file that you could load independently. If Growth has a large-enough amount of custom components, this approach might be worth exploring. In this situation a lot of the existing Codex Vite configuration could be re-used, and DST could help you with initial setup. |
How to monitor application errors, performance, memory leaks, etc? | Are there recommended patterns (eg: patch Instrumentation: Monitor navigation duration, transferSize, first paint), tools for CI or local development (eg: Vue devtools) to monitor Vue specific app metrics. | Consider using the logger plugin that you already have and enhancing it with a few additional methods – that will also help to de-clutter your components. |
Is there a way to programmatically spot uneeded reactivity? | Using Vue's reactivity API is meant to be used when the nature of the data is changing. However in the GrowthExperiments extension some features load a significant amount of data from the server in JS config vars and then mount a Vue application with the data in place so reactivity is not really useful. Is there a way to programmatically find this situation? Is it relevant from a performance point of view? | Vue has some tools for this (v-once, etc) but I'm not sure you'd see any performance benefit unless you are rendering a lot of components in the user's browser. |