This is possibly not perfect but seems to serve for a start; follows up on r91591 that adds JSMin+ to use it in some unit tests. May want to adjust some related bits.
- $wgResourceLoaderValidateJs on by default (can be disabled)
- when loading a JS file through ResourceLoaderFileModule or ResourceLoaderWikiModule, parse it using JSMinPlus's JSParser class. If the parser throws an exception, the JS code of the offending file will be replaced by a JS exception throw listing the file or page name, line number (in original form), and description of the error from the parser.
- parsing results are cached based on md5 of content to avoid re-parsing identical text
- for JS pages loaded via direct load.php request, the parse error is thrown and visible in the JS console/error log
Issues:
- the primary use case for this is when a single load.php request implements multiple modules via mw.loader.implement() -- the loader catches the exception and skips on to the next module (good) but doesn't re-throw the exception for the JS console. It does log to console if present, but it'll only show up as a regular debug message, not an error. This can suppress visibility of errors in a module that's loaded together with other modules (such as a gadget).
- have not done performance testing on the JSParser
- have not done thorough unit testing with the JSParser
Also rearranges the loading order a little bit such that only=messages comes before only=scripts, and config comes before everything except startup and jquery+mediawiki
TODO: Since the alias is globally available from the start, the 'mw' argument in the wrapper is redundant, so that should be removed at some point as well.
* Modified ResourceLoader to lazy-initialise module objects, for a further performance advantage.
* Deleted ResourceLoader::getModules(), provided getModuleNames() instead. Although the startup module needs this functionality, it's slow to generate, so to avoid misuse, it's better to provide a foolproof fast interface and let the startup module do the slow thing itself.
* Modified ResourceLoader::register() to optionally accept an info array instead of an object.
* Added $wgResourceModules, allowing extensions to efficiently define their own resource loader modules. The trouble with hooks is that they contain code, and code is slow. We've been through all this before with i18n. Hooks are useful as a performance tool only if you call them very rarely.
* Moved ResourceLoader settings to their own section in DefaultSettings.php
* Added options to ResourceLoaderFileModule equivalent to the $localBasePath and $remoteBasePath parameters, to allow it to be instantiated via the new array style. Also added remoteExtPath, which allows modules to be registered before $wgExtensionAssetsPath is known.
* Added OutputPage::getResourceLoader(), mostly for debugging.
* The time saving at the moment is about 5ms per request with no extensions, which is significant already with 6 load.php requests for a cold cache page view. This is a much more scalable interface; the relative saving will grow as more extensions are added which use this interface, especially for non-APC installs.
Although the interface is backwards compatible, extension updates will follow in a subsequent commit.
* For readability, rewrote ResourceLoaderFileModule::readScriptFiles() to use a loop instead of an excessively cute nested array_map() construction.
* In ResourceLoaderFileModule, check file_get_contents() result for errors. Golden rule of error checking: always check fopen(). Every call to fopen will fail some day for some user.
* In mediaWiki.loader.filter(): broke up a complex multi-line conditional into multiple commented if statements, for readability.
* Possessive "its" has no apostrophe.
* Modified Xml::encodeJsVar() to allow it to pass through JS expressions without encoding, using a special object.
* In ResourceLoader::makeModuleResponse(), renamed $messages to $messagesBlob to make it clear that it's JSON-encoded, not an array.
* Fixed MessageBlobStore to store {} for an empty message array instead of [].
* In ResourceLoader::makeMessageSetScript(), fixed call to non-existent function mediaWiki.msg.set.
* For security, changed the calling convention of makeMessageSetScript() and makeLoaderImplementScript() to require explicit object construction of XmlJsCode() before interpreting their input as JS code.
* Documented several ResourceLoader static functions.
* In ResourceLoaderWikiModule, for readability, reduced the indenting level by flipping some if blocks and adding continue statements.
* In makeCustomLoaderScript(), allow non-numeric $version. The only caller I can find is already sending a non-numeric $version, presumably it was broken. Luckily there aren't any loader scripts in existence, I had to make one to test it.
* wfGetDb -> wfGetDB
* Added an extra line break in the startup module output, for readability.
* In ResourceLoaderStartUpModule::getModuleRegistrations(), fixed another assignment expression
* Break long lines.
* Convert long or unnecessary ternary operator usages to if/else.
* Fixed excessively clever assignment expressions.
* Rename $cache to $cacheEntry.
* Removed unnecessary web invocation guards. Their perlish form was making me uncomfortable. BTW, unlike in Perl, die() is not a function, it's a special case in the PHP grammar which very roughly simulates the Perl syntax:
die "x"; // works
0 || die("x"); // works
0 || (die); // works
0 || (die "x"); // fail!
What actually happens here
* Add $localBasePath, $remoteBasePath params to the FileModule constructor, defaulting to $IP and $wgScriptPath respectively
* Add getLocalPath() and getRemotePath(), which use this information to build a proper FS or URL path for a file
* Make readScriptFiles() non-static so it can use these functions
* Run every single file path we use through either getLocalPath() or getRemotePath() as appropriate
** Except file dependencies, these are already prefixed. Our inability to give them special treatment caused bugs earlier
* Kill prefixFilePathList() and resolveFilePath(), no longer needed