Stable interface policy/Frontend

From mediawiki.org

The stable interface policy for MediaWiki frontend code (CSS, JavaScript and HTML) defines what parts of the software are considered stable and safe for use by browser-based code from other components.

For guidelines on PHP, see stable interface policy . The frontend stable interface policy is maintained separately from the PHP stable interface policy due to the difference in audience and scope (e.g. this policy also addresses gadget developers).

This document applies to all developers of browser-based code that relies on MediaWiki. The scope of this policy regards wiki-hosted code that runs on one of the Wikimedia projects. The policy does not apply to gadgets running on third-party MediaWiki instances.

Gadgets developers on Wikimedia Foundation projects should additionally consider Recommendations for gadget developers on Wikimedia wikis as complement to this.

Quick guide[edit]

Using code[edit]

  • The mw object is the primary stable API for interacting with MediaWiki in the browser.
  • HTML should not be considered stable. Direct access and manipulation of the DOM is not safe. The only safe way to access parts of the DOM is through utilities provided through the mw object to obtain or modify existing elements on the page rather than DOM queries. If there is no utility function that satisfies your use case, please let us know.

Communication[edit]

Writing code[edit]

  • HTML is not a stable interface, but providers must consider communicating changes that change HTML markup with IDs or HTML class attributes containing mw- given they may historically have been used by developers of wiki-based code.
  • When renaming or removing ResourceLoader modules, follow the deprecation process
  • Limit code exposed on the mw object, since it must be maintained as a stable API unless it has been marked as @private.
  • Keep public methods exposed on the mw object and mw.hook signatures compatible for callers. Follow the deprecation process for breaking changes.

Communication[edit]

Terminology[edit]

MAY, MUST, SHOULD
See RFC 2119 to understand the language used in this policy to indicate requirement levels.
Wikimedia wikis
all public Wikimedia Foundation projects
wiki-hosted code
code that executes on Wikimedia Foundation projects, whose source code lives inside a page that is editable on-wiki
frontend code
any code that is executed by the browser such as HTML, CSS, and client-side JavaScript, including both wiki-hosted code as well MediaWiki code deployed server-side (MediaWiki core, extensions, and skins)
MediaWiki developer
someone who contributes code to MediaWiki core or to a MediaWiki extension or skin that is deployed on any Wikimedia Foundation project
providers
MediaWiki developers who are defining stable interfaces
consumers
code that makes use of stable interfaces, and the maintainers of such code, including MediaWiki developers as well as developers of wiki-hosted code
caching implications
Caching implications is used to describe the situation on Wikimedia production sites where old HTML markup is served to users alongside new styles. We cache HTML for a longer period than JavaScript and CSS assets. Caching implications apply to any page that is cached on the edge layer (typically any page that can be rendered by anonymous users excluding the special namespace). Explaining caching in detail is out of scope for the document; for more information, see Readers/Web/Building features with cached HTML in mind .
popularity of a gadget
The popularity of a gadget refers to how widely used or important a gadget is in the Wikimedia ecosystem. Popularity can be evaluated using Special:GadgetUsage and User scripts/Most imported scripts) using Global Search. As a general rule, popularity can be judged by 50+ scripts in MediaWiki namespace or more than 1000 scripts across the user and MediaWiki namespace impacted by any given change. Use your best judgement on determining usage and popularity. For example, the Twinkle gadget is widely used, so an issue that impacts the Twinkle gadget may be more significant than a change that impacts 100 user scripts. Participants in Wikimedia development should be forgiving when mistakes occur and propose revisions to our definition of gadget popularity based on real world experience via discussion on the talk page.
Codesearch
the MediaWiki Codesearch tool available at codesearch.wmcloud.org
Global Search
the search tool for Wikimedia wikis available at global-search.toolforge.org

Definition of the stable interface[edit]

What can be considered stable?[edit]

ResourceLoader modules[edit]

All ResourceLoader modules inside MediaWiki core MUST be considered stable to load and must follow the deprecation process, unless marked as deprecated. For modules provided by a MediaWiki extension or skin, there is no need to follow the deprecation process, unless you have explicitly designated a module as for consumption by other extensions, skins, or gadgets.

JavaScript code[edit]

Note: We aim to clarify stable contracts where ambiguous before the 1.42 release as part of phab:T348076 by adding @stable, @ignore and @internal tags. Please bear with us while we perform this cleanup of our documentation !

JavaScript code that is considered stable MUST follow the deprecation process. This includes:

  • Code that declares itself as stable in its JavaScript documentation either on doc.wikimedia.org or ResourceLoader/Core modules , preferably by using the @stable tag. If a property or module is marked as stable that indicates all of its public methods are also stable.
    Note: Clearer documentation guidelines will be provided as part of phab:T138401.
    // Provider of mediawiki.foo.module:
    /**
    * mediawiki.foo.module
    * @stable for use inside gadgets and extensions
    */
    module.exports = {
        stableMethod
    };
    
    // Consumer of mediawiki.foo.module:
    var foo = require( 'mediawiki.foo.module' );
    foo.stableMethod();
    
  • Code that is defined on the public mw object, that has not been documented as @private, regardless of how the code is added (extension, skin or wiki-based code), even if the code has not been marked as @stable.
    mw.mobileFrontend = {
        /**
         * Even though this code is on the global mw method it has been documented as
         * private so it is not stable.
         * @private
        */
        privateMethod: function () { ... },
        /**
         * If the method is on the mw object and not marked as private, it can be considered
         * stable. If the provider does not want to consider the method private, the method
         * must follow the deprecation process.
         */
        stableMethod: function () {
            this.privateMethod();
        }
    };
    // consumer of mw public method
    mw.mobileFrontend.stableMethod();
    
  • The function signature of the callback function for hooks fired using the mw.hook object in MediaWiki core code SHOULD be considered stable unless marked as @private or @internal. Consumers can expect that the hook will be fired in the circumstances described in its documentation.
    // Hooks are stable.
    mw.hook.fire( 'foo',  alert, 'This hook should be considered stable and is subject to the deprecation policy' );
    
    // The following code is safe to use given it uses code that is described as stable.
    mw.hook.add( 'foo', function ( fn, message ) {
        fn( message );
    } );
    
Additional information for providers[edit]

Providers SHOULD document all stable methods on doc.wikimedia.org and follow current coding conventions .

Providers looking to avoid adding code on the public mw object SHOULD instead share code between modules using ResourceLoader/Package files (using module.exports and require( '<filename>' )). See OptionalParamWidget.js as an example of a class that is not defined on the mw object and can only be used by mediawiki.special.apisandbox.

Providers using ResourceLoader/Package files SHOULD limit what functions are exported in the main module file to those that need to be shared between multiple ResourceLoader modules.

Additional information for consumers[edit]

The require() function is only accessible to ResourceLoader modules and currently SHOULD NOT be considered a stable interface outside ResourceLoader modules where it is undefined.

What is not stable?[edit]

HTML markup and CSS cannot be considered stable (unless explicitly stated). All frontend code (including wiki-hosted code, extensions and skins) relying on HTML structure does so at its own risk. However, consumers often do rely on the DOM structure and unstable identifiers for historic reasons due to missing frontend APIs. For example:

Stable
$( '<div>Hello world</div>').prependTo( mw.util.$content );
Unstable
$( '<div>Hello world</div>').prependTo( '#content' );
Advice for providers[edit]

MediaWiki developers are not required, but have a responsibility to respect gadget developers' existing work by proactively communicating any changes to HTML markup where alternative APIs are not currently available, particularly in projects which have high visibility or operate in the article namespace. This requirement will be dropped 2 years after the roll out of the frontend stable policy (September 2025).

In cases where there might be mutually beneficial for wiki-hosted code developers and MediaWiki developers to share stylesheets, for example for performance reasons, while not advised, the relationship MUST be documented in the source-controlled code using the @public and @since tags and linking to the on-wiki discussion. Classes defined in HTML class attributes that do wish to be considered stable MUST add an inline comment indicating in which MediaWiki version they were introduced using the @since annotation and must follow the deprecation process in the relevant section below. For example:

Yes
/**
 * When changing this file or associated markup, please take care to note it is stable and in use on various wikis!
 */

/* BEGIN */
/**
 * @public for use by templates
 * @stable this class is used by 10,000+ templates on page load and should not be removed from the page without following the deprecation process. See discussion on [[mediawiki:Can we share the banana styles?]] for more context.
 * @since August 2023 (MediaWiki 1.41)
 */
.mw-banana {
   color: yellow;
   padding: 10px;
}
No
.mw-banana {
   color: yellow;
   padding: 10px;
}
Advice for consumers[edit]

Wiki-hosted code SHOULD NOT make use of stylesheets defined by MediaWiki core for styling custom HTML markup, as doing so can lead to misuse, misunderstandings and breakage (T213239, T287997) unless the consuming code makes this relationship clear via @public and @since tags (please refer to advice for providers). Instead Wiki-hosted code SHOULD define its own class and styling rules.

For example: Gadgets should not replicate the HTML markup of a dropdown menu in Vector, using Vector's stylesheets. The stylesheet is not stable and may change without notice. Instead wiki-hosted code should use the mw.util.addPortletLink function to add additional menu items, because as part of the mw object it should be considered stable, and if imitating the HTML markup they should also imitate the CSS that goes with it, so it can rely on the styles not changing.
Guidelines for providers needing to change HTML markup and CSS classes safely[edit]

MediaWiki developers MUST understand and consider caching implications, namely that HTML from a previous deploy may be served to users alongside newer CSS. For pages subject to cache, MediaWiki developers MUST consider how HTML that is greater than a week old (such as HTML generated during the last train cycle) will be styled.

MediaWiki developers SHOULD first assess the impact of their change to HTML markup on wiki-hosted code, based on the communication guidelines and whether communication is advised.

Particular care MUST be taken when:

  • changing any element using a class or ID prefixed with mw- as traditionally the prefix has been associated by some as a stable interface.
  • removing an HTML element class attribute from output HTML that is provided by the MediaWiki wikitext parser (for example, .wikitable and .external).
    • In the case of renaming IDs which might be mistakenly considered stable (such as due to historic association with the mw- prefix, or an ID that hasn't changed in over 5 years), developers SHOULD consider a longer grace period since there is no way to do backwards compatibility.
    • In the case of renaming classes, it is recommended that the new class SHOULD be added along with the removed class for at least one MediaWiki release cycle in case third parties may be relying on them e.g. for HTML processing. An inline comment SHOULD indicate in which release the old class was deprecated.
    • Where APIs do not exist, providers SHOULD create tasks for missing APIs on Phabricator.

MediaWiki developers MUST follow the conventions in Manual:Coding_conventions/CSS#Naming . The benefits of using naming conventions are twofold:

  1. Developers can use the Codesearch tool to easily locate locate where HTML is generated.
  2. Gadget developers due to historic usage will often rely on the mw- prefixed selectors, and assume they are stable and not prone to change.
Guidelines for consumers to avoid reliance on HTML structure[edit]

For adding items to menus, the mw.util.addPortletLink method is encouraged rather than relying on jQuery. For adding subtitles, use mw.util.addSubtitle rather than appending to #contentSub or #mw-content-subtitle elements.

If you find yourself relying on CSS in core you SHOULD request a function for generating markup that is compatible for that CSS. Where APIs do not exist, consumers SHOULD request APIs to access elements or extend existing elements via Phabricator.

Guidelines for providers modifying default styles[edit]

MediaWiki developers MAY change default CSS for content generated by wikitext (such as changing the default link colors or changing typography). While rare, developers SHOULD consult Global Search to inform themselves about potential local overrides made by editors in MediaWiki:Common.css and SHOULD follow the guidelines for communicating changes to gadget developers when the change may be controversial or potentially cause visual changes.

Deprecation process[edit]

For frontend code we do not make a distinction between soft and hard deprecation since we do not log deprecation warnings and their primary purpose is for communicating to developers.

Guidelines for providers making breaking changes to stable JavaScript interfaces[edit]

Code that was never part of a public MediaWiki release, and never consumed according to Codesearch and Global Search MAY be changed (including marked explicitly as @private) or removed without deprecation, since the code has never become part of the stable interface or used.

When deprecating JavaScript code:

  • The @deprecated MUST be added to the JavaScript documentation and SHOULD note the MediaWiki release number.
  • The method mw.log.deprecate MUST be used to signal the deprecation of the API. The deprecation message SHOULD state the release in which the deprecation happened.

For example:

/**
 * @deprecated 1.40 use mw.util.bar instead.
 */
 mw.util.foo = function () {
    mw.log.deprecate(
        'Foo has been deprecated in MediaWiki 1.40. Please use mw.util.bar instead.'
    );
    mw.util.bar();
};

Deprecated methods MUST NOT be removed until they have been logging deprecation warnings in at least one stable release and for at least one month in the Wikimedia production environment. MediaWiki developers MUST follow guidelines for communicating changes to gadget developers.

When changing the function signature or removing a hook consumers MUST call the mw.log.deprecate function in a callback defined by itself. For example:

/**
 * Fired when indicators are being added to the DOM
 *
 * @event foo
 * @deprecated 1.40 use X instead.
 * @member mw.hook
 * @param {jQuery} $content jQuery object with the elements of the indicators
 */
mw.hook( 'foo' ).add( function ( p ) {
    mw.log.deprecate(
        'The hook `foo` has been deprecated in MediaWiki 1.40. Please use X instead.'
    );
} ).fire( param1 );

Guidelines for providers removing ResourceLoader modules[edit]

Code that was never part of a public MediaWiki release, and never consumed according to Codesearch and Global Search MAY be changed or removed without deprecation, since the code has never become part of the stable interface or used.

Before removing a module, the module MUST be deprecated so that using the module logs hard-deprecation warnings for at least one MediaWiki release prior to removal using the deprecated key in its ResourceLoader definition. This is to support third party developers who need to be notified and respond to any upstream changes.

When deprecating a ResourceLoader module, set the deprecated key on the associated ResourceLoader. The developer MUST document the deprecation in RELEASE_NOTES and mention the release number in which the deprecation occurred. For example:

[
	'wvui' => [
		'deprecated' => 'Deprecated in 1.39. Use `@wikimedia/codex` instead.',
		'packageFiles' => [
			'resources/src/wvui/wvui.js',
			'resources/lib/wvui/wvui.commonjs2.js',
		],
	],
]

Developers MAY fix consumers of a module prior to deprecation, but doing so is not required as a precursor to deprecation.

When completing a deprecation, the removal MUST be documented in RELEASE_NOTES. Communicate the change to gadget developers per communication guidelines.

Responsibilities of a MediaWiki developer[edit]

Providers[edit]

  • MediaWiki developers MUST pay attention to Phabricator tickets with requests for code maintenance and communicate any challenges they see with resolving them.
  • All new MediaWiki code deployed to Wikimedia wikis SHOULD consider providing a stable way for on-wiki code to support extensibility if this property is desired.
  • MediaWiki developers MUST review popular gadgets, using Global Search, annually to evaluate code that makes assumptions about the HTML structure and to flag opportunities and plan construction of new APIs. MediaWiki developers MAY evaluate as part of their planning process, and MUST evaluate in situations where a gadget developer raises a Phabricator ticket after an incident has occurred (for example, in a situation where a popular gadget breaks).
  • MediaWiki developers MAY use feature flagging (such as BetaFeatures or user preferences) in deployments to allow editors to test interfaces prior to development and SHOULD advertise their availability via Tech News.

Consumers[edit]

  • MediaWiki developers SHOULD regularly check the JavaScript console for deprecation notices and warnings and engage with them within one release cycle, by either fixing the issue or making clear why that is not possible.
  • Newly written code SHOULD NOT use deprecated ResourceLoader modules (such as jQuery.UI).

How providers can make breaking changes that impact widely used but unmaintained gadgets[edit]

When making breaking changes, despite good intentions it is inevitable even with good communication that some on-wiki scripts will not be updated by their maintainers and the change will lead to production errors and/or disruption to editor workflows.

Client side errors occurring in wiki-hosted code are tracked alongside errors in MediaWiki code on Grafana and can be explored further inside our logstash instance.

When making breaking changes, MediaWiki developers have a responsibility to fix or disable certain gadgets in the following scenarios:

  • MediaWiki developers MUST fix or disable error logging for any wiki-hosted code and/or user script errors with error volumes that trigger alerts via Wikimedia alerting systems. Having healthy metrics helps us have more confidence when we deploy code. Ideally the fix SHOULD be made by the maintainer of the code after discussion on the script's talk page, however in time sensitive situations MediaWiki developers MAY take action themselves if they feel comfortable doing so.
  • MediaWiki developers MAY fix or disable wiki-hosted code and/or user script errors that undermine user privacy. For example, if an active user is triggering an error on every page load, which reveals their page history, fixing the error is encouraged.
  • MediaWiki developers MAY fix or disable wiki-hosted code that is broken, provided the edit summary or the talk page documents how the issue can be fixed.
  • MediaWiki developers MAY run bots to automate fixing wiki-hosted code where resolution is straightforward. Example: a method is renamed.

How to communicate changes to consumers[edit]

Communication of changes to developers of wiki-hosted code[edit]

If any gadgets/scripts are impacted, then MediaWiki developers SHOULD notify Tech News. For changes that impact popular gadgets in such a way that they break functionality or where stable interfaces have changed (regardless of whether they are used), MediaWiki developers MUST do so. If MediaWiki developers are confident that gadgets will not be severely impacted (for example if the gadget is still functional after the change but stylistically different) communication can be skipped.

When communication is required:

  • A period of at least one month MUST be given for wiki-hosted code developers to respond and raise any concerns relating to the change regardless of MediaWiki release.
  • MediaWiki developers MUST consider any feedback from gadget developers to minimize disruption (for example create tickets for introducing APIs where missing).

For all communications:

  • The Tech News entry MUST mention "BREAKING CHANGE" in the title and provide steps to resolve the problem inside the description.
  • Providers SHOULD use their best judgement to determine the timeline for changes that impact non-stable interfaces.

When learning about the breakage of gadgets on Wikimedia wikis that are not covered by the wiki-hosted code policy, e.g. using unstable interfaces due to unavailability, MediaWiki developers MUST assess the inclusion of a new stable interface to reduce future breakage.

Communication of changes to other MediaWiki developers[edit]

If code running on Wikimedia projects is impacted by breaking changes, developers MUST open Phabricator ticket(s) tracking the issue for impacted skins and/or extensions. The Phabricator ticket(s) SHOULD tag the impacted project and detail the timeline for the removal and provide details on the required change. Developers MAY provide patches, and are encouraged to do so especially in the case where the fix is simple.

Meta[edit]

Motivation[edit]

This policy is designed to make consumers more robust against changes in MediaWiki core, and provide more freedom for MediaWiki core code to evolve.

The motivation for the frontend stable interface policy is twofold:

  • Offer guarantees to the maintainers of frontend code, providing guidance on what interfaces that they can safely rely upon.
  • Provide guarantees to developers working on MediaWiki core, telling them what aspects of the code they can safely change without having to worry about breaking extensions or wiki-hosted code.

Gadgets and user scripts (which will be referred to as wiki-hosted code) are key components of MediaWiki projects.

Before the introduction of this policy, there was no clearly defined API that such code could rely upon. This has caused misunderstandings and unexpected problems particularly for wiki-hosted code.

This situation has also made it difficult to improve MediaWiki code, since it was unclear how changes would impact wiki-hosted code and developers often did not feel empowered to make changes in an acceptable fashion.

In addition, it has not been clear who is responsible for fixing issues in wiki-hosted code.

This document aims to build agreements between Wikimedia staff, third party extension developers, and developers of wiki-hosted code developers to create a better experience for all groups and to build trust between them.

History[edit]

  • September 2023 - The document is now official.
  • August-September 2023 - Changes to organization and phrasing including addition of clearer examples.
  • - Last call for objections before making it official.
  • July-August 2023 - Incorporated changes based on talk page feedback.
  • June 2023 - Folding feedback from outside wiki into document.
  • May 2023 - Targeted readers of mediawiki.org [1]
  • March 2023 - Revised format of document.
  • January 2023 - Recommendations for gadget developers was separated from this document.
  • May 2022 - Emailed engineering-all@wikimedia.org to request feedback.
  • February 2022 - Emailed wikitech-l@lists.wikimedia.org [2]
  • August 2021 - This document began life in User:Jdlrobson/Extension:Gadget/Policy.