diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index a0acf1f30bb..637bae640af 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -1484,7 +1484,7 @@ MESSAGE; } /** - * Wraps JavaScript code to run after startup and base modules. + * Wraps JavaScript code to run after the startup module. * * @param string $script JavaScript code * @return string JavaScript code diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php index a4fd71233f7..53c10df4b1a 100644 --- a/includes/resourceloader/ResourceLoaderStartUpModule.php +++ b/includes/resourceloader/ResourceLoaderStartUpModule.php @@ -319,17 +319,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { return true; } - /** - * @param ResourceLoaderContext $context - * @return array - */ - public function getPreloadLinks( ResourceLoaderContext $context ) { - $url = $this->getBaseModulesUrl( $context ); - return [ - $url => [ 'as' => 'script' ] - ]; - } - /** * Internal modules used by ResourceLoader that cannot be depended on. * @@ -353,10 +342,18 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { return []; } + /** + * @private For internal use by SpecialJavaScriptTest + * @since 1.32 + * @return array + */ + public function getBaseModulesInternal() { + return $this->getBaseModules(); + } + /** * Base modules implicitly available to all modules. * - * @since 1.32 * @return array */ private function getBaseModules() { @@ -370,25 +367,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { return $baseModules; } - /** - * Get the load URL of the startup modules. - * - * This is a helper for getScript(). - * - * @param ResourceLoaderContext $context - * @return string - */ - private function getBaseModulesUrl( ResourceLoaderContext $context ) { - $rl = $context->getResourceLoader(); - $derivative = new DerivativeResourceLoaderContext( $context ); - $derivative->setModules( $this->getBaseModules() ); - $derivative->setOnly( 'scripts' ); - // Must setModules() before makeVersionQuery() - $derivative->setVersion( $rl->makeVersionQuery( $derivative ) ); - - return $rl->createLoaderURL( 'local', $derivative ); - } - /** * @param ResourceLoaderContext $context * @return string JavaScript code @@ -399,35 +377,43 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { return '/* Requires only=script */'; } - $out = file_get_contents( "$IP/resources/src/startup/startup.js" ); + $startupCode = file_get_contents( "$IP/resources/src/startup/startup.js" ); - // Keep in sync with maintenance/jsduck/eg-iframe.html and, - // keep in sync with 'fileHashes' in StartUpModule::getDefinitionSummary(). + // The files read here MUST be kept in sync with maintenance/jsduck/eg-iframe.html, + // and MUST be considered by 'fileHashes' in StartUpModule::getDefinitionSummary(). $mwLoaderCode = file_get_contents( "$IP/resources/src/startup/mediawiki.js" ) . file_get_contents( "$IP/resources/src/startup/mediawiki.requestIdleCallback.js" ); if ( $context->getDebug() ) { $mwLoaderCode .= file_get_contents( "$IP/resources/src/startup/mediawiki.log.js" ); } - $pairs = array_map( function ( $value ) { + $mapToJson = function ( $value ) { $value = FormatJson::encode( $value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK ); // Fix indentation $value = str_replace( "\n", "\n\t", $value ); return $value; - }, [ + }; + + // 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 ), - // This url may be preloaded. See getPreloadLinks(). - '$VARS.baseModulesUri' => $this->getBaseModulesUrl( $context ), ] ); + // Raw JavaScript code (not for JSON) $pairs['$CODE.registrations();'] = str_replace( "\n", "\n\t", trim( $this->getModuleRegistrations( $context ) ) ); $pairs['$CODE.defineLoader();'] = $mwLoaderCode; + $startupCode = strtr( $startupCode, $pairs ); - return strtr( $out, $pairs ); + return $startupCode; } /** diff --git a/includes/specials/SpecialJavaScriptTest.php b/includes/specials/SpecialJavaScriptTest.php index b786c869fb6..f858f5c2cd3 100644 --- a/includes/specials/SpecialJavaScriptTest.php +++ b/includes/specials/SpecialJavaScriptTest.php @@ -103,65 +103,56 @@ class SpecialJavaScriptTest extends SpecialPage { $query['only'] = 'scripts'; $startupContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) ); - $query['raw'] = true; - $modules = $rl->getTestModuleNames( 'qunit' ); // Disable autostart because we load modules asynchronously. By default, QUnit would start // at domready when there are no tests loaded and also fire 'QUnit.done' which then instructs - // Karma to end the run before the tests even started. + // Karma to exit the browser process before the tests even finished loading. $qunitConfig = 'QUnit.config.autostart = false;' . 'if (window.__karma__) {' // karma-qunit's use of autostart=false and QUnit.start conflicts with ours. - // Hack around this by replacing 'karma.loaded' with a no-op and call it ourselves later. - // See . + // Hack around this by replacing 'karma.loaded' with a no-op and perfom its duty of calling + // `__karma__.start()` ourselves. See . . 'window.__karma__.loaded = function () {};' . '}'; // The below is essentially a pure-javascript version of OutputPage::headElement(). - $startup = $rl->makeModuleResponse( $startupContext, [ + $code = $rl->makeModuleResponse( $startupContext, [ 'startup' => $rl->getModule( 'startup' ), ] ); - // Embed page-specific mw.config variables. - // The current Special page shouldn't be relevant to tests, but various modules (which - // are loaded before the test suites), reference mw.config while initialising. - $code = ResourceLoader::makeConfigSetScript( $out->getJSVars() ); - // Embed private modules as they're not allowed to be loaded dynamically - $code .= $rl->makeModuleResponse( $embedContext, [ - 'user.options' => $rl->getModule( 'user.options' ), - 'user.tokens' => $rl->getModule( 'user.tokens' ), - ] ); - // Catch exceptions (such as "dependency missing" or "unknown module") so that we - // always start QUnit. Re-throw so that they are caught and reported as global exceptions - // by QUnit and Karma. - $modules = Xml::encodeJsVar( $modules ); - $code .= <<getJSVars() ) + // Embed private modules as they're not allowed to be loaded dynamically + . $rl->makeModuleResponse( $embedContext, [ + 'user.options' => $rl->getModule( 'user.options' ), + 'user.tokens' => $rl->getModule( 'user.tokens' ), + ] ) + // Load all the test suites + . Xml::encodeJsCall( 'mw.loader.load', [ $modules ] ) + ); + $encModules = Xml::encodeJsVar( $modules ); + $code .= ResourceLoader::makeInlineCodeWithModule( 'mediawiki.base', <<