resourceloader: Ensure 'user' loads after 'site' (asynchronously)
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoader.php
index 92b0156..7875048 100644 (file)
@@ -206,7 +206,7 @@ class ResourceLoader implements LoggerAwareInterface {
                if ( !$options['cache'] ) {
                        $result = $this->applyFilter( $filter, $data );
                } else {
-                       $key = wfMemcKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) );
+                       $key = wfGlobalCacheKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) );
                        $cache = wfGetCache( wfIsHHVM() ? CACHE_ACCEL : CACHE_ANYTHING );
                        $cacheEntry = $cache->get( $key );
                        if ( is_string( $cacheEntry ) ) {
@@ -215,12 +215,17 @@ class ResourceLoader implements LoggerAwareInterface {
                        }
                        $result = '';
                        try {
-                               wfIncrStats( "resourceloader_cache.$filter.miss" );
+                               $stats = RequestContext::getMain()->getStats();
+                               $statStart = microtime( true );
+
                                $result = $this->applyFilter( $filter, $data );
+
+                               $stats->timing( "resourceloader_cache.$filter.miss", microtime( true ) - $statStart );
                                if ( $options['cacheReport'] ) {
                                        $result .= "\n/* cache key: $key */";
                                }
-                               $cache->set( $key, $result );
+                               // Set a TTL since HHVM's APC doesn't have any limitation or eviction logic.
+                               $cache->set( $key, $result, 24 * 3600 );
                        } catch ( Exception $e ) {
                                MWExceptionHandler::logException( $e );
                                $this->logger->warning( 'Minification failed: {exception}', array(
@@ -234,16 +239,17 @@ class ResourceLoader implements LoggerAwareInterface {
        }
 
        private function applyFilter( $filter, $data ) {
-                       switch ( $filter ) {
-                               case 'minify-js':
-                                       return JavaScriptMinifier::minify( $data,
-                                               $this->config->get( 'ResourceLoaderMinifierStatementsOnOwnLine' ),
-                                               $this->config->get( 'ResourceLoaderMinifierMaxLineLength' )
-                                       );
-                               case 'minify-css':
-                                       return CSSMin::minify( $data );
-                       }
-                       return $data;
+               switch ( $filter ) {
+                       case 'minify-js':
+                               return JavaScriptMinifier::minify( $data,
+                                       $this->config->get( 'ResourceLoaderMinifierStatementsOnOwnLine' ),
+                                       $this->config->get( 'ResourceLoaderMinifierMaxLineLength' )
+                               );
+                       case 'minify-css':
+                               return CSSMin::minify( $data );
+               }
+
+               return $data;
        }
 
        /* Methods */
@@ -804,10 +810,15 @@ class ResourceLoader implements LoggerAwareInterface {
                        header( 'Cache-Control: private, no-cache, must-revalidate' );
                        header( 'Pragma: no-cache' );
                } else {
-                       header( "Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" );
+                       header( "Cache-Control: public, must-revalidate, max-age=$maxage, s-maxage=$smaxage" );
                        $exp = min( $maxage, $smaxage );
                        header( 'Expires: ' . wfTimestamp( TS_RFC2822, $exp + time() ) );
                }
+
+               // Send the current time expressed as fractional seconds since epoch,
+               // with microsecond precision. This helps distinguish hits from misses
+               // in edge caches.
+               header( 'MediaWiki-Timestamp: ' . microtime( true ) );
        }
 
        /**
@@ -1094,7 +1105,11 @@ MESSAGE;
                $name, $scripts, $styles, $messages, $templates
        ) {
                if ( is_string( $scripts ) ) {
-                       $scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
+                       // Site and user module are a legacy scripts that run in the global scope (no closure).
+                       // Transportation as string instructs mw.loader.implement to use globalEval.
+                       if ( $name !== 'site' && $name !== 'user' ) {
+                               $scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
+                       }
                } elseif ( !is_array( $scripts ) ) {
                        throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' );
                }