X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fresourceloader%2FResourceLoaderModule.php;h=30b2aa7949f5261c00e29211b8b54da66c1d1efe;hb=1dee28cb5f1efd6d9e14d6cc1d0c73c3f69269b4;hp=02d5802e97c18a7ca440ad9f86d635fbda61a454;hpb=dc3fc6cf81ecc2c84e6e45f3f4401c4b8976861c;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/resourceloader/ResourceLoaderModule.php b/includes/resourceloader/ResourceLoaderModule.php index 02d5802e97..30b2aa7949 100644 --- a/includes/resourceloader/ResourceLoaderModule.php +++ b/includes/resourceloader/ResourceLoaderModule.php @@ -689,79 +689,77 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface { $stats = MediaWikiServices::getInstance()->getStatsdDataFactory(); $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 - // templates). This helps prevent invalidating cache for all modules when new - // optional properties are introduced. + // 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. + // 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 - if ( $context->shouldIncludeScripts() ) { - // If we are in debug mode, we'll want to return an array of URLs if possible - // However, we can't do this if the module doesn't support it - // We also can't do this if there is an only= parameter, because we have to give - // the module a way to return a load.php URL without causing an infinite loop - if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) { - $scripts = $this->getScriptURLsForDebug( $context ); - } else { - $scripts = $this->getScript( $context ); - // Make the script safe to concatenate by making sure there is at least one - // trailing new line at the end of the content. Previously, this looked for - // a semi-colon instead, but that breaks concatenation if the semicolon - // is inside a comment like "// foo();". Instead, simply use a - // line break as separator which matches JavaScript native logic for implicitly - // ending statements even if a semi-colon is missing. - // Bugs: T29054, T162719. - if ( is_string( $scripts ) - && strlen( $scripts ) - && substr( $scripts, -1 ) !== "\n" - ) { - $scripts .= "\n"; - } + // If we are in debug mode, we'll want to return an array of URLs if possible + // However, we can't do this if the module doesn't support it. + // We also can't do this if there is an only= parameter, because we have to give + // the module a way to return a load.php URL without causing an infinite loop + if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) { + $scripts = $this->getScriptURLsForDebug( $context ); + } else { + $scripts = $this->getScript( $context ); + // Make the script safe to concatenate by making sure there is at least one + // trailing new line at the end of the content. Previously, this looked for + // a semi-colon instead, but that breaks concatenation if the semicolon + // is inside a comment like "// foo();". Instead, simply use a + // line break as separator which matches JavaScript native logic for implicitly + // ending statements even if a semi-colon is missing. + // Bugs: T29054, T162719. + if ( is_string( $scripts ) + && strlen( $scripts ) + && substr( $scripts, -1 ) !== "\n" + ) { + $scripts .= "\n"; } - $content['scripts'] = $scripts; } + $content['scripts'] = $scripts; // Styles - if ( $context->shouldIncludeStyles() ) { - $styles = []; - // Don't create empty stylesheets like [ '' => '' ] for modules - // that don't *have* any stylesheets (T40024). - $stylePairs = $this->getStyles( $context ); - if ( count( $stylePairs ) ) { - // If we are in debug mode without &only= set, we'll want to return an array of URLs - // See comment near shouldIncludeScripts() for more details - if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) { - $styles = [ - 'url' => $this->getStyleURLsForDebug( $context ) - ]; - } else { - // Minify CSS before embedding in mw.loader.implement call - // (unless in debug mode) - if ( !$context->getDebug() ) { - foreach ( $stylePairs as $media => $style ) { - // Can be either a string or an array of strings. - if ( is_array( $style ) ) { - $stylePairs[$media] = []; - foreach ( $style as $cssText ) { - if ( is_string( $cssText ) ) { - $stylePairs[$media][] = - ResourceLoader::filter( 'minify-css', $cssText ); - } + $styles = []; + // Don't create empty stylesheets like [ '' => '' ] for modules + // that don't *have* any stylesheets (T40024). + $stylePairs = $this->getStyles( $context ); + if ( count( $stylePairs ) ) { + // If we are in debug mode without &only= set, we'll want to return an array of URLs + // See comment near shouldIncludeScripts() for more details + if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) { + $styles = [ + 'url' => $this->getStyleURLsForDebug( $context ) + ]; + } else { + // Minify CSS before embedding in mw.loader.implement call + // (unless in debug mode) + if ( !$context->getDebug() ) { + foreach ( $stylePairs as $media => $style ) { + // Can be either a string or an array of strings. + if ( is_array( $style ) ) { + $stylePairs[$media] = []; + foreach ( $style as $cssText ) { + if ( is_string( $cssText ) ) { + $stylePairs[$media][] = + ResourceLoader::filter( 'minify-css', $cssText ); } - } elseif ( is_string( $style ) ) { - $stylePairs[$media] = ResourceLoader::filter( 'minify-css', $style ); } + } elseif ( is_string( $style ) ) { + $stylePairs[$media] = ResourceLoader::filter( 'minify-css', $style ); } } - // Wrap styles into @media groups as needed and flatten into a numerical array - $styles = [ - 'css' => $rl->makeCombinedStyles( $stylePairs ) - ]; } + // Wrap styles into @media groups as needed and flatten into a numerical array + $styles = [ + 'css' => $rl->makeCombinedStyles( $stylePairs ) + ]; } - $content['styles'] = $styles; } + $content['styles'] = $styles; // Messages $blob = $this->getMessageBlob( $context ); @@ -805,27 +803,17 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface { * @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( [] ); - // 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 ) ) { if ( $this->enableModuleContentVersion() ) { - // Detect changes directly + // Detect changes directly by hashing the module contents. $str = json_encode( $this->getModuleContent( $context ) ); } 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 ); @@ -895,7 +883,9 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface { 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, ]; }