Wonderful! WordPress

Google PAGESPEED INSIGHTS との闘い - それから

このページは、「Google PAGESPEED INSIGHTS との闘い」の続編となるページです。

その後・・・。

ノンブロッキングなスクリプトの読み込み

javascript に関連することの見直しを改めて。
前述してる「 O’REILLY High Performance JavaScript 」にあった、ノンブロッキングなスクリプトの読み込みというのをやってみた。
インラインで JavaScript ファイルを動的に読み込むための必要なコードだけを書いておいて、それを使ってページに必要な JavaScript ファイルをロードさせるとのこと。ページ内に置かれるコードの量を可能な限り小さくすることで、そのダウンロードと実行を非常にすばやく行うことが可能になり、スクリプトの読み込みと実行がページに与える悪影響を最小限に抑えることができるということだ。で、これはなかなか期待大なのであった。
我が WordPress DIY のページにおいては、prism 関連で2つ、自作プラグインのコメント編集機能で一つ、そしてメインの js ファイルということで4つの js ファイルをロードさせてる。やった内容は、その本からほぼそのままで使わせてもらったので、ここに載せるのはちょっと気が引ける。まっ、ソースをみれば・・・、なんだけれど。
そして細かいところで、javascript のコードにおいてループだとか条件文とか DOM の更新とかでわずがでも改善できそうなところを少し直してみた。実は前編に載せているコードにおいても連想配列の部分は全て配列に置き換えてしまった。そのあたりのことは極めて初歩的なことだけれども、ベンチなどしたことも含めて次のページのネタにするつもり。
で、その結果は・・・。

PC の方はそれなりに努力した結果が出たような気がするが、モバイルの方は逆に悪くなってしまった。なんだろうなこりゃ?ノンブロッキングな読み込みが原因なのだろうか?
後日、改めて計測してみると、 PC が 94、モバイルが 84 という結果だったので、計測したときの状況とかでのゆらぎなのだろうか。
とりあえず、大きな背景画像を使ってもいるし PC の方はこんなものだろうかと思うのだけれど、モバイルの方はどうにも納得できないので、やはりスクリプトの読み込みを元にもどしてみると、数値もそれぞれに元の数値へと落ち着く。PC の方は速くなるけれどモバイルの方は逆に悪化してしまうというのは実際のデバイスにおいても本当にそういう結果がでるのだろうか。よくわからない。

モバイルの方はといえば、大きな背景画像も使っていないのにということで、まだまだ改善の余地がありそうだが。さて、いったい何をやればいいのか?というところで。

Largest Contentful Paint (LCP) 最大コンテンツの描画の改善

ちょっと気になるのが、「最大コンテンツの描画」というところ。確かにここのページは全ての本文が一つの div タグに入っている。内容物は p とか span とかに入ってはいるけれど。その一つの div に、ということが問題なのだろうか?と思い、コンテンツをいくつかの div に分けて細切れにしてみた。すると、その結果は・・・。

と、言う具合。
PC は変わらず、モバイルに関してはかなり改善された。確かにより良い数値の出る別のいくつかのページにおいては、細切れになっているそれぞれの div の内容がもっと少なかったりするので、細切れにした一つ一つの div の内容をもっと少なくすれば、より数値は上がりそうである。
でもなぁ、意味なく細切れにするというのは、コンテンツを意味のあるマークアップにするという方向とは逆行するのではないだろうか。何か違うような気がする。
しかし、以前の classic editor で書いている投稿に関しては、細切れにするのは骨が折れる。どうすっかな?
その点でいえば、最近の投稿で使っている block editor の方は、グループがあるのでまだ楽そうなんだけれど、しかしそもそも Gutenberg を使うこと自体で表示が遅くなっていると思わざるをえないし、そのグループ化にしても親子2つの div でラッピングされるという具合で、なぜ二重の囲いが必要なのかも疑問であるし。階層が深くなってしまうだけなのに・・・。と、いうことで自分としてはただ細切れにするだけの用途であるし、Gutenberghandbook サイトには、innerblock のチュートリアルにそのままズバリの innerblock の div のコードがあるので、 すぐにそれを装備することとなる。ただ、既存の投稿は書き換えるのが面倒なので、それを使うのは新規の投稿になるかと思いつつも・・・。どうせ書き換えるのなら、text editor にしてしまったほうがいいと思うし。text editor で、p タグを記入して wpautopshortcode の処理を通らないようにすれば、速度的にはそれが一番だと思う。ただし、投稿者が自分だけということが前提であるけれど。
と、いいつつも、本当にそうだろうかと思い、やはり実際に試してみないことにははじまらない。もともと block editor で書いていたページ( JavaScript をわずかでも速くするために )を text editor に変換し、いらない block editor 用のコメントやら class やらを取り去って試してみた。なお、p タグも br タグも既にはいっており、div で細切れになっていた。そして wpautopdo_shortcode も通さずに出来る状況。なお、block editor 時の結果は PC 94、モバイル 84 という点数。いざいざ・・・。
が、結果は予想外となった。text editor においての結果は、PC 93、モバイル 85 というもの。あれ~!ほとんどかわらなかった、って、そんなことはないだろう~?と、いう感じがするのだけれど。
と、いうことで Gutenberg でも速度的にはほとんどかわらないよう。ちょっとがっかりしたような、ほっとしたような、びみょう~な心持ちなのです。

ちなみに、この時点での我がサイトにおける PageSpeed Insights における最高点は 99。モバイルにおいて出たもの。もちろんWordPress サイト。まだこれといって速度対策を施していないページだった。やはり背景画像がない分、速いのだろうと思う。このページ、 PC においては 95点。

あと、元々の問題点として表示されていた、「CLS に関する問題: 0.25 超(パソコン)」。
これに関しては、手動により PageSpeed Insights で計測させた場合は、問題点として認識されないようであるが、Google Search Console の方には、36件のページが問題ありと表示されてる。
こっちでは出なくて、あっちでは出る、ということで、今ひとつわかりにくい部分ではあるのだけれど、もしかすると、動く a タグ(リンク)が、他の a タグの上に乗ってしまったりすることが問題なのかと思い、そのあたりの変更もしてみた。結果はすぐには出ないので、google の bot 待ち。それぐらいしか見当たらないのだけれどもね。

コンテンツの独自キャッシュ化

これまで対策してきた先のページに関しては、PC においてもモバイルにしても、まぁ、こんなところか、というレベルにはなったと思うわけで。しかるに、本文の量がものすごく多いとか、prism.js で処理する code タグの量が多いページとなると、状況は著しく違ってきたりする。
たとえば、ここなんてのもそう。「いまさらのさらば Crayon Syntax Highlighter」
PC なら 96 点が出るのにモバイルだと 73 点という具合。
なぜに同じページにおいてこんなにも違うのだろうか?しかも、モバイルの方がでかい画像が無い分、圧倒的に有利なはずなのに・・・?

まぁ、でも、ちょっと考えてみれば、モバイルにおいては処理能力が低く設定されているであろうし、であるならば、「Total Blocking Time」が圧倒的に悪いことからも、やはり javascript の重い処理があればその影響が強くでるということではないのだろうか。
と、いうことなら、単純に prism.js における処理を減らせば、それなりの効果が期待できそうではある。
と、いってもそれはなかなか簡単なことでもなさそうではあるし、思いつくのはページの本文のキャッシュ化ぐらい。
あらかじめ、生成されたページを prism.js で処理させたものを、ファイルなどに保存しておいて、ページにアクセスがあった場合はそのファイルから読み込んだものを表示させれば、ということ。それならば、アクセスのあるたびに prism.js で処理させることもなくなるし、prism.js 自体のロードも必要なくなるのではないだろうか。ただ、送信されるコンテンツのデータ量は、まちがいなく多くなるので、それがいかほどになるだろうか、といったところ。試してみる価値はありそうだ。

さてさて、必要なことはといえば・・・。

  • ページにアクセスがあった場合、そのページのキャッシュファイルが存在すればそのファイルをインクルードしてページを表示。
  • キャッシュファイルが存在しなければ、javascript によって主コンテンツを取得し、Ajax にてキャッシュファイルを保存。
  • 投稿が公開、編集されたときにその投稿のキャッシュファイルを消去。

と、いったところか。
prism.js 関連の付加的機能部分で、スクリーンサイズの違いで異なる動的な javascript の部分は、一度停止させておいてキャッシュファイルを作る必要があるなど、ちょっと手間が必要ではある。でもまぁ、投稿が編集されないかぎり同じキャッシュファイルを使い続ければいいので、手間がかかるのはその時だけですみそう。
作るもの自体はなんてことはなさそうなものですむ。

と、いうことでとりあえずテンプレート。
とある single.php をはしょってとりだせば・・・。
キャッシュファイルを作る投稿を指定し、ファイルがあればそれを読み込んで表示。なければ javascript で作成する処理を動かすためのフラグとなるタグを設定し通常のループに入る処理をして表示させる、というだけ。

<?php get_header(); ?>
	<section id="content">
        	<!-- id="maincont" の ariticle の全内容がキャッシュ対象 -->
		<article class="post" id="maincont">
		<?php
			$cache = '';
			$is_cache = false;
			$no_cache_tag = '';
			$currentid = $post->ID;
			$targetids= [ 158389 ];

            // とりあえず指定したページだけでキャッシュを保存するためそのページを ID で指定
			if ( in_array( $currentid, $targetids, true ) ) {
				$cache = dirname( __FILE__ ) . '/cache_data/cache_data_' . $currentid . '.php';
			}

			if ( $cache ) {
				$is_cache = file_exists( $cache );
			}

			if ( $is_cache ) {// その投稿のキャッシュファイルが存在する

				echo '<!-- use cache data contents -->';

               			 // prism.js ファイルのロード登録を消去
				wp_dequeue_script( 'prism_js' );

				include_once $cache;

			} else {
                // キャッシュファイル保存を指定したページで、キャッシュファイルが存在しない場合
                // javascript でキャッシュファイルを作るためのフラグとなるタグを生成、既存のタグでもなんでもいい
                // id="maincont" の ariticle の外に設置
				if ( $cache ) {
					$no_cache_tag = '<input type="hidden" id="nocache" value="' . $post->ID . '">';
				}
		?>
			<div class="inpost">

                <nav id="breadcrumbs"><p><a href="./">Bird photo</a>><a href="https://strix.main.jp/?page_id=16227">Wordpress DIY</a>><span id="curhere"><?php the_title(); ?></span></p></nav>
                <nav class="pagelink">
                    <span class="oldpage"><?php previous_post_link('%link »'); ?></span>
                    <span class="newpage"><?php next_post_link('« %link'); ?></span>
                </nav>

		        <?php if(have_posts()):while(have_posts()):the_post(); ?>
                    ・・・
                    the_content();
                    ・・・
                <?php endwhile;endif; ?>
            </div>
        <?php
            }
        ?>
        </article>
        <?php echo $no_cache_tag; ?>
PHP
CopyExpand

で、javascript の部分。

( function () {
	function send_cache_data() {
		const doc = document,
			tmpdata = doc.getElementById( 'maincont' ).innerHTML,
			data =  encodeURIComponent( tmpdata ),
			dataid = doc.getElementById( 'nocache' ).value,
			wpajaxurl = 'https://strix.main.jp/wp/wp-admin/admin-ajax.php',
			strsend = 'action=make_page_cache&dataid=' + dataid + '&data=' + data;
		
		var req=new XMLHttpRequest();
    
		req.open( 'POST', wpajaxurl, true );
		req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
		req.send( strsend );	
	}	

	window.addEventListener( 'load', function() {
		if ( null !== document.getElementById( 'nocache' ) ) {
			send_cache_data();
		}
	});	
}());
JavaScript
CopyExpand

そして、javascript からAjax でコンテンツデータを受け取ってファイルに保存する php の関数。

<?php
    function make_page_cache() {

        $dataid = isset( $_POST['dataid'] ) ? $_POST['dataid'] : '';
        $data = isset( $_POST['data'] ) ? $_POST['data'] : '';
        // ↓たぶん $_POST に代入される時点で自動的に urldecode されるのでわざわざデコードさせる必要はないようだ
        // $data = urldecode( $data );
        // ↓ただし、"、'、\、などはエスケープされているのでそれを戻す必要がある
        $data = str_replace( array( '\"', '\\\'', '\\\\' ), array( '"', '\'', '\\' ), $data );

        if ( $dataid and $data ) {
            $cache_file = get_stylesheet_directory() . '/cache_data/cache_data_' . $dataid . '.php';

            if ( ! file_exists( $cache_file ) ) {// ファイルが無い時だけ
                $res = file_put_contents( $cache_file, $data, LOCK_EX );
            } else {
                echo 'error:already file exists';
                exit;
            }

            if ( $res ) {
                echo 'success';
            } else {
                echo 'error:enable cache save:' . $res;
            }
        } else {
            echo 'error:no send data';
        }

        exit;
    }
    add_action( 'wp_ajax_make_page_cache', 'make_page_cache' );
    add_action( 'wp_ajax_nopriv_make_page_cache', 'make_page_cache' );
?>
PHP
CopyExpand

javascripthtml データを送信するには encodeURIComponent でエンコードしておかないと、php 側でデータを受け取ってそれぞれのパラメータに分割する時に、データが “>” などの文字で途中でちぎれてしまう。それと、”、’、\、などはエスケープされているのでそれも戻さなくてはいけない。

そしてもう一つ、投稿が公開、または編集されたときにキャッシュファイルを消去する処理。これに関しては、以前によく調べて記事にしている部分なんだけれども、う~、なんてこった、すっかり忘れてしまった。これで良かったはず。

<?php
    function cache_dell( $post_id, $post, $update ) {

        //自動保存なら無効
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }

        $pstate = $post->post_status;
    
        // 投稿が publish(公開)のステイタスを持っているときだけ
        if ( 'publish' === $pstate ) {
        
            $cache_file = get_stylesheet_directory() . '/cache_data/cache_data_' . ( string )$post_id . '.php';

            if ( file_exists( $cache_file ) ) {
                unlink ( $cache_file );
            }
        }
    }
 // カスタム投稿 "diys" だけで動く save_post フック
    add_action('save_post_diys','cache_dell', 10, 3 );
?>
PHP
CopyExpand

と、いうことでその結果はいかなるものに・・・!

PC は 96 ポイントで同じ?、モバイルの方は 90 ポイントということでかなり改善された。「Total Blocking Time」に関しては、920ミリ秒が380ミリ秒に。これはまぁ、予想通り、かなりの効果があるということだと思うが、PC の方が変わらずというのがちょっと疑問?もしかするとモバイルの方も、もう少し良い結果がでた可能性があるかも。
ちなみに、ちょっと気になっていた、そのページ 「いまさらのさらば Crayon Syntax Highlighter」の、キャッシュファイルのサイズはといえば、124KB で画像一枚ほど。気にするほどのものではなかった。

ちなみに、このページの値はといえば、PC 97、モバイル 96 でキャッシュファイルサイズは 56KB。
このページよりも相当に文字数も code ブロックも多い、前篇である「Google PAGESPEED INSIGHTS との闘い」の方は、PC 94、モバイル 94 と同スコア。で、キャッシュファイルサイズは 118KB。ちょうど倍ほどあるということになる。モバイルも安定して PC とほぼ同程度のスコアがでるようになった。

と、一応ある程度の結果も得られたし、ということでとりあえずこの件はこれにて。
ぼちぼち、キャッシュファイルを保存させていくことになりまする。

キャッシュファイルの保存に関しても忘れないように書いておかないと、と。
ページ読み込みの際に javascript で動的に html 要素を追加などさせていると、その状態でキャッシュファイルとして保存してしまうと、その動的に付加される要素がダブってしまうことになる。まぁ、コードの書き方によるところもあるけれど・・・。ゆえに、キャッシュを保存する時はその動的に追加する部分の javascript を停止させておく必要がある。そのあたりが、ちょっと面倒くさいのでワンタッチでできるようにもう少し手を入れることとなる。
理屈はこんな具合。

  • 自分がアクセスした時にだけ表示させる要素をページに仕込み、例えばその ID を makecache とかにする。
  • その要素をクリックした時に、そのページの url に、例えば svcache=en とかパラメータをつけてリロードさせる。
  • ページロードの時に、例えば svcache=en のパラメータがついていたら、停止させるべき javascript をロードさせないようにする。
  • そして、もし既にそのページのキャッシュファイルが存在していたらそれを消去する。
  • そのうえで javascript でキャッシュファイルを保存するための Ajax を動かすためのフラグとなる html の要素を仕込む。

という具合でよさそうだ。
まずは先述の single.php を変更する。

<?php get_header(); ?>
	<section id="content">
        <!-- id="maincont" の ariticle の全内容がキャッシュ対象 -->
		<article class="post" id="maincont">
		<?php
			$cache = '';
			$is_cache = false;
			$no_cache_tag = '';
			$currentid = $post->ID;
            // ↓キャッシュを作る時に動かしたくない javascript 用
            // この配列に 投稿ID を入れ、それをfooter.phpにおいて条件式に使う
            // べつに配列じゃなくてもただの boolean な変数でもいいけれど・・・
            $negtloadids = [];

            // url にsvcache というパラメータがついていたら新規にキャッシュファイルを保存するべく処理に入る
            if ( isset( $_GET['svcache'] ) ) {
				$cache = dirname( __FILE__ ) . '/diy_cache/diy_cache_' . $currentid . '.php';
				if ( file_exists( $cache ) ) {
					unlink ( $cache );
				}
				$negtloadids[] = $currentid;
			}	

			$cache = dirname( __FILE__ ) . '/cache_data/cache_data_' . $currentid . '.php';
            $is_cache = file_exists( $cache );

			if ( $is_cache ) {// その投稿のキャッシュファイルが存在する

				echo '<!-- use cache data contents -->';

                // prism.js ファイルのロード登録を消去
				wp_dequeue_script( 'prism_js' );

				include_once $cache;

			} else {
                // $negtloadids が空じゃない場合は javascript を動かすためのフラグとなる要素を設置する
                // キャッシュするコンテンツ の外に設置
				if ( $negtloadids ) {
					$no_cache_tag = '<input type="hidden" id="nocache" value="' . $post->ID . '">';
				}
		?>
			<div class="inpost">

                <nav id="breadcrumbs"><p><a href="./">Bird photo</a>><a href="https://strix.main.jp/?page_id=16227">Wordpress DIY</a>><span id="curhere"><?php the_title(); ?></span></p></nav>
                <nav class="pagelink">
                    <span class="oldpage"><?php previous_post_link('%link »'); ?></span>
                    <span class="newpage"><?php next_post_link('« %link'); ?></span>
                </nav>

		        <?php if(have_posts()):while(have_posts()):the_post(); ?>
                    ・・・
                    the_content();
                    ・・・
                <?php endwhile;endif; ?>
            </div>
        <?php
            }
        ?>
        </article>
        <?php echo $no_cache_tag; ?>
PHP
CopyExpand

そして javascript のクリックイベント

( function () {
	window.addEventListener( 'load', function() {
		if ( null !== doc.getElementById( 'makecache' ) ) {
			doc.getElementById( 'makecache' ).onclick = function() {
				const cururl = location.href + '&svcache=en';

				location = cururl;	
			}
		}
	});	
}());
JavaScript
CopyExpand

わずかなものでした。
ではあるけれど、もう一つ、考えないといけないことがある。
コンテンツの内容が少ない投稿においては、キャッシュ化せずともモバイルで 90 以上のスコアが出るので、キャッシュ化するのは必然的に、文字数が相当に多いか、code ブロックにおいて prism.js による処理が多く必要な投稿のページということになる。これ、実際に試してみると、prism.js による加工が施される前に、コンテンツの内容が Ajax で送信されてしまうことがあったりする。と、いうことであるなら、Ajax での送信を、prism.js の処理が終わるまで待たせる必要が生じてくる。
この件においては、そのページの最後の code ブロックに prism.js にて生成される span タグのクラスである、token が存在するか否かで判断させることにした。
先述の、load イベントにおいての send_cache_data() 関数の呼び出しを以下のように変更してる。

( function () {
	window.addEventListener( 'load', function() {
		if ( null !== doc.getElementById( 'nocache' ) ) {
			const codes = doc.getElementsByTagName( 'code' ),
				codes_len = codes.length;

			if ( codes_len ) {
				let lastcode,
					intct = 0;

				lastcode = codes[ ( codes_len - 1 ) ];

				let codeId = setInterval( function() {
					intct++;
					if ( intct > 10 ) {
						clearInterval( codeId );
					}
	
					const token = lastcode.getElementsByClassName( 'token' );
	
					if ( token.length > 0 ) {
						clearInterval( codeId );

						send_cache_data();
					}
				}, 20 );
			}
		}

	});	
}());
JavaScript
CopyExpand

というわけで、これで意図したページだけをキャッシュファイル化することができるし、あとはキャッシュファイルの有無だけで判別させられるので他になんの設定もいらないしで。まぁ、javascript の都合上、キャッシュファイル化にしたくないページもいくつかあるし、そもそもキャッシュ化する必要のないページもあるということで、これがもっとも手間いらずで最善ではなかろうかと。
ちょっと、本文が増えたから PEGESPEED のスコアがわるくなったかな!

で、このあたりまで進んでやっと気がついたことが一つ。
実は、PAGESPEED INSIGHTS は、わざわざそのサイトにアクセスせずとも、Chrome のディベロッパーツールにある Lighthouse で測定することができたってこと。あれま!
私は Netscape の頃からの Mozilla 信者なもので、日頃必要がなければあまり Chrome のお世話になることはなく、やっと今頃になって気がついたという体たらくぶり。で、このページのスコア! はっ!モバイルの方が 97 でよくなった!

そしてもうひとつ。
Google Search Console の方に問題点として表示されていた「CLS に関する問題: 0.25 超(パソコン)」の36件。
動く a タグ(リンク)が、他の a タグの上を通過していた件を変更してから半月ほど経ったか。やはりそれが問題だったようでめでたく 0 件となった。

その後、こつこつと各ページの手直しをしてたら、このページ「知らなくて損してた$post->IDとかcssの::afterとか」において、PC で 100 ポイントが出た。コンテンツの容量がかなり少なめということもあるが、キャッシュ化していないにもかかわらずこの点数。ちなみにモバイルは 99 だった。サイト版の PAGESPEED INSIGHTS では、PC 97、モバイル 98 という値だった。そんなに大したことでもないのだろうけれど、やっぱり 100 点は気持ちいいもので。

そしてサイト全体の常時 SSL 化

で、実はこれでまだ終わらなかった。
と、いうのはついにというか、サイト全体の常時 SSL 化に踏み切った。
なんというか、google が推奨しはじめた時に、個人データなどほぼやりとりしないのに、なぜにそんなわざわざ遅くなるものを導入しないといけないのかと、はなはだ疑問をもっていたからなのだけれど。
でも、今になって少し気になったので改めて調べてみると、いまでは新しい規格にもなって、SSL の方が速くなるというではないか。もう、そうなると SSL 化しない手はない。
で、都合良くというか、自分がお世話になっているロリポップの共有SSL が今まで通りの url でプロトコルだけ https にすれば、SSL が使えるようになっていたと。
と、いうことで、ページの種類がそれなりに多いので、結構な手間がかかったけれど、サイト全体の常時 SSL 化ができた。結果的にはやはり速くなったようで、いくつかのページで PAGESPEED INSIGHTS において 100 のスコアを得ることができるようになった。ちなみにこのページも、Chrome Lighthouseモバイルで 100、PC で 99 のスコア。サイト版の PAGESPEED INSIGHTS では、両方とも 99 だった。
ちなみにサーバーはといえば、ロリポップのスタンダードプラン。で、このページはといえば、Gutenberg だけれどキャッシュ化されている。

と、いうことで、これにて終了!

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=165260

Sanbanse Funabashi
2011.01.01 sunrise

Top

スクロールさせるか画像をクリックすると元に戻ります。