/**
* Whether the position returned by getPosition() is a default value or comes from the module
- * definition. This method is meant to be short-lived, and is only useful until classes added via
- * addModuleStyles with a default value define an explicit position. See getModuleStyles() in
- * OutputPage for the related migration warning.
+ * definition. This method is meant to be short-lived, and is only useful until classes added
+ * via addModuleStyles with a default value define an explicit position. See getModuleStyles()
+ * in OutputPage for the related migration warning.
*
* @return bool
* @since 1.26
}
$dbr = wfGetDB( DB_SLAVE );
- $deps = $dbr->selectField( 'module_deps', 'md_deps', array(
+ $deps = $dbr->selectField( 'module_deps',
+ 'md_deps',
+ array(
'md_module' => $this->getName(),
'md_skin' => $skin,
- ), __METHOD__
+ ),
+ __METHOD__
);
+
if ( !is_null( $deps ) ) {
$this->fileDeps[$skin] = (array)FormatJson::decode( $deps, true );
} else {
$this->fileDeps[$skin] = array();
}
+
return $this->fileDeps[$skin];
}
}
$dbr = wfGetDB( DB_SLAVE );
- $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array(
+ $msgBlobMtime = $dbr->selectField( 'msg_resource',
+ 'mr_timestamp',
+ array(
'mr_resource' => $this->getName(),
'mr_lang' => $lang
- ), __METHOD__
+ ),
+ __METHOD__
);
// If no blob was found, but the module does have messages, that means we need
// to regenerate it. Return NOW
// Cache this expensive operation. This calls builds the scripts, styles, and messages
// content which typically involves filesystem and/or database access.
if ( !array_key_exists( $contextHash, $this->contents ) ) {
- $this->contents[ $contextHash ] = $this->buildContent( $context );
+ $this->contents[$contextHash] = $this->buildContent( $context );
}
- return $this->contents[ $contextHash ];
+ return $this->contents[$contextHash];
}
/**
*/
final protected function buildContent( ResourceLoaderContext $context ) {
$rl = $context->getResourceLoader();
+ $stats = RequestContext::getMain()->getStats();
+ $statStart = microtime( true );
// Only include properties that are relevant to this context (e.g. only=scripts)
// and that are non-empty (e.g. don't include "templates" for modules without
$stylePairs[$media] = array();
foreach ( $style as $cssText ) {
if ( is_string( $cssText ) ) {
- $stylePairs[$media][] = $rl->filter( 'minify-css', $cssText );
+ $stylePairs[$media][] =
+ $rl->filter( 'minify-css', $cssText );
}
}
} elseif ( is_string( $style ) ) {
$content['templates'] = $templates;
}
+ $statTiming = microtime( true ) - $statStart;
+ $statName = str_replace( '.', '_', $this->getName() );
+ $stats->timing( "resourceloader_build.all", $statTiming );
+ $stats->timing( "resourceloader_build.$statName", $statTiming );
+
return $content;
}
* @return string Hash (should use ResourceLoader::makeHash)
*/
public function getVersionHash( ResourceLoaderContext $context ) {
+ // The startup module produces a manifest with versions representing the entire module.
+ // Typically, the request for the startup module itself has only=scripts. That must apply
+ // only to the startup module content, and not to the module version computed here.
+ $context = new DerivativeResourceLoaderContext( $context );
+ $context->setModules( array() );
+ // Version hash must cover all resources, regardless of startup request itself.
+ $context->setOnly( null );
+ // Compute version hash based on content, not debug urls.
+ $context->setDebug( false );
+
// Cache this somewhat expensive operation. Especially because some classes
// (e.g. startup module) iterate more than once over all modules to get versions.
$contextHash = $context->getHash();
if ( !array_key_exists( $contextHash, $this->versionHash ) ) {
- $summary = $this->getDefinitionSummary( $context );
- if ( !isset( $summary['_cacheEpoch'] ) ) {
- throw new Exception( 'getDefinitionSummary must call parent method' );
- }
- $str = json_encode( $summary );
+ if ( $this->enableModuleContentVersion() ) {
+ // Detect changes directly
+ $str = json_encode( $this->getModuleContent( $context ) );
+ } else {
+ // Infer changes based on definition and other metrics
+ $summary = $this->getDefinitionSummary( $context );
+ if ( !isset( $summary['_cacheEpoch'] ) ) {
+ throw new LogicException( 'getDefinitionSummary must call parent method' );
+ }
+ $str = json_encode( $summary );
- $mtime = $this->getModifiedTime( $context );
- if ( $mtime !== null ) {
- // Support: MediaWiki 1.25 and earlier
- $str .= strval( $mtime );
- }
+ $mtime = $this->getModifiedTime( $context );
+ if ( $mtime !== null ) {
+ // Support: MediaWiki 1.25 and earlier
+ $str .= strval( $mtime );
+ }
- $mhash = $this->getModifiedHash( $context );
- if ( $mhash !== null ) {
- // Support: MediaWiki 1.25 and earlier
- $str .= strval( $mhash );
+ $mhash = $this->getModifiedHash( $context );
+ if ( $mhash !== null ) {
+ // Support: MediaWiki 1.25 and earlier
+ $str .= strval( $mhash );
+ }
}
- $this->versionHash[ $contextHash ] = ResourceLoader::makeHash( $str );
+ $this->versionHash[$contextHash] = ResourceLoader::makeHash( $str );
}
- return $this->versionHash[ $contextHash ];
+ return $this->versionHash[$contextHash];
+ }
+
+ /**
+ * Whether to generate version hash based on module content.
+ *
+ * If a module requires database or file system access to build the module
+ * content, consider disabling this in favour of manually tracking relevant
+ * aspects in getDefinitionSummary(). See getVersionHash() for how this is used.
+ *
+ * @return bool
+ */
+ public function enableModuleContentVersion() {
+ return false;
}
/**
protected function validateScriptFile( $fileName, $contents ) {
if ( $this->getConfig()->get( 'ResourceLoaderValidateJS' ) ) {
// Try for cache hit
- // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
- $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
+ // Use CACHE_ANYTHING since parsing JS is much slower than a DB query
+ $key = wfMemcKey(
+ 'resourceloader',
+ 'jsparse',
+ self::$parseCacheVersion,
+ md5( $contents )
+ );
$cache = wfGetCache( CACHE_ANYTHING );
$cacheEntry = $cache->get( $key );
if ( is_string( $cacheEntry ) ) {
} catch ( Exception $e ) {
// We'll save this to cache to avoid having to validate broken JS over and over...
$err = $e->getMessage();
- $result = "mw.log.error(" . Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");";
+ $result = "mw.log.error(" .
+ Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");";
}
$cache->set( $key, $result );