ResourceLoader/Developing with ResourceLoader

This is a high-level walkthrough of the PHP interface for ResourceLoader for understanding how to create and register ResourceLoader modules in MediaWiki core or an extension.

For more about how ResourceLoader is designed, its features and why it works the way it does, see ResourceLoader/Features.

Registering

 * See also Manual:$wgResourceModules

In order for all the ResourceLoader features to function properly it is required to register modules under a symbolic name. We do that by adding the module definition to the configuration variable in your   file, or by adding to the array in   (for MediaWiki core).

Below is an example for registering a module called  in MediaWiki 1.25 and later using   (see also: Extension registration).


 * naming : Because (in this example) ext.myExtension is a module provided by and related to an extension, the module name begins with " ".


 * composition : This defined module consists primarily of two scripts and a CSS file that goes with it. The module also declares that it wants to be able to use two translatable message-keys. Any messages declared here will be available through mw.msg after your module has loaded. Tip: Pass single resources as a string. Pass multiple resources as an array of strings.


 * dependencies : The example script depends on the  module. Loading and execution of scripts is fully asynchronous, so it is important to declare your dependencies, to make sure that they are loaded and available before your scripts try to use or reference it.

There are a multitude of additional properties that a module can have, and these options are mostly intended to influence the delivery behavior.
 * Look at  and   if (part of) your code is skin specific.
 * Use  if you are adding polyfills that could be loaded conditionally.
 * When you need to include translations, you might want to check out.
 * When you want your module to be loaded in mobile variants as well, use . (See also Writing a mobile friendly ResourceLoader module)

Server-side

 * see also Manual:OutputPage.php and ParserOutput

While building the page, add one or more modules to the page by calling the  method on the   or   object and passing it one or more module names (such as " ", " " or " ")

adds the given module names to the load queue of the page. The client side loader requests all of the components for this module (scripts, styles, messages, dependencies, etc.) and executes them correctly. If your module contains styles that affect elements outputted by PHP as well as elements created dynamically, then you should split the module. One for styling/enhancing the output, and one for dynamic stuff. The first module should only have stylesheets and be loaded with  (see ). The other module will simply be loaded asynchronously by the client, not blocking further parsing of the page.

To get a reference to OutputPage object from an extension, use the BeforePageDisplay hook.

CSS
If you have CSS that should be loaded before the page renders (and even when JavaScript is unavailable), queue it via. This will make sure the module is loaded from a  tag.

For styles relating to anything involving JavaScript, the preferred method is to include them with  which loads modules as a complete package in a combined request (scripts, styles, messages) dynamically (from a lightweight client in JavaScript). This is because it is more efficient for this purpose (single request for all resources), supports dependency resolution, request batching, is highly cacheable (through access to the startup manifest with all version numbers it can dynamically generate permanently cacheable urls), and reduces cache fragmentation (modules previously loaded on other page views are loaded directly from Local Storage). It should not be used for CSS-only modules.

Since dependency changes can be deployed independently from caching the page, static loading with  cannot use dependencies. And since you can't dynamically access the latest version of the startup manifest from static HTML without JavaScript execution, it cannot have versions in the urls either and are therefore cached for a shorter time.

In practice you should only use  for stylesheets that are required for basic presentation of server-generated content (PHP output and the core Skin). Separate this CSS from modules with JavaScript and styling of dynamically-generated content.

JavaScript
JavaScript files are, like CSS files, also evaluated in the order they are defined in the  array.

In the following example, one would use the entry  when registering the module.

The page loading this module would somewhere use  to output the element.

Passing information from PHP to Javascript
You will often find yourself having to pass information from the server side to the client-side run Javascript. Usually you will do this by using either HTML (e.g. data attributes) or through the API (e.g. Ajax request).

In a case where this is not possible, you can export the information from PHP to a JavaScript value. To do this, call  on the   or   object. In rare cases where you can't access an OutputPage or ParserOutput object, the MakeGlobalVariablesScript hook be used.

Client-side (dynamically)
Gadgets should list their dependencies through the "dependencies" options in their definition.

For user scripts, dependencies cannot be declared ahead of time (unlike gadgets). Instead, for user scripts, wrap the code in a  block, and specify the required modules. For example:

This will guarantee that the specified modules are loaded. Don't worry about multiple (separate) scripts both asking the loader for the same module. ResourceLoader internally ensures nothing is loaded multiple times.

Conditional lazy loading
If you have a script that only needs another module in a certain scenario of the user interface, you can create small separate module (known as an "init module"), and from there use JavaScript to dynamically load the rest of the module.

Example:

Parallel execution
If you have multiple asynchronous tasks, it is best to run these tasks in parallel. Use  to track multiple separate asynchronous tasks (known as a "Promise", or a "Deferred"). Below is an example of waiting for and AJAX request, and the loading of ResourceLoader modules, and the "document ready" status:

CSS
Your styling resources can be either CSS or, since MediaWiki 1.22, LESS files. When writing styles we advise you to follow our conventions.

Media queries
You can use media queries when you define your modules, to specify when a CSS/Less file applies:

In the above example, the  stylesheet will always apply to all screens, the   stylesheet applies on print (and in the "Printable version" mode), and the   stylesheet applies when the viewport width is at least 982 pixels. The contents of the corresponding CSS/Less file will then be wrapped in the defined media query:

Annotations
The CSS preprocessors in ResourceLoader support several annotations that you can use to optimise your stylesheets.

@embed

 * See also ResourceLoader/Features

If an image is specified with the CSS  function and is small enough (up to 24kB) the annotation   can be used in a CSS comment. This instructs ResourceLoader to embed the image in the CSS output as a data URI. For example: If you view a ResourceLoader request for this module, you can see that ResourceLoader transformed this image file into an embedded data URL, with the external URL only as a fallback. Reformatted for clarity, the ResourceLoader response includes: Browsers that support data URIs in CSS use the embedded image instead of making another network request.

In MediaWiki 1.22 and newer you can also use a LESS mixin to specify an image, and the mixin function outputs the  directive for you. For example, the  mixin (in ) in your LESS file: See also ResourceLoaderImage, which generates raster images and multiple colored icons from a single source SVG file.

@noflip

 * See also ResourceLoader/Features

To disable the flipping functionality for one CSS declaration or on an entire ruleset, use the  annotation:

For example:

Toggle debug mode
ResourceLoader supports complex client-side web applications in production and development environments. As these different environments have different needs, ResourceLoader offers two distinct modes: production mode and debug mode (also known as "development") mode.

Debug mode is designed to make development as easy as possible, prioritizing the ease of identifying and resolving problems in the software over performance. Production mode makes the opposite prioritization, emphasizing performance over ease of development.

It is important to test your code in both debug and production modes. In day-to-day development, most developers will find it beneficial to use debug mode most of the time, only validating their code's functionality in production mode before committing changes.

You can enable debug mode for all page views, or for a single page request (by appending  to the URL); see ResourceLoader/Features for details on toggling it.

Server-side exceptions
ResourceLoader catches any errors thrown during module packaging (such as an error in a module definition or a missing file) in  requests. It outputs this error information in a JavaScript comment at the top of its response to that request, for example: You can inspect the request in the network panel in the developer tools for most browsers, or you can copy the  URL and load it in a new browser window. Note that the HTTP request with a failing module still returns status 200 OK, it does not return an error.

You can also output errors to a server-side log file by setting up a log file in. They aren't added to the main debug log since logging is disabled by default for requests to.

Client-side errors

 * Unreviewed

JavaScript returned by ResourceLoader is executed in the browser, and can have run-time errors. Most browsers do not display these to the user, so you should leave your browser's JavaScript console open during development to notice them.

You can use ResourceLoader's  function to check the state of a module, for example enter   in your browser's JavaScript console. If it returns:
 * null
 * The module is not known to ResourceLoader. Check for typos, and verify whether the module registered and defined correctly.


 * registered
 * ResourceLoader knows about the module, but hasn't (yet) loaded it on the current page. Check your logic for adding the module, either server-side or client-side. You can force it to load by entering.


 * error
 * Something went wrong, either server-side or during client-side execution, with this module or one of its dependencies. Check the browser console and Network inspector for error relating to a load.php request. Alternatively, consider reloading the the page in debug mode.


 * ready
 * The module loaded on the current page without errors.

Breaking cache
When making frequent changes to code and checking them in a browser, the caching mechanisms designed to improve the performance of web-browsing can quickly become inconvenient. When developing on a system which is not making use of a reverse proxy, you only need to force your browser to bypass its cache while refreshing. This can be achieved by pressing  in Internet Explorer, or holding the shift key while clicking the browser's refresh button in most other browsers.

If you are developing behind a reverse proxy, you can either change the values of  or use   to bypass cache.