* Get all JS for this module for a given language and skin.
* Includes all relevant JS except loader scripts.
*
+ * For "plain" script modules, this should return a string with JS code. For multi-file modules
+ * where require() is used to load one file from another file, this should return an array
+ * structured as follows:
+ * [
+ * 'files' => [
+ * 'file1.js' => [ 'type' => 'script', 'content' => 'JS code' ],
+ * 'file2.js' => [ 'type' => 'script', 'content' => 'JS code' ],
+ * 'data.json' => [ 'type' => 'data', 'content' => array ]
+ * ],
+ * 'main' => 'file1.js'
+ * ]
+ *
* @param ResourceLoaderContext $context
- * @return string JavaScript code
+ * @return string|array JavaScript code (string), or multi-file structure described above (array)
*/
public function getScript( ResourceLoaderContext $context ) {
// Stub, override expected
// This MUST build both scripts and styles, regardless of whether $context->getOnly()
// is 'scripts' or 'styles' because the result is used by getVersionHash which
- // must be consistent regardles of the 'only' filter on the current request.
+ // must be consistent regardless of the 'only' filter on the current request.
// Also, when introducing new module content resources (e.g. templates, headers),
// these should only be included in the array when they are non-empty so that
// existing modules not using them do not get their cache invalidated.
}
$content['scripts'] = $scripts;
- // Styles
$styles = [];
// Don't create empty stylesheets like [ '' => '' ] for modules
// that don't *have* any stylesheets (T40024).
} else {
// Infer changes based on definition and other metrics
$summary = $this->getDefinitionSummary( $context );
- if ( !isset( $summary['_cacheEpoch'] ) ) {
+ if ( !isset( $summary['_class'] ) ) {
throw new LogicException( 'getDefinitionSummary must call parent method' );
}
$str = json_encode( $summary );
public function getDefinitionSummary( ResourceLoaderContext $context ) {
return [
'_class' => static::class,
- '_cacheEpoch' => $this->getConfig()->get( 'CacheEpoch' ),
+ // Make sure that when filter cache for minification is invalidated,
+ // we also change the HTTP urls and mw.loader.store keys (T176884).
+ '_cacheVersion' => ResourceLoader::CACHE_VERSION,
];
}
if ( !$this->getConfig()->get( 'ResourceLoaderValidateJS' ) ) {
return $contents;
}
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
return $cache->getWithSetCallback(
$cache->makeGlobalKey(
'resourceloader',
$cache::TTL_WEEK,
function () use ( $contents, $fileName ) {
$parser = self::javaScriptParser();
+ $err = null;
try {
+ Wikimedia\suppressWarnings();
$parser->parse( $contents, $fileName, 1 );
- $result = $contents;
} catch ( Exception $e ) {
- // We'll save this to cache to avoid having to re-validate broken JS
- $err = $e->getMessage();
- $result = "mw.log.error(" .
- Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");";
+ $err = $e;
+ } finally {
+ Wikimedia\restoreWarnings();
+ }
+ if ( $err ) {
+ // Send the error to the browser console client-side.
+ // By returning this as replacement for the actual script,
+ // we ensure modules are safe to load in a batch request,
+ // without causing other unrelated modules to break.
+ return 'mw.log.error(' .
+ Xml::encodeJsVar( 'JavaScript parse error: ' . $err->getMessage() ) .
+ ');';
}
- return $result;
+ return $contents;
}
);
}