r96978 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r96977‎ | r96978 | r96979 >
Date:17:13, 13 September 2011
Author:catrope
Status:resolved (Comments)
Tags:
Comment:
Fix the fixme on r88053: dependency handling was broken in debug mode in certain cases. More specifically, if A is a file module that depends on B, B is a wiki module that depends on C and C is a file module, the loading order is CBA (correct) in production mode but was BCA (wrong) in debug mode. Fixed this by URL-ifying scripts and styles for those modules in debug mode, as I said to on CR. What this means is that the initial debug=true request for a module will now always return arrays of URLs, never the JS or CSS itself. This was already the case for file modules (which returned arrays of URLs to the raw files), but not for other modules (which returned the JS and CSS itself). So for non-file modules, load.php?modules=foo&debug=true now returns some JS that instructs the loader to fetch the module's JS from load.php?modules=foo&debug=true&only=scripts and the CSS from ...&only=styles .

* Removed the magic behavior where ResourceLoaderModule::getScripts() and getStyles() could return an array of URLs where the documentation said they should return a JS/CSS string. Because I didn't restructure the calling code too much, the old magical behavior should still work.
* Instead, move this behavior to getScriptURLsForDebug() and getStyleURLsForDebug(). The default implementation constructs a single URL for a load.php request for the module with debug=true&only=scripts (or styles). The URL building code duplicates some things from OutputPage::makeResourceLoaderLink(), I'll clean that up later. ResourceLoaderFileModule overrides this method to return URLs to the raw files, using code that I removed from getScripts()/getStyles()
* Add ResourceLoaderModule::supportsURLLoading(), which returns true by default but may return false to indicate that a module does not support loading via a URL. This is needed to respect $this->debugRaw in ResourceLoaderFileModule (set to true for jquery and mediawiki), and obviously for the startup module as well, because we get bootstrapping problems otherwise (can't call mw.loader.implement() when the code for mw.loader isn't loaded yet)
Modified paths:
  • /trunk/phase3/includes/resourceloader/ResourceLoader.php (modified) (history)
  • /trunk/phase3/includes/resourceloader/ResourceLoaderFileModule.php (modified) (history)
  • /trunk/phase3/includes/resourceloader/ResourceLoaderModule.php (modified) (history)
  • /trunk/phase3/includes/resourceloader/ResourceLoaderStartUpModule.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/resourceloader/ResourceLoaderStartUpModule.php
@@ -241,6 +241,10 @@
242242 return $out;
243243 }
244244
 245+ public function supportsURLLoading() {
 246+ return false;
 247+ }
 248+
245249 /**
246250 * @param $context ResourceLoaderContext
247251 * @return array|mixed
Index: trunk/phase3/includes/resourceloader/ResourceLoader.php
@@ -529,17 +529,31 @@
530530 try {
531531 $scripts = '';
532532 if ( $context->shouldIncludeScripts() ) {
533 - $scripts = $module->getScript( $context );
534 - if ( is_string( $scripts ) ) {
535 - // bug 27054: Append semicolon to prevent weird bugs
536 - // caused by files not terminating their statements right
537 - $scripts .= ";\n";
 533+ // If we are in debug mode, we'll want to return an array of URLs if possible
 534+ // However, we can't do this if the module doesn't support it
 535+ // We also can't do this if there is an only= parameter, because we have to give
 536+ // the module a way to return a load.php URL without causing an infinite loop
 537+ if ( $context->getDebug() && !$context->getOnly() && $module->supportsURLLoading() ) {
 538+ $scripts = $module->getScriptURLsForDebug( $context );
 539+ } else {
 540+ $scripts = $module->getScript( $context );
 541+ if ( is_string( $scripts ) ) {
 542+ // bug 27054: Append semicolon to prevent weird bugs
 543+ // caused by files not terminating their statements right
 544+ $scripts .= ";\n";
 545+ }
538546 }
539547 }
540548 // Styles
541549 $styles = array();
542550 if ( $context->shouldIncludeStyles() ) {
543 - $styles = $module->getStyles( $context );
 551+ // If we are in debug mode, we'll want to return an array of URLs
 552+ // See comment near shouldIncludeScripts() for more details
 553+ if ( $context->getDebug() && !$context->getOnly() && $module->supportsURLLoading() ) {
 554+ $styles = $module->getStyleURLsForDebug( $context );
 555+ } else {
 556+ $styles = $module->getStyles( $context );
 557+ }
544558 }
545559
546560 // Messages
Index: trunk/phase3/includes/resourceloader/ResourceLoaderFileModule.php
@@ -217,16 +217,21 @@
218218 */
219219 public function getScript( ResourceLoaderContext $context ) {
220220 $files = $this->getScriptFiles( $context );
221 - if ( $context->getDebug() && $this->debugRaw ) {
222 - $urls = array();
223 - foreach ( $this->getScriptFiles( $context ) as $file ) {
224 - $urls[] = $this->getRemotePath( $file );
225 - }
226 - return $urls;
227 - }
228221 return $this->readScriptFiles( $files );
229222 }
 223+
 224+ public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
 225+ $urls = array();
 226+ foreach ( $this->getScriptFiles( $context ) as $file ) {
 227+ $urls[] = $this->getRemotePath( $file );
 228+ }
 229+ return $urls;
 230+ }
230231
 232+ public function supportsURLLoading() {
 233+ return $this->debugRaw;
 234+ }
 235+
231236 /**
232237 * Gets loader script.
233238 *
@@ -250,16 +255,6 @@
251256 $this->getStyleFiles( $context ),
252257 $this->getFlip( $context )
253258 );
254 - if ( !$context->getOnly() && $context->getDebug() && $this->debugRaw ) {
255 - $urls = array();
256 - foreach ( $this->getStyleFiles( $context ) as $mediaType => $list ) {
257 - $urls[$mediaType] = array();
258 - foreach ( $list as $file ) {
259 - $urls[$mediaType][] = $this->getRemotePath( $file );
260 - }
261 - }
262 - return $urls;
263 - }
264259 // Collect referenced files
265260 $this->localFileRefs = array_unique( $this->localFileRefs );
266261 // If the list has been modified since last time we cached it, update the cache
@@ -276,6 +271,17 @@
277272 return $styles;
278273 }
279274
 275+ public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
 276+ $urls = array();
 277+ foreach ( $this->getStyleFiles( $context ) as $mediaType => $list ) {
 278+ $urls[$mediaType] = array();
 279+ foreach ( $list as $file ) {
 280+ $urls[$mediaType][] = $this->getRemotePath( $file );
 281+ }
 282+ }
 283+ return $urls;
 284+ }
 285+
280286 /**
281287 * Gets list of message keys used by this module.
282288 *
Index: trunk/phase3/includes/resourceloader/ResourceLoaderModule.php
@@ -126,6 +126,44 @@
127127 // Stub, override expected
128128 return '';
129129 }
 130+
 131+ /**
 132+ * Get the URL or URLs to load for this module's JS in debug mode.
 133+ * The default behavior is to return a load.php?only=scripts URL for
 134+ * the module, but file-based modules will want to override this to
 135+ * load the files directly.
 136+ *
 137+ * This function is called only when 1) we're in debug mode, 2) there
 138+ * is no only= parameter and 3) supportsURLLoading() returns true.
 139+ * #2 is important to prevent an infinite loop, therefore this function
 140+ * MUST return either an only= URL or a non-load.php URL.
 141+ *
 142+ * @param $context ResourceLoaderContext: Context object
 143+ * @return Array of URLs
 144+ */
 145+ public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
 146+ global $wgLoadScript; // TODO factor out to ResourceLoader static method and deduplicate from makeResourceLoaderLink()
 147+ $query = array(
 148+ 'modules' => $this->getName(),
 149+ 'only' => 'scripts',
 150+ 'skin' => $context->getSkin(),
 151+ 'user' => $context->getUser(),
 152+ 'debug' => 'true',
 153+ 'version' => $context->getVersion()
 154+ );
 155+ ksort( $query );
 156+ return array( wfAppendQuery( $wgLoadScript, $query ) . '&*' );
 157+ }
 158+
 159+ /**
 160+ * Whether this module supports URL loading. If this function returns false,
 161+ * getScript() will be used even in cases (debug mode, no only param) where
 162+ * getScriptURLsForDebug() would normally be used instead.
 163+ * @return bool
 164+ */
 165+ public function supportsURLLoading() {
 166+ return true;
 167+ }
130168
131169 /**
132170 * Get all CSS for this module for a given skin.
@@ -137,6 +175,29 @@
138176 // Stub, override expected
139177 return array();
140178 }
 179+
 180+ /**
 181+ * Get the URL or URLs to load for this module's CSS in debug mode.
 182+ * The default behavior is to return a load.php?only=styles URL for
 183+ * the module, but file-based modules will want to override this to
 184+ * load the files directly. See also getScriptURLsForDebug()
 185+ *
 186+ * @param $context ResourceLoaderContext: Context object
 187+ * @return Array: array( mediaType => array( URL1, URL2, ... ), ... )
 188+ */
 189+ public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
 190+ global $wgLoadScript; // TODO factor out to ResourceLoader static method and deduplicate from makeResourceLoaderLink()
 191+ $query = array(
 192+ 'modules' => $this->getName(),
 193+ 'only' => 'styles',
 194+ 'skin' => $context->getSkin(),
 195+ 'user' => $context->getUser(),
 196+ 'debug' => 'true',
 197+ 'version' => $context->getVersion()
 198+ );
 199+ ksort( $query );
 200+ return array( 'all' => array( wfAppendQuery( $wgLoadScript, $query ) . '&*' ) );
 201+ }
141202
142203 /**
143204 * Get the messages needed for this module.

Follow-up revisions

RevisionCommit summaryAuthorDate
r96999Followup r96978, clean up code duplication by factoring out the code building...catrope20:36, 13 September 2011
r97263REL1_18 MFT r93626, r96562, r96640, r96978, r97050reedy13:19, 16 September 2011
r98502Address fixme on r96978: expand URLs fed to the client-side loadercatrope10:14, 30 September 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r88053Added direct file loading functionality to debug mode for both scripts and st...tparscal12:15, 14 May 2011

Comments

#Comment by Catrope (talk | contribs)   17:16, 13 September 2011

Hmm, this probably needs some tests too. I'll whip some up after I clean up the code duplication.

#Comment by Krinkle (talk | contribs)   08:06, 30 September 2011

Urls that eventually end up in the client-side loader must be absolute, otherwise they are interpreted as module names.

mw.loader.implement("ext.gadget.HoverPopTools", ["/mediawiki-trunk/load.php?debug=true\x26lang=nl\x26modules=ext.gadget.HoverPopTools\x26only=scripts\x26skin=vector\x26version=20110930T075402Z\x26*"], {"all": ["/mediawiki-trunk/load.php?debug=true\x26lang=nl\x26modules=ext.gadget.HoverPopTools\x26only=styles\x26skin=vector\x26version=20110930T075402Z\x26*"]}, {});

Currently fails, marking fixme. Needs wgServer expansion.

Status & tagging log