resourceloader: Compile documentElement.className server-side
authorTimo Tijhof <krinklemail@gmail.com>
Sun, 25 Aug 2019 16:24:55 +0000 (17:24 +0100)
committerKrinkle <krinklemail@gmail.com>
Thu, 29 Aug 2019 02:27:25 +0000 (02:27 +0000)
Reduces output by not needlessly performing a change client-side
for which we already know the result server-side.

Bug: T231168
Change-Id: I4b8749f976d04d24f85236ddd641c7a4c7f6c23a

includes/OutputPage.php
includes/resourceloader/ResourceLoaderClientHtml.php
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php

index 3f2dcf7..d63d376 100644 (file)
@@ -3027,10 +3027,11 @@ class OutputPage extends ContextSource {
                $sitedir = MediaWikiServices::getInstance()->getContentLanguage()->getDir();
 
                $pieces = [];
-               $pieces[] = Html::htmlHeader( Sanitizer::mergeAttributes(
+               $htmlAttribs = Sanitizer::mergeAttributes(
                        $this->getRlClient()->getDocumentAttributes(),
                        $sk->getHtmlElementAttributes()
-               ) );
+               );
+               $pieces[] = Html::htmlHeader( $htmlAttribs );
                $pieces[] = Html::openElement( 'head' );
 
                if ( $this->getHTMLTitle() == '' ) {
@@ -3050,7 +3051,7 @@ class OutputPage extends ContextSource {
                }
 
                $pieces[] = Html::element( 'title', null, $this->getHTMLTitle() );
-               $pieces[] = $this->getRlClient()->getHeadHtml();
+               $pieces[] = $this->getRlClient()->getHeadHtml( $htmlAttribs['class'] ?? null );
                $pieces[] = $this->buildExemptModules();
                $pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
                $pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
index e17b393..151b5fd 100644 (file)
@@ -240,19 +240,22 @@ class ResourceLoaderClientHtml {
         * - Inline scripts can't be asynchronous.
         * - For styles, earlier is better.
         *
+        * @param string|null $nojsClass Class name that caller uses on HTML document element
         * @return string|WrappedStringList HTML
         */
-       public function getHeadHtml() {
+       public function getHeadHtml( $nojsClass = null ) {
                $nonce = $this->options['nonce'];
                $data = $this->getData();
                $chunks = [];
 
                // Change "client-nojs" class to client-js. This allows easy toggling of UI components.
                // This must happen synchronously on every page view to avoid flashes of wrong content.
-               // See also #getDocumentAttributes() and /resources/src/startup.js.
-               $script = <<<'JAVASCRIPT'
-document.documentElement.className = document.documentElement.className
-       .replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );
+               // See also startup/startup.js.
+               $nojsClass = $nojsClass ?? $this->getDocumentAttributes()['class'];
+               $jsClass = preg_replace( '/(^|\s)client-nojs(\s|$)/', '$1client-js$2', $nojsClass );
+               $jsClassJson = ResourceLoader::encodeJsonForScript( $jsClass );
+               $script = <<<JAVASCRIPT
+document.documentElement.className = {$jsClassJson};
 JAVASCRIPT;
 
                // Inline script: Declare mw.config variables for this page.
index e1ee324..4152cdf 100644 (file)
@@ -108,7 +108,7 @@ Deprecation message.' ]
 
                // phpcs:disable Generic.Files.LineLength
                $expected = '<script>'
-                       . 'document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");'
+                       . 'document.documentElement.className="client-js";'
                        . 'RLCONF={"key":"value"};'
                        . 'RLSTATE={"test.exempt":"ready","test.private":"loading","test.styles.pure":"ready","test.styles.private":"ready","test.styles.deprecated":"ready"};'
                        . 'RLPAGEMODULES=["test"];'
@@ -135,7 +135,7 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
+               $expected = '<script>document.documentElement.className="client-js";</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;raw=1&amp;target=example"></script>';
                // phpcs:enable
 
@@ -152,7 +152,7 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
+               $expected = '<script>document.documentElement.className="client-js";</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;raw=1&amp;safemode=1"></script>';
                // phpcs:enable
 
@@ -169,7 +169,7 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
+               $expected = '<script>document.documentElement.className="client-js";</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;raw=1"></script>';
                // phpcs:enable