Jump to content

User:SD0001/Making user scripts load faster

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by SD0001 (talk | contribs) at 16:02, 30 April 2021 (code updates). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

User scripts can be made to load faster with the help of caching.

Add the following code to the top of your your common JavaScript page:

// Enable caching for resource loads, see [[User:SD0001/Making_user_scripts_load_faster]]
function loadResource(page, sitename, ctype) {
	return $.get(
		'https://' + sitename + '/w/api.php?titles=' + encodeURIComponent(page) + 
		'&origin=*&format=json&formatversion=2&uselang=content&maxage=86400&smaxage=86400' + 
		'&action=query&prop=revisions|info&rvprop=content&rvlimit=1'
	).then(function(apiResponse) {
		var apiPage = apiResponse.query.pages[0];
		if (apiPage.missing) return;
		var content = apiPage.revisions[0].content;
    	if ((!ctype || ctype === 'text/javascript') && apiPage.contentmodel === 'javascript') {
			eval(content); // jshint ignore:line 
	    } else if (ctype === 'text/css' && apiPage.contentmodel === 'css') {
			mw.loader.addStyleTag(content);
		} else {
			return $.Deferred().reject('Refused to load "' + page + '"@' + sitename + ': content type mismatch');
		}
	});
}
window.importScript = function(page) {
	loadResource(page, mw.config.get('wgServerName'), 'text/javascript');
};
window.importStyleSheet = function(page) {
	loadResource(page, mw.config.get('wgServerName'), 'text/css');
};
function getSiteTitle(url) {
	var siteRgx = /^(?:(?:https:)?\/\/(.*))?\/w\/index.php/.exec(url),
		titleRgx = /\btitle=([^=?&]*)/.exec(url);
	if (siteRgx && titleRgx && /\baction=raw\b/.test(url) && /\bctype=/.test(url)) {
		return [titleRgx[1], siteRgx[1] || mw.config.get('wgServerName')];	
	} else return null;
}
var oldMwLoaderLoad = mw.loader.load;
var oldMwLoaderGetScript = mw.loader.getScript;
mw.loader.load = function(url, type) {
	var linkParts = getSiteTitle(url);
	if (linkParts) {
		loadResource(linkParts[0], linkParts[1], type);
	} else {
		oldMwLoaderLoad.apply(mw.loader, Array.prototype.slice.call(arguments));
	}
};
mw.loader.getScript = function(url) {
	var linkParts = getSiteTitle(url);
	if (linkParts) {
		return loadResource(linkParts[0], linkParts[1], 'text/javascript');
	} else {
		return oldMwLoaderGetScript.apply(mw.loader, Array.prototype.slice.call(arguments));
	}
};

Note that this code block necessarily needs to go at the top of the page for it to take effect.

This replaces the existing implementations of mw.loader.load, mw.loader.getScript, importScript and importStyleSheet. No changes are needed in the way you normally add new user scripts.

The effect can be seen by keeping the network tab of the browser dev tools open and navigating between different pages. (Note that reloading the same page isn't the same – that's seen as a hard reload in some browsers that causes bypassing of cache.) In Chrome, you should see that most script fetches are resolved by the disk cache itself which is very fast.

Caveats

The snippet above makes all scripts and stylesheets cached by your browser for up to one day (86400 seconds).

If any of the scripts are updated, it may take you up to 1 day to see the updates. However, doing a hard reload will clear the caches. On Google Chrome, just hitting the "reload" button on any page causes a hard reload. On other browsers, you may need to use Ctrl+F5.

Technical notes

  • The uselang=content attribute enables public caching. See phab:T97096.
  • The origin=* causes the API to set the relevant header to avoid CORS issue while loading cross-wiki scripts.