/** * Get registration code for all modules. * * @param ResourceLoaderContext $context * @return string JavaScript code for registering all modules with the client loader */ public function getModuleRegistrations(ResourceLoaderContext $context) { $resourceLoader = $context->getResourceLoader(); $target = $context->getRequest()->getVal('target', 'desktop'); // Bypass target filter if this request is Special:JavaScriptTest. // To prevent misuse in production, this is only allowed if testing is enabled server-side. $byPassTargetFilter = $this->getConfig()->get('EnableJavaScriptTest') && $target === 'test'; $out = ''; $registryData = []; // Get registry data foreach ($resourceLoader->getModuleNames() as $name) { $module = $resourceLoader->getModule($name); $moduleTargets = $module->getTargets(); if (!$byPassTargetFilter && !in_array($target, $moduleTargets)) { continue; } 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.) continue; } $versionHash = $module->getVersionHash($context); if (strlen($versionHash) !== 8) { $context->getLogger()->warning("Module '{module}' produced an invalid version hash: '{version}'.", ['module' => $name, 'version' => $versionHash]); // Module implementation either broken or deviated from ResourceLoader::makeHash // Asserted by tests/phpunit/structure/ResourcesTest. $versionHash = ResourceLoader::makeHash($versionHash); } $skipFunction = $module->getSkipFunction(); if ($skipFunction !== null && !ResourceLoader::inDebugMode()) { $skipFunction = ResourceLoader::filter('minify-js', $skipFunction); } $registryData[$name] = ['version' => $versionHash, 'dependencies' => $module->getDependencies($context), 'group' => $module->getGroup(), 'source' => $module->getSource(), 'skip' => $skipFunction]; } self::compileUnresolvedDependencies($registryData); // Register sources $out .= ResourceLoader::makeLoaderSourcesScript($resourceLoader->getSources()); // Figure out the different call signatures for mw.loader.register $registrations = []; foreach ($registryData as $name => $data) { // Call mw.loader.register(name, version, dependencies, group, source, skip) $registrations[] = [$name, $data['version'], $data['dependencies'], $data['group'], $data['source'] === 'local' ? null : $data['source'], $data['skip']]; } // Register modules $out .= "\n" . ResourceLoader::makeLoaderRegisterScript($registrations); return $out; }
/** * Bundle all resources attached to this module into an array. * * @since 1.26 * @param ResourceLoaderContext $context * @return array */ protected final 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 // templates). This helps prevent invalidating cache for all modules when new // optional properties are introduced. $content = array(); // 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); // rtrim() because there are usually a few line breaks // after the last ';'. A new line at EOF, a new line // added by ResourceLoaderFileModule::readScriptFiles, etc. if (is_string($scripts) && strlen($scripts) && substr(rtrim($scripts), -1) !== ';') { // Append semicolon to prevent weird bugs caused by files not // terminating their statements right (bug 27054) $scripts .= ";\n"; } } $content['scripts'] = $scripts; } // Styles if ($context->shouldIncludeStyles()) { $styles = array(); // Don't create empty stylesheets like array( '' => '' ) for modules // that don't *have* any stylesheets (bug 38024). $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 = array('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] = array(); 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); } } } // Wrap styles into @media groups as needed and flatten into a numerical array $styles = array('css' => $rl->makeCombinedStyles($stylePairs)); } } $content['styles'] = $styles; } // Messages $blobs = $rl->getMessageBlobStore()->get($rl, array($this->getName() => $this), $context->getLanguage()); if (isset($blobs[$this->getName()])) { $content['messagesBlob'] = $blobs[$this->getName()]; } $templates = $this->getTemplates(); if ($templates) { $content['templates'] = $templates; } $statTiming = microtime(true) - $statStart; $statName = strtr($this->getName(), '.', '_'); $stats->timing("resourceloader_build.all", 1000 * $statTiming); $stats->timing("resourceloader_build.{$statName}", 1000 * $statTiming); return $content; }