追記:
タイトルが長かったため
「SyntaxHighlighter:ページの表示速度を改善するため、ページ内にSyntaxHighlighterを使用する箇所がある場合に、jsとcssを読み込むようにした」
を
「ページ表示速度改善:SyntaxHighlighter使用箇所があれば読み込む」
に修正しました。
SyntaxHighlighterを使用するとページに記載したソースコードをきれいに表示することができます。タイトルが長かったため
「SyntaxHighlighter:ページの表示速度を改善するため、ページ内にSyntaxHighlighterを使用する箇所がある場合に、jsとcssを読み込むようにした」
を
「ページ表示速度改善:SyntaxHighlighter使用箇所があれば読み込む」
に修正しました。
はじめに
しかし、SyntaxHighlighterを利用する場合、(当然ですが)外部のJavaScriptとスタイルシートを読み込む必要があり、その分表示が遅くなります。
従って、SyntaxHighlighterを使用しているページならその表示遅延は許容せざるを得ませんが、SyntaxHighlighterを使用していないページまでその表示遅延を許容する必要はありません。
そこで、SyntaxHighlighterの使用状況に応じて、読み込むSyntaxHighlighterのJavaScriptとスタイルシートを動的に変更する仕組みを考えてみました。
今回は前回作成した SyntaxHighlighter の動的読み込み JavaScript を 少し修正し、Blogger に設置してみました。
Blogger で使用している SyntaxHighlighter の機能
私の Blogger で使用している SyntaxHighlighter の機能は以下のとおりです。<!-- SyntaxHighlighter START --> <link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/> <link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'> </script> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'> </script> <script language='javascript' type='text/javascript'> SyntaxHighlighter.config.bloggerMode = true; SyntaxHighlighter.all(); </script> <!-- SyntaxHighlighter END -->
これらを読み込めるように、前回作成した JavaScript を修正します。
必要な SyntaxHighlighter の機能を読み込めるように修正した Blogger用のJavaScript
Blogger用のJavaScript と書いてますが、<script type="text/javascript"></script>のすぐ内側に//<![CDATA[ と //]]> を追加しただけです。それ以外の部分はそのまま普通の Web ページに設置できる形をとっています。
<script type="text/javascript">
//<![CDATA[ <!-- (function () { // --- デバッグ用 Util ------------------------------------------- var isDebug = true; // デバッグフラグ function log(txt) { if (isDebug) { console.log(txt); } } (function () { // consoleが使えない場合は空のオブジェクトを設定しておく if (typeof console === "undefined") { console = {}; } // console.@@がメソッドでない場合は空のメソッドを用意する if (typeof console.log !== "function") { console.log = function () { }; } })(); // --- Util ------------------------------------------- // css動的挿入 function addStyleSheet(href) { log("LoadMinimumSyntaxHighlighter, addStyleSheet, href=" + href); var link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); link.setAttribute("href", href); header_setChild(link); } // JavaScript動的挿入 function addScript(src, sync) { log("LoadMinimumSyntaxHighlighter, addScript, src=" + src + ", sync=" + sync); var script = document.createElement('script'); script.setAttribute("type", "text/javascript"); script.setAttribute("src", src); // 同期的に読み込むように指定されていた場合、 // スクリプトの終了を検出するコードを埋め込み if (sync) { script.onload = script.onreadystatechange = function () { log("LoadMinimumSyntaxHighlighter, onload|onreadystatechange, script.readyState=" + script.readyState); // onload イベント もしくは onreadystatechange イベントで 読み込みが完了状態 のいずれかだったら // IE と その他ブラウザに対応するために onload と onreadystatechange の両方のイベントに対応している if (!script.readyState || /loaded|complete/.test(script.readyState)) { script.onload = script.onreadystatechange = null; // 非同期メソッドの終了を通知する runSync_NotifyAsyncMethodEnd() log("LoadMinimumSyntaxHighlighter, ScriptLoaded, script.readyState=" + script.readyState); } }; // 非同期処理である JavaScript の動的挿入を同期的に実行する runSync_AsyncMethod(function () { header_setChild(script); }); } else { header_setChild(script); } } // <head>取得 function getHeader() { return document.getElementsByTagName("head")[0]; } // <head>に子要素を追加 function header_setChild(child) { var head = getHeader(); head.appendChild(child); } // 同期実行:即終了メソッド function runSync_SyncMethod(func) { runSync(function () { log("LoadMinimumSyntaxHighlighter, SyncMethod, Start"); syncRunningFlag = true; func(); syncRunningFlag = false; log("LoadMinimumSyntaxHighlighter, SyncMethod, End"); }); } // 同期実行:非同期メソッド function runSync_AsyncMethod(func) { runSync(function () { log("LoadMinimumSyntaxHighlighter, AsyncMethod, Start"); syncRunningFlag = true; func(); /* syncRunningFlag = false; は非同期メソッドの終了イベントに委譲 */ log("LoadMinimumSyntaxHighlighter, AsyncMethod, TrigEnd"); }); } // 同期実行:非同期メソッドの終了を通知する function runSync_NotifyAsyncMethodEnd() { syncRunningFlag = false; // 同期的に実行するためのチェーン処理 runSyncChain(); } // 要素の同期的実行 var syncFuncArray = new Array(); // 実行待ち配列(先頭から実行されていく) var syncRunningFlag = false; // 同期実行中フラグ function runSync(func) { // 同期実行中かつ実行待ちメソッドがなければ即実行するが、 // それ以外であれば、実行待ち状態にする if ((!syncRunningFlag) && (syncFuncArray.length == 0)) { log("LoadMinimumSyntaxHighlighter, runSync, NowRun"); runSyncChainAfterRunFunc(func); } else { log("LoadMinimumSyntaxHighlighter, runSync, RunLater"); syncFuncArray.push(function () { runSyncChainAfterRunFunc(func); }); } } // 同期処理の必要なメソッドを実行した後に、同期的に実行するためのチェーン処理を実施 function runSyncChainAfterRunFunc(func) { func(); runSyncChain(); } // 同期的に実行するためのチェーン処理 function runSyncChain() { log("LoadMinimumSyntaxHighlighter, runSyncChain, Start, syncRunningFlag=" + syncRunningFlag + ", syncFuncArray.length=" + syncFuncArray.length); // 処理未実行状態 かつ 実行待ちメソッドがある場合に実行待ちメソッドを実行 if (!syncRunningFlag) { if (syncFuncArray.length > 0) { log("LoadMinimumSyntaxHighlighter, runSyncChain, RunSyncChain, Start"); // 先頭の実行待ちメソッドを取り出し、実行待ちから削除した後実行 var func = syncFuncArray[0]; syncFuncArray.splice(0, 1); func(); log("LoadMinimumSyntaxHighlighter, runSyncChain, RunSyncChain, End"); } } log("LoadMinimumSyntaxHighlighter, runSyncChain, End, syncRunningFlag=" + syncRunningFlag + ", syncFuncArray.length=" + syncFuncArray.length); } // --- main ------------------------------------------- LoadMinimumSyntaxHighlighter(); // 最低限の SyntaxHighlighter を読み込む function LoadMinimumSyntaxHighlighter() { log("LoadMinimumSyntaxHighlighter, Start"); var commonURL = "http://alexgorbatchev.com/pub/sh/current/"; // 共通 URL var scriptURL = commonURL + "scripts/"; var cssURL = commonURL + "styles/"; var brushURLs = new Array(); // 各ブラシ用 URL brushURLs["js"] = scriptURL + 'shBrushJScript.js'; brushURLs["xml"] = scriptURL + 'shBrushXml.js'; brushURLs["csharp"] = scriptURL + 'shBrushCSharp.js'; brushURLs["cpp"] = scriptURL + 'shBrushCpp.js'; brushURLs["css"] = scriptURL + 'shBrushCss.js'; brushURLs["java"] = scriptURL + 'shBrushJava.js'; brushURLs["perl"] = scriptURL + 'shBrushPerl.js'; brushURLs["plain"] = scriptURL + 'shBrushPlain.js'; brushURLs["vb"] = scriptURL + 'shBrushVb.js'; /* <pre> を検索し、SyntaxHighlighter のブラシを検索する ブラシが見つかったら、ブラシに応じた js を読み込む 初期発見時には共通の css と js を読み込む */ var brushCount = 0; // 見つかったブラシの数 var preTags = document.getElementsByTagName("pre"); for (var i = 0; i < preTags.length; i++) { var target = /(brush:\s*)([^\s]+)/; // ブラシを発見するための正規表現 var found = preTags[i].className.match(target); if (found != null) { // 初回発見時は共通データの読み込みを実施 if (brushCount == 0) { log("LoadMinimumSyntaxHighlighter, LoadCommon, Start"); addStyleSheet(cssURL + 'shCore.css'); addStyleSheet(cssURL + 'shThemeDefault.css'); addScript(scriptURL + 'shCore.js', true); log("LoadMinimumSyntaxHighlighter, LoadCommon, End"); } // ブラシ名からスクリプトを読み込む addScriptFromBrush(found[2]); brushCount++; } } // ページ内にブラシが存在したら、SyntaxHighlighter の使用準備を実行 if (brushCount > 0) { runSync_SyncMethod(function () { log("LoadMinimumSyntaxHighlighter, SyntaxHighlighter, Init, Start"); SyntaxHighlighter.config.bloggerMode = true; SyntaxHighlighter.all(); log("LoadMinimumSyntaxHighlighter, SyntaxHighlighter, Init, End"); }); } log("LoadMinimumSyntaxHighlighter, End"); // 各ブラシに対応するスクリプトの読み込みを行う function addScriptFromBrush(brush) { switch (brush) { case "js": case "jscript": case "javascript": addScriptFirst("js", brushURLs); break; case "xml": case "xhtml": case "xslt": case "html": case "xhtml": addScriptFirst("xml", brushURLs); break; case "csharp": case "c-sharp": addScriptFirst("csharp", brushURLs); break; case "cpp": case "c": addScriptFirst("cpp", brushURLs); break; case "css": addScriptFirst("css", brushURLs); break; case "java": addScriptFirst("java", brushURLs); break; case "perl": case "pl": addScriptFirst("perl", brushURLs); break; case "plain": case "text": addScriptFirst("plain", brushURLs); break; case "vb": case "vbnet": addScriptFirst("vb", brushURLs); break; default: log("LoadMinimumSyntaxHighlighter, addScriptFromBrush, Brush Not Found"); } } // 初回のみスクリプトの読み込みを実施 function addScriptFirst(type, URLs) { if (URLs[type] != "") { log("LoadMinimumSyntaxHighlighter, addScriptFirst, type=" + type + ", URLs[type]=" + URLs[type]); addScript(URLs[type], true); URLs[type] = ""; } } } })(); //--> //]]> </script>
Blogger への設置
以前のコードは<head>内に設置していましたが、今回私が作成したソースコードはSyntaxHighlighterで処理対象の<pre>が全て読み込まれた段階で実行するように調整します。そこで、</body>のすぐ上に設置することにしました。
結果
表示・読み込まれたファイル
変更前
↓
変更後
変更前・変更後の変化からわかるように、変更後は変更前では読み込まれていたページで使用されていないSyntaxHighlighterの機能の JavaScript は読み込まれていません。
かつ、ページのソースコードに SyntaxHighlighter が適用され、ソースコードがきれいに表示されています。
Blogger への SyntaxHighlighter の動的必要最低限機能の読み込み JavaScript の設置は成功です!!
まとめ
Blogger への SyntaxHighlighter の動的必要最低限機能の読み込み JavaScript の設置は成功しました。今回設置した JavaScript コードは全く最適化されていないものです。
次回は 最適化した JavaScript コードを設置し、ページの読み込み速度の計測を行いたいと思います。
コメントを投稿
コメント投稿機能について