Manual:Coding conventions/Vue

From mediawiki.org
Jump to navigation Jump to search
shortcut: CC/V

This page describes coding conventions for Vue in the MediaWiki codebase. See also the JavaScript and CSS/LESS conventions which apply to such code within Vue files.

Linting[edit]

We use ESLint as our code quality tool, with the Vue profile within the custom config for Wikimedia (eslint-config-wikimedia).

Naming[edit]

Single-file Components[edit]

Vue's single-file components format (.vue) should be used wherever possible. This allows templates, logic, and (optionally) styles for a given component to live together in one file. ResourceLoader supports on-the-fly compilation of .vue files (see here for more info about using Vue with ResourceLoader). This allows developers to write .vue files without needing to rely on any new build tools (Rollup, Webpack, etc), while still benefiting from the various optimizations that ResourceLoader provides for front-end code (RTL styling via CSS Janus, JS minification, etc).

Where possible, Vue code should follow the Vue community's style guide. In particular, all recommendations in "Priority A: Essential" should be followed at all times. Any MediaWiki-specific exceptions will be called out below.

ES5/ResourceLoader[edit]

General Structure[edit]

Single-file components are broken into three sections: <template>, <script>, and <style>; components should follow this order, with the <style> block being optional. Each component file should be listed individually under the packageFiles property in the appropriate module definition in extension.json. Make sure that the module definition also includes the vue module as a dependency.

Template[edit]

  • <template> tags should contain a single root element
  • Component tags must not be self-closing: this is a departure from Vue's style guide recommendations based on current limitations in ResourceLoader. Regardless of whether a component uses slots, it should have a closing tag. This recommendation will likely change to conform to Vue's community style guide once ResourceLoader has been updated to remove this limitation.
    <!-- Do this: -->
    <slot-based-component>
        <h1>Hello world</h1>
    </slot-based-component>
    
    <props-component
      :foo="bar"
      :baz="quux"
      @click="doSomething"
    ></props-component>
    
    <basic-component></basic-component>
    
    <!-- Don't do this: -->
    <props-component
      :foo="bar"
      :baz="quux"
      @click="doSomething"
    />
    
    <basic-component />
    
  • Use the directive short-hands (:foo instead of v-bind:foo, @click instead of v-on:click).
  • Elements with multiple attributes should break them out onto separate lines
  • Component templates should only include simple expressions; for anything more complex, define a computed property or method in the <script> section instead.
  • Message strings in templates must be internationalized just like in standard JS or PHP UI development. The vue resource module in MediaWiki core includes an i18n plugin that provides helper functions and directives to simplify this for most use cases. The $i18n() function is an alias for mw.message() that can be used in template expressions. Template expressions can only return plain text; for messages that contain wikitext that must be parsed to HTML, use the v-i18n-html directive instead.
    <!-- Basic usage -->
    <p>{{ $i18n( 'message-key' ) }}</p>
    
    <!-- Message params are supported as variadic args or as an array; these usages are equivalent -->
    <p>{{ $i18n( 'message-key', param1, param2 ) }}</p>
    <p>{{ $i18n( 'message-key' ).params( [ param1, param2 ] ) }}</p>
    
    <!-- Parsed messages should use the v-i18n-html directive provided by this plugin  -->
    <p v-i18n-html:message-key></p>
    

Script[edit]

  • Code should be written in ES5 and polyfills should be provided for any feature being utilized which may not be present in all Grade-A browsers of MediaWiki's browser support matrix (which still includes IE11 at the time of writing)
  • Single-file components delivered via ResourceLoader should follow the CommonJS module format and should use ResourceLoader's PackageFiles feature. This means that each component file should include a module.exports statement, and should import other code using require()
    var OtherComponent = require( './OtherComponent.js' );
    
    module.exports = {
        name: 'MyComponent',
        components: {
            'other-component': OtherComponent
        }
        
        //... etc.
    };
    
  • Component options should be specified in the order defined here: https://github.com/wikimedia/eslint-config-wikimedia/blob/master/vue-common.json. Generally this means: name, components, mixins, props, data, computed properties, methods, watchers, lifecycle hooks, and finally render functions (in the rare situations where those need to be defined manually).
  • Render functions should be avoided outside of special cases; HTML-style templates are preferred instead. The vue module provided in MediaWiki core is the full version, which includes the template compiler.
  • Use prop definitions and consider specifying defaults or validating data where necessary. Boolean props should have no default (they will implicitly default to false).
  • Avoid implicit parent-child communication and the mutation of received props within a child component. Prefer the "props down / events up" approach

Style[edit]

  • MediaWiki CSS and LESS conventions apply
  • Since each component should contain a single top-level component, styles should be nested under a single selector (if using LESS)
  • Conditional CSS classes should be used for dynamic styles. Object syntax is preferred for computed properties that are bound to class attributes.
  • Since computed property names don't exist in ES5, dynamic class names require an extra step:
    var dynamicClass = 'class-name--' + this.modifier,
        classObject = {};
    
    classObject[ dynamicClass ] = true;
    return classObject;
    
  • Vue transition names should follow the same pattern as CSS class names (e.g. including an extension-specific prefix)

ES6/ResourceLoader[edit]

Coming soon!

Progressive Enhancement[edit]

TBD: define a no-JS fallback for most features you build this way.