Merge "user: Allow "CAS update failed" exceptions to be normalised"
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoaderStartUpModule.php
index 2457fe8..e4a753f 100644 (file)
@@ -40,21 +40,13 @@ use MediaWiki\MediaWikiServices;
  *   See also: OutputPage::disallowUserJs()
  */
 class ResourceLoaderStartUpModule extends ResourceLoaderModule {
-
-       // Cache for getConfigSettings() as it's called by multiple methods
-       protected $configVars = [];
        protected $targets = [ 'desktop', 'mobile' ];
 
        /**
         * @param ResourceLoaderContext $context
         * @return array
         */
-       protected function getConfigSettings( $context ) {
-               $hash = $context->getHash();
-               if ( isset( $this->configVars[$hash] ) ) {
-                       return $this->configVars[$hash];
-               }
-
+       private function getConfigSettings( $context ) {
                $conf = $this->getConfig();
 
                // We can't use Title::newMainPage() if 'mainpage' is in
@@ -136,8 +128,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
 
                Hooks::run( 'ResourceLoaderGetConfigVars', [ &$vars ] );
 
-               $this->configVars[$hash] = $vars;
-               return $this->configVars[$hash];
+               return $vars;
        }
 
        /**
@@ -222,9 +213,23 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                $out = '';
                $states = [];
                $registryData = [];
+               $moduleNames = $resourceLoader->getModuleNames();
+
+               // Preload with a batch so that the below calls to getVersionHash() for each module
+               // don't require on-demand loading of more information.
+               try {
+                       $resourceLoader->preloadModuleInfo( $moduleNames, $context );
+               } catch ( Exception $e ) {
+                       // Don't fail the request (T152266)
+                       // Also print the error in the main output
+                       $resourceLoader->outputErrorAndLog( $e,
+                               'Preloading module info from startup failed: {exception}',
+                               [ 'exception' => $e ]
+                       );
+               }
 
                // Get registry data
-               foreach ( $resourceLoader->getModuleNames() as $name ) {
+               foreach ( $moduleNames as $name ) {
                        $module = $resourceLoader->getModule( $name );
                        $moduleTargets = $module->getTargets();
                        if (
@@ -235,18 +240,25 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        }
 
                        if ( $module->isRaw() ) {
-                               // Don't register "raw" modules (like 'jquery' and 'mediawiki') client-side because
-                               // depending on them is illegal anyway and would only lead to them being reloaded
-                               // causing any state to be lost (like jQuery plugins, mw.config etc.)
+                               // Don't register "raw" modules (like 'startup') client-side because depending on them
+                               // is illegal anyway and would only lead to them being loaded a second time,
+                               // causing any state to be lost.
+
+                               // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
+                               // Think carefully before making changes to this code!
+                               // The below code is going to call ResourceLoaderModule::getVersionHash() for every module.
+                               // For StartUpModule (this module) the hash is computed based on the manifest content,
+                               // which is the very thing we are computing right here. As such, this must skip iterating
+                               // over 'startup' itself.
                                continue;
                        }
 
                        try {
                                $versionHash = $module->getVersionHash( $context );
                        } catch ( Exception $e ) {
-                               // See also T152266 and ResourceLoader::getCombinedVersion()
-                               MWExceptionHandler::logException( $e );
-                               $context->getLogger()->warning(
+                               // Don't fail the request (T152266)
+                               // Also print the error in the main output
+                               $resourceLoader->outputErrorAndLog( $e,
                                        'Calculating version for "{module}" failed: {exception}',
                                        [
                                                'module' => $name,
@@ -388,31 +400,41 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                if ( $context->getDebug() ) {
                        $mwLoaderCode .= file_get_contents( "$IP/resources/src/startup/mediawiki.log.js" );
                }
-
-               $mapToJson = function ( $value ) {
-                       $value = FormatJson::encode( $value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK );
-                       // Fix indentation
-                       $value = str_replace( "\n", "\n\t", $value );
-                       return $value;
-               };
+               if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
+                       $mwLoaderCode .= file_get_contents( "$IP/resources/src/startup/profiler.js" );
+               }
 
                // Perform replacements for mediawiki.js
-               $mwLoaderCode = strtr( $mwLoaderCode, [
-                       '$VARS.baseModules' => $mapToJson( $this->getBaseModules() ),
-               ] );
-
-               // Perform replacements for startup.js
-               $pairs = array_map( $mapToJson, [
-                       '$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
-                       '$VARS.configuration' => $this->getConfigSettings( $context ),
-               ] );
-               // Raw JavaScript code (not for JSON)
-               $pairs['$CODE.registrations();'] = str_replace(
-                       "\n",
-                       "\n\t",
-                       trim( $this->getModuleRegistrations( $context ) )
-               );
-               $pairs['$CODE.defineLoader();'] = $mwLoaderCode;
+               $mwLoaderPairs = [
+                       '$VARS.baseModules' => ResourceLoader::encodeJsonForScript( $this->getBaseModules() ),
+               ];
+               $profilerStubs = [
+                       '$CODE.profileExecuteStart();' => 'mw.loader.profiler.onExecuteStart( module );',
+                       '$CODE.profileExecuteEnd();' => 'mw.loader.profiler.onExecuteEnd( module );',
+                       '$CODE.profileScriptStart();' => 'mw.loader.profiler.onScriptStart( module );',
+                       '$CODE.profileScriptEnd();' => 'mw.loader.profiler.onScriptEnd( module );',
+               ];
+               if ( $this->getConfig()->get( 'ResourceLoaderEnableJSProfiler' ) ) {
+                       // When profiling is enabled, insert the calls.
+                       $mwLoaderPairs += $profilerStubs;
+               } else {
+                       // When disabled (by default), insert nothing.
+                       $mwLoaderPairs += array_fill_keys( array_keys( $profilerStubs ), '' );
+               }
+               $mwLoaderCode = strtr( $mwLoaderCode, $mwLoaderPairs );
+
+               // Perform string replacements for startup.js
+               $pairs = [
+                       '$VARS.wgLegacyJavaScriptGlobals' => ResourceLoader::encodeJsonForScript(
+                               $this->getConfig()->get( 'LegacyJavaScriptGlobals' )
+                       ),
+                       '$VARS.configuration' => ResourceLoader::encodeJsonForScript(
+                               $this->getConfigSettings( $context )
+                       ),
+                       // Raw JavaScript code (not JSON)
+                       '$CODE.registrations();' => trim( $this->getModuleRegistrations( $context ) ),
+                       '$CODE.defineLoader();' => $mwLoaderCode,
+               ];
                $startupCode = strtr( $startupCode, $pairs );
 
                return $startupCode;
@@ -426,50 +448,12 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
        }
 
        /**
-        * Get the definition summary for this module.
-        *
-        * @param ResourceLoaderContext $context
-        * @return array
-        */
-       public function getDefinitionSummary( ResourceLoaderContext $context ) {
-               global $IP;
-               $summary = parent::getDefinitionSummary( $context );
-               $summary[] = [
-                       // Detect changes to variables exposed in mw.config (T30899).
-                       'vars' => $this->getConfigSettings( $context ),
-                       // Changes how getScript() creates mw.Map for mw.config
-                       'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
-                       // Detect changes to the module registrations
-                       'moduleHashes' => $this->getAllModuleHashes( $context ),
-
-                       'fileHashes' => [
-                               $this->safeFileHash( "$IP/resources/src/startup/startup.js" ),
-                               $this->safeFileHash( "$IP/resources/src/startup/mediawiki.js" ),
-                               $this->safeFileHash( "$IP/resources/src/startup/mediawiki.requestIdleCallback.js" ),
-                       ],
-               ];
-               return $summary;
-       }
-
-       /**
-        * Helper method for getDefinitionSummary().
-        *
-        * @param ResourceLoaderContext $context
-        * @return string SHA-1
+        * @return bool
         */
-       protected function getAllModuleHashes( ResourceLoaderContext $context ) {
-               $rl = $context->getResourceLoader();
-               // Preload for getCombinedVersion()
-               $rl->preloadModuleInfo( $rl->getModuleNames(), $context );
-
-               // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
-               // Think carefully before making changes to this code!
-               // Pre-populate versionHash with something because the loop over all modules below includes
-               // the startup module (this module).
-               // See ResourceLoaderModule::getVersionHash() for usage of this cache.
-               $this->versionHash[$context->getHash()] = null;
-
-               return $rl->getCombinedVersion( $context, $rl->getModuleNames() );
+       public function enableModuleContentVersion() {
+               // Enabling this means that ResourceLoader::getVersionHash will simply call getScript()
+               // and hash it to determine the version (as used by E-Tag HTTP response header).
+               return true;
        }
 
        /**