Vue.js/Guidelines

The following guidelines apply to usage of Vue.js inside of MediaWiki

Get Vue.js from ResourceLoader

edit

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. MediaWiki ships with Vue 3.

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

edit

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 (SFCs) is incomplete, and has the following limitations:

Files/tags:

  • .vue files are only supported in package modules (modules that use packageFiles)
  • 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>).

Scripts:

  • <script setup>, syntax used for the Composition API, is not supported. (However, using the Composition API without <script setup> is supported.)
  • Pre-processors, such as <template lang="pug"> or <script lang="ts"> (TypeScript) are not supported.
  • Src Imports are not supported (but support for this feature could potentially be added, if developers find it useful).
  • ES6 import and export are not supported. Instead of import, use require(); instead of export default { ... }; use module.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, and Object.values()/Object.entries().

Stylesheets/styles:

  • Advanced style features, such as <style scoped>, <style module>, and v-bind in styles are not supported.
  • Unlike TypeScript, Less preprocessor via <style lang="less"> is supported.
  • Less styles are processed using MediaWiki's Less processor, which uses an old version of Less! This means, though, that all the features supported in other Less files in MediaWiki are supported here too.
  • To access Codex design tokens and mixins inside Vue files, import MediaWiki skin variables @import 'mediawiki.skin.variables.less'; at the beginning of your style section.

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.

Initialise with createMwApp()

edit

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 internationalisation 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 passes props to the root component, uses a custom plugin and a Pinia store would look like this:

var Vue = require( 'vue' ),
    App = require( './App.vue' ),
    rootProps = { foo: 1, bar: 2 },
    fooPlugin = require( './plugins/foo.js' ),
    Pinia = require( 'pinia' ),
    pinia = Pinia.createPinia();

Vue.createMwApp( App, rootProps )
    .use( fooPlugin )
    .use( pinia )
    // Assuming there's a <div id="my-component-placeholder"> on the page
    .mount( '#my-component-placeholder' );

Don't rely on build tools or server-side rendering

edit

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

edit
MediaWiki version:
1.41

Pinia will be made available in MediaWiki in v1.41. 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

edit

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.