Vue.js is the Wikimedia Foundation's official choice for adoption as the JavaScript framework for use within MediaWiki. This page documents guidelines, best practices, and resources for using Vue within MediaWiki. This is not a general guide for using or developing with Vue.js; for that, see the general Vue.js documentation.
Background and History
Vue.js is a modern JavaScript framework used to build interactive user interfaces with ease and consistency. Its component-based approach, performance, approachable paradigms and documentation, and ecosystem of associated libraries make it a powerful tool for building simple or complex UIs. Since Vue is widely used, using it in MediaWiki means many more developers will be able to contribute. Vue is an open-source project supported by a core team and a community of volunteer contributors.
Discussions about adopting a modern JavaScript framework into MediaWiki began in early 2019. In December 2019, an RFC on the subject was started. Vue.js was added to core MediaWiki in February 2020. The NearbyPages extension, the first MediaWiki extension to use Vue.js, was released soon afterwards. The RFC ended in March 2020, with the official decision to use Vue.js (though this decision was not clearly announced until August 2021). WVUI (Wikimedia Vue User Interface), the first attempt at a shared library for Vue.js-based components for use within Wikimedia projects, was created in May 2020. The first MediaWiki version to include Vue.js, and the related Vuex library, was 1.35, released in September 2020. A replacement library for Vue.js within Wikimedia, Codex, was started in September 2021 following feedback from WMDE. WVUI was removed in MediaWiki 1.40 in April 2023. Vue.js within MediaWiki was upgraded from version 2 to 3 in December 2021. In April 2023, Pinia was added to MediaWiki core.
Current Status
Goals
Our goals for the current quarter are captured in our FY22-23 Q4 OKRs. The objectives being:
- Increase WMF + WMDE awareness of DST and Codex.
- Support increased WMF + WMDE adoption of Codex.
- Make progress against known hurdles to future adoption.
Work Streams
Basic Vue.js support in MediaWiki
Done
Vue.js is now shipped as part of MediaWiki core. JS code in skins and extensions can require( 'vue' )
from ResourceLoader just like any other module. Single-file components (.vue
files) are supported via ResourceLoader. See here for guidelines about using Vue.js within MediaWiki.
Development of library of Codex components
In progress
Codex contains a library of components that is under active development. Components are built with Vue.js, and some components also have a CSS-only version that does not require JavaScript. Documentation for Codex can be found here.
- Some components are still being developed; developers may need to supplement Codex components with custom components suitable for their needs. Check out the list of components that we plan to add to Codex.
- This is an open-source project and contributions are welcome! Learn how to contribute a new or updated component.
To learn more about Codex, check out:
- Phabricator workboard (see the Design Systems Team workboard for sorted and prioritized tasks)
- Code (or GitHub mirror)
- Live demo site
Modern user interfaces for all users
In progress
Codex components are currently only available when modern JavaScript is available and once JavaScript has loaded, which would exclude users of older browsers. We would like to find a way to make user interfaces built with Codex work for these users as well.
- See timeline for current status
Design and define design tokens
Done
Design tokens are the smallest pieces of our design system — specifically, they are named entities that store visual design attributes. We use them in place of hard-coded values (such as hex values for color or pixel values for spacing) in order to maintain a scalable and consistent visual system for UI development.
Design tokens are now available for use in MediaWiki.
Support for ES6 across MediaWiki
In progress
MediaWiki is using Vue 3, which dropped support for IE11. Features using Vue.js should ensure they are only delivered to modern browsers by setting "es6": true
in their module definitions.
- Developers of skins and extensions are encouraged to start using ES6 features in their Vue.js code now; Wikimedia's eslint-config rules include a preset for
vue3-es6
that will be useful here. - This is in alignment with current guidelines about how to support legacy browsers like IE11 – in general new JS features should not target these browsers; if they must be supported, a server-rendered fallback should be defined.
- Support for ES6 in gadgets is currently limited due to lack of support in the JS syntax checker. See T75714 for more information.
Vue 2 to Vue 3 Migration
In progress
The provided copy of Vue has been upgraded to the Vue 3 Migration Build. By default, the library will still behave in alignment with the Vue 2 API, but users can opt-in to the Vue 3 behavior by setting appropriate compatibility flags in their code.
- Teams writing new Vue features should opt-in to Vue 3 behavior starting now.
- Teams maintaining existing features (written for Vue 2 originally) should start planning their migrations.
- Eventually the compatibility build will be removed (T289105), and all Vue code must be made Vue 3 compatible.
Guidelines
Get Vue.js from ResourceLoader
Developers should rely on the version of Vue that is already provided via ResourceLoader rather than bundling or vendoring their own copy of the library. Currently MW ships Vue 3 with the Compatibility Build included.
Developers of skins or extensions which list "vue" as a dependency in extension.json
or skin.json
can require the library as they would any other RL module.
const Vue = require( 'vue' );
Developers of gadgets, or of any feature where Vue is to be loaded conditionally, can load the Vue module on the client-side:
mw.loader.using( [ 'vue' ] ).then( function ( require ) {
const Vue = require( 'vue' );
} );
Use Single-file components
MediaWiki supports Vue single-file components (aka .vue
files) within any ResourceLoader module that is using the packageFiles feature. However, MediaWiki's support for single-file components is incomplete, and has the following limitations:
<script setup=''>
is not supported- Advanced style features, such as
<style scoped=''>
,<style module=''>
, andv-bind
in styles are not supported - Src Imports are not supported (but support for this feature could potentially be added, if developers find it useful)
- Pre-processors, such as
<template lang="pug">
or<script lang='ts'>
(TypeScript) are not supported. For styles, only<style lang='less'>
is supported. - LESS styles are processed using MediaWiki's LESS processor, which uses an old version of LESS. On the other hand, this means all the features supported in other LESS files in MediaWiki are supported here too.
- ES6
import
andexport
are not supported. Instead ofimport
, userequire()
; instead ofexport default { ... };
usemodule.exports = { ... };
. Other ES6 syntax is supported. - ES2016 and newer syntax is not supported. Notable examples of unsupported syntax include the spread operator in object literals (
{ foo, ...bar }
),async
/await
, andObject.values()
/Object.entries()
. - Self-closing tags for components (e.g.
<my-component />
) are not supported. Instead, you have to use open and close tags (e.g.<my-component></my-component>
). - Component tags using PascalCase (e.g.
<MyComponent>
) are not supported. Instead, you have to use kebab-case for component names (e.g.<my-component>
). .vue
files are only supported in package modules (modules that usepackageFiles
)
If you try to use an unsupported SFC feature, ResourceLoader will throw an error at runtime. Unsupported JS or template syntax results in a lint error, so make sure you set up linting for your code to catch these, as well as other pitfalls and style guideline violations.
Initialize with createMwApp()
To mount your component to the DOM, use Vue.createMwApp()
. This function works the same as Vue.createApp()
, but adds shared MediaWiki-specific plugins for internationalization and error logging. The code mounting your component should be in a simple init file that requires the top-level component (plus any stores and plugins) and mounts it to a placeholder div. Other logic and UI code should live in other files (for example, the top-level component) as much as possible. Conventionally, the top-level component file is called App.vue
and the init file is called init.js
, unless there are multiple entry points that each have their own top-level component.
A simple example of an init file would look like this:
var Vue = require( 'vue' ),
App = require( './App.vue' );
// Assuming there's a <div id="my-component-placeholder"> on the page
Vue.createMwApp( App ).mount( '#my-component-placeholder' );
A more complex init file that uses a Vuex store and a custom plugin would look like this:
var Vue = require( 'vue' ),
App = require( './App.vue' ),
store = require( './store/index.js' ),
fooPlugin = require( './plugins/foo.js' );
Vue.createMwApp( App )
.use( store )
.use( fooPlugin )
// Assuming there's a <div id="my-component-placeholder"> on the page
.mount( '#my-component-placeholder' );
Write Vue3-compatible code
MediaWiki uses the compatibility build of Vue 3. This means that Vue will try to provide compatibility with Vue 2 code by default, which breaks certain Vue 3 features (in particular v-model
on components, and setting attributes to false
). To avoid this breakage, all new code written for Vue 3 (and old code that has been fully migrated to Vue 3) must set compatConfig: { MODE: 3 }
and compilerOptions: { whitespace: 'condense' }
in the component definition of every component, like this:
// @vue/component
module.exports = exports = {
// Enable Vue 3 mode with compatConfig and compilerOptions
compatConfig: {
MODE: 3
},
compilerOptions: {
whitespace: 'condense'
},
// The rest of your component definition goes here:
components: {
// ...
},
data() {
return {
// ...
};
},
methods: {
// ...
}
// etc.
};
Once all old code written for Vue 2 has been migrated to Vue 3, MediaWiki will migrate to the non-compatibility build of Vue 3. Once that has happened, these compatConfig settings will no longer be necessary.
Don't rely on build tools or server-side rendering
In the wider Vue.js community, developers make frequent use of Node.js build tools like Vite, Rollup, Nuxt.js, etc. MediaWiki is a PHP application, and currently no Node.js service is available for use in production in WMF projects. For the time being, developers working with Vue in MediaWiki must limit themselves to client-side functionality only. The Design Systems Team is currently exploring ways to support a front-end build step or server-side component rendering, but this remains experimental.
Use Pinia for state management
Pinia is available in MediaWiki. Pinia is the new official state management library for use with Vue 3 and successor to Vuex 4. Pinia is recommended for new projects; for existing Vuex-based projects, MediaWiki also makes Vuex 4 available. See also the guide for Vuex to Pinia migrations.
Follow MediaWiki coding conventions
See MediaWiki's Vue coding conventions, which are largely based on the official Vue Style Guide. We use ESLint to enforce these conventions; see here for how to set up ESLint in your repository.
Internationalization
The i18n plugin
The vue
module comes with a small i18n plugin that wraps MediaWiki's i18n system (mw.message
), so you can use MediaWiki i18n messages in your templates. This plugin creates an $i18n()
function that you can use inside templates, which is an alias for mw.message()
. For plain text messages (most cases), you can simply use:
<p>{{ $i18n( 'message-key' ) }}</p>
You can pass parameters either variadically, or as an array:
<p>{{ $i18n( 'message-key', param1, param2 ) }}</p>
<!-- or: -->
<p>{{ $i18n( 'message-key' ).params( [ param1, param2 ] ) }}</p>
The $i18n()
function returns a Message object, so you can use it in all the same ways that you can use mw.message()
in "normal" JS code. Remember that all message keys you use have to be added to the "messages"
array in the ResourceLoader module definition.
Parsed messages
Because parsed messages return HTML rather than text, they have to be invoked differently:
<!-- Parsed message without parameters: -->
<p v-i18n-html:category-empty></p>
<!-- Parsed message with array of parameters: -->
<p v-i18n-html:namespace-protected="[ namespaceName ]"></p>
<!-- Parsed message with dynamic message name: -->
<p v-i18n-html="msgNameVariable"></p>
Note that <p>{{ $i18n( 'category-empty' ).parse() }}</p>
doesn't work, because the {{ variable }}
syntax only works for text, not HTML. If you try to use a parsed message this way, the user will see the resulting HTML as plain text.
See the documentation comments in resources/src/vue/i18n.js
for a more detailed explanation of v-i18n-html
.
Complex use cases
If the parameters to a message are complex, or if both the message name and its parameters are dynamic, it may be better to create a computed property for the message, as follows:
<template>
<p v-i18n-html="fooOrBarMsg"></p>
</template>
<script>
module.exports = {
computed: {
fooOrBarMsg: function () {
// Note that this returns a Message object, not a string
return mw.message( this.foo ? 'foo-msg' : 'bar-msg' )
.params( [ this.baz, this.quux ] );
}
}
};
</script>
Other topics
Testing
You should write tests! The current recommendation is to use Jest.
See the Vue.js testing guide for more information about how to test Vue components in a MediaWiki environment.
Error reporting
Client side errors can be monitored in Logstash. Dedicated documentation forthcoming in T248884.
TypeScript
(coming soon)
IE 11
As MediaWiki is using Vue 3, any features built with it will not work with IE11. See Compatibility/IE11 for more information.
Projects using Vue.js
Project | Author | Status | Components | Docs | Source Code | Notes |
---|---|---|---|---|---|---|
Desktop Improvements Typeahead Search | Web Team | In Production | Codex | Desktop Improvements | Part of Vector 2022 | The initial pilot project for Vue.js usage in MediaWiki. This project was originally developed using WVUI (Web Team Vue 2 component library), but has since been migrated to Codex. The TypeaheadSearch component itself lives within the Codex library and can be used elsewhere. |
QuickSurveys Extension | Web Team | In Production | Codex | Extension:QuickSurveys | Gerrit | Originally developed using WVUI, QuickSurveys has been migrated to Codex as of July 2022. |
RelatedArticles Extension | Web Team | Bootstrap version in production; Vue.js port in progress | Codex port in progress | Extension:RelatedArticles | Gerrit | Deployment of Vue.js version is currently blocked until some questions around performance/SSR can be resolved. |
NearbyPages Extension | Web Team | In Development | WVUI (Codex port in progress) | Extension:NearbyPages | Gerrit | NearbyPages was originally part of MobileFrontend extension; it is being migrated to Vue & Codex as part of its refactor into a stand-alone extension that can be used more widely. |
ReadingLists extension | Web Team | In Production | Codex | Extension:ReadingLists | Gerrit | |
WikiSearchFront (extension) | Robis Koopmans (Wikibase Soltuions) | Released | MW 1.31+; ships with its own vue.min.js | Extension:WikiSearchFront | Github | Front-end for the WikiSearch extension |
Wikibase Termbox | WMDE | In Production (mobile only) | Wikit | WMDE developed a stand-alone SSR service to support this feature. | ||
Wikidata Bridge | WMDE | In Production | Wikit | Wikidata bridge | Gerrit | Currently on selected wikis only |
Wikibase Tainted References | WMDE | Gerrit | ||||
Wikidata Query Builder | WMDE | In Production | Wikit | Query Builder | Gerrit | |
Commons MediaSearch | Structured Data Team | In Production | Structured Data custom components | Extension:MediaSearch | Gerrit | Still running in Vue 2 compat mode. The development of this feature was written about in a Wikimedia Tech Blog post. Provides a fallback no-js interface using PHP and Mustache; the Vue-based UI replaces this when JS initializes. |
Commons Suggested Tags | Structured Data Team | In Production | Structured Data custom components | Extension:MachineVision | Gerrit | Still running in Vue 2 compat mode. The development of this feature was written about in a Wikimedia Tech Blog post. |
SearchVue Extension | Structured Data Team | In Development | ?? | Extension:SearchVue | Gerrit | Experimental project. Will adapt some of the UI elements from MediaSearch to enhance the standard search page. |
Growth Experiments Mentor Dashboard | Growth Team | In production | Codex, custom components | Extension:GrowthExperiments | See T297763 | |
Growth Experiments New Impact module | Growth Team | In production | Codex, custom components | Extension:GrowthExperiments | https://phabricator.wikimedia.org/T222310 | |
Content Translation 3 (CX3) | Language Team | In Production | MW components (see here for source) | Extension:ContentTranslationContent translation/Section translation | Gerrit | One of the first MediaWiki features to adopt Vue.js. This feature is developed as a stand-alone application outside of MediaWiki and bundled using Vite. More info about the development of CX3 can be found here. |
WikiLambda | Abstract Wikipedia Team | In Development | Codex | Extension:WikiLambda | Gerrit | DST collaborated with Abstract Wikipedia team to alpha-test some Codex components in this project. |
WikiLove | Unmaintained | In production | Codex (minimally) | Extension:WikiLove | Gerrit | A minimal port to Vue was done by Jon Robson, but more work remains (e.g. using the Codex Dialog component) |
VueTest | Design Systems Team | Experimental | Vue 3 (compat. mode)/Codex | Extension:VueTest | Gerrit | Sandbox and testing ground for Vue.js code in MediaWiki. |
Toolhub | Wikimedia Technical Engagement | In Production | Custom components | Toolhub on Meta-wiki | Gerrit | Developed outside of MediaWiki using Vue-CLI. Vue 2 application. |
CodexExample | Design Systems Team | Experimental | Codex | Extension:CodexExample | GitLab | Example MediaWiki extension that uses Codex components (Vue and CSS-only), design tokens, and icons |
Resources
Most important
Additional
Training vendors
- Vue School
- Frontend Masters
- Vue Mastery (includes some free courses too)
Further reading
From around MediaWiki
- Successful Technical RFC on evaluating front-end frameworks within the MediaWiki ecosystem
- 2020: The Year in Vue from the Wikimedia Tech Blog
External organizations choosing Vue
GitLab
Subpages
Special:Prefixindex/Vue.js/