Cache ResourceLoader modules in localStorage

To minimize the number of discrete requests that the browser has to make in
order to render the page, ResourceLoader tries to condense as many modules as
possible into each request. To ensure that the response is not stale,
ResourceLoader tacks the modification time of the most recently modified module
to the request. This behavior makes poor use of locality: an update to a single
module will change the URL that is used to retrieve it and a number of
unrelated modules, causing those modules to be re-retrieved even though they
have not changed since they were last retrieved. This is because the browser
cache is not aware that the response from load.php is a composite of modules
that should be versioned separately.

This patch adds mw.loader.store. On browsers that implement the localStorage
API, the module store serves as a smart complement to the browser cache. Unlike
the browser cache, the module store can slice a concatenated response from
ResourceLoader into its constituent modules and cache each of them separately,
using each module's versioning scheme to determine when the cache should be
invalidated.

Because the localStorage API is synchronous and slower than memory access,
modules are cached as a single JSON blob. At the beginning of the page load
process, the entire blob is loaded from storage into memory. During the load
process, any required modules that are not in the store are fetched from the
server and set in the in-memory store. When the DOM is complete, the store is
synced back to localStorage in a single operation.

* NOTE: The module store is enabled only if $wgResourceLoaderStorageEnabled is
  set to true; it is false by default. We can change the default if / when we
  establish conclusively that the feature is beneficial and stable.

Change-Id: If2ad2d80db2336fb447817f5c56599667141ec66
Merge "Cache ResourceLoader modules in localStorage"